mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Beginning of PDF conversion
This commit is contained in:
parent
358ec20ceb
commit
9ff64bd715
69
src/calibre/ebooks/pdf/from_any.py
Normal file
69
src/calibre/ebooks/pdf/from_any.py
Normal file
@ -0,0 +1,69 @@
|
||||
'''
|
||||
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())
|
153
src/calibre/ebooks/pdf/writer.py
Normal file
153
src/calibre/ebooks/pdf/writer.py
Normal file
@ -0,0 +1,153 @@
|
||||
'''
|
||||
Write content to PDF.
|
||||
'''
|
||||
from __future__ import with_statement
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
|
||||
|
||||
import os, logging, shutil, sys
|
||||
from calibre.ebooks.oeb.base import Logger, OEBBook
|
||||
from calibre.ebooks.oeb.profile import Context
|
||||
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
|
||||
from PyQt4.Qt import *
|
||||
from PyQt4.QtWebKit import QWebView
|
||||
|
||||
from pyPdf import PdfFileWriter, PdfFileReader
|
||||
|
||||
class PDFWriter(QObject):
|
||||
def __init__(self):
|
||||
if QApplication.instance() is None:
|
||||
QApplication([])
|
||||
QObject.__init__(self)
|
||||
|
||||
self.loop = QEventLoop()
|
||||
self.view = QWebView()
|
||||
self.connect(self.view, SIGNAL('loadFinished(bool)'), self._render_html)
|
||||
self.render_queue = []
|
||||
self.combine_queue = []
|
||||
self.tmp_path = PersistentTemporaryDirectory('_any2pdf_parts')
|
||||
|
||||
def dump(self, oeb, oebpath, path):
|
||||
self._reset()
|
||||
|
||||
opf = OPF(oebpath, os.path.dirname(oebpath))
|
||||
self.render_queue = [SpineItem(i.path) for i in opf.spine]
|
||||
|
||||
self.path = path
|
||||
|
||||
QMetaObject.invokeMethod(self, "_render_book", Qt.QueuedConnection)
|
||||
self.loop.exec_()
|
||||
|
||||
@QtCore.pyqtSignature('_render_book()')
|
||||
def _render_book(self):
|
||||
if len(self.render_queue) == 0:
|
||||
self._write()
|
||||
else:
|
||||
self._render_next()
|
||||
|
||||
def _render_next(self):
|
||||
item = str(self.render_queue.pop(0))
|
||||
self.combine_queue.append(os.path.join(self.tmp_path, '%s.pdf' % os.path.basename(item)))
|
||||
|
||||
self.view.load(QUrl(item))
|
||||
|
||||
def _render_html(self, ok):
|
||||
if ok:
|
||||
printer = QPrinter(QPrinter.HighResolution)
|
||||
printer.setPageMargins(1, 1, 1, 1, QPrinter.Inch)
|
||||
printer.setOutputFormat(QPrinter.PdfFormat)
|
||||
printer.setOutputFileName(os.path.join(self.tmp_path, '%s.pdf' % os.path.basename(str(self.view.url().toLocalFile()))))
|
||||
self.view.print_(printer)
|
||||
self._render_book()
|
||||
|
||||
def _reset(self):
|
||||
self.render_queue = []
|
||||
self.combine_queue = []
|
||||
self.path = ''
|
||||
if os.path.exists(self.tmp_path):
|
||||
shutil.rmtree(self.tmp_path, True)
|
||||
self.tmp_path = PersistentTemporaryDirectory('_any2pdf_parts')
|
||||
|
||||
def _write(self):
|
||||
print self.path
|
||||
try:
|
||||
outPDF = PdfFileWriter()
|
||||
for item in self.combine_queue:
|
||||
inputPDF = PdfFileReader(file(item, 'rb'))
|
||||
for page in inputPDF.pages:
|
||||
outPDF.addPage(page)
|
||||
outputStream = file(self.path, 'wb')
|
||||
outPDF.write(outputStream)
|
||||
outputStream.close()
|
||||
finally:
|
||||
self._reset()
|
||||
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.'))
|
||||
|
||||
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 = Logger(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'
|
||||
# source = opts.source_profile
|
||||
# if source not in Context.PROFILES:
|
||||
# logger.error(_('Unknown source profile %r') % source)
|
||||
# return 1
|
||||
# dest = opts.dest_profile
|
||||
# if dest not in Context.PROFILES:
|
||||
# logger.error(_('Unknown destination profile %r') % dest)
|
||||
# return 1
|
||||
|
||||
oeb = OEBBook(inpath, logger=logger, encoding=opts.encoding)
|
||||
writer = PDFWriter()
|
||||
writer.dump(oeb, inpath, outpath)
|
||||
run_plugins_on_postprocess(outpath, 'pdf')
|
||||
logger.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())
|
||||
|
@ -51,6 +51,7 @@ entry_points = {
|
||||
'any2epub = calibre.ebooks.epub.from_any:main',
|
||||
'any2lit = calibre.ebooks.lit.from_any:main',
|
||||
'any2mobi = calibre.ebooks.mobi.from_any:main',
|
||||
'any2pdf = calibre.ebooks.pdf.from_any:main',
|
||||
'lrf2lrs = calibre.ebooks.lrf.lrfparser:main',
|
||||
'lrs2lrf = calibre.ebooks.lrf.lrs.convert_from:main',
|
||||
'pdfreflow = calibre.ebooks.lrf.pdf.reflow:main',
|
||||
|
@ -71,6 +71,9 @@ PARALLEL_FUNCS = {
|
||||
'any2mobi' :
|
||||
('calibre.ebooks.mobi.from_any', 'any2mobi', {}, None),
|
||||
|
||||
'any2pdf' :
|
||||
('calibre.ebooks.pdf.from_any', 'any2pdf', {}, None),
|
||||
|
||||
'feeds2mobi' :
|
||||
('calibre.ebooks.mobi.from_feeds', 'main', {}, 'notification'),
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user