mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Fix various bugs in the EPUB version of the User Manual and add workarounds for proper rendering in Adobe Digital Editions
This commit is contained in:
parent
62ce1a4e92
commit
7cce3562ab
@ -114,14 +114,13 @@ html_short_title = 'Start'
|
|||||||
html_logo = 'resources/logo.png'
|
html_logo = 'resources/logo.png'
|
||||||
|
|
||||||
epub_author = 'Kovid Goyal'
|
epub_author = 'Kovid Goyal'
|
||||||
kovid_epub_cover = 'epub_cover.jpg'
|
|
||||||
epub_publisher = 'Kovid Goyal'
|
epub_publisher = 'Kovid Goyal'
|
||||||
epub_identifier = 'http://manual.calibre-ebook.com'
|
epub_identifier = 'http://manual.calibre-ebook.com'
|
||||||
epub_scheme = 'url'
|
epub_scheme = 'url'
|
||||||
epub_uid = 'S54a88f8e9d42455e9c6db000e989225f'
|
epub_uid = 'S54a88f8e9d42455e9c6db000e989225f'
|
||||||
epub_tocdepth = 4
|
epub_tocdepth = 4
|
||||||
epub_tocdup = True
|
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.
|
# Custom sidebar templates, maps document names to template names.
|
||||||
#html_sidebars = {}
|
#html_sidebars = {}
|
||||||
|
@ -249,7 +249,6 @@ def template_docs(app):
|
|||||||
update_cli_doc('template_ref.rst', raw, info)
|
update_cli_doc('template_ref.rst', raw, info)
|
||||||
|
|
||||||
def setup(app):
|
def setup(app):
|
||||||
app.add_config_value('kovid_epub_cover', None, False)
|
|
||||||
app.add_builder(EPUBHelpBuilder)
|
app.add_builder(EPUBHelpBuilder)
|
||||||
app.add_builder(LaTeXHelpBuilder)
|
app.add_builder(LaTeXHelpBuilder)
|
||||||
app.connect('doctree-read', substitute)
|
app.connect('doctree-read', substitute)
|
||||||
|
126
manual/epub.py
126
manual/epub.py
@ -6,89 +6,75 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
import os, time, glob
|
import os
|
||||||
|
|
||||||
from lxml import etree
|
|
||||||
|
|
||||||
from sphinx.builders.epub import EpubBuilder
|
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):
|
class EPUBHelpBuilder(EpubBuilder):
|
||||||
name = 'myepub'
|
name = 'myepub'
|
||||||
|
|
||||||
def add_cover(self, outdir, cover_fname):
|
def build_epub(self, outdir, outname):
|
||||||
href = '_static/'+cover_fname
|
EpubBuilder.build_epub(self, outdir, outname)
|
||||||
opf = os.path.join(self.outdir, 'content.opf')
|
container = get_container(os.path.join(outdir, outname))
|
||||||
|
self.fix_epub(container)
|
||||||
|
container.commit()
|
||||||
|
|
||||||
cover = '''\
|
def fix_epub(self, container):
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
' Fix all the brokenness that sphinx\'s epub builder creates '
|
||||||
<head>
|
for name, mt in container.mime_map.iteritems():
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
if mt in OEB_DOCS:
|
||||||
<meta name="calibre:cover" content="true" />
|
self.workaround_ade_quirks(container, name)
|
||||||
<title>Cover</title>
|
pretty_html_tree(container, container.parsed(name))
|
||||||
<style type="text/css" title="override_css">
|
container.dirty(name)
|
||||||
@page {padding: 0pt; margin:0pt}
|
self.fix_opf(container)
|
||||||
body { text-align: center; padding:0pt; margin: 0pt; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
||||||
width="100%%" height="100%%" viewBox="0 0 600 800"
|
|
||||||
preserveAspectRatio="none">
|
|
||||||
<image width="600" height="800" xlink:href="%s"/>
|
|
||||||
</svg>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
'''%href
|
|
||||||
self.files.append('epub_titlepage.html')
|
|
||||||
open(os.path.join(outdir, self.files[-1]), 'wb').write(cover)
|
|
||||||
|
|
||||||
|
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()
|
def fix_opf(self, container):
|
||||||
raw = raw.replace('</metadata>',
|
spine_names = {n for n, l in container.spine_names}
|
||||||
('<meta name="cover" content="%s"/>\n'
|
spine = container.opf_xpath('//opf:spine')[0]
|
||||||
'<dc:date>%s</dc:date>\n</metadata>') %
|
rmap = {v:k for k, v in container.manifest_id_map.iteritems()}
|
||||||
(href.replace('/', '_'), time.strftime('%Y-%m-%d')))
|
# Add unreferenced text files to the spine
|
||||||
raw = raw.replace('</manifest>',
|
for name, mt in container.mime_map.iteritems():
|
||||||
('<item id="{0}" href="{0}" media-type="application/xhtml+xml"/>\n</manifest>').\
|
if mt in OEB_DOCS and name not in spine_names:
|
||||||
format('epub_titlepage.html'))
|
spine_names.add(name)
|
||||||
open(opf, 'wb').write(raw)
|
container.insert_into_xml(spine, spine.makeelement(OPF('itemref'), idref=rmap[name]))
|
||||||
|
|
||||||
def build_epub(self, outdir, *args, **kwargs):
|
# Remove duplicate entries from spine
|
||||||
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())
|
|
||||||
seen = set()
|
seen = set()
|
||||||
for x in root.xpath(
|
for item, name, linear in container.spine_iter:
|
||||||
'//*[local-name()="spine"]/*[local-name()="itemref"]'):
|
if name in seen:
|
||||||
idref = x.get('idref')
|
container.remove_from_xml(item)
|
||||||
if idref in seen:
|
seen.add(name)
|
||||||
x.getparent().remove(x)
|
|
||||||
else:
|
|
||||||
seen.add(idref)
|
|
||||||
|
|
||||||
with open(opf, 'wb') as f:
|
# Ensure that the meta cover tag is correct
|
||||||
f.write(etree.tostring(root, encoding='utf-8', xml_declaration=True))
|
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]
|
# Remove unreferenced files
|
||||||
root = etree.fromstring(open(ncx, 'rb').read())
|
for error in check_links(container):
|
||||||
seen = set()
|
if error.__class__ is UnreferencedResource:
|
||||||
for x in root.xpath(
|
container.remove_item(error.name)
|
||||||
'//*[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))
|
|
||||||
|
|
||||||
|
# Pretty print the OPF
|
||||||
|
pretty_opf(container.parsed(container.opf_name))
|
||||||
|
container.dirty(container.opf_name)
|
||||||
|
|
||||||
|
20
manual/templates/epub_cover_template.html
Normal file
20
manual/templates/epub_cover_template.html
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<meta name="calibre:cover" content="true" />
|
||||||
|
<title>{{ title }}</title>
|
||||||
|
<style type="text/css" title="override_css">
|
||||||
|
@page {padding: 0pt; margin:0pt}
|
||||||
|
body { text-align: center; padding:0pt; margin: 0pt; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
width="100%" height="100%" viewBox="0 0 600 800"
|
||||||
|
preserveAspectRatio="none">
|
||||||
|
<image width="600" height="800" xlink:href="{{ pathto('_static/' + image, 1) }}"/>
|
||||||
|
</svg>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user