home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 November / maximum-cd-2010-11.iso / DiscContents / calibre-0.7.13.msi / file_1009 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-08-06  |  8.7 KB  |  241 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. from __future__ import with_statement
  5. __license__ = 'GPL v3'
  6. __copyright__ = '2008, Marshall T. Vandegrift <llasram@gmail.com>'
  7. import os
  8. from urlparse import urldefrag
  9. import base64
  10. from lxml import etree
  11. from PyQt4.QtCore import Qt
  12. from PyQt4.QtCore import QByteArray
  13. from PyQt4.QtCore import QBuffer
  14. from PyQt4.QtCore import QIODevice
  15. from PyQt4.QtGui import QColor
  16. from PyQt4.QtGui import QImage
  17. from PyQt4.QtGui import QPainter
  18. from PyQt4.QtSvg import QSvgRenderer
  19. from calibre.ebooks.oeb.base import XHTML, XLINK
  20. from calibre.ebooks.oeb.base import SVG_MIME, PNG_MIME
  21. from calibre.ebooks.oeb.base import xml2str, xpath
  22. from calibre.ebooks.oeb.base import urlnormalize
  23. from calibre.ebooks.oeb.stylizer import Stylizer
  24. IMAGE_TAGS = set([
  25.     XHTML('img'),
  26.     XHTML('object')])
  27. KEEP_ATTRS = set([
  28.     'class',
  29.     'style',
  30.     'width',
  31.     'height',
  32.     'align'])
  33.  
  34. class Unavailable(Exception):
  35.     pass
  36.  
  37.  
  38. class SVGRasterizer(object):
  39.     
  40.     def __init__(self):
  41.         is_ok_to_use_qt = is_ok_to_use_qt
  42.         import calibre.gui2
  43.         if not is_ok_to_use_qt():
  44.             raise Unavailable('Not OK to use Qt')
  45.         is_ok_to_use_qt()
  46.  
  47.     
  48.     def config(cls, cfg):
  49.         return cfg
  50.  
  51.     config = classmethod(config)
  52.     
  53.     def generate(cls, opts):
  54.         return cls()
  55.  
  56.     generate = classmethod(generate)
  57.     
  58.     def __call__(self, oeb, context):
  59.         oeb.logger.info('Rasterizing SVG images...')
  60.         self.oeb = oeb
  61.         self.opts = context
  62.         self.profile = context.dest
  63.         self.images = { }
  64.         self.dataize_manifest()
  65.         self.rasterize_spine()
  66.         self.rasterize_cover()
  67.  
  68.     
  69.     def rasterize_svg(self, elem, width = 0, height = 0, format = 'PNG'):
  70.         data = QByteArray(xml2str(elem))
  71.         svg = QSvgRenderer(data)
  72.         size = svg.defaultSize()
  73.         view_box = elem.get('viewBox', elem.get('viewbox', None))
  74.         if width or height:
  75.             size.scale(width, height, Qt.KeepAspectRatio)
  76.         
  77.         logger = self.oeb.logger
  78.         logger.info('Rasterizing %r to %dx%d' % (elem, size.width(), size.height()))
  79.         image = QImage(size, QImage.Format_ARGB32_Premultiplied)
  80.         image.fill(QColor('white').rgb())
  81.         painter = QPainter(image)
  82.         svg.render(painter)
  83.         painter.end()
  84.         array = QByteArray()
  85.         buffer = QBuffer(array)
  86.         buffer.open(QIODevice.WriteOnly)
  87.         image.save(buffer, format)
  88.         return str(array)
  89.  
  90.     
  91.     def dataize_manifest(self):
  92.         for item in self.oeb.manifest.values():
  93.             if item.media_type == SVG_MIME:
  94.                 self.dataize_svg(item)
  95.                 continue
  96.         
  97.  
  98.     
  99.     def dataize_svg(self, item, svg = None):
  100.         if svg is None:
  101.             svg = item.data
  102.         
  103.         hrefs = self.oeb.manifest.hrefs
  104.         for elem in xpath(svg, '//svg:*[@xl:href]'):
  105.             href = urlnormalize(elem.attrib[XLINK('href')])
  106.             path = urldefrag(href)[0]
  107.             if not path:
  108.                 continue
  109.             
  110.             abshref = item.abshref(path)
  111.             if abshref not in hrefs:
  112.                 continue
  113.             
  114.             linkee = hrefs[abshref]
  115.             data = base64.encodestring(str(linkee))
  116.             data = 'data:%s;base64,%s' % (linkee.media_type, data)
  117.             elem.attrib[XLINK('href')] = data
  118.         
  119.         return svg
  120.  
  121.     
  122.     def rasterize_spine(self):
  123.         for item in self.oeb.spine:
  124.             html = item.data
  125.             stylizer = Stylizer(html, item.href, self.oeb, self.opts, self.profile)
  126.             self.rasterize_item(item, stylizer)
  127.         
  128.  
  129.     
  130.     def rasterize_item(self, item, stylizer):
  131.         html = item.data
  132.         hrefs = self.oeb.manifest.hrefs
  133.         for elem in xpath(html, '//h:img[@src]'):
  134.             src = urlnormalize(elem.attrib['src'])
  135.             image = hrefs.get(item.abshref(src), None)
  136.             if image and image.media_type == SVG_MIME:
  137.                 style = stylizer.style(elem)
  138.                 self.rasterize_external(elem, style, item, image)
  139.                 continue
  140.         
  141.         for elem in xpath(html, '//h:object[@type="%s" and @data]' % SVG_MIME):
  142.             data = urlnormalize(elem.attrib['data'])
  143.             image = hrefs.get(item.abshref(data), None)
  144.             if image and image.media_type == SVG_MIME:
  145.                 style = stylizer.style(elem)
  146.                 self.rasterize_external(elem, style, item, image)
  147.                 continue
  148.         
  149.         for elem in xpath(html, '//svg:svg'):
  150.             style = stylizer.style(elem)
  151.             self.rasterize_inline(elem, style, item)
  152.         
  153.  
  154.     
  155.     def rasterize_inline(self, elem, style, item):
  156.         width = style['width']
  157.         height = style['height']
  158.         width = (width / 72) * self.profile.dpi
  159.         height = (height / 72) * self.profile.dpi
  160.         elem = self.dataize_svg(item, elem)
  161.         data = self.rasterize_svg(elem, width, height)
  162.         manifest = self.oeb.manifest
  163.         href = os.path.splitext(item.href)[0] + '.png'
  164.         (id, href) = manifest.generate(item.id, href)
  165.         manifest.add(id, href, PNG_MIME, data = data)
  166.         img = etree.Element(XHTML('img'), src = item.relhref(href))
  167.         elem.getparent().replace(elem, img)
  168.         for prop in ('width', 'height'):
  169.             if prop in elem.attrib:
  170.                 img.attrib[prop] = elem.attrib[prop]
  171.                 continue
  172.         
  173.  
  174.     
  175.     def rasterize_external(self, elem, style, item, svgitem):
  176.         width = style['width']
  177.         height = style['height']
  178.         width = (width / 72) * self.profile.dpi
  179.         height = (height / 72) * self.profile.dpi
  180.         data = QByteArray(str(svgitem))
  181.         svg = QSvgRenderer(data)
  182.         size = svg.defaultSize()
  183.         size.scale(width, height, Qt.KeepAspectRatio)
  184.         key = (svgitem.href, size.width(), size.height())
  185.         if key in self.images:
  186.             href = self.images[key]
  187.         else:
  188.             logger = self.oeb.logger
  189.             logger.info('Rasterizing %r to %dx%d' % (svgitem.href, size.width(), size.height()))
  190.             image = QImage(size, QImage.Format_ARGB32_Premultiplied)
  191.             image.fill(QColor('white').rgb())
  192.             painter = QPainter(image)
  193.             svg.render(painter)
  194.             painter.end()
  195.             array = QByteArray()
  196.             buffer = QBuffer(array)
  197.             buffer.open(QIODevice.WriteOnly)
  198.             image.save(buffer, 'PNG')
  199.             data = str(array)
  200.             manifest = self.oeb.manifest
  201.             href = os.path.splitext(svgitem.href)[0] + '.png'
  202.             (id, href) = manifest.generate(svgitem.id, href)
  203.             manifest.add(id, href, PNG_MIME, data = data)
  204.             self.images[key] = href
  205.         elem.tag = XHTML('img')
  206.         for attr in elem.attrib:
  207.             if attr not in KEEP_ATTRS:
  208.                 del elem.attrib[attr]
  209.                 continue
  210.         
  211.         elem.attrib['src'] = item.relhref(href)
  212.         if elem.text:
  213.             elem.attrib['alt'] = elem.text
  214.             elem.text = None
  215.         
  216.         for child in elem:
  217.             elem.remove(child)
  218.         
  219.  
  220.     
  221.     def rasterize_cover(self):
  222.         covers = self.oeb.metadata.cover
  223.         if not covers:
  224.             return None
  225.         if unicode(covers[0]) not in self.oeb.manifest.ids:
  226.             self.oeb.logger.warn('Cover not in manifest, skipping.')
  227.             self.oeb.metadata.clear('cover')
  228.             return None
  229.         cover = self.oeb.manifest.ids[unicode(covers[0])]
  230.         if not cover.media_type == SVG_MIME:
  231.             return None
  232.         width = (self.profile.width / 72) * self.profile.dpi
  233.         height = (self.profile.height / 72) * self.profile.dpi
  234.         data = self.rasterize_svg(cover.data, width, height)
  235.         href = os.path.splitext(cover.href)[0] + '.png'
  236.         (id, href) = self.oeb.manifest.generate(cover.id, href)
  237.         self.oeb.manifest.add(id, href, PNG_MIME, data = data)
  238.         covers[0].value = id
  239.  
  240.  
  241.