From 79e509eeb48bf7156e62bae9ca9291311dd25778 Mon Sep 17 00:00:00 2001 From: John Schember Date: Tue, 31 Mar 2009 20:23:49 -0400 Subject: [PATCH] Move PDF output to use new conversion framework --- src/calibre/customize/builtins.py | 3 +- src/calibre/ebooks/pdf/from_any.py | 69 --------------------- src/calibre/ebooks/pdf/output.py | 62 +++++++++++++++++++ src/calibre/ebooks/pdf/writer.py | 99 +++++------------------------- src/calibre/ebooks/txt/output.py | 1 + 5 files changed, 79 insertions(+), 155 deletions(-) delete mode 100644 src/calibre/ebooks/pdf/from_any.py create mode 100644 src/calibre/ebooks/pdf/output.py diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index acc7ba71ec..932261c45d 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -267,9 +267,10 @@ from calibre.ebooks.epub.input import EPUBInput from calibre.ebooks.mobi.input import MOBIInput from calibre.ebooks.oeb.output import OEBOutput from calibre.ebooks.txt.output import TXTOutput +from calibre.ebooks.pdf.output import PDFOutput from calibre.customize.profiles import input_profiles, output_profiles -plugins = [HTML2ZIP, EPUBInput, MOBIInput, OEBOutput, TXTOutput] +plugins = [HTML2ZIP, EPUBInput, MOBIInput, OEBOutput, TXTOutput, PDFOutput] plugins += [x for x in list(locals().values()) if isinstance(x, type) and \ x.__name__.endswith('MetadataReader')] plugins += [x for x in list(locals().values()) if isinstance(x, type) and \ diff --git a/src/calibre/ebooks/pdf/from_any.py b/src/calibre/ebooks/pdf/from_any.py deleted file mode 100644 index e4fb937cdb..0000000000 --- a/src/calibre/ebooks/pdf/from_any.py +++ /dev/null @@ -1,69 +0,0 @@ -''' -Convert any ebook format to PDF. -''' - -from __future__ import with_statement - -__license__ = 'GPL v3' -__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net ' \ - 'and Marshall T. Vandegrift ' \ - 'and John Schember ' -__docformat__ = 'restructuredtext en' - -import sys, os, glob, logging - -from calibre.ebooks.epub.from_any import any2epub, formats, USAGE -from calibre.ebooks.epub import config as common_config -from calibre.ptempfile import TemporaryDirectory -from calibre.ebooks.pdf.writer import oeb2pdf, config as pdf_config - -def config(defaults=None): - c = common_config(defaults=defaults, name='pdf') - c.remove_opt('profile') - pdfc = pdf_config(defaults=defaults) - c.update(pdfc) - return c - -def option_parser(usage=USAGE): - usage = usage % ('PDF', formats()) - parser = config().option_parser(usage=usage) - return parser - -def any2pdf(opts, path, notification=None): - ext = os.path.splitext(path)[1] - if not ext: - raise ValueError('Unknown file type: '+path) - ext = ext.lower()[1:] - - if opts.output is None: - opts.output = os.path.splitext(os.path.basename(path))[0]+'.pdf' - - opts.output = os.path.abspath(opts.output) - orig_output = opts.output - - with TemporaryDirectory('_any2pdf') as tdir: - oebdir = os.path.join(tdir, 'oeb') - os.mkdir(oebdir) - opts.output = os.path.join(tdir, 'dummy.epub') - opts.profile = 'None' - opts.dont_split_on_page_breaks = True - orig_bfs = opts.base_font_size2 - opts.base_font_size2 = 0 - any2epub(opts, path, create_epub=False, oeb_cover=True, extract_to=oebdir) - opts.base_font_size2 = orig_bfs - opf = glob.glob(os.path.join(oebdir, '*.opf'))[0] - opts.output = orig_output - logging.getLogger('html2epub').info(_('Creating PDF file from EPUB...')) - oeb2pdf(opts, opf) - -def main(args=sys.argv): - parser = option_parser() - opts, args = parser.parse_args(args) - if len(args) < 2: - parser.print_help() - print 'No input file specified.' - return 1 - any2pdf(opts, args[1]) - -if __name__ == '__main__': - sys.exit(main()) diff --git a/src/calibre/ebooks/pdf/output.py b/src/calibre/ebooks/pdf/output.py new file mode 100644 index 0000000000..71bd77ee73 --- /dev/null +++ b/src/calibre/ebooks/pdf/output.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +__license__ = 'GPL 3' +__copyright__ = '2009, John Schember ' +__docformat__ = 'restructuredtext en' + +''' +Convert OEB ebook format to PDF. +''' + +#unit, papersize, orientation, custom_size, profile + +import os + +from calibre.customize.conversion import OutputFormatPlugin, \ + OptionRecommendation +from calibre.ebooks.pdf.writer import PDFWriter, PDFMargins + +class PDFOutput(OutputFormatPlugin): + + name = 'PDF Output' + author = 'John Schember' + file_type = 'pdf' + + options = set([ + OptionRecommendation(name='margin_top', recommended_value='1', + level=OptionRecommendation.LOW, long_switch='margin_top', + help=_('The top margin around the document.')), + OptionRecommendation(name='margin_bottom', recommended_value='1', + level=OptionRecommendation.LOW, long_switch='margin_bottom', + help=_('The bottom margin around the document.')), + OptionRecommendation(name='margin_left', recommended_value='1', + level=OptionRecommendation.LOW, long_switch='margin_left', + help=_('The left margin around the document.')), + OptionRecommendation(name='margin_right', recommended_value='1', + level=OptionRecommendation.LOW, long_switch='margin_right', + help=_('The right margin around the document.')), + ]) + + def convert(self, oeb_book, output_path, input_plugin, opts, log): + margins = PDFMargins() + margins.top = opts.margin_top + margins.bottom = opts.margin_bottom + margins.left = opts.margin_left + margins.right = opts.margin_right + + writer = PDFWriter(log, margins) + + close = False + if not hasattr(output_path, 'write'): + close = True + if not os.path.exists(os.path.dirname(output_path)) and os.path.dirname(output_path) != '': + os.makedirs(os.path.dirname(output_path)) + out_stream = open(output_path, 'wb') + else: + out_stream = output_path + + out_stream.seek(0) + out_stream.truncate() + writer.dump(oeb_book.spine, out_stream) + + if close: + out_stream.close() diff --git a/src/calibre/ebooks/pdf/writer.py b/src/calibre/ebooks/pdf/writer.py index c189407dac..511c968a20 100644 --- a/src/calibre/ebooks/pdf/writer.py +++ b/src/calibre/ebooks/pdf/writer.py @@ -1,20 +1,17 @@ -''' -Write content to PDF. -''' +# -*- coding: utf-8 -*- from __future__ import with_statement __license__ = 'GPL v3' __copyright__ = '2009, John Schember ' +__docformat__ = 'restructuredtext en' -import os, logging, shutil, sys +''' +Write content to PDF. +''' + +import os, shutil, sys -from calibre import LoggingInterface -from calibre.ebooks.epub.iterator import SpineItem -from calibre.ebooks.metadata.opf2 import OPF from calibre.ptempfile import PersistentTemporaryDirectory -from calibre.customize.ui import run_plugins_on_postprocess -from calibre.utils.config import Config, StringConfig - from PyQt4 import QtCore from PyQt4.Qt import QUrl, QEventLoop, SIGNAL, QObject, QApplication, QPrinter, \ QMetaObject, Qt @@ -29,13 +26,14 @@ class PDFMargins: self.left = margin self.right = margin + class PDFWriter(QObject): - def __init__(self, margins=PDFMargins()): + def __init__(self, log, margins=PDFMargins()): if QApplication.instance() is None: QApplication([]) QObject.__init__(self) - self.logger = logging.getLogger('oeb2pdf') + self.logger = log self.loop = QEventLoop() self.view = QWebView() @@ -45,13 +43,12 @@ class PDFWriter(QObject): self.tmp_path = PersistentTemporaryDirectory('_any2pdf_parts') self.margins = margins - def dump(self, oebpath, path): + def dump(self, spine, out_stream): self._delete_tmpdir() - opf = OPF(oebpath, os.path.dirname(oebpath)) - self.render_queue = [SpineItem(i.path) for i in opf.spine] + self.render_queue = spine[:] self.combine_queue = [] - self.path = path + self.out_stream = out_stream QMetaObject.invokeMethod(self, "_render_book", Qt.QueuedConnection) self.loop.exec_() @@ -98,75 +95,7 @@ class PDFWriter(QObject): inputPDF = PdfFileReader(file(item, 'rb')) for page in inputPDF.pages: outPDF.addPage(page) - outputStream = file(self.path, 'wb') - outPDF.write(outputStream) - outputStream.close() + outPDF.write(self.out_stream) finally: self._delete_tmpdir() self.loop.exit(0) - - -def config(defaults=None): - desc = _('Options to control the conversion to PDF') - if defaults is None: - c = Config('pdf', desc) - else: - c = StringConfig(defaults, desc) - - pdf = c.add_group('PDF', _('PDF options.')) - - pdf('margin_top', ['--margin_top'], default=1, - help=_('The top margin around the document in inches.')) - pdf('margin_bottom', ['--margin_bottom'], default=1, - help=_('The bottom margin around the document in inches.')) - pdf('margin_left', ['--margin_left'], default=1, - help=_('The left margin around the document in inches.')) - pdf('margin_right', ['--margin_right'], default=1, - help=_('The right margin around the document in inches.')) - - return c - -def option_parser(): - c = config() - parser = c.option_parser(usage='%prog '+_('[options]')+' file.opf') - parser.add_option( - '-o', '--output', default=None, - help=_('Output file. Default is derived from input filename.')) - parser.add_option( - '-v', '--verbose', default=0, action='count', - help=_('Useful for debugging.')) - return parser - -def oeb2pdf(opts, inpath): - logger = LoggingInterface(logging.getLogger('oeb2pdf')) - logger.setup_cli_handler(opts.verbose) - - outpath = opts.output - if outpath is None: - outpath = os.path.basename(inpath) - outpath = os.path.splitext(outpath)[0] + '.pdf' - - margins = PDFMargins() - margins.top = opts.margin_top - margins.bottom = opts.margin_bottom - margins.left = opts.margin_left - margins.right = opts.margin_right - - writer = PDFWriter(margins) - writer.dump(inpath, outpath) - run_plugins_on_postprocess(outpath, 'pdf') - logger.log_info(_('Output written to ') + outpath) - -def main(argv=sys.argv): - parser = option_parser() - opts, args = parser.parse_args(argv[1:]) - if len(args) != 1: - parser.print_help() - return 1 - inpath = args[0] - retval = oeb2pdf(opts, inpath) - return retval - -if __name__ == '__main__': - sys.exit(main()) - diff --git a/src/calibre/ebooks/txt/output.py b/src/calibre/ebooks/txt/output.py index 21498074ac..7d44172b3f 100644 --- a/src/calibre/ebooks/txt/output.py +++ b/src/calibre/ebooks/txt/output.py @@ -56,6 +56,7 @@ class TXTOutput(OutputFormatPlugin): out_stream = output_path out_stream.seek(0) + out_stream.truncate() out_stream.write(txt) if close: