mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 10:14:46 -04:00
Preserve existing nav markup when converting from EPUB 3 to EPUB 3
This commit is contained in:
parent
b7d88ff218
commit
09ffa06cc4
@ -289,7 +289,7 @@ class EPUBInput(InputFormatPlugin):
|
||||
|
||||
epub3_nav = opf.epub3_nav
|
||||
if epub3_nav is not None:
|
||||
self.convert_epub3_nav(epub3_nav, opf, log)
|
||||
self.convert_epub3_nav(epub3_nav, opf, log, options)
|
||||
|
||||
if len(parts) > 1 and parts[0]:
|
||||
delta = '/'.join(parts[:-1])+'/'
|
||||
@ -346,11 +346,11 @@ class EPUBInput(InputFormatPlugin):
|
||||
|
||||
return os.path.abspath(u'content.opf')
|
||||
|
||||
def convert_epub3_nav(self, nav_path, opf, log):
|
||||
def convert_epub3_nav(self, nav_path, opf, log, opts):
|
||||
from lxml import etree
|
||||
from calibre.ebooks.chardet import xml_to_unicode
|
||||
from calibre.ebooks.oeb.polish.parsing import parse
|
||||
from calibre.ebooks.oeb.base import EPUB_NS, XHTML, NCX_MIME, NCX
|
||||
from calibre.ebooks.oeb.base import EPUB_NS, XHTML, NCX_MIME, NCX, urlnormalize
|
||||
from calibre.ebooks.oeb.polish.toc import first_child
|
||||
from tempfile import NamedTemporaryFile
|
||||
with lopen(nav_path, 'rb') as f:
|
||||
@ -401,6 +401,9 @@ class EPUBInput(InputFormatPlugin):
|
||||
ncx_id = opf.add_path_to_manifest(f.name, NCX_MIME)
|
||||
for spine in opf.root.xpath('//*[local-name()="spine"]'):
|
||||
spine.set('toc', ncx_id)
|
||||
href = os.path.relpath(nav_path).replace(os.sep, '/')
|
||||
opts.epub3_nav_href = urlnormalize(href)
|
||||
opts.epub3_nav_parsed = root
|
||||
|
||||
def postprocess_book(self, oeb, opts, log):
|
||||
rc = getattr(self, 'removed_cover', None)
|
||||
|
@ -295,7 +295,8 @@ class EPUBOutput(OutputFormatPlugin):
|
||||
from calibre.ebooks.oeb.polish.container import EpubContainer
|
||||
container = EpubContainer(tdir, self.log)
|
||||
from calibre.ebooks.oeb.polish.upgrade import epub_2_to_3
|
||||
epub_2_to_3(container, self.log.info)
|
||||
existing_nav = getattr(self.opts, 'epub3_nav_parsed', None)
|
||||
epub_2_to_3(container, self.log.info, previous_nav=existing_nav)
|
||||
container.commit()
|
||||
os.remove(f.name)
|
||||
try:
|
||||
|
@ -655,14 +655,17 @@ def ensure_single_nav_of_type(root, ntype='toc'):
|
||||
return nav
|
||||
|
||||
|
||||
def commit_nav_toc(container, toc, lang=None, landmarks=None):
|
||||
def commit_nav_toc(container, toc, lang=None, landmarks=None, previous_nav=None):
|
||||
from calibre.ebooks.oeb.polish.pretty import pretty_xml_tree
|
||||
tocname = find_existing_nav_toc(container)
|
||||
if tocname is None:
|
||||
item = container.generate_item('nav.xhtml', id_prefix='nav')
|
||||
item.set('properties', 'nav')
|
||||
tocname = container.href_to_name(item.get('href'), base=container.opf_name)
|
||||
root = container.parse_xhtml(P('templates/new_nav.html', data=True).decode('utf-8'))
|
||||
if previous_nav is not None:
|
||||
root = previous_nav
|
||||
else:
|
||||
root = container.parse_xhtml(P('templates/new_nav.html', data=True).decode('utf-8'))
|
||||
container.replace(tocname, root)
|
||||
else:
|
||||
root = container.parsed(tocname)
|
||||
|
@ -100,7 +100,7 @@ guide_epubtype_map = {
|
||||
}
|
||||
|
||||
|
||||
def create_nav(container, toc, landmarks):
|
||||
def create_nav(container, toc, landmarks, previous_nav=None):
|
||||
lang = get_book_language(container)
|
||||
if lang == 'und':
|
||||
lang = None
|
||||
@ -109,10 +109,10 @@ def create_nav(container, toc, landmarks):
|
||||
entry['type'] = guide_epubtype_map.get(entry['type'].lower())
|
||||
if entry['type'] == 'cover' and container.mime_map.get(entry['dest'], '').lower() in OEB_DOCS:
|
||||
container.apply_unique_properties(entry['dest'], 'calibre:title-page')
|
||||
commit_nav_toc(container, toc, lang=lang, landmarks=landmarks)
|
||||
commit_nav_toc(container, toc, lang=lang, landmarks=landmarks, previous_nav=previous_nav)
|
||||
|
||||
|
||||
def epub_2_to_3(container, report):
|
||||
def epub_2_to_3(container, report, previous_nav=None):
|
||||
upgrade_metadata(container.opf)
|
||||
collect_properties(container)
|
||||
toc = get_toc(container)
|
||||
@ -123,7 +123,7 @@ def epub_2_to_3(container, report):
|
||||
landmarks = get_landmarks(container)
|
||||
for guide in container.opf_xpath('./opf:guide'):
|
||||
guide.getparent().remove(guide)
|
||||
create_nav(container, toc, landmarks)
|
||||
create_nav(container, toc, landmarks, previous_nav)
|
||||
container.opf.set('version', '3.0')
|
||||
fix_font_mime_types(container)
|
||||
container.dirty(container.opf_name)
|
||||
|
@ -179,6 +179,11 @@ class CSSFlattener(object):
|
||||
titlepage = titlepage.item
|
||||
if titlepage is not None and titlepage not in self.items:
|
||||
self.items.append(titlepage)
|
||||
epub3_nav = None
|
||||
if getattr(self.opts, 'epub3_nav_href', None):
|
||||
epub3_nav = self.oeb.manifest.hrefs.get(self.opts.epub3_nav_href)
|
||||
if epub3_nav is not None and epub3_nav not in self.items:
|
||||
self.items.append(epub3_nav)
|
||||
|
||||
self.filter_css = frozenset()
|
||||
if self.opts.filter_css:
|
||||
@ -210,6 +215,8 @@ class CSSFlattener(object):
|
||||
self.sbase = self.baseline_spine() if self.fbase else None
|
||||
self.fmap = FontMapper(self.sbase, self.fbase, self.fkey)
|
||||
self.flatten_spine()
|
||||
if epub3_nav is not None:
|
||||
self.opts.epub3_nav_parsed = epub3_nav.data
|
||||
|
||||
def get_embed_font_info(self, family, failure_critical=True):
|
||||
efi = []
|
||||
@ -436,12 +443,11 @@ class CSSFlattener(object):
|
||||
cssdict['font-weight'] = 'normal' # ADE chokes on font-weight medium
|
||||
|
||||
fsize = font_size
|
||||
is_drop_cap = (cssdict.get('float', None) == 'left' and 'font-size' in
|
||||
cssdict and len(node) == 0 and node.text and
|
||||
(len(node.text) == 1 or (len(node.text) == 2 and 0x2000 <= ord(node.text[0]) <= 0x206f)))
|
||||
is_drop_cap = (cssdict.get('float', None) == 'left' and 'font-size' in cssdict and len(node) == 0 and node.text and (
|
||||
len(node.text) == 1 or (len(node.text) == 2 and 0x2000 <= ord(node.text[0]) <= 0x206f)))
|
||||
# Detect drop caps generated by the docx input plugin
|
||||
if (node.tag and node.tag.endswith('}p') and len(node) == 0 and node.text and len(node.text.strip()) == 1 and
|
||||
not node.tail and 'line-height' in cssdict and 'font-size' in cssdict):
|
||||
if node.tag and node.tag.endswith('}p') and len(node) == 0 and node.text and len(node.text.strip()) == 1 and \
|
||||
not node.tail and 'line-height' in cssdict and 'font-size' in cssdict:
|
||||
dp = node.getparent()
|
||||
if dp.tag and dp.tag.endswith('}div') and len(dp) == 1 and not dp.text:
|
||||
if stylizer.style(dp).cssdict().get('float', None) == 'left':
|
||||
@ -473,8 +479,8 @@ class CSSFlattener(object):
|
||||
if cssdict:
|
||||
for x in self.filter_css:
|
||||
popval = cssdict.pop(x, None)
|
||||
if (self.body_font_family and popval and x == 'font-family' and
|
||||
popval.partition(',')[0][1:-1] == self.body_font_family.partition(',')[0][1:-1]):
|
||||
if self.body_font_family and popval and x == 'font-family' \
|
||||
and popval.partition(',')[0][1:-1] == self.body_font_family.partition(',')[0][1:-1]:
|
||||
cssdict[x] = popval
|
||||
|
||||
if cssdict:
|
||||
@ -499,8 +505,7 @@ class CSSFlattener(object):
|
||||
lineh = self.lineh / psize
|
||||
cssdict['line-height'] = "%0.5fem" % lineh
|
||||
|
||||
if (self.context.remove_paragraph_spacing or
|
||||
self.context.insert_blank_line) and tag in ('p', 'div'):
|
||||
if (self.context.remove_paragraph_spacing or self.context.insert_blank_line) and tag in ('p', 'div'):
|
||||
if item_id != 'calibre_jacket' or self.context.output_profile.name == 'Kindle':
|
||||
for prop in ('margin', 'padding', 'border'):
|
||||
for edge in ('top', 'bottom'):
|
||||
@ -510,8 +515,7 @@ class CSSFlattener(object):
|
||||
'%fem'%self.context.insert_blank_line_size
|
||||
indent_size = self.context.remove_paragraph_spacing_indent_size
|
||||
keep_indents = indent_size < 0.0
|
||||
if (self.context.remove_paragraph_spacing and not keep_indents and
|
||||
cssdict.get('text-align', None) not in ('center', 'right')):
|
||||
if (self.context.remove_paragraph_spacing and not keep_indents and cssdict.get('text-align', None) not in ('center', 'right')):
|
||||
cssdict['text-indent'] = "%1.1fem" % indent_size
|
||||
|
||||
pseudo_classes = style.pseudo_classes(self.filter_css)
|
||||
@ -618,8 +622,7 @@ class CSSFlattener(object):
|
||||
items = sorted(stylizer.page_rule.items())
|
||||
css = ';\n'.join("%s: %s" % (key, val) for key, val in items)
|
||||
css = ('@page {\n%s\n}\n'%css) if items else ''
|
||||
rules = [r.cssText for r in stylizer.font_face_rules +
|
||||
self.embed_font_rules]
|
||||
rules = [r.cssText for r in stylizer.font_face_rules + self.embed_font_rules]
|
||||
raw = '\n\n'.join(rules)
|
||||
css += '\n\n' + raw
|
||||
global_css[css].append(item)
|
||||
|
Loading…
x
Reference in New Issue
Block a user