Fix #1694 (ePub cover pages with images to MOBI)

This commit is contained in:
Kovid Goyal 2009-01-28 08:16:45 -08:00
commit e2a2701e23
2 changed files with 39 additions and 32 deletions

View File

@ -106,9 +106,11 @@ class CoverRenderer(QObject):
WIDTH = 600 WIDTH = 600
HEIGHT = 800 HEIGHT = 800
def __init__(self, url, size, loop): def __init__(self, path):
if QApplication.instance() is None:
QApplication([])
QObject.__init__(self) QObject.__init__(self)
self.loop = loop self.loop = QEventLoop()
self.page = QWebPage() self.page = QWebPage()
pal = self.page.palette() pal = self.page.palette()
pal.setBrush(QPalette.Background, Qt.white) pal.setBrush(QPalette.Background, Qt.white)
@ -117,33 +119,43 @@ class CoverRenderer(QObject):
self.page.mainFrame().setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff) self.page.mainFrame().setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff)
self.page.mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff) self.page.mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
QObject.connect(self.page, SIGNAL('loadFinished(bool)'), self.render_html) QObject.connect(self.page, SIGNAL('loadFinished(bool)'), self.render_html)
self.image_data = None self._image_data = None
self.rendered = False self.rendered = False
url = QUrl.fromLocalFile(os.path.normpath(path))
self.page.mainFrame().load(url) self.page.mainFrame().load(url)
def render_html(self, ok): def render_html(self, ok):
self.rendered = True
try: try:
if not ok: if not ok:
self.rendered = True
return return
#size = self.page.mainFrame().contentsSize()
#width, height = fit_image(size.width(), size.height(), self.WIDTH, self.HEIGHT)[1:]
#self.page.setViewportSize(QSize(width, height))
image = QImage(self.page.viewportSize(), QImage.Format_ARGB32) image = QImage(self.page.viewportSize(), QImage.Format_ARGB32)
image.setDotsPerMeterX(96*(100/2.54)) image.setDotsPerMeterX(96*(100/2.54))
image.setDotsPerMeterY(96*(100/2.54)) image.setDotsPerMeterY(96*(100/2.54))
painter = QPainter(image) painter = QPainter(image)
self.page.mainFrame().render(painter) self.page.mainFrame().render(painter)
painter.end() painter.end()
ba = QByteArray() ba = QByteArray()
buf = QBuffer(ba) buf = QBuffer(ba)
buf.open(QBuffer.WriteOnly) buf.open(QBuffer.WriteOnly)
image.save(buf, 'JPEG') image.save(buf, 'JPEG')
self.image_data = str(ba.data()) self._image_data = str(ba.data())
finally: finally:
self.loop.exit(0) self.loop.exit(0)
self.rendered = True
def image_data():
def fget(self):
if not self.rendered:
self.loop.exec_()
count = 0
while count < 50 and not self.rendered:
time.sleep(0.1)
count += 1
return self._image_data
return property(fget=fget)
image_data = image_data()
def get_cover(opf, opf_path, stream): def get_cover(opf, opf_path, stream):
spine = list(opf.spine_items()) spine = list(opf.spine_items())
@ -155,20 +167,11 @@ def get_cover(opf, opf_path, stream):
stream.seek(0) stream.seek(0)
ZipFile(stream).extractall() ZipFile(stream).extractall()
opf_path = opf_path.replace('/', os.sep) opf_path = opf_path.replace('/', os.sep)
cpage = os.path.join(tdir, os.path.dirname(opf_path), *cpage.split('/')) cpage = os.path.join(tdir, os.path.dirname(opf_path), cpage)
if not os.path.exists(cpage): if not os.path.exists(cpage):
return return
if QApplication.instance() is None: cr = CoverRenderer(cpage)
QApplication([]) return cr.image_data
url = QUrl.fromLocalFile(cpage)
loop = QEventLoop()
cr = CoverRenderer(url, os.stat(cpage).st_size, loop)
loop.exec_()
count = 0
while count < 50 and not cr.rendered:
time.sleep(0.1)
count += 1
return cr.image_data
def get_metadata(stream, extract_cover=True): def get_metadata(stream, extract_cover=True):
""" Return metadata as a :class:`MetaInformation` object """ """ Return metadata as a :class:`MetaInformation` object """

View File

@ -23,6 +23,8 @@ from calibre import LoggingInterface
from calibre.translations.dynamic import translate from calibre.translations.dynamic import translate
from calibre.startup import get_lang from calibre.startup import get_lang
from calibre.ebooks.oeb.entitydefs import ENTITYDEFS from calibre.ebooks.oeb.entitydefs import ENTITYDEFS
from calibre.ebooks.metadata.epub import CoverRenderer
from calibre.ptempfile import TemporaryDirectory
XML_NS = 'http://www.w3.org/XML/1998/namespace' XML_NS = 'http://www.w3.org/XML/1998/namespace'
XHTML_NS = 'http://www.w3.org/1999/xhtml' XHTML_NS = 'http://www.w3.org/1999/xhtml'
@ -798,7 +800,6 @@ class TOC(object):
class OEBBook(object): class OEBBook(object):
COVER_SVG_XP = XPath('h:body//svg:svg[position() = 1]') COVER_SVG_XP = XPath('h:body//svg:svg[position() = 1]')
COVER_OBJECT_XP = XPath('h:body//h:object[@data][position() = 1]') COVER_OBJECT_XP = XPath('h:body//h:object[@data][position() = 1]')
COVER_IMG_XP = XPath('h:body//h:img[@src][position() = 1]')
def __init__(self, opfpath=None, container=None, encoding=None, def __init__(self, opfpath=None, container=None, encoding=None,
logger=FauxLogger()): logger=FauxLogger()):
@ -1055,6 +1056,17 @@ class OEBBook(object):
if self._toc_from_html(opf): return if self._toc_from_html(opf): return
self._toc_from_spine(opf) self._toc_from_spine(opf)
def _cover_from_html(self, hcover):
with TemporaryDirectory('_html_cover') as tdir:
writer = DirWriter()
writer.dump(self, tdir)
path = os.path.join(tdir, hcover.href)
renderer = CoverRenderer(path)
data = renderer.image_data
id, href = self.manifest.generate('cover', 'cover.jpeg')
item = self.manifest.add(id, href, JPEG_MIME, data=data)
return item
def _locate_cover_image(self): def _locate_cover_image(self):
if self.metadata.cover: if self.metadata.cover:
id = str(self.metadata.cover[0]) id = str(self.metadata.cover[0])
@ -1088,18 +1100,10 @@ class OEBBook(object):
item = self.manifest.hrefs.get(href, None) item = self.manifest.hrefs.get(href, None)
if item is not None and item.media_type in OEB_IMAGES: if item is not None and item.media_type in OEB_IMAGES:
return item return item
if self.COVER_IMG_XP(html): return self._cover_from_html(hcover)
img = self.COVER_IMG_XP(html)[0]
href = hcover.abshref(img.get('src'))
item = self.manifest.hrefs.get(href, None)
if item is not None and item.media_type in OEB_IMAGES:
return item
return None
def _ensure_cover_image(self): def _ensure_cover_image(self):
cover = self._locate_cover_image() cover = self._locate_cover_image()
if not cover:
return
if self.metadata.cover: if self.metadata.cover:
self.metadata.cover[0].value = cover.id self.metadata.cover[0].value = cover.id
return return