Logo Search packages:      
Sourcecode: calibre version File versions  Download package

writer.py

# -*- coding: utf-8 -*-

__license__   = 'GPL v3'
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
__docformat__ = 'restructuredtext en'

'''
Write content to PDF.
'''

import os
import shutil

from calibre.ptempfile import PersistentTemporaryDirectory
from calibre.ebooks.pdf.pageoptions import unit, paper_size, \
    orientation
from calibre.ebooks.metadata import authors_to_string

from PyQt4 import QtCore
from PyQt4.Qt import QUrl, QEventLoop, SIGNAL, QObject, \
    QPrinter, QMetaObject, QSizeF, Qt, QPainter
from PyQt4.QtWebKit import QWebView

from pyPdf import PdfFileWriter, PdfFileReader

def get_custom_size(opts):
    custom_size = None
    if opts.custom_size != None:
        width, sep, height = opts.custom_size.partition('x')
        if height != '':
            try:
                width = int(width)
                height = int(height)
                custom_size = (width, height)
            except:
                custom_size = None
    return custom_size

def get_pdf_page_size(opts):
    from calibre.gui2 import is_ok_to_use_qt
    if not is_ok_to_use_qt():
        raise Exception('Not OK to use Qt')

    printer = QPrinter(QPrinter.HighResolution)
    custom_size = get_custom_size(opts)

    if opts.output_profile.short_name == 'default':
        if custom_size is None:
            printer.setPaperSize(paper_size(opts.paper_size))
        else:
            printer.setPaperSize(QSizeF(custom_size[0], custom_size[1]), unit(opts.unit))
    else:
        printer.setPaperSize(QSizeF(opts.output_profile.width / opts.output_profile.dpi,
            opts.output_profile.height / opts.output_profile.dpi), QPrinter.Inch)

    printer.setPageMargins(0, 0, 0, 0, QPrinter.Point)
    printer.setOrientation(orientation(opts.orientation))
    printer.setOutputFormat(QPrinter.PdfFormat)

    size = printer.paperSize(QPrinter.Millimeter)

    return size.width() / 10, size.height() / 10

def get_imagepdf_page_size(opts):
    printer = QPrinter(QPrinter.HighResolution)
    custom_size = get_custom_size(opts)

    if opts.output_profile.short_name == 'default':
        if custom_size == None:
            printer.setPaperSize(paper_size(opts.paper_size))
        else:
            printer.setPaperSize(QSizeF(custom_size[0], custom_size[1]), unit(opts.unit))
    else:
        printer.setPaperSize(QSizeF(opts.output_profile.comic_screen_size[0] / opts.output_profile.dpi,
            opts.output_profile.comic_screen_size[1] / opts.output_profile.dpi), QPrinter.Inch)

    printer.setPageMargins(0, 0, 0, 0, QPrinter.Point)
    printer.setOrientation(orientation(opts.orientation))
    printer.setOutputFormat(QPrinter.PdfFormat)

    size = printer.paperSize(QPrinter.Millimeter)

    return size.width() / 10, size.height() / 10

class PDFMetadata(object):
    def __init__(self, oeb_metadata=None):
        self.title = _('Unknown')
        self.author = _('Unknown')

        if oeb_metadata != None:
            if len(oeb_metadata.title) >= 1:
                self.title = oeb_metadata.title[0].value
            if len(oeb_metadata.creator) >= 1:
                self.author = authors_to_string([x.value for x in oeb_metadata.creator])


class PDFWriter(QObject):

    def __init__(self, opts, log):
        from calibre.gui2 import is_ok_to_use_qt
        if not is_ok_to_use_qt():
            raise Exception('Not OK to use Qt')
        QObject.__init__(self)

        self.logger = log

        self.loop = QEventLoop()
        self.view = QWebView()
        self.view.setRenderHints(QPainter.Antialiasing|QPainter.TextAntialiasing|QPainter.SmoothPixmapTransform)
        self.connect(self.view, SIGNAL('loadFinished(bool)'), self._render_html)
        self.render_queue = []
        self.combine_queue = []
        self.tmp_path = PersistentTemporaryDirectory('_pdf_output_parts')

        self.opts = opts

        self.size = get_pdf_page_size(opts)

    def dump(self, items, out_stream, pdf_metadata):
        self.metadata = pdf_metadata
        self._delete_tmpdir()

        self.render_queue = items
        self.combine_queue = []
        self.out_stream = out_stream

        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, '%i.pdf' % (len(self.combine_queue) + 1)))

        self.logger.debug('Processing %s...' % item)

        self.view.load(QUrl.fromLocalFile(item))

    def _render_html(self, ok):
        if ok:
            item_path = os.path.join(self.tmp_path, '%i.pdf' % len(self.combine_queue))

            self.logger.debug('\tRendering item %s as %i' % (os.path.basename(str(self.view.url().toLocalFile())), len(self.combine_queue)))

            printer = QPrinter(QPrinter.HighResolution)
            printer.setPaperSize(QSizeF(self.size[0] * 10, self.size[1] * 10), QPrinter.Millimeter)
            printer.setPageMargins(0, 0, 0, 0, QPrinter.Point)
            printer.setOrientation(orientation(self.opts.orientation))
            printer.setOutputFormat(QPrinter.PdfFormat)
            printer.setOutputFileName(item_path)
            self.view.print_(printer)
        self._render_book()

    def _delete_tmpdir(self):
        if os.path.exists(self.tmp_path):
            shutil.rmtree(self.tmp_path, True)
            self.tmp_path = PersistentTemporaryDirectory('_pdf_output_parts')

    def _write(self):
        self.logger.debug('Combining individual PDF parts...')

        try:
            outPDF = PdfFileWriter(title=self.metadata.title, author=self.metadata.author)
            for item in self.combine_queue:
                inputPDF = PdfFileReader(open(item, 'rb'))
                for page in inputPDF.pages:
                    outPDF.addPage(page)
            outPDF.write(self.out_stream)
        finally:
            self._delete_tmpdir()
            self.loop.exit(0)


class ImagePDFWriter(PDFWriter):

    def __init__(self, opts, log):
        PDFWriter.__init__(self, opts, log)
        self.size = get_imagepdf_page_size(opts)

    def _render_next(self):
        item = str(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)

        height = 'height: %fcm;' % (self.size[1] * 1.3)

        html = '<html><body style="margin: 0;"><img src="%s" style="%s display: block; margin-left: auto; margin-right: auto; padding: 0px;" /></body></html>' % (item, height)

        self.view.setHtml(html)



Generated by  Doxygen 1.6.0   Back to index