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'
|
||||
|
||||
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 = {}
|
||||
|
@ -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)
|
||||
|
126
manual/epub.py
126
manual/epub.py
@ -6,89 +6,75 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__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 = '''\
|
||||
<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>Cover</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="%s"/>
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
||||
'''%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('</metadata>',
|
||||
('<meta name="cover" content="%s"/>\n'
|
||||
'<dc:date>%s</dc:date>\n</metadata>') %
|
||||
(href.replace('/', '_'), time.strftime('%Y-%m-%d')))
|
||||
raw = raw.replace('</manifest>',
|
||||
('<item id="{0}" href="{0}" media-type="application/xhtml+xml"/>\n</manifest>').\
|
||||
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)
|
||||
|
||||
|
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