mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Fixed various bugs; added various improvements.
This commit is contained in:
parent
28512fac5a
commit
4346c7f66c
@ -104,7 +104,7 @@ class MobiMLizer(object):
|
|||||||
return ptsize
|
return ptsize
|
||||||
fbase = self.profile.fbase
|
fbase = self.profile.fbase
|
||||||
if ptsize < fbase:
|
if ptsize < fbase:
|
||||||
return "%dpt" % int(round(ptsize * 2))
|
return "%dpt" % int(round(ptsize))
|
||||||
return "%dem" % int(round(ptsize / fbase))
|
return "%dem" % int(round(ptsize / fbase))
|
||||||
|
|
||||||
def preize_text(self, text):
|
def preize_text(self, text):
|
||||||
@ -284,9 +284,9 @@ class MobiMLizer(object):
|
|||||||
else:
|
else:
|
||||||
istate.family = 'serif'
|
istate.family = 'serif'
|
||||||
valign = style['vertical-align']
|
valign = style['vertical-align']
|
||||||
if valign in ('super', 'sup') and asfloat(valign) > 0:
|
if valign in ('super', 'sup') or asfloat(valign) > 0:
|
||||||
istate.valign = 'super'
|
istate.valign = 'super'
|
||||||
elif valign == 'sub' and asfloat(valign) < 0:
|
elif valign == 'sub' or asfloat(valign) < 0:
|
||||||
istate.valign = 'sub'
|
istate.valign = 'sub'
|
||||||
else:
|
else:
|
||||||
istate.valign = 'baseline'
|
istate.valign = 'baseline'
|
||||||
@ -300,6 +300,15 @@ class MobiMLizer(object):
|
|||||||
if tag == 'img' and 'src' in elem.attrib:
|
if tag == 'img' and 'src' in elem.attrib:
|
||||||
istate.attrib['src'] = elem.attrib['src']
|
istate.attrib['src'] = elem.attrib['src']
|
||||||
istate.attrib['align'] = 'baseline'
|
istate.attrib['align'] = 'baseline'
|
||||||
|
for prop in ('width', 'height'):
|
||||||
|
if style[prop] != 'auto':
|
||||||
|
value = style[prop]
|
||||||
|
if value == getattr(self.profile, prop):
|
||||||
|
result = '100%'
|
||||||
|
else:
|
||||||
|
ems = int(round(value / self.profile.fbase))
|
||||||
|
result = "%dem" % ems
|
||||||
|
istate.attrib[prop] = result
|
||||||
elif tag == 'hr' and asfloat(style['width']) > 0:
|
elif tag == 'hr' and asfloat(style['width']) > 0:
|
||||||
prop = style['width'] / self.profile.width
|
prop = style['width'] / self.profile.width
|
||||||
istate.attrib['width'] = "%d%%" % int(round(prop * 100))
|
istate.attrib['width'] = "%d%%" % int(round(prop * 100))
|
||||||
|
@ -225,11 +225,22 @@ class MobiWriter(object):
|
|||||||
self._oeb = oeb
|
self._oeb = oeb
|
||||||
self._stream = stream
|
self._stream = stream
|
||||||
self._records = [None]
|
self._records = [None]
|
||||||
|
self._remove_html_cover()
|
||||||
self._generate_content()
|
self._generate_content()
|
||||||
self._generate_record0()
|
self._generate_record0()
|
||||||
self._write_header()
|
self._write_header()
|
||||||
self._write_content()
|
self._write_content()
|
||||||
|
|
||||||
|
def _remove_html_cover(self):
|
||||||
|
oeb = self._oeb
|
||||||
|
if not oeb.metadata.cover \
|
||||||
|
or 'cover' not in oeb.guide:
|
||||||
|
return
|
||||||
|
href = oeb.guide['cover'].href
|
||||||
|
del oeb.guide['cover']
|
||||||
|
item = oeb.manifest.hrefs[href]
|
||||||
|
oeb.manifest.remove(item)
|
||||||
|
|
||||||
def _generate_content(self):
|
def _generate_content(self):
|
||||||
self._map_image_names()
|
self._map_image_names()
|
||||||
self._generate_text()
|
self._generate_text()
|
||||||
@ -391,7 +402,7 @@ class MobiWriter(object):
|
|||||||
nrecs += 1
|
nrecs += 1
|
||||||
if oeb.metadata.cover:
|
if oeb.metadata.cover:
|
||||||
id = str(oeb.metadata.cover[0])
|
id = str(oeb.metadata.cover[0])
|
||||||
item = oeb.manifest[id]
|
item = oeb.manifest.ids[id]
|
||||||
href = item.href
|
href = item.href
|
||||||
index = self._images[href] - 1
|
index = self._images[href] - 1
|
||||||
exth.write(pack('>III', 0xc9, 0x0c, index))
|
exth.write(pack('>III', 0xc9, 0x0c, index))
|
||||||
|
@ -17,6 +17,7 @@ import logging
|
|||||||
import re
|
import re
|
||||||
import htmlentitydefs
|
import htmlentitydefs
|
||||||
import uuid
|
import uuid
|
||||||
|
import copy
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from calibre import LoggingInterface
|
from calibre import LoggingInterface
|
||||||
|
|
||||||
@ -32,10 +33,11 @@ XSI_NS = 'http://www.w3.org/2001/XMLSchema-instance'
|
|||||||
DCTERMS_NS = 'http://purl.org/dc/terms/'
|
DCTERMS_NS = 'http://purl.org/dc/terms/'
|
||||||
NCX_NS = 'http://www.daisy.org/z3986/2005/ncx/'
|
NCX_NS = 'http://www.daisy.org/z3986/2005/ncx/'
|
||||||
SVG_NS = 'http://www.w3.org/2000/svg'
|
SVG_NS = 'http://www.w3.org/2000/svg'
|
||||||
|
XLINK_NS = 'http://www.w3.org/1999/xlink'
|
||||||
XPNSMAP = {'h': XHTML_NS, 'o1': OPF1_NS, 'o2': OPF2_NS,
|
XPNSMAP = {'h': XHTML_NS, 'o1': OPF1_NS, 'o2': OPF2_NS,
|
||||||
'd09': DC09_NS, 'd10': DC10_NS, 'd11': DC11_NS,
|
'd09': DC09_NS, 'd10': DC10_NS, 'd11': DC11_NS,
|
||||||
'xsi': XSI_NS, 'dt': DCTERMS_NS, 'ncx': NCX_NS,
|
'xsi': XSI_NS, 'dt': DCTERMS_NS, 'ncx': NCX_NS,
|
||||||
'svg': SVG_NS}
|
'svg': SVG_NS, 'xl': XLINK_NS}
|
||||||
|
|
||||||
def XML(name): return '{%s}%s' % (XML_NS, name)
|
def XML(name): return '{%s}%s' % (XML_NS, name)
|
||||||
def XHTML(name): return '{%s}%s' % (XHTML_NS, name)
|
def XHTML(name): return '{%s}%s' % (XHTML_NS, name)
|
||||||
@ -43,6 +45,7 @@ def OPF(name): return '{%s}%s' % (OPF2_NS, name)
|
|||||||
def DC(name): return '{%s}%s' % (DC11_NS, name)
|
def DC(name): return '{%s}%s' % (DC11_NS, name)
|
||||||
def NCX(name): return '{%s}%s' % (NCX_NS, name)
|
def NCX(name): return '{%s}%s' % (NCX_NS, name)
|
||||||
def SVG(name): return '{%s}%s' % (SVG_NS, name)
|
def SVG(name): return '{%s}%s' % (SVG_NS, name)
|
||||||
|
def XLINK(name): return '{%s}%s' % (XLINK_NS, name)
|
||||||
|
|
||||||
EPUB_MIME = 'application/epub+zip'
|
EPUB_MIME = 'application/epub+zip'
|
||||||
XHTML_MIME = 'application/xhtml+xml'
|
XHTML_MIME = 'application/xhtml+xml'
|
||||||
@ -246,10 +249,10 @@ class Metadata(object):
|
|||||||
self.oeb = oeb
|
self.oeb = oeb
|
||||||
self.items = defaultdict(list)
|
self.items = defaultdict(list)
|
||||||
|
|
||||||
def add(self, term, value, attrib={}, **kwargs):
|
def add(self, term, value, attrib={}, index=-1, **kwargs):
|
||||||
item = self.Item(term, value, attrib, **kwargs)
|
item = self.Item(term, value, attrib, **kwargs)
|
||||||
items = self.items[barename(item.term)]
|
items = self.items[barename(item.term)]
|
||||||
items.append(item)
|
items.insert(index, item)
|
||||||
return item
|
return item
|
||||||
|
|
||||||
def iterkeys(self):
|
def iterkeys(self):
|
||||||
@ -323,8 +326,7 @@ class Manifest(object):
|
|||||||
data = self._loader(self.href)
|
data = self._loader(self.href)
|
||||||
if self.media_type in OEB_DOCS:
|
if self.media_type in OEB_DOCS:
|
||||||
data = self._force_xhtml(data)
|
data = self._force_xhtml(data)
|
||||||
elif self.media_type[-4:] in ('+xml', '/xml') \
|
elif self.media_type[-4:] in ('+xml', '/xml'):
|
||||||
and self.media_type != SVG_MIME:
|
|
||||||
data = etree.fromstring(data, parser=XML_PARSER)
|
data = etree.fromstring(data, parser=XML_PARSER)
|
||||||
self._data = data
|
self._data = data
|
||||||
return data
|
return data
|
||||||
@ -341,6 +343,9 @@ class Manifest(object):
|
|||||||
return xml2str(data)
|
return xml2str(data)
|
||||||
return str(data)
|
return str(data)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return id(self) == id(other)
|
||||||
|
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
result = cmp(self.spine_position, other.spine_position)
|
result = cmp(self.spine_position, other.spine_position)
|
||||||
if result != 0:
|
if result != 0:
|
||||||
@ -558,9 +563,12 @@ class Guide(object):
|
|||||||
for type, ref in self.refs.items():
|
for type, ref in self.refs.items():
|
||||||
yield type, ref
|
yield type, ref
|
||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, key):
|
||||||
return self.refs[index]
|
return self.refs[key]
|
||||||
|
|
||||||
|
def __delitem__(self, key):
|
||||||
|
del self.refs[key]
|
||||||
|
|
||||||
def __contains__(self, key):
|
def __contains__(self, key):
|
||||||
return key in self.refs
|
return key in self.refs
|
||||||
|
|
||||||
@ -891,20 +899,27 @@ class OEBBook(object):
|
|||||||
|
|
||||||
def _ensure_cover_image(self):
|
def _ensure_cover_image(self):
|
||||||
cover = None
|
cover = None
|
||||||
|
spine0 = self.spine[0]
|
||||||
|
html = spine0.data
|
||||||
if self.metadata.cover:
|
if self.metadata.cover:
|
||||||
id = str(self.metadata.cover[0])
|
id = str(self.metadata.cover[0])
|
||||||
cover = self.manifest[id]
|
cover = self.manifest.ids[id]
|
||||||
elif MS_COVER_TYPE in self.guide:
|
elif MS_COVER_TYPE in self.guide:
|
||||||
href = self.guide[MS_COVER_TYPE].href
|
href = self.guide[MS_COVER_TYPE].href
|
||||||
cover = self.manifest.hrefs[href]
|
cover = self.manifest.hrefs[href]
|
||||||
elif 'cover' in self.guide:
|
elif xpath(html, '//h:img[position()=1]'):
|
||||||
href = self.guide['cover'].href
|
img = xpath(html, '//h:img[position()=1]')[0]
|
||||||
|
href = img.get('src')
|
||||||
cover = self.manifest.hrefs[href]
|
cover = self.manifest.hrefs[href]
|
||||||
else:
|
elif xpath(html, '//h:object[position()=1]'):
|
||||||
html = self.spine[0].data
|
object = xpath(html, '//h:object[position()=1]')[0]
|
||||||
imgs = xpath(html, '//h:img[position()=1]')
|
href = object.get('data')
|
||||||
href = imgs[0].get('src') if imgs else None
|
cover = self.manifest.hrefs[href]
|
||||||
cover = self.manifest.hrefs[href] if href else None
|
elif xpath(html, '//svg:svg[position()=1]'):
|
||||||
|
svg = copy.deepcopy(xpath(html, '//svg:svg[position()=1]')[0])
|
||||||
|
href = os.path.splitext(spine0.href)[0] + '.svg'
|
||||||
|
id, href = self.manifest.generate(spine0.id, href)
|
||||||
|
cover = self.manifest.add(id, href, SVG_MIME, data=svg)
|
||||||
if cover and not self.metadata.cover:
|
if cover and not self.metadata.cover:
|
||||||
self.metadata.add('cover', cover.id)
|
self.metadata.add('cover', cover.id)
|
||||||
|
|
||||||
|
@ -35,7 +35,8 @@
|
|||||||
*
|
*
|
||||||
* ***** END LICENSE BLOCK ***** */
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
@namespace url(http://www.w3.org/1999/xhtml); /* set default namespace to HTML */
|
@namespace url(http://www.w3.org/1999/xhtml);
|
||||||
|
@namespace svg url(http://www.w3.org/2000/svg);
|
||||||
|
|
||||||
/* blocks */
|
/* blocks */
|
||||||
|
|
||||||
@ -399,8 +400,8 @@ br {
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Images and embedded object size defaults */
|
/* Images, embedded object, and SVG size defaults */
|
||||||
img, object {
|
img, object, svg|svg {
|
||||||
width: auto;
|
width: auto;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
@ -41,8 +41,8 @@ PROFILES = {
|
|||||||
|
|
||||||
# Not really, but let's pretend
|
# Not really, but let's pretend
|
||||||
'MobiDesktop':
|
'MobiDesktop':
|
||||||
Profile(width=280, height=300, dpi=96, fbase=12,
|
Profile(width=280, height=300, dpi=96, fbase=18,
|
||||||
fsizes=[9, 10, 11, 12, 14, 17, 20, 24]),
|
fsizes=[14, 14, 16, 18, 20, 22, 22, 24]),
|
||||||
|
|
||||||
# No clue on usable screen size and DPI
|
# No clue on usable screen size and DPI
|
||||||
'CybookG3':
|
'CybookG3':
|
||||||
|
@ -268,6 +268,7 @@ class Style(object):
|
|||||||
self._style = {}
|
self._style = {}
|
||||||
self._fontSize = None
|
self._fontSize = None
|
||||||
self._width = None
|
self._width = None
|
||||||
|
self._height = None
|
||||||
stylizer._styles[element] = self
|
stylizer._styles[element] = self
|
||||||
|
|
||||||
def _update_cssdict(self, cssdict):
|
def _update_cssdict(self, cssdict):
|
||||||
@ -390,17 +391,38 @@ class Style(object):
|
|||||||
base = styles[self._element.getparent()].width
|
base = styles[self._element.getparent()].width
|
||||||
else:
|
else:
|
||||||
base = self._profile.width
|
base = self._profile.width
|
||||||
if 'width' in self._style:
|
if 'width' is self._element.attrib:
|
||||||
|
width = self._element.attrib['width']
|
||||||
|
elif 'width' in self._style:
|
||||||
width = self._style['width']
|
width = self._style['width']
|
||||||
if width == 'auto':
|
|
||||||
result = base
|
|
||||||
else:
|
|
||||||
result = self._unit_convert(width, base=base)
|
|
||||||
else:
|
else:
|
||||||
result = base
|
result = base
|
||||||
|
if not result:
|
||||||
|
result = self._unit_convert(width, base=base)
|
||||||
self._width = result
|
self._width = result
|
||||||
return self._width
|
return self._width
|
||||||
|
|
||||||
|
@property
|
||||||
|
def height(self):
|
||||||
|
if self._height is None:
|
||||||
|
result = None
|
||||||
|
base = None
|
||||||
|
if self._has_parent():
|
||||||
|
styles = self._stylizer._styles
|
||||||
|
base = styles[self._element.getparent()].height
|
||||||
|
else:
|
||||||
|
base = self._profile.height
|
||||||
|
if 'height' is self._element.attrib:
|
||||||
|
height = self._element.attrib['height']
|
||||||
|
elif 'height' in self._style:
|
||||||
|
height = self._style['height']
|
||||||
|
else:
|
||||||
|
result = base
|
||||||
|
if not result:
|
||||||
|
result = self._unit_convert(height, base=base)
|
||||||
|
self._height = result
|
||||||
|
return self._height
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
items = self._style.items()
|
items = self._style.items()
|
||||||
items.sort()
|
items.sort()
|
||||||
|
@ -8,17 +8,21 @@ __copyright__ = '2008, Marshall T. Vandegrift <llasram@gmail.com>'
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
from urlparse import urldefrag
|
||||||
|
import base64
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from PyQt4.QtCore import Qt
|
from PyQt4.QtCore import Qt
|
||||||
from PyQt4.QtCore import QByteArray
|
from PyQt4.QtCore import QByteArray
|
||||||
from PyQt4.QtCore import QBuffer
|
from PyQt4.QtCore import QBuffer
|
||||||
from PyQt4.QtCore import QIODevice
|
from PyQt4.QtCore import QIODevice
|
||||||
|
from PyQt4.QtGui import QColor
|
||||||
from PyQt4.QtGui import QImage
|
from PyQt4.QtGui import QImage
|
||||||
from PyQt4.QtGui import QPainter
|
from PyQt4.QtGui import QPainter
|
||||||
from PyQt4.QtSvg import QSvgRenderer
|
from PyQt4.QtSvg import QSvgRenderer
|
||||||
from PyQt4.QtGui import QApplication
|
from PyQt4.QtGui import QApplication
|
||||||
from calibre.ebooks.oeb.base import XHTML, SVG, SVG_NS, SVG_MIME
|
from calibre.ebooks.oeb.base import XHTML_NS, XHTML, SVG_NS, SVG, XLINK
|
||||||
from calibre.ebooks.oeb.base import namespace, barename
|
from calibre.ebooks.oeb.base import SVG_MIME, PNG_MIME
|
||||||
|
from calibre.ebooks.oeb.base import xml2str, xpath, namespace, barename
|
||||||
from calibre.ebooks.oeb.stylizer import Stylizer
|
from calibre.ebooks.oeb.stylizer import Stylizer
|
||||||
|
|
||||||
IMAGE_TAGS = set([XHTML('img'), XHTML('object')])
|
IMAGE_TAGS = set([XHTML('img'), XHTML('object')])
|
||||||
@ -32,8 +36,55 @@ class SVGRasterizer(object):
|
|||||||
self.oeb = oeb
|
self.oeb = oeb
|
||||||
self.profile = context.dest
|
self.profile = context.dest
|
||||||
self.images = {}
|
self.images = {}
|
||||||
|
self.dataize_manifest()
|
||||||
self.rasterize_spine()
|
self.rasterize_spine()
|
||||||
|
self.rasterize_cover()
|
||||||
|
|
||||||
|
def rasterize_svg(self, elem, width=0, height=0):
|
||||||
|
data = QByteArray(xml2str(elem))
|
||||||
|
svg = QSvgRenderer(data)
|
||||||
|
size = svg.defaultSize()
|
||||||
|
if size.width() == 100 and size.height() == 100 \
|
||||||
|
and 'viewBox' in elem.attrib:
|
||||||
|
box = [float(x) for x in elem.attrib['viewBox'].split()]
|
||||||
|
size.setWidth(box[2] - box[0])
|
||||||
|
size.setHeight(box[3] - box[1])
|
||||||
|
if width or height:
|
||||||
|
size.scale(width, height, Qt.KeepAspectRatio)
|
||||||
|
image = QImage(size, QImage.Format_ARGB32_Premultiplied)
|
||||||
|
image.fill(QColor("white").rgb())
|
||||||
|
painter = QPainter(image)
|
||||||
|
svg.render(painter)
|
||||||
|
painter.end()
|
||||||
|
array = QByteArray()
|
||||||
|
buffer = QBuffer(array)
|
||||||
|
buffer.open(QIODevice.WriteOnly)
|
||||||
|
image.save(buffer, 'PNG')
|
||||||
|
return str(array)
|
||||||
|
|
||||||
|
def dataize_manifest(self):
|
||||||
|
for item in self.oeb.manifest.values():
|
||||||
|
if item.media_type == SVG_MIME:
|
||||||
|
self.dataize_svg(item)
|
||||||
|
|
||||||
|
def dataize_svg(self, item, svg=None):
|
||||||
|
if svg is None:
|
||||||
|
svg = item.data
|
||||||
|
hrefs = self.oeb.manifest.hrefs
|
||||||
|
for elem in xpath(svg, '//svg:*[@xl:href]'):
|
||||||
|
href = elem.attrib[XLINK('href')]
|
||||||
|
path, frag = urldefrag(href)
|
||||||
|
if not path:
|
||||||
|
continue
|
||||||
|
abshref = item.abshref(path)
|
||||||
|
if abshref not in hrefs:
|
||||||
|
continue
|
||||||
|
linkee = hrefs[abshref]
|
||||||
|
data = base64.encodestring(str(linkee))
|
||||||
|
data = "data:%s;base64,%s" % (linkee.media_type, data)
|
||||||
|
elem.attrib[XLINK('href')] = data
|
||||||
|
return svg
|
||||||
|
|
||||||
def rasterize_spine(self):
|
def rasterize_spine(self):
|
||||||
for item in self.oeb.spine:
|
for item in self.oeb.spine:
|
||||||
html = item.data
|
html = item.data
|
||||||
@ -44,7 +95,7 @@ class SVGRasterizer(object):
|
|||||||
if not isinstance(elem.tag, basestring): return
|
if not isinstance(elem.tag, basestring): return
|
||||||
style = stylizer.style(elem)
|
style = stylizer.style(elem)
|
||||||
if namespace(elem.tag) == SVG_NS:
|
if namespace(elem.tag) == SVG_NS:
|
||||||
return self.rasterize_inline(elem, style)
|
return self.rasterize_inline(elem, style, item)
|
||||||
if elem.tag in IMAGE_TAGS:
|
if elem.tag in IMAGE_TAGS:
|
||||||
manifest = self.oeb.manifest
|
manifest = self.oeb.manifest
|
||||||
src = elem.get('src', None) or elem.get('data', None)
|
src = elem.get('src', None) or elem.get('data', None)
|
||||||
@ -54,27 +105,46 @@ class SVGRasterizer(object):
|
|||||||
for child in elem:
|
for child in elem:
|
||||||
self.rasterize_elem(child, item, stylizer)
|
self.rasterize_elem(child, item, stylizer)
|
||||||
|
|
||||||
def rasterize_inline(self, elem, style):
|
def rasterize_inline(self, elem, style, item):
|
||||||
pass
|
|
||||||
|
|
||||||
def rasterize_external(self, elem, style, item, svgitem):
|
|
||||||
data = QByteArray(svgitem.data)
|
|
||||||
svg = QSvgRenderer(data)
|
|
||||||
size = svg.defaultSize()
|
|
||||||
height = style['height']
|
|
||||||
if height == 'auto':
|
|
||||||
height = self.profile.height
|
|
||||||
width = style['width']
|
width = style['width']
|
||||||
if width == 'auto':
|
if width == 'auto':
|
||||||
width = self.profile.width
|
width = self.profile.width
|
||||||
|
height = style['height']
|
||||||
|
if height == 'auto':
|
||||||
|
height = self.profile.height
|
||||||
width = (width / 72) * self.profile.dpi
|
width = (width / 72) * self.profile.dpi
|
||||||
height = (height / 72) * self.profile.dpi
|
height = (height / 72) * self.profile.dpi
|
||||||
|
elem = self.dataize_svg(item, elem)
|
||||||
|
data = self.rasterize_svg(elem, width, height)
|
||||||
|
manifest = self.oeb.manifest
|
||||||
|
href = os.path.splitext(item.href)[0] + '.png'
|
||||||
|
id, href = manifest.generate(item.id, href)
|
||||||
|
manifest.add(id, href, PNG_MIME, data=data)
|
||||||
|
img = etree.Element(XHTML('img'), src=item.relhref(href))
|
||||||
|
elem.getparent().replace(elem, img)
|
||||||
|
for prop in ('width', 'height'):
|
||||||
|
if prop in elem.attrib:
|
||||||
|
img.attrib[prop] = elem.attrib[prop]
|
||||||
|
|
||||||
|
def rasterize_external(self, elem, style, item, svgitem):
|
||||||
|
width = style['width']
|
||||||
|
if width == 'auto':
|
||||||
|
width = self.profile.width
|
||||||
|
height = style['height']
|
||||||
|
if height == 'auto':
|
||||||
|
height = self.profile.height
|
||||||
|
width = (width / 72) * self.profile.dpi
|
||||||
|
height = (height / 72) * self.profile.dpi
|
||||||
|
data = QByteArray(str(svgitem))
|
||||||
|
svg = QSvgRenderer(data)
|
||||||
|
size = svg.defaultSize()
|
||||||
size.scale(width, height, Qt.KeepAspectRatio)
|
size.scale(width, height, Qt.KeepAspectRatio)
|
||||||
key = (svgitem.href, size.width(), size.height())
|
key = (svgitem.href, size.width(), size.height())
|
||||||
if key in self.images:
|
if key in self.images:
|
||||||
href = self.images[key]
|
href = self.images[key]
|
||||||
else:
|
else:
|
||||||
image = QImage(size, QImage.Format_ARGB32_Premultiplied)
|
image = QImage(size, QImage.Format_ARGB32_Premultiplied)
|
||||||
|
image.fill(QColor("white").rgb())
|
||||||
painter = QPainter(image)
|
painter = QPainter(image)
|
||||||
svg.render(painter)
|
svg.render(painter)
|
||||||
painter.end()
|
painter.end()
|
||||||
@ -86,7 +156,7 @@ class SVGRasterizer(object):
|
|||||||
manifest = self.oeb.manifest
|
manifest = self.oeb.manifest
|
||||||
href = os.path.splitext(svgitem.href)[0] + '.png'
|
href = os.path.splitext(svgitem.href)[0] + '.png'
|
||||||
id, href = manifest.generate(svgitem.id, href)
|
id, href = manifest.generate(svgitem.id, href)
|
||||||
manifest.add(id, href, 'image/png', data=data)
|
manifest.add(id, href, PNG_MIME, data=data)
|
||||||
self.images[key] = href
|
self.images[key] = href
|
||||||
elem.tag = XHTML('img')
|
elem.tag = XHTML('img')
|
||||||
elem.attrib['src'] = item.relhref(href)
|
elem.attrib['src'] = item.relhref(href)
|
||||||
@ -94,3 +164,15 @@ class SVGRasterizer(object):
|
|||||||
for child in elem:
|
for child in elem:
|
||||||
elem.remove(child)
|
elem.remove(child)
|
||||||
|
|
||||||
|
def rasterize_cover(self):
|
||||||
|
covers = self.oeb.metadata.cover
|
||||||
|
if not covers:
|
||||||
|
return
|
||||||
|
cover = self.oeb.manifest.ids[str(covers[0])]
|
||||||
|
if not cover.media_type == SVG_MIME:
|
||||||
|
return
|
||||||
|
data = self.rasterize_svg(cover.data, 600, 800)
|
||||||
|
href = os.path.splitext(cover.href)[0] + '.png'
|
||||||
|
id, href = self.oeb.manifest.generate(cover.id, href)
|
||||||
|
self.oeb.manifest.add(id, href, PNG_MIME, data=data)
|
||||||
|
covers[0].value = id
|
||||||
|
Loading…
x
Reference in New Issue
Block a user