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

« back to all changes in this revision

Viewing changes to src/calibre/ebooks/metadata/epub.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:
5
5
 
6
6
'''Read meta information from epub files'''
7
7
 
8
 
import sys, os, time
 
8
import os
9
9
from cStringIO import StringIO
10
10
from contextlib import closing
11
11
 
12
 
from PyQt4.Qt import QUrl, QEventLoop, QSize, QByteArray, QBuffer, \
13
 
                     SIGNAL, QPainter, QImage, QObject, QApplication, Qt, QPalette
14
 
from PyQt4.QtWebKit import QWebPage
15
 
 
16
12
from calibre.utils.zipfile import ZipFile, BadZipfile, safe_replace
17
13
from calibre.ebooks.BeautifulSoup import BeautifulStoneSoup
18
 
from calibre.ebooks.metadata import get_parser, MetaInformation
 
14
from calibre.ebooks.metadata import MetaInformation
19
15
from calibre.ebooks.metadata.opf2 import OPF
20
16
from calibre.ptempfile import TemporaryDirectory
21
17
from calibre import CurrentDir
102
98
    def open(self, path, *args, **kwargs):
103
99
        return open(os.path.join(self.root, path), *args, **kwargs)
104
100
 
105
 
class CoverRenderer(QObject):
106
 
    WIDTH  = 600
107
 
    HEIGHT = 800
108
 
 
109
 
    def __init__(self, path):
110
 
        if QApplication.instance() is None:
111
 
            QApplication([])
112
 
        QObject.__init__(self)
113
 
        self.loop = QEventLoop()
114
 
        self.page = QWebPage()
115
 
        pal = self.page.palette()
116
 
        pal.setBrush(QPalette.Background, Qt.white)
117
 
        self.page.setPalette(pal)
118
 
        self.page.setViewportSize(QSize(self.WIDTH, self.HEIGHT))
119
 
        self.page.mainFrame().setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff)
120
 
        self.page.mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
121
 
        QObject.connect(self.page, SIGNAL('loadFinished(bool)'), self.render_html)
122
 
        self._image_data = None
123
 
        self.rendered = False
124
 
        url = QUrl.fromLocalFile(os.path.normpath(path))
125
 
        self.page.mainFrame().load(url)
126
 
 
127
 
    def render_html(self, ok):
128
 
        try:
129
 
            if not ok:
130
 
                self.rendered = True
131
 
                return
132
 
            image = QImage(self.page.viewportSize(), QImage.Format_ARGB32)
133
 
            image.setDotsPerMeterX(96*(100/2.54))
134
 
            image.setDotsPerMeterY(96*(100/2.54))
135
 
            painter = QPainter(image)
136
 
            self.page.mainFrame().render(painter)
137
 
            painter.end()
138
 
            ba = QByteArray()
139
 
            buf = QBuffer(ba)
140
 
            buf.open(QBuffer.WriteOnly)
141
 
            image.save(buf, 'JPEG')
142
 
            self._image_data = str(ba.data())
143
 
        finally:
144
 
            self.loop.exit(0)
145
 
        self.rendered = True
146
 
 
147
 
    def image_data():
148
 
        def fget(self):
149
 
            if not self.rendered:
150
 
                self.loop.exec_()
151
 
                count = 0
152
 
                while count < 50 and not self.rendered:
153
 
                    time.sleep(0.1)
154
 
                    count += 1
155
 
            return self._image_data
156
 
        return property(fget=fget)
157
 
    image_data = image_data()
158
 
 
159
 
 
160
101
def get_cover(opf, opf_path, stream):
161
 
    from calibre.gui2 import is_ok_to_use_qt
162
 
    if not is_ok_to_use_qt(): return None
 
102
    from calibre.ebooks import render_html_svg_workaround
 
103
    from calibre.utils.logging import default_log
163
104
    spine = list(opf.spine_items())
164
105
    if not spine:
165
106
        return
172
113
            cpage = os.path.join(tdir, os.path.dirname(opf_path), cpage)
173
114
            if not os.path.exists(cpage):
174
115
                return
175
 
            cr = CoverRenderer(cpage)
176
 
            return cr.image_data
 
116
            return render_html_svg_workaround(cpage, default_log)
177
117
 
178
118
def get_metadata(stream, extract_cover=True):
179
119
    """ Return metadata as a :class:`MetaInformation` object """
193
133
def set_metadata(stream, mi):
194
134
    stream.seek(0)
195
135
    reader = OCFZipReader(stream, root=os.getcwdu())
 
136
    mi = MetaInformation(mi)
 
137
    for x in ('guide', 'toc', 'manifest', 'spine'):
 
138
        setattr(mi, x, None)
196
139
    reader.opf.smart_update(mi)
197
140
    newopf = StringIO(reader.opf.render())
198
141
    safe_replace(stream, reader.container[OPF.MIMETYPE], newopf)
199
142
 
200
 
def option_parser():
201
 
    parser = get_parser('epub')
202
 
    parser.remove_option('--category')
203
 
    parser.add_option('--tags', default=None,
204
 
                      help=_('A comma separated list of tags to set'))
205
 
    parser.add_option('--series', default=None,
206
 
                      help=_('The series to which this book belongs'))
207
 
    parser.add_option('--series-index', default=None,
208
 
                      help=_('The series index'))
209
 
    parser.add_option('--language', default=None,
210
 
                      help=_('The book language'))
211
 
    parser.add_option('--get-cover', default=False, action='store_true',
212
 
                      help=_('Extract the cover'))
213
 
    return parser
214
 
 
215
 
def main(args=sys.argv):
216
 
    parser = option_parser()
217
 
    opts, args = parser.parse_args(args)
218
 
    if len(args) != 2:
219
 
        parser.print_help()
220
 
        return 1
221
 
    with open(args[1], 'r+b') as stream:
222
 
        mi = get_metadata(stream, extract_cover=opts.get_cover)
223
 
        changed = False
224
 
        if opts.title:
225
 
            mi.title = opts.title
226
 
            changed = True
227
 
        if opts.authors:
228
 
            mi.authors = opts.authors.split(',')
229
 
            changed = True
230
 
        if opts.tags:
231
 
            mi.tags = opts.tags.split(',')
232
 
            changed = True
233
 
        if opts.comment:
234
 
            mi.comments = opts.comment
235
 
            changed = True
236
 
        if opts.series:
237
 
            mi.series = opts.series
238
 
            changed = True
239
 
        if opts.series_index:
240
 
            mi.series_index = opts.series_index
241
 
            changed = True
242
 
        if opts.language is not None:
243
 
            mi.language = opts.language
244
 
            changed = True
245
 
 
246
 
        if changed:
247
 
            set_metadata(stream, mi)
248
 
        print unicode(get_metadata(stream, extract_cover=False)).encode('utf-8')
249
 
 
250
 
    if mi.cover_data[1] is not None:
251
 
        cpath = os.path.splitext(os.path.basename(args[1]))[0] + '_cover.jpg'
252
 
        with open(cpath, 'wb') as f:
253
 
            f.write(mi.cover_data[1])
254
 
            print 'Cover saved to', f.name
255
 
 
256
 
    return 0
257
 
 
258
 
if __name__ == '__main__':
259
 
    sys.exit(main())