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 + + + + + +