~ubuntu-branches/debian/sid/calibre/sid

« back to all changes in this revision

Viewing changes to manual/epub.py

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2014-02-27 07:48:06 UTC
  • mto: This revision was merged to the branch mainline in revision 74.
  • Revision ID: package-import@ubuntu.com-20140227074806-64wdebb3ptosxhhx
Tags: upstream-1.25.0+dfsg
ImportĀ upstreamĀ versionĀ 1.25.0+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
6
6
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
7
7
__docformat__ = 'restructuredtext en'
8
8
 
9
 
import os, time, glob
10
 
 
11
 
from lxml import etree
 
9
import os
12
10
 
13
11
from sphinx.builders.epub import EpubBuilder
14
12
 
 
13
from calibre.ebooks.oeb.base import OPF, DC
 
14
from calibre.ebooks.oeb.polish.container import get_container, OEB_DOCS
 
15
from calibre.ebooks.oeb.polish.check.links import check_links, UnreferencedResource
 
16
from calibre.ebooks.oeb.polish.pretty import pretty_html_tree, pretty_opf
 
17
from calibre.utils.magick.draw import identify_data
 
18
 
15
19
class EPUBHelpBuilder(EpubBuilder):
16
20
    name = 'myepub'
17
21
 
18
 
    def add_cover(self, outdir, cover_fname):
19
 
        href = '_static/'+cover_fname
20
 
        opf = os.path.join(self.outdir, 'content.opf')
21
 
 
22
 
        cover = '''\
23
 
        <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
24
 
            <head>
25
 
                <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
26
 
                <meta name="calibre:cover" content="true" />
27
 
                <title>Cover</title>
28
 
                <style type="text/css" title="override_css">
29
 
                    @page {padding: 0pt; margin:0pt}
30
 
                    body { text-align: center; padding:0pt; margin: 0pt; }
31
 
                </style>
32
 
            </head>
33
 
            <body>
34
 
                <svg version="1.1" xmlns="http://www.w3.org/2000/svg"
35
 
                    xmlns:xlink="http://www.w3.org/1999/xlink"
36
 
                    width="100%%" height="100%%" viewBox="0 0 600 800"
37
 
                    preserveAspectRatio="none">
38
 
                    <image width="600" height="800" xlink:href="%s"/>
39
 
                </svg>
40
 
            </body>
41
 
        </html>
42
 
        '''%href
43
 
        self.files.append('epub_titlepage.html')
44
 
        open(os.path.join(outdir, self.files[-1]), 'wb').write(cover)
45
 
 
46
 
 
47
 
        raw = open(opf, 'rb').read()
48
 
        raw = raw.replace('</metadata>',
49
 
                ('<meta name="cover" content="%s"/>\n'
50
 
                 '<dc:date>%s</dc:date>\n</metadata>') %
51
 
                (href.replace('/', '_'), time.strftime('%Y-%m-%d')))
52
 
        raw = raw.replace('</manifest>',
53
 
                ('<item id="{0}" href="{0}" media-type="application/xhtml+xml"/>\n</manifest>').\
54
 
                        format('epub_titlepage.html'))
55
 
        open(opf, 'wb').write(raw)
56
 
 
57
 
    def build_epub(self, outdir, *args, **kwargs):
58
 
        if self.config.kovid_epub_cover:
59
 
            self.add_cover(outdir, self.config.kovid_epub_cover)
60
 
        self.fix_duplication_bugs(outdir)
61
 
        EpubBuilder.build_epub(self, outdir, *args, **kwargs)
62
 
 
63
 
    def fix_duplication_bugs(self, outdir):
64
 
        opf = glob.glob(outdir+os.sep+'*.opf')[0]
65
 
        root = etree.fromstring(open(opf, 'rb').read())
66
 
        seen = set()
67
 
        for x in root.xpath(
68
 
                '//*[local-name()="spine"]/*[local-name()="itemref"]'):
69
 
            idref = x.get('idref')
70
 
            if idref in seen:
71
 
                x.getparent().remove(x)
72
 
            else:
73
 
                seen.add(idref)
74
 
 
75
 
        with open(opf, 'wb') as f:
76
 
            f.write(etree.tostring(root, encoding='utf-8', xml_declaration=True))
77
 
 
78
 
 
79
 
        ncx = glob.glob(outdir+os.sep+'*.ncx')[0]
80
 
        root = etree.fromstring(open(ncx, 'rb').read())
81
 
        seen = set()
82
 
        for x in root.xpath(
83
 
                '//*[local-name()="navMap"]/*[local-name()="navPoint"]'):
84
 
            text = x.xpath('descendant::*[local-name()="text"]')[0]
85
 
            text = text.text
86
 
            if text in seen:
87
 
                x.getparent().remove(x)
88
 
            else:
89
 
                seen.add(text)
90
 
 
91
 
        with open(ncx, 'wb') as f:
92
 
            f.write(etree.tostring(root, encoding='utf-8', xml_declaration=True))
93
 
 
 
22
    def build_epub(self, outdir, outname):
 
23
        EpubBuilder.build_epub(self, outdir, outname)
 
24
        container = get_container(os.path.join(outdir, outname))
 
25
        self.fix_epub(container)
 
26
        container.commit()
 
27
 
 
28
    def fix_epub(self, container):
 
29
        ' Fix all the brokenness that sphinx\'s epub builder creates '
 
30
        for name, mt in container.mime_map.iteritems():
 
31
            if mt in OEB_DOCS:
 
32
                self.workaround_ade_quirks(container, name)
 
33
                pretty_html_tree(container, container.parsed(name))
 
34
                container.dirty(name)
 
35
        self.fix_opf(container)
 
36
 
 
37
    def workaround_ade_quirks(self, container, name):
 
38
        root = container.parsed(name)
 
39
        # ADE blows up floating images if their sizes are not specified
 
40
        for img in root.xpath('//*[local-name() = "img" and (@class = "float-right-img" or @class = "float-left-img")]'):
 
41
            if 'style' not in img.attrib:
 
42
                imgname = container.href_to_name(img.get('src'), name)
 
43
                width, height, fmt = identify_data(container.raw_data(imgname))
 
44
                img.set('style', 'width: %dpx; height: %dpx' % (width, height))
 
45
 
 
46
    def fix_opf(self, container):
 
47
        spine_names = {n for n, l in container.spine_names}
 
48
        spine = container.opf_xpath('//opf:spine')[0]
 
49
        rmap = {v:k for k, v in container.manifest_id_map.iteritems()}
 
50
        # Add unreferenced text files to the spine
 
51
        for name, mt in container.mime_map.iteritems():
 
52
            if mt in OEB_DOCS and name not in spine_names:
 
53
                spine_names.add(name)
 
54
                container.insert_into_xml(spine, spine.makeelement(OPF('itemref'), idref=rmap[name]))
 
55
 
 
56
        # Remove duplicate entries from spine
 
57
        seen = set()
 
58
        for item, name, linear in container.spine_iter:
 
59
            if name in seen:
 
60
                container.remove_from_xml(item)
 
61
            seen.add(name)
 
62
 
 
63
        # Ensure that the meta cover tag is correct
 
64
        cover_id = rmap['_static/' + self.config.epub_cover[0]]
 
65
        for meta in container.opf_xpath('//opf:meta[@name="cover"]'):
 
66
            meta.set('content', cover_id)
 
67
 
 
68
        # Add description metadata
 
69
        metadata = container.opf_xpath('//opf:metadata')[0]
 
70
        container.insert_into_xml(metadata, metadata.makeelement(DC('description')))
 
71
        metadata[-1].text = 'Comprehensive documentation for calibre'
 
72
 
 
73
        # Remove search.html since it is useless in EPUB
 
74
        container.remove_item('search.html')
 
75
 
 
76
        # Remove unreferenced files
 
77
        for error in check_links(container):
 
78
            if error.__class__ is UnreferencedResource:
 
79
                container.remove_item(error.name)
 
80
 
 
81
        # Pretty print the OPF
 
82
        pretty_opf(container.parsed(container.opf_name))
 
83
        container.dirty(container.opf_name)
94
84