6
6
'''Read meta information from epub files'''
9
9
from cStringIO import StringIO
10
10
from contextlib import closing
12
from PyQt4.Qt import QUrl, QEventLoop, QSize, QByteArray, QBuffer, \
13
SIGNAL, QPainter, QImage, QObject, QApplication, Qt, QPalette
14
from PyQt4.QtWebKit import QWebPage
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)
105
class CoverRenderer(QObject):
109
def __init__(self, path):
110
if QApplication.instance() is None:
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)
127
def render_html(self, ok):
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)
140
buf.open(QBuffer.WriteOnly)
141
image.save(buf, 'JPEG')
142
self._image_data = str(ba.data())
149
if not self.rendered:
152
while count < 50 and not self.rendered:
155
return self._image_data
156
return property(fget=fget)
157
image_data = image_data()
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())
172
113
cpage = os.path.join(tdir, os.path.dirname(opf_path), cpage)
173
114
if not os.path.exists(cpage):
175
cr = CoverRenderer(cpage)
116
return render_html_svg_workaround(cpage, default_log)
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):
195
135
reader = OCFZipReader(stream, root=os.getcwdu())
136
mi = MetaInformation(mi)
137
for x in ('guide', 'toc', 'manifest', 'spine'):
196
139
reader.opf.smart_update(mi)
197
140
newopf = StringIO(reader.opf.render())
198
141
safe_replace(stream, reader.container[OPF.MIMETYPE], newopf)
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'))
215
def main(args=sys.argv):
216
parser = option_parser()
217
opts, args = parser.parse_args(args)
221
with open(args[1], 'r+b') as stream:
222
mi = get_metadata(stream, extract_cover=opts.get_cover)
225
mi.title = opts.title
228
mi.authors = opts.authors.split(',')
231
mi.tags = opts.tags.split(',')
234
mi.comments = opts.comment
237
mi.series = opts.series
239
if opts.series_index:
240
mi.series_index = opts.series_index
242
if opts.language is not None:
243
mi.language = opts.language
247
set_metadata(stream, mi)
248
print unicode(get_metadata(stream, extract_cover=False)).encode('utf-8')
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
258
if __name__ == '__main__':