Fix handling of covers in epub output. Various fixes for minor regressions.

This commit is contained in:
Kovid Goyal 2008-09-28 09:20:27 -07:00
parent 16ab9fbf02
commit 6f5dd55f98
9 changed files with 58 additions and 10 deletions

View File

@ -162,7 +162,7 @@ def fit_image(width, height, pwidth, pheight):
@param height: Height of image
@param pwidth: Width of box
@param pheight: Height of box
@return: scaled, new_width, new_height. scaled is True iff new_widdth and/or new_height is different from width or height.
@return: scaled, new_width, new_height. scaled is True iff new_width and/or new_height is different from width or height.
'''
scaled = height > pheight or width > pwidth
if height > pheight:

View File

@ -15,10 +15,12 @@ from calibre.ebooks.html import config as common_config, tostring
class DefaultProfile(object):
flow_size = sys.maxint
screen_size = None
class PRS505(DefaultProfile):
flow_size = 300000
flow_size = 300000
screen_size = (600, 775)
PROFILES = {

View File

@ -33,6 +33,8 @@ def mobi2opf(path, tdir, opts):
reader = MobiReader(path)
reader.extract_content(tdir)
files = list(walk(tdir))
opts.dont_preserve_structure = True
opts.encoding = 'utf-8'
for f in files:
if f.lower().endswith('.opf'):
return f

View File

@ -162,6 +162,15 @@ def convert(htmlfile, opts, notification=None):
spine = [htmlfile_map[f.path] for f in filelist]
if mi.cover:
cpath = '/'.join(('resources', os.path.basename(mi.cover)))
if opts.profile.screen_size is not None:
im = PILImage.open(os.path.join(tdir, 'content', *cpath.split('/')))
width, height = im.size
dw, dh = (opts.profile.screen_size[0]-width)/float(width), (opts.profile.screen_size[1]-height)/float(height)
delta = min(dw, dh)
if delta > 0:
nwidth = int(width + delta*(width))
nheight = int(height + delta*(height))
im.resize((int(nwidth), int(nheight)), PILImage.ANTIALIAS).convert('RGB').save(os.path.join(tdir, 'content', *cpath.split('/')))
cover = '''\
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head><title>Cover Page</title><style type="text/css">@page {padding: 0pt; margin:0pt}</style></head>

View File

@ -348,12 +348,16 @@ def split(pathtoopf, opts):
item.set('href', item.get('href').replace('&', '%26'))
html_files.append(f)
changes = []
always_remove = getattr(opts, 'dont_preserve_structure', False)
for f in html_files:
if os.stat(content(f)).st_size > opts.profile.flow_size:
try:
changes.append(Splitter(f, opts))
changes.append(Splitter(f, opts, always_remove=always_remove))
except SplitError:
changes.append(Splitter(f, opts, always_remove=True))
if not always_remove:
changes.append(Splitter(f, opts, always_remove=True))
else:
raise
changes[-1].fix_opf(opf)
open(pathtoopf, 'wb').write(opf.render())

View File

@ -356,6 +356,7 @@ class Parser(PreProcessor, LoggingInterface):
'''
ans = tostring(self.root, pretty_print=self.opts.pretty_print)
ans = re.compile(r'<html>', re.IGNORECASE).sub('<html xmlns="http://www.w3.org/1999/xhtml">', ans[:1000]) + ans[1000:]
ans = re.compile(r'<head>', re.IGNORECASE).sub('<head>\n\t<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\n', ans[:1000])+ans[1000:]
with open(self.save_path(), 'wb') as f:
f.write(ans)
@ -747,6 +748,7 @@ def create_metadata(basepath, mi, filelist, resources):
Create an OPF metadata object with correct spine and manifest.
'''
mi = OPFCreator(basepath, mi)
mi.guide = None
entries = [('content/'+f, 'application/xhtml+xml') for f in filelist] + [(f, None) for f in resources]
for f in filelist:
if os.path.exists(os.path.join(basepath, 'content', 'resources', f+'.css')):

View File

@ -162,7 +162,7 @@ class ManifestItem(Resource):
def from_opf_manifest_item(item, basedir):
href = item.get('href', None)
if href:
res = ManifestItem(href, basedir=basedir, is_path=False)
res = ManifestItem(href, basedir=basedir, is_path=True)
mt = item.get('media-type', '').strip()
if mt:
res.mime_type = mt
@ -607,6 +607,35 @@ class OPF(object):
matches[0].text = unicode(val)
return property(fget=fget, fset=fset)
@apply
def cover():
def fget(self):
if self.guide is not None:
for t in ('cover', 'other.ms-coverimage-standard', 'other.ms-coverimage'):
for item in self.guide:
if item.type.lower() == t:
return item.path
def fset(self, path):
if self.guide is not None:
self.guide.set_cover(path)
else:
g = etree.SubElement(self.root, 'opf:guide', nsmap=self.NAMESPACES)
self.guide = Guide()
self.guide.set_cover(path)
etree.SubElement(g, 'opf:reference', nsmap=self.NAMESPACES,
attrib={'type':'cover', 'href':self.guide[-1].href()})
id = self.manifest.id_for_path(self.cover)
if id is None:
for t in ('cover', 'other.ms-coverimage-standard', 'other.ms-coverimage'):
for item in self.guide:
if item.type.lower() == t:
self.create_manifest_item(item.href(), mimetypes.guess_type(path)[0])
return property(fget=fget, fset=fset)
def get_metadata_element(self, name):
matches = self.metadata_elem_path(self.metadata, name=name)
if matches:

View File

@ -21,8 +21,8 @@ def _config():
c = Config('gui', 'preferences for the calibre GUI')
c.add_opt('frequently_used_directories', default=[],
help=_('Frequently used directories'))
c.add_opt('send_to_device_by_default', default=True,
help=_('Send downloaded periodical content to device automatically'))
c.add_opt('send_to_storage_card_by_default', default=False,
help=_('Send file to storage card instead of main memory by default'))
c.add_opt('save_to_disk_single_format', default='lrf',
help=_('The format to use when saving single files to disk'))
c.add_opt('confirm_delete', default=False,

View File

@ -122,13 +122,13 @@ class Main(MainWindow, Ui_MainWindow):
sm.addAction(_('Send to storage card by default'))
sm.actions()[-1].setCheckable(True)
def default_sync(checked):
config.set('send_to_device_by_default', bool(checked))
config.set('send_to_storage_card_by_default', bool(checked))
QObject.disconnect(self.action_sync, SIGNAL("triggered(bool)"), self.sync_to_main_memory)
QObject.disconnect(self.action_sync, SIGNAL("triggered(bool)"), self.sync_to_card)
QObject.connect(self.action_sync, SIGNAL("triggered(bool)"), self.sync_to_card if checked else self.sync_to_main_memory)
QObject.connect(sm.actions()[-1], SIGNAL('toggled(bool)'), default_sync)
sm.actions()[-1].setChecked(config.get('send_to_device_by_default'))
sm.actions()[-1].setChecked(config.get('send_to_storage_card_by_default'))
default_sync(sm.actions()[-1].isChecked())
self.sync_menu = sm # Needed
md = QMenu()
@ -514,7 +514,7 @@ class Main(MainWindow, Ui_MainWindow):
'cover':self.default_thumbnail, 'tags':[]})
if not to_device:
model = self.current_view().model()
model = self.library_view.model()
html_pat = re.compile(r'\.x{0,1}htm(l{0,1})\s*$', re.IGNORECASE)
paths = list(paths)
for i, path in enumerate(paths):