diff --git a/src/calibre/ebooks/conversion/plugins/epub_output.py b/src/calibre/ebooks/conversion/plugins/epub_output.py
index 123c071467..72ceac308e 100644
--- a/src/calibre/ebooks/conversion/plugins/epub_output.py
+++ b/src/calibre/ebooks/conversion/plugins/epub_output.py
@@ -117,6 +117,12 @@ class EPUBOutput(OutputFormatPlugin):
help=_('Title for any generated in-line table of contents.')
),
+ OptionRecommendation(name='epub_version', recommended_value='2', choices=('2', '3'),
+ help=_('The version of the EPUB file to generate. EPUB 2 is the'
+ ' most widely compatible, only use EPUB 3 if you know you'
+ ' actually need it.')
+ ),
+
])
recommendations = set([('pretty_print', True, OptionRecommendation.HIGH)])
@@ -168,6 +174,7 @@ class EPUBOutput(OutputFormatPlugin):
seen_names.add(name)
# }}}
+
def convert(self, oeb, output_path, input_plugin, opts, log):
self.log, self.opts, self.oeb = log, opts, oeb
@@ -249,6 +256,8 @@ class EPUBOutput(OutputFormatPlugin):
opf = [x for x in os.listdir(tdir) if x.endswith('.opf')][0]
self.condense_ncx([os.path.join(tdir, x) for x in os.listdir(tdir)
if x.endswith('.ncx')][0])
+ if self.opts.epub_version == '3':
+ self.upgrade_to_epub3(tdir, opf)
encryption = None
if encrypted_fonts:
encryption = self.encrypt_fonts(encrypted_fonts, tdir, uuid)
@@ -274,6 +283,26 @@ class EPUBOutput(OutputFormatPlugin):
zf.extractall(path=opts.extract_to)
self.log.info('EPUB extracted to', opts.extract_to)
+ def upgrade_to_epub3(self, tdir, opf):
+ self.log.info('Upgrading to EPUB 3...')
+ from calibre.ebooks.epub import simple_container_xml
+ try:
+ os.mkdir(os.path.join(tdir, 'META-INF'))
+ except EnvironmentError:
+ pass
+ with open(os.path.join(tdir, 'META-INF', 'container.xml'), 'wb') as f:
+ f.write(simple_container_xml(os.path.basename(opf)).encode('utf-8'))
+ from calibre.ebooks.oeb.polish.container import EpubContainer
+ container = EpubContainer(tdir, self.log)
+ from calibre.ebooks.oeb.polish.upgrade import epub_2_to_3
+ epub_2_to_3(container, self.log.info)
+ container.commit()
+ os.remove(f.name)
+ try:
+ os.rmdir(os.path.join(tdir, 'META-INF'))
+ except EnvironmentError:
+ pass
+
def encrypt_fonts(self, uris, tdir, uuid): # {{{
from binascii import unhexlify
@@ -324,7 +353,7 @@ class EPUBOutput(OutputFormatPlugin):
return ans
# }}}
- def condense_ncx(self, ncx_path):
+ def condense_ncx(self, ncx_path): # {{{
from lxml import etree
if not self.opts.pretty_print:
tree = etree.parse(ncx_path)
@@ -335,6 +364,7 @@ class EPUBOutput(OutputFormatPlugin):
tag.tail = tag.tail.strip()
compressed = etree.tostring(tree.getroot(), encoding='utf-8')
open(ncx_path, 'wb').write(compressed)
+ # }}}
def workaround_ade_quirks(self): # {{{
'''
@@ -420,8 +450,7 @@ class EPUBOutput(OutputFormatPlugin):
if not tag.text:
tag.getparent().remove(tag)
for tag in XPath('//h:script')(root):
- if (not tag.text and not tag.get('src', False) and
- tag.get('type', None) != 'text/x-mathjax-config'):
+ if (not tag.text and not tag.get('src', False) and tag.get('type', None) != 'text/x-mathjax-config'):
tag.getparent().remove(tag)
for tag in XPath('//h:body/descendant::h:script')(root):
tag.getparent().remove(tag)
diff --git a/src/calibre/ebooks/epub/__init__.py b/src/calibre/ebooks/epub/__init__.py
index 1632ad576c..b7c54e0edc 100644
--- a/src/calibre/ebooks/epub/__init__.py
+++ b/src/calibre/ebooks/epub/__init__.py
@@ -17,6 +17,18 @@ def rules(stylesheets):
yield r
+def simple_container_xml(opf_path, extra_entries=''):
+ return u'''\
+
+
+
+
+ {extra_entries}
+
+
+ '''.format(opf_path, extra_entries=extra_entries)
+
+
def initialize_container(path_to_container, opf_name='metadata.opf',
extra_entries=[]):
'''
@@ -26,15 +38,7 @@ def initialize_container(path_to_container, opf_name='metadata.opf',
for path, mimetype, _ in extra_entries:
rootfiles += u''.format(
path, mimetype)
- CONTAINER = u'''\
-
-
-
-
- {extra_entries}
-
-
- '''.format(opf_name, extra_entries=rootfiles).encode('utf-8')
+ CONTAINER = simple_container_xml(opf_name, rootfiles).encode('utf-8')
zf = ZipFile(path_to_container, 'w')
zf.writestr('mimetype', 'application/epub+zip', compression=ZIP_STORED)
zf.writestr('META-INF/', '', 0755)
@@ -42,5 +46,3 @@ def initialize_container(path_to_container, opf_name='metadata.opf',
for path, _, data in extra_entries:
zf.writestr(path, data)
return zf
-
-
diff --git a/src/calibre/gui2/convert/epub_output.py b/src/calibre/gui2/convert/epub_output.py
index 6616590331..c7e78ac665 100644
--- a/src/calibre/gui2/convert/epub_output.py
+++ b/src/calibre/gui2/convert/epub_output.py
@@ -23,9 +23,11 @@ class PluginWidget(Widget, Ui_Form):
['dont_split_on_page_breaks', 'flow_size',
'no_default_epub_cover', 'no_svg_cover',
'epub_inline_toc', 'epub_toc_at_end', 'toc_title',
- 'preserve_cover_aspect_ratio', 'epub_flatten']
+ 'preserve_cover_aspect_ratio', 'epub_flatten', 'epub_version']
)
for i in range(2):
self.opt_no_svg_cover.toggle()
+ ev = get_option('epub_version')
+ self.opt_epub_version.addItems(list(ev.option.choices))
self.db, self.book_id = db, book_id
self.initialize_options(get_option, get_help, db, book_id)
diff --git a/src/calibre/gui2/convert/epub_output.ui b/src/calibre/gui2/convert/epub_output.ui
index 75ad4b7c08..4e5048006c 100644
--- a/src/calibre/gui2/convert/epub_output.ui
+++ b/src/calibre/gui2/convert/epub_output.ui
@@ -50,7 +50,7 @@
- -
+
-
Qt::Vertical
@@ -118,6 +118,19 @@
-
+ -
+
+
+ EP&UB version:
+
+
+ opt_epub_version
+
+
+
+ -
+
+