PDF Output: Do not create duplicate embedded fonts in the PDF for every individual HTML file in the input document

This commit is contained in:
Kovid Goyal 2012-08-29 17:10:31 +05:30
parent 05de8b4b21
commit e20450d956

View File

@ -12,7 +12,7 @@ import os, shutil, json
from future_builtins import map from future_builtins import map
from PyQt4.Qt import (QEventLoop, QObject, QPrinter, QSizeF, Qt, QPainter, from PyQt4.Qt import (QEventLoop, QObject, QPrinter, QSizeF, Qt, QPainter,
QPixmap, QTimer, pyqtProperty, QString) QPixmap, QTimer, pyqtProperty, QString, QSize)
from PyQt4.QtWebKit import QWebView, QWebPage, QWebSettings from PyQt4.QtWebKit import QWebView, QWebPage, QWebSettings
from calibre.ptempfile import PersistentTemporaryDirectory from calibre.ptempfile import PersistentTemporaryDirectory
@ -192,8 +192,17 @@ class PDFWriter(QObject): # {{{
self.insert_cover() self.insert_cover()
self.render_succeeded = False self.render_succeeded = False
self.combine_queue.append(os.path.join(self.tmp_path,
'qprinter_out.pdf'))
self.first_page = True
self.setup_printer(self.combine_queue[-1])
QTimer.singleShot(0, self._render_book) QTimer.singleShot(0, self._render_book)
self.loop.exec_() self.loop.exec_()
if self.painter is not None:
self.painter.end()
if self.printer is not None:
self.printer.abort()
if not self.render_succeeded: if not self.render_succeeded:
raise Exception('Rendering HTML to PDF failed') raise Exception('Rendering HTML to PDF failed')
@ -209,7 +218,6 @@ class PDFWriter(QObject): # {{{
def _render_next(self): def _render_next(self):
item = unicode(self.render_queue.pop(0)) item = unicode(self.render_queue.pop(0))
self.combine_queue.append(os.path.join(self.tmp_path, '%i.pdf' % (len(self.combine_queue) + 1)))
self.logger.debug('Processing %s...' % item) self.logger.debug('Processing %s...' % item)
self.current_item = item self.current_item = item
@ -217,9 +225,7 @@ class PDFWriter(QObject): # {{{
def _render_html(self, ok): def _render_html(self, ok):
if ok: if ok:
item_path = os.path.join(self.tmp_path, '%i.pdf' % len(self.combine_queue)) self.do_paged_render()
self.logger.debug('\tRendering item %s as %i.pdf' % (os.path.basename(str(self.view.url().toLocalFile())), len(self.combine_queue)))
self.do_paged_render(item_path)
else: else:
# The document is so corrupt that we can't render the page. # The document is so corrupt that we can't render the page.
self.logger.error('Document cannot be rendered.') self.logger.error('Document cannot be rendered.')
@ -237,25 +243,28 @@ class PDFWriter(QObject): # {{{
_pass_json_value = pyqtProperty(QString, fget=_pass_json_value_getter, _pass_json_value = pyqtProperty(QString, fget=_pass_json_value_getter,
fset=_pass_json_value_setter) fset=_pass_json_value_setter)
def do_paged_render(self, outpath): def setup_printer(self, outpath):
from PyQt4.Qt import QSize, QPainter self.printer = self.painter = None
if self.paged_js is None:
from calibre.utils.resources import compiled_coffeescript
self.paged_js = compiled_coffeescript('ebooks.oeb.display.utils')
self.paged_js += compiled_coffeescript('ebooks.oeb.display.indexing')
self.paged_js += compiled_coffeescript('ebooks.oeb.display.paged')
printer = get_pdf_printer(self.opts, output_file_name=outpath) printer = get_pdf_printer(self.opts, output_file_name=outpath)
painter = QPainter(printer) painter = QPainter(printer)
zoomx = printer.logicalDpiX()/self.view.logicalDpiX() zoomx = printer.logicalDpiX()/self.view.logicalDpiX()
zoomy = printer.logicalDpiY()/self.view.logicalDpiY() zoomy = printer.logicalDpiY()/self.view.logicalDpiY()
painter.scale(zoomx, zoomy) painter.scale(zoomx, zoomy)
pr = printer.pageRect()
self.printer, self.painter = printer, painter
self.viewport_size = QSize(pr.width()/zoomx, pr.height()/zoomy)
self.page.setViewportSize(self.viewport_size)
def do_paged_render(self):
if self.paged_js is None:
from calibre.utils.resources import compiled_coffeescript
self.paged_js = compiled_coffeescript('ebooks.oeb.display.utils')
self.paged_js += compiled_coffeescript('ebooks.oeb.display.indexing')
self.paged_js += compiled_coffeescript('ebooks.oeb.display.paged')
self.view.page().mainFrame().addToJavaScriptWindowObject("py_bridge", self) self.view.page().mainFrame().addToJavaScriptWindowObject("py_bridge", self)
pr = printer.pageRect()
evaljs = self.view.page().mainFrame().evaluateJavaScript evaljs = self.view.page().mainFrame().evaluateJavaScript
evaljs(self.paged_js) evaljs(self.paged_js)
self.view.page().setViewportSize(QSize(pr.width()/zoomx,
pr.height()/zoomy))
evaljs(''' evaljs('''
py_bridge.__defineGetter__('value', function() { py_bridge.__defineGetter__('value', function() {
return JSON.parse(this._pass_json_value); return JSON.parse(this._pass_json_value);
@ -271,11 +280,13 @@ class PDFWriter(QObject): # {{{
''') ''')
mf = self.view.page().mainFrame() mf = self.view.page().mainFrame()
while True: while True:
mf.render(painter) if not self.first_page:
self.printer.newPage()
self.first_page = False
mf.render(self.painter)
nsl = evaljs('paged_display.next_screen_location()').toInt() nsl = evaljs('paged_display.next_screen_location()').toInt()
if not nsl[1] or nsl[0] <= 0: break if not nsl[1] or nsl[0] <= 0: break
evaljs('window.scrollTo(%d, 0)'%nsl[0]) evaljs('window.scrollTo(%d, 0)'%nsl[0])
printer.newPage()
self.bridge_value = tuple(self.outline.anchor_map[self.current_item]) self.bridge_value = tuple(self.outline.anchor_map[self.current_item])
evaljs('py_bridge.value = book_indexing.anchor_positions(py_bridge.value)') evaljs('py_bridge.value = book_indexing.anchor_positions(py_bridge.value)')
@ -288,10 +299,6 @@ class PDFWriter(QObject): # {{{
pagenum, ypos = x pagenum, ypos = x
self.outline.set_pos(self.current_item, anchor, pages + pagenum, ypos) self.outline.set_pos(self.current_item, anchor, pages + pagenum, ypos)
painter.end()
printer.abort()
self.append_doc(outpath)
def append_doc(self, outpath): def append_doc(self, outpath):
doc = self.podofo.PDFDoc() doc = self.podofo.PDFDoc()
with open(outpath, 'rb') as f: with open(outpath, 'rb') as f:
@ -322,7 +329,10 @@ class PDFWriter(QObject): # {{{
printer.abort() printer.abort()
def _write(self): def _write(self):
self.logger.debug('Combining individual PDF parts...') self.painter.end()
self.printer.abort()
self.painter = self.printer = None
self.append_doc(self.combine_queue[-1])
try: try:
self.doc.creator = u'%s %s [http://calibre-ebook.com]'%( self.doc.creator = u'%s %s [http://calibre-ebook.com]'%(