mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Move PDF output to use new conversion framework
This commit is contained in:
parent
90362ab56a
commit
79e509eeb4
@ -267,9 +267,10 @@ from calibre.ebooks.epub.input import EPUBInput
|
|||||||
from calibre.ebooks.mobi.input import MOBIInput
|
from calibre.ebooks.mobi.input import MOBIInput
|
||||||
from calibre.ebooks.oeb.output import OEBOutput
|
from calibre.ebooks.oeb.output import OEBOutput
|
||||||
from calibre.ebooks.txt.output import TXTOutput
|
from calibre.ebooks.txt.output import TXTOutput
|
||||||
|
from calibre.ebooks.pdf.output import PDFOutput
|
||||||
from calibre.customize.profiles import input_profiles, output_profiles
|
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 \
|
plugins += [x for x in list(locals().values()) if isinstance(x, type) and \
|
||||||
x.__name__.endswith('MetadataReader')]
|
x.__name__.endswith('MetadataReader')]
|
||||||
plugins += [x for x in list(locals().values()) if isinstance(x, type) and \
|
plugins += [x for x in list(locals().values()) if isinstance(x, type) and \
|
||||||
|
@ -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 <llasram@gmail.com>' \
|
|
||||||
'and John Schember <john@nachtimwald.com>'
|
|
||||||
__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())
|
|
62
src/calibre/ebooks/pdf/output.py
Normal file
62
src/calibre/ebooks/pdf/output.py
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
__license__ = 'GPL 3'
|
||||||
|
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
|
||||||
|
__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()
|
@ -1,20 +1,17 @@
|
|||||||
'''
|
# -*- coding: utf-8 -*-
|
||||||
Write content to PDF.
|
|
||||||
'''
|
|
||||||
from __future__ import with_statement
|
from __future__ import with_statement
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
|
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
|
||||||
|
__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.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 import QtCore
|
||||||
from PyQt4.Qt import QUrl, QEventLoop, SIGNAL, QObject, QApplication, QPrinter, \
|
from PyQt4.Qt import QUrl, QEventLoop, SIGNAL, QObject, QApplication, QPrinter, \
|
||||||
QMetaObject, Qt
|
QMetaObject, Qt
|
||||||
@ -29,13 +26,14 @@ class PDFMargins:
|
|||||||
self.left = margin
|
self.left = margin
|
||||||
self.right = margin
|
self.right = margin
|
||||||
|
|
||||||
|
|
||||||
class PDFWriter(QObject):
|
class PDFWriter(QObject):
|
||||||
def __init__(self, margins=PDFMargins()):
|
def __init__(self, log, margins=PDFMargins()):
|
||||||
if QApplication.instance() is None:
|
if QApplication.instance() is None:
|
||||||
QApplication([])
|
QApplication([])
|
||||||
QObject.__init__(self)
|
QObject.__init__(self)
|
||||||
|
|
||||||
self.logger = logging.getLogger('oeb2pdf')
|
self.logger = log
|
||||||
|
|
||||||
self.loop = QEventLoop()
|
self.loop = QEventLoop()
|
||||||
self.view = QWebView()
|
self.view = QWebView()
|
||||||
@ -45,13 +43,12 @@ class PDFWriter(QObject):
|
|||||||
self.tmp_path = PersistentTemporaryDirectory('_any2pdf_parts')
|
self.tmp_path = PersistentTemporaryDirectory('_any2pdf_parts')
|
||||||
self.margins = margins
|
self.margins = margins
|
||||||
|
|
||||||
def dump(self, oebpath, path):
|
def dump(self, spine, out_stream):
|
||||||
self._delete_tmpdir()
|
self._delete_tmpdir()
|
||||||
|
|
||||||
opf = OPF(oebpath, os.path.dirname(oebpath))
|
self.render_queue = spine[:]
|
||||||
self.render_queue = [SpineItem(i.path) for i in opf.spine]
|
|
||||||
self.combine_queue = []
|
self.combine_queue = []
|
||||||
self.path = path
|
self.out_stream = out_stream
|
||||||
|
|
||||||
QMetaObject.invokeMethod(self, "_render_book", Qt.QueuedConnection)
|
QMetaObject.invokeMethod(self, "_render_book", Qt.QueuedConnection)
|
||||||
self.loop.exec_()
|
self.loop.exec_()
|
||||||
@ -98,75 +95,7 @@ class PDFWriter(QObject):
|
|||||||
inputPDF = PdfFileReader(file(item, 'rb'))
|
inputPDF = PdfFileReader(file(item, 'rb'))
|
||||||
for page in inputPDF.pages:
|
for page in inputPDF.pages:
|
||||||
outPDF.addPage(page)
|
outPDF.addPage(page)
|
||||||
outputStream = file(self.path, 'wb')
|
outPDF.write(self.out_stream)
|
||||||
outPDF.write(outputStream)
|
|
||||||
outputStream.close()
|
|
||||||
finally:
|
finally:
|
||||||
self._delete_tmpdir()
|
self._delete_tmpdir()
|
||||||
self.loop.exit(0)
|
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())
|
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ class TXTOutput(OutputFormatPlugin):
|
|||||||
out_stream = output_path
|
out_stream = output_path
|
||||||
|
|
||||||
out_stream.seek(0)
|
out_stream.seek(0)
|
||||||
|
out_stream.truncate()
|
||||||
out_stream.write(txt)
|
out_stream.write(txt)
|
||||||
|
|
||||||
if close:
|
if close:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user