1
from __future__ import with_statement
3
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
4
__docformat__ = 'restructuredtext en'
7
from itertools import cycle
11
from calibre.customize.conversion import InputFormatPlugin, OptionRecommendation
13
class EPUBInput(InputFormatPlugin):
16
author = 'Kovid Goyal'
17
description = 'Convert EPUB files (.epub) to HTML'
18
file_types = set(['epub'])
20
recommendations = set([('page_breaks_before', '/', OptionRecommendation.MED)])
23
def decrypt_font(cls, key, path):
24
raw = open(path, 'rb').read()
26
key = cycle(iter(key))
27
decrypt = ''.join([chr(ord(x)^key.next()) for x in crypt])
28
with open(path, 'wb') as f:
33
def process_encryption(cls, encfile, opf, log):
35
m = re.search(r'(?i)(urn:uuid:[0-9a-f-]+)', open(opf, 'rb').read())
38
key = list(map(ord, uuid.UUID(key).bytes))
40
root = etree.parse(encfile)
41
for em in root.xpath('descendant::*[contains(name(), "EncryptionMethod")]'):
42
algorithm = em.get('Algorithm', '')
43
if algorithm != 'http://ns.adobe.com/pdf/enc#RC':
45
cr = em.getparent().xpath('descendant::*[contains(name(), "CipherReference")]')[0]
47
path = os.path.abspath(os.path.join(os.path.dirname(encfile), '..', *uri.split('/')))
48
if os.path.exists(path):
49
cls.decrypt_font(key, path)
56
def rationalize_cover(self, opf, log):
57
guide_cover, guide_elem = None, None
58
for guide_elem in opf.iterguide():
59
if guide_elem.get('type', '').lower() == 'cover':
60
guide_cover = guide_elem.get('href', '')
64
spine = list(opf.iterspine())
67
# Check if the cover specified in the guide is also
68
# the first element in spine
69
idref = spine[0].get('idref', '')
70
manifest = list(opf.itermanifest())
73
elem = [x for x in manifest if x.get('id', '') == idref]
74
if not elem or elem[0].get('href', None) != guide_cover:
76
log('Found HTML cover', guide_cover)
78
# Remove from spine as covers must be treated
80
if not self.for_viewer:
81
spine[0].getparent().remove(spine[0])
82
guide_elem.set('href', 'calibre_raster_cover.jpg')
83
from calibre.ebooks.oeb.base import OPF
84
t = etree.SubElement(elem[0].getparent(), OPF('item'),
85
href=guide_elem.get('href'), id='calibre_raster_cover')
86
t.set('media-type', 'image/jpeg')
87
for elem in list(opf.iterguide()):
88
if elem.get('type', '').lower() == 'titlepage':
89
elem.getparent().remove(elem)
90
t = etree.SubElement(guide_elem.getparent(), OPF('reference'))
91
t.set('type', 'titlepage')
92
t.set('href', guide_cover)
93
t.set('title', 'Title Page')
94
from calibre.ebooks import render_html_svg_workaround
95
renderer = render_html_svg_workaround(guide_cover, log)
96
if renderer is not None:
97
open('calibre_raster_cover.jpg', 'wb').write(
100
def convert(self, stream, options, file_ext, log, accelerators):
101
from calibre.utils.zipfile import ZipFile
102
from calibre import walk
103
from calibre.ebooks import DRMError
104
from calibre.ebooks.metadata.opf2 import OPF
106
zf.extractall(os.getcwd())
107
encfile = os.path.abspath(os.path.join('META-INF', 'encryption.xml'))
110
if f.lower().endswith('.opf'):
111
opf = os.path.abspath(f)
113
path = getattr(stream, 'name', 'stream')
116
raise ValueError('%s is not a valid EPUB file'%path)
118
if os.path.exists(encfile):
119
if not self.process_encryption(encfile, opf, log):
120
raise DRMError(os.path.basename(path))
122
opf = os.path.relpath(opf, os.getcwdu())
123
parts = os.path.split(opf)
124
opf = OPF(opf, os.path.dirname(os.path.abspath(opf)))
126
if len(parts) > 1 and parts[0]:
127
delta = '/'.join(parts[:-1])+'/'
128
for elem in opf.itermanifest():
129
elem.set('href', delta+elem.get('href'))
130
for elem in opf.iterguide():
131
elem.set('href', delta+elem.get('href'))
133
self.rationalize_cover(opf, log)
135
with open('content.opf', 'wb') as nopf:
136
nopf.write(opf.render())
138
return os.path.abspath('content.opf')