~ubuntu-branches/ubuntu/karmic/calibre/karmic

« back to all changes in this revision

Viewing changes to src/calibre/ebooks/pdf/writer.py

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-07-30 12:49:41 UTC
  • mfrom: (1.3.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20090730124941-qjdsmri25zt8zocn
Tags: 0.6.3+dfsg-0ubuntu1
* New upstream release. Please see http://calibre.kovidgoyal.net/new_in_6/
  for the list of new features and changes.
* remove_postinstall.patch: Update for new version.
* build_debug.patch: Does not apply any more, disable for now. Might not be
  necessary any more.
* debian/copyright: Fix reference to versionless GPL.
* debian/rules: Drop obsolete dh_desktop call.
* debian/rules: Add workaround for weird Python 2.6 setuptools behaviour of
  putting compiled .so files into src/calibre/plugins/calibre/plugins
  instead of src/calibre/plugins.
* debian/rules: Drop hal fdi moving, new upstream version does not use hal
  any more. Drop hal dependency, too.
* debian/rules: Install udev rules into /lib/udev/rules.d.
* Add debian/calibre.preinst: Remove unmodified
  /etc/udev/rules.d/95-calibre.rules on upgrade.
* debian/control: Bump Python dependencies to 2.6, since upstream needs
  it now.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
 
 
3
__license__   = 'GPL v3'
 
4
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
 
5
__docformat__ = 'restructuredtext en'
 
6
 
 
7
'''
 
8
Write content to PDF.
 
9
'''
 
10
 
 
11
import os
 
12
import shutil
 
13
 
 
14
from calibre.ptempfile import PersistentTemporaryDirectory
 
15
from calibre.ebooks.pdf.pageoptions import unit, paper_size, \
 
16
    orientation
 
17
from calibre.ebooks.metadata import authors_to_string
 
18
 
 
19
from PyQt4 import QtCore
 
20
from PyQt4.Qt import QUrl, QEventLoop, SIGNAL, QObject, \
 
21
    QApplication, QPrinter, QMetaObject, QSizeF, Qt
 
22
from PyQt4.QtWebKit import QWebView
 
23
 
 
24
from pyPdf import PdfFileWriter, PdfFileReader
 
25
 
 
26
class PDFMetadata(object):
 
27
    def __init__(self, oeb_metadata=None):
 
28
        self.title = _('Unknown')
 
29
        self.author = _('Unknown')
 
30
 
 
31
        if oeb_metadata != None:
 
32
            if len(oeb_metadata.title) >= 1:
 
33
                self.title = oeb_metadata.title[0].value
 
34
            if len(oeb_metadata.creator) >= 1:
 
35
                self.author = authors_to_string([x.value for x in oeb_metadata.creator])
 
36
 
 
37
 
 
38
class PDFWriter(QObject):
 
39
    def __init__(self, opts, log):
 
40
        if QApplication.instance() is None:
 
41
            QApplication([])
 
42
        QObject.__init__(self)
 
43
 
 
44
        self.logger = log
 
45
 
 
46
        self.loop = QEventLoop()
 
47
        self.view = QWebView()
 
48
        self.connect(self.view, SIGNAL('loadFinished(bool)'), self._render_html)
 
49
        self.render_queue = []
 
50
        self.combine_queue = []
 
51
        self.tmp_path = PersistentTemporaryDirectory('_pdf_output_parts')
 
52
 
 
53
        self.custom_size = None
 
54
        if opts.custom_size != None:
 
55
            width, sep, height = opts.custom_size.partition('x')
 
56
            if height != '':
 
57
                try:
 
58
                    width = int(width)
 
59
                    height = int(height)
 
60
                    self.custom_size = (width, height)
 
61
                except:
 
62
                    self.custom_size = None
 
63
 
 
64
        self.opts = opts
 
65
        
 
66
        self.size = self._size()
 
67
 
 
68
    def dump(self, items, out_stream, pdf_metadata):
 
69
        self.metadata = pdf_metadata
 
70
        self._delete_tmpdir()
 
71
 
 
72
        self.render_queue = items
 
73
        self.combine_queue = []
 
74
        self.out_stream = out_stream
 
75
 
 
76
        QMetaObject.invokeMethod(self, "_render_book", Qt.QueuedConnection)
 
77
        self.loop.exec_()
 
78
 
 
79
    def _size(self):
 
80
        '''
 
81
        The size of a pdf page in cm.
 
82
        '''
 
83
        printer = QPrinter(QPrinter.HighResolution)
 
84
 
 
85
        if self.opts.output_profile.short_name == 'default':
 
86
            if self.custom_size == None:
 
87
                printer.setPaperSize(paper_size(self.opts.paper_size))
 
88
            else:
 
89
                printer.setPaperSize(QSizeF(self.custom_size[0], self.custom_size[1]), unit(self.opts.unit))
 
90
        else:
 
91
            printer.setPaperSize(QSizeF(self.opts.output_profile.width / self.opts.output_profile.dpi, self.opts.output_profile.height / self.opts.output_profile.dpi), QPrinter.Inch)
 
92
 
 
93
        printer.setPageMargins(0, 0, 0, 0, QPrinter.Point)
 
94
        printer.setOrientation(orientation(self.opts.orientation))
 
95
        printer.setOutputFormat(QPrinter.PdfFormat)
 
96
 
 
97
        size = printer.paperSize(QPrinter.Millimeter)
 
98
 
 
99
        return size.width() / 10, size.height() / 10
 
100
 
 
101
    @QtCore.pyqtSignature('_render_book()')
 
102
    def _render_book(self):
 
103
        if len(self.render_queue) == 0:
 
104
            self._write()
 
105
        else:
 
106
            self._render_next()
 
107
 
 
108
    def _render_next(self):
 
109
        item = str(self.render_queue.pop(0))
 
110
        self.combine_queue.append(os.path.join(self.tmp_path, '%i.pdf' % (len(self.combine_queue) + 1)))
 
111
 
 
112
        self.logger.debug('Processing %s...' % item)
 
113
 
 
114
        self.view.load(QUrl(item))
 
115
 
 
116
    def _render_html(self, ok):
 
117
        if ok:
 
118
            item_path = os.path.join(self.tmp_path, '%i.pdf' % len(self.combine_queue))
 
119
 
 
120
            self.logger.debug('\tRendering item %s as %i' % (os.path.basename(str(self.view.url().toLocalFile())), len(self.combine_queue)))
 
121
 
 
122
            printer = QPrinter(QPrinter.HighResolution)
 
123
            printer.setPaperSize(QSizeF(self.size[0] * 10, self.size[1] * 10), QPrinter.Millimeter)
 
124
            printer.setPageMargins(0, 0, 0, 0, QPrinter.Point)
 
125
            printer.setOrientation(orientation(self.opts.orientation))
 
126
            printer.setOutputFormat(QPrinter.PdfFormat)
 
127
            printer.setOutputFileName(item_path)
 
128
            self.view.print_(printer)
 
129
        self._render_book()
 
130
 
 
131
    def _delete_tmpdir(self):
 
132
        if os.path.exists(self.tmp_path):
 
133
            shutil.rmtree(self.tmp_path, True)
 
134
            self.tmp_path = PersistentTemporaryDirectory('_pdf_output_parts')
 
135
 
 
136
    def _write(self):
 
137
        self.logger.debug('Combining individual PDF parts...')
 
138
 
 
139
        try:
 
140
            outPDF = PdfFileWriter(title=self.metadata.title, author=self.metadata.author)
 
141
            for item in self.combine_queue:
 
142
                inputPDF = PdfFileReader(open(item, 'rb'))
 
143
                for page in inputPDF.pages:
 
144
                    outPDF.addPage(page)
 
145
            outPDF.write(self.out_stream)
 
146
        finally:
 
147
            self._delete_tmpdir()
 
148
            self.loop.exit(0)
 
149
 
 
150
 
 
151
class ImagePDFWriter(PDFWriter):
 
152
    
 
153
    def _render_next(self):
 
154
        item = str(self.render_queue.pop(0))
 
155
        self.combine_queue.append(os.path.join(self.tmp_path, '%i.pdf' % (len(self.combine_queue) + 1)))
 
156
 
 
157
        self.logger.debug('Processing %s...' % item)
 
158
        
 
159
        height = 'height: %fcm;' % (self.size[1] * 1.3)
 
160
        
 
161
        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)
 
162
 
 
163
        self.view.setHtml(html)
 
164
 
 
165
    def _size(self):
 
166
            printer = QPrinter(QPrinter.HighResolution)
 
167
 
 
168
            if self.opts.output_profile.short_name == 'default':
 
169
                if self.custom_size == None:
 
170
                    printer.setPaperSize(paper_size(self.opts.paper_size))
 
171
                else:
 
172
                    printer.setPaperSize(QSizeF(self.custom_size[0], self.custom_size[1]), unit(self.opts.unit))
 
173
            else:
 
174
                printer.setPaperSize(QSizeF(self.opts.output_profile.comic_screen_size[0] / self.opts.output_profile.dpi, self.opts.output_profile.comic_screen_size[1] / self.opts.output_profile.dpi), QPrinter.Inch)
 
175
 
 
176
            printer.setPageMargins(0, 0, 0, 0, QPrinter.Point)
 
177
            printer.setOrientation(orientation(self.opts.orientation))
 
178
            printer.setOutputFormat(QPrinter.PdfFormat)
 
179
 
 
180
            size = printer.paperSize(QPrinter.Millimeter)
 
181
 
 
182
            return size.width() / 10, size.height() / 10
 
183