mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Fix handling of covers in epub output. Various fixes for minor regressions.
This commit is contained in:
parent
16ab9fbf02
commit
6f5dd55f98
@ -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:
|
||||
|
@ -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 = {
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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())
|
||||
|
@ -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')):
|
||||
|
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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):
|
||||
|
Loading…
x
Reference in New Issue
Block a user