From 7cce3562ab40da12e000f72c8badb7d108feff8a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 13 Feb 2014 09:51:28 +0530 Subject: [PATCH] Fix various bugs in the EPUB version of the User Manual and add workarounds for proper rendering in Adobe Digital Editions --- manual/conf.py | 3 +- manual/custom.py | 1 - manual/epub.py | 126 ++++++++++------------ manual/templates/epub_cover_template.html | 20 ++++ 4 files changed, 77 insertions(+), 73 deletions(-) create mode 100644 manual/templates/epub_cover_template.html diff --git a/manual/conf.py b/manual/conf.py index 967b6f0c65..f30babc964 100644 --- a/manual/conf.py +++ b/manual/conf.py @@ -114,14 +114,13 @@ html_short_title = 'Start' html_logo = 'resources/logo.png' epub_author = 'Kovid Goyal' -kovid_epub_cover = 'epub_cover.jpg' epub_publisher = 'Kovid Goyal' epub_identifier = 'http://manual.calibre-ebook.com' epub_scheme = 'url' epub_uid = 'S54a88f8e9d42455e9c6db000e989225f' epub_tocdepth = 4 epub_tocdup = True -epub_pre_files = [('epub_titlepage.html', 'Cover')] +epub_cover = ('epub_cover.jpg', 'epub_cover_template.html') # Custom sidebar templates, maps document names to template names. #html_sidebars = {} diff --git a/manual/custom.py b/manual/custom.py index bffe3d914b..1351261004 100644 --- a/manual/custom.py +++ b/manual/custom.py @@ -249,7 +249,6 @@ def template_docs(app): update_cli_doc('template_ref.rst', raw, info) def setup(app): - app.add_config_value('kovid_epub_cover', None, False) app.add_builder(EPUBHelpBuilder) app.add_builder(LaTeXHelpBuilder) app.connect('doctree-read', substitute) diff --git a/manual/epub.py b/manual/epub.py index 5a20aea530..3a22f5d2ee 100644 --- a/manual/epub.py +++ b/manual/epub.py @@ -6,89 +6,75 @@ __license__ = 'GPL v3' __copyright__ = '2009, Kovid Goyal ' __docformat__ = 'restructuredtext en' -import os, time, glob - -from lxml import etree +import os from sphinx.builders.epub import EpubBuilder +from calibre.ebooks.oeb.base import OPF, DC +from calibre.ebooks.oeb.polish.container import get_container, OEB_DOCS +from calibre.ebooks.oeb.polish.check.links import check_links, UnreferencedResource +from calibre.ebooks.oeb.polish.pretty import pretty_html_tree, pretty_opf +from calibre.utils.magick.draw import identify_data + class EPUBHelpBuilder(EpubBuilder): name = 'myepub' - def add_cover(self, outdir, cover_fname): - href = '_static/'+cover_fname - opf = os.path.join(self.outdir, 'content.opf') + def build_epub(self, outdir, outname): + EpubBuilder.build_epub(self, outdir, outname) + container = get_container(os.path.join(outdir, outname)) + self.fix_epub(container) + container.commit() - cover = '''\ - - - - - Cover - - - - - - - - - '''%href - self.files.append('epub_titlepage.html') - open(os.path.join(outdir, self.files[-1]), 'wb').write(cover) + def fix_epub(self, container): + ' Fix all the brokenness that sphinx\'s epub builder creates ' + for name, mt in container.mime_map.iteritems(): + if mt in OEB_DOCS: + self.workaround_ade_quirks(container, name) + pretty_html_tree(container, container.parsed(name)) + container.dirty(name) + self.fix_opf(container) + def workaround_ade_quirks(self, container, name): + root = container.parsed(name) + # ADE blows up floating images if their sizes are not specified + for img in root.xpath('//*[local-name() = "img" and (@class = "float-right-img" or @class = "float-left-img")]'): + imgname = container.href_to_name(img.get('src'), name) + width, height, fmt = identify_data(container.raw_data(imgname)) + img.set('style', 'width: %dpx; height: %dpx' % (width, height)) - raw = open(opf, 'rb').read() - raw = raw.replace('', - ('\n' - '%s\n') % - (href.replace('/', '_'), time.strftime('%Y-%m-%d'))) - raw = raw.replace('', - ('\n').\ - format('epub_titlepage.html')) - open(opf, 'wb').write(raw) + def fix_opf(self, container): + spine_names = {n for n, l in container.spine_names} + spine = container.opf_xpath('//opf:spine')[0] + rmap = {v:k for k, v in container.manifest_id_map.iteritems()} + # Add unreferenced text files to the spine + for name, mt in container.mime_map.iteritems(): + if mt in OEB_DOCS and name not in spine_names: + spine_names.add(name) + container.insert_into_xml(spine, spine.makeelement(OPF('itemref'), idref=rmap[name])) - def build_epub(self, outdir, *args, **kwargs): - if self.config.kovid_epub_cover: - self.add_cover(outdir, self.config.kovid_epub_cover) - self.fix_duplication_bugs(outdir) - EpubBuilder.build_epub(self, outdir, *args, **kwargs) - - def fix_duplication_bugs(self, outdir): - opf = glob.glob(outdir+os.sep+'*.opf')[0] - root = etree.fromstring(open(opf, 'rb').read()) + # Remove duplicate entries from spine seen = set() - for x in root.xpath( - '//*[local-name()="spine"]/*[local-name()="itemref"]'): - idref = x.get('idref') - if idref in seen: - x.getparent().remove(x) - else: - seen.add(idref) + for item, name, linear in container.spine_iter: + if name in seen: + container.remove_from_xml(item) + seen.add(name) - with open(opf, 'wb') as f: - f.write(etree.tostring(root, encoding='utf-8', xml_declaration=True)) + # Ensure that the meta cover tag is correct + cover_id = rmap['_static/' + self.config.epub_cover[0]] + for meta in container.opf_xpath('//opf:meta[@name="cover"]'): + meta.set('content', cover_id) + # Add description metadata + metadata = container.opf_xpath('//opf:metadata')[0] + container.insert_into_xml(metadata, metadata.makeelement(DC('description'))) + metadata[-1].text = 'Comprehensive documentation for calibre' - ncx = glob.glob(outdir+os.sep+'*.ncx')[0] - root = etree.fromstring(open(ncx, 'rb').read()) - seen = set() - for x in root.xpath( - '//*[local-name()="navMap"]/*[local-name()="navPoint"]'): - text = x.xpath('descendant::*[local-name()="text"]')[0] - text = text.text - if text in seen: - x.getparent().remove(x) - else: - seen.add(text) - - with open(ncx, 'wb') as f: - f.write(etree.tostring(root, encoding='utf-8', xml_declaration=True)) + # Remove unreferenced files + for error in check_links(container): + if error.__class__ is UnreferencedResource: + container.remove_item(error.name) + # Pretty print the OPF + pretty_opf(container.parsed(container.opf_name)) + container.dirty(container.opf_name) diff --git a/manual/templates/epub_cover_template.html b/manual/templates/epub_cover_template.html new file mode 100644 index 0000000000..9cbcf49b0e --- /dev/null +++ b/manual/templates/epub_cover_template.html @@ -0,0 +1,20 @@ + + + + + {{ title }} + + + + + + + + +