home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 January / maximum-cd-2011-01.iso / DiscContents / calibre-0.7.26.msi / file_917 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-10-31  |  16.2 KB  |  495 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__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
  7. __docformat__ = 'restructuredtext en'
  8. import os
  9. import textwrap
  10. from copy import deepcopy
  11. from lxml import etree
  12. from calibre.customize.conversion import InputFormatPlugin
  13. from calibre.ebooks.conversion.utils import PreProcessor
  14. from calibre import guess_type
  15.  
  16. class Canvas(etree.XSLTExtension):
  17.     
  18.     def __init__(self, doc, styles, text_block, log):
  19.         self.doc = doc
  20.         self.styles = styles
  21.         self.text_block = text_block
  22.         self.log = log
  23.         self.processed = set([])
  24.  
  25.     
  26.     def execute(self, context, self_node, input_node, output_parent):
  27.         cid = input_node.get('objid', None)
  28.         if cid is None or cid in self.processed:
  29.             return None
  30.         self.processed.add(cid)
  31.         input_node = self.doc.xpath('//Canvas[@objid="%s"]' % cid)[0]
  32.         objects = list(self.get_objects(input_node))
  33.         if len(objects) == 1 and objects[0][0].tag == 'ImageBlock':
  34.             self.image_page(input_node, objects[0][0], output_parent)
  35.         else:
  36.             canvases = [
  37.                 input_node]
  38.             for x in input_node.itersiblings():
  39.                 if x.tag == 'Canvas':
  40.                     oid = x.get('objid', None)
  41.                     if oid is not None:
  42.                         canvases.append(x)
  43.                         self.processed.add(oid)
  44.                     
  45.                 oid is not None
  46.             
  47.             table = etree.Element('table')
  48.             table.text = '\n\t'
  49.             for canvas in canvases:
  50.                 oid = canvas.get('objid')
  51.                 tr = table.makeelement('tr')
  52.                 tr.set('id', oid)
  53.                 tr.tail = '\n\t'
  54.                 table.append(tr)
  55.                 for obj, x, y in self.get_objects(canvas):
  56.                     if obj.tag != 'TextBlock':
  57.                         self.log.warn(obj.tag, 'elements in Canvas not supported')
  58.                         continue
  59.                     
  60.                     td = table.makeelement('td')
  61.                     self.text_block.render_block(obj, td)
  62.                     tr.append(td)
  63.                 
  64.             
  65.             output_parent.append(table)
  66.  
  67.     
  68.     def image_page(self, input_node, block, output_parent):
  69.         div = etree.Element('div')
  70.         div.set('id', input_node.get('objid', 'scuzzy'))
  71.         div.set('class', 'image_page')
  72.         width = self.styles.to_num(block.get('xsize', None))
  73.         height = self.styles.to_num(block.get('ysize', None))
  74.         img = div.makeelement('img')
  75.         if width is not None:
  76.             img.set('width', str(int(width)))
  77.         
  78.         if height is not None:
  79.             img.set('height', str(int(height)))
  80.         
  81.         ref = block.get('refstream', None)
  82.         if ref is not None:
  83.             imstr = self.doc.xpath('//ImageStream[@objid="%s"]' % ref)
  84.             if imstr:
  85.                 src = imstr[0].get('file', None)
  86.                 if src:
  87.                     img.set('src', src)
  88.                 
  89.             
  90.         
  91.         div.append(img)
  92.         output_parent.append(div)
  93.  
  94.     
  95.     def get_objects(self, node):
  96.         for x in node.xpath('descendant::PutObj[@refobj and @x1 and @y1]'):
  97.             objs = node.xpath('//*[@objid="%s"]' % x.get('refobj'))
  98.             (x, y) = map(self.styles.to_num, (x.get('x1'), x.get('y1')))
  99.             if objs and x is not None and y is not None:
  100.                 yield (objs[0], int(x), int(y))
  101.                 continue
  102.         
  103.  
  104.  
  105.  
  106. class MediaType(etree.XSLTExtension):
  107.     
  108.     def execute(self, context, self_node, input_node, output_parent):
  109.         name = input_node.get('file', None)
  110.         typ = guess_type(name)[0]
  111.         if not typ:
  112.             typ = 'application/octet-stream'
  113.         
  114.         output_parent.text = typ
  115.  
  116.  
  117.  
  118. class ImageBlock(etree.XSLTExtension):
  119.     
  120.     def __init__(self, canvas):
  121.         etree.XSLTExtension.__init__(self)
  122.         self.canvas = canvas
  123.  
  124.     
  125.     def execute(self, context, self_node, input_node, output_parent):
  126.         self.canvas.image_page(input_node, input_node, output_parent)
  127.  
  128.  
  129.  
  130. class RuledLine(etree.XSLTExtension):
  131.     
  132.     def execute(self, context, self_node, input_node, output_parent):
  133.         hr = etree.Element('hr')
  134.         output_parent.append(hr)
  135.  
  136.  
  137.  
  138. class TextBlock(etree.XSLTExtension):
  139.     
  140.     def __init__(self, styles, char_button_map, plot_map, log):
  141.         etree.XSLTExtension.__init__(self)
  142.         self.styles = styles
  143.         self.log = log
  144.         self.char_button_map = char_button_map
  145.         self.plot_map = plot_map
  146.  
  147.     
  148.     def execute(self, context, self_node, input_node, output_parent):
  149.         input_node = deepcopy(input_node)
  150.         div = etree.Element('div')
  151.         self.render_block(input_node, div)
  152.         output_parent.append(div)
  153.  
  154.     
  155.     def render_block(self, node, root):
  156.         ts = node.get('textstyle', None)
  157.         classes = []
  158.         bs = node.get('blockstyle')
  159.         if bs in self.styles.block_style_map:
  160.             classes.append('bs%d' % self.styles.block_style_map[bs])
  161.         
  162.         if ts in self.styles.text_style_map:
  163.             classes.append('ts%d' % self.styles.text_style_map[ts])
  164.         
  165.         if classes:
  166.             root.set('class', ' '.join(classes))
  167.         
  168.         objid = node.get('objid', None)
  169.         if objid:
  170.             root.set('id', objid)
  171.         
  172.         root.text = node.text
  173.         self.root = root
  174.         self.parent = root
  175.         self.add_text_to = (self.parent, 'text')
  176.         for child in node:
  177.             self.process_child(child)
  178.         
  179.  
  180.     
  181.     def add_text(self, text):
  182.         if text:
  183.             if getattr(self.add_text_to[0], self.add_text_to[1]) is None:
  184.                 setattr(self.add_text_to[0], self.add_text_to[1], '')
  185.             
  186.             setattr(self.add_text_to[0], self.add_text_to[1], getattr(self.add_text_to[0], self.add_text_to[1]) + text)
  187.         
  188.  
  189.     
  190.     def process_container(self, child, tgt):
  191.         idx = self.styles.get_text_styles(child)
  192.         if idx is not None:
  193.             tgt.set('class', 'ts%d' % idx)
  194.         
  195.         self.parent.append(tgt)
  196.         orig_parent = self.parent
  197.         self.parent = tgt
  198.         self.add_text_to = (self.parent, 'text')
  199.         self.add_text(child.text)
  200.         for gchild in child:
  201.             self.process_child(gchild)
  202.         
  203.         self.parent = orig_parent
  204.         self.add_text_to = (tgt, 'tail')
  205.         self.add_text(child.tail)
  206.  
  207.     
  208.     def process_child(self, child):
  209.         if child.tag == 'CR':
  210.             if self.parent == self.root or self.parent.tag == 'p':
  211.                 self.parent = self.root.makeelement('p')
  212.                 self.root.append(self.parent)
  213.                 self.add_text_to = (self.parent, 'text')
  214.             else:
  215.                 br = self.parent.makeelement('br')
  216.                 self.parent.append(br)
  217.                 self.add_text_to = (br, 'tail')
  218.             self.add_text(child.tail)
  219.         elif child.tag in ('P', 'Span', 'EmpLine', 'NoBR'):
  220.             span = self.root.makeelement('span')
  221.             if child.tag == 'EmpLine':
  222.                 td = None if child.get('emplineposition', 'before') == 'before' else 'overline'
  223.                 span.set('style', 'text-decoration: ' + td)
  224.             
  225.             self.process_container(child, span)
  226.         elif child.tag == 'Sup':
  227.             sup = self.root.makeelement('sup')
  228.             self.process_container(child, sup)
  229.         elif child.tag == 'Sub':
  230.             sub = self.root.makeelement('sub')
  231.             self.process_container(child, sub)
  232.         elif child.tag == 'Italic':
  233.             sup = self.root.makeelement('i')
  234.             self.process_container(child, sup)
  235.         elif child.tag == 'CharButton':
  236.             a = self.root.makeelement('a')
  237.             oid = child.get('refobj', None)
  238.             if oid in self.char_button_map:
  239.                 a.set('href', self.char_button_map[oid])
  240.             
  241.             self.process_container(child, a)
  242.         elif child.tag == 'Plot':
  243.             xsize = self.styles.to_num(child.get('xsize', None), 166 / 720)
  244.             ysize = self.styles.to_num(child.get('ysize', None), 166 / 720)
  245.             img = self.root.makeelement('img')
  246.             if xsize is not None:
  247.                 img.set('width', str(int(xsize)))
  248.             
  249.             if ysize is not None:
  250.                 img.set('height', str(int(ysize)))
  251.             
  252.             ro = child.get('refobj', None)
  253.             if ro in self.plot_map:
  254.                 img.set('src', self.plot_map[ro])
  255.             
  256.             self.parent.append(img)
  257.             self.add_text_to = (img, 'tail')
  258.             self.add_text(child.tail)
  259.         else:
  260.             self.log.warn('Unhandled Text element:', child.tag)
  261.  
  262.  
  263.  
  264. class Styles(etree.XSLTExtension):
  265.     
  266.     def __init__(self):
  267.         etree.XSLTExtension.__init__(self)
  268.         self.text_styles = []
  269.         self.block_styles = []
  270.         self.text_style_map = { }
  271.         self.block_style_map = { }
  272.         self.CSS = textwrap.dedent('\n        .image_page { text-align:center }\n        ')
  273.  
  274.     
  275.     def write(self, name = 'styles.css'):
  276.         
  277.         def join(style):
  278.             ans = [ '%s : %s;' % (k, v) for k, v in style.items() ]
  279.             return '\n\t'.join(ans)
  280.  
  281.         
  282.         try:
  283.             f = _[1]
  284.             f.write(self.CSS)
  285.             for w, sel in [
  286.                 (self.text_styles, 'ts'),
  287.                 (self.block_styles, 'bs')]:
  288.                 for i, s in enumerate(w):
  289.                     rsel = '.%s%d' % (sel, i)
  290.                     s = join(s)
  291.                     f.write(rsel + ' {\n\t' + s + '\n}\n\n')
  292.                 
  293.         finally:
  294.             pass
  295.  
  296.  
  297.     
  298.     def execute(self, context, self_node, input_node, output_parent):
  299.         if input_node.tag == 'TextStyle':
  300.             idx = self.get_text_styles(input_node)
  301.             if idx is not None:
  302.                 self.text_style_map[input_node.get('objid')] = idx
  303.             
  304.         else:
  305.             idx = self.get_block_styles(input_node)
  306.             self.block_style_map[input_node.get('objid')] = idx
  307.  
  308.     
  309.     def px_to_pt(self, px):
  310.         
  311.         try:
  312.             px = float(px)
  313.             return px * 72 / 166
  314.         except:
  315.             return None
  316.  
  317.  
  318.     
  319.     def color(self, val):
  320.         
  321.         try:
  322.             val = int(val, 16)
  323.             (r, g, b, a) = (val & 255, val >> 8 & 255, val >> 16 & 255, val >> 24 & 255)
  324.             if a == 255:
  325.                 return None
  326.             if a == 0:
  327.                 return 'rgb(%d,%d,%d)' % (r, g, b)
  328.             return 'rgba(%d,%d,%d,%f)' % (r, g, b, 1 - a / 255)
  329.         except:
  330.             return None
  331.  
  332.  
  333.     
  334.     def get_block_styles(self, node):
  335.         ans = { }
  336.         sm = self.px_to_pt(node.get('sidemargin', None))
  337.         if sm is not None:
  338.             ans['margin-left'] = ans['margin-right'] = '%fpt' % sm
  339.         
  340.         ts = self.px_to_pt(node.get('topskip', None))
  341.         if ts is not None:
  342.             ans['margin-top'] = '%fpt' % ts
  343.         
  344.         fs = self.px_to_pt(node.get('footskip', None))
  345.         if fs is not None:
  346.             ans['margin-bottom'] = '%fpt' % fs
  347.         
  348.         fw = self.px_to_pt(node.get('framewidth', None))
  349.         if fw is not None:
  350.             ans['border-width'] = '%fpt' % fw
  351.             ans['border-style'] = 'solid'
  352.         
  353.         fc = self.color(node.get('framecolor', None))
  354.         if fc is not None:
  355.             ans['border-color'] = fc
  356.         
  357.         bc = self.color(node.get('bgcolor', None))
  358.         if bc is not None:
  359.             ans['background-color'] = bc
  360.         
  361.         if ans not in self.block_styles:
  362.             self.block_styles.append(ans)
  363.         
  364.         return self.block_styles.index(ans)
  365.  
  366.     
  367.     def to_num(self, val, factor = 1):
  368.         
  369.         try:
  370.             return float(val) * factor
  371.         except:
  372.             return None
  373.  
  374.  
  375.     
  376.     def get_text_styles(self, node):
  377.         ans = { }
  378.         fs = self.to_num(node.get('fontsize', None), 0.1)
  379.         if fs is not None:
  380.             ans['font-size'] = '%fpt' % fs
  381.         
  382.         fw = self.to_num(node.get('fontweight', None))
  383.         if fw is not None:
  384.             ans['font-weight'] = None if fw >= 700 else 'normal'
  385.         
  386.         fg = self.color(node.get('textcolor', None))
  387.         if fg is not None:
  388.             ans['color'] = fg
  389.         
  390.         bg = self.color(node.get('textbgcolor', None))
  391.         if bg is not None:
  392.             ans['background-color'] = bg
  393.         
  394.         al = node.get('align', None)
  395.         if al is not None:
  396.             all = dict(head = 'left', center = 'center', foot = 'right')
  397.             ans['text-align'] = all.get(al, 'left')
  398.         
  399.         pi = self.to_num(node.get('parindent', None), 0.1)
  400.         if pi is not None:
  401.             ans['text-indent'] = '%fpt' % pi
  402.         
  403.         if not ans:
  404.             return None
  405.         if ans not in self.text_styles:
  406.             self.text_styles.append(ans)
  407.         
  408.         return self.text_styles.index(ans)
  409.  
  410.  
  411.  
  412. class LRFInput(InputFormatPlugin):
  413.     name = 'LRF Input'
  414.     author = 'Kovid Goyal'
  415.     description = 'Convert LRF files to HTML'
  416.     file_types = set([
  417.         'lrf'])
  418.     
  419.     def convert(self, stream, options, file_ext, log, accelerators):
  420.         self.log = log
  421.         self.log('Generating XML')
  422.         LRFDocument = LRFDocument
  423.         import calibre.ebooks.lrf.lrfparser
  424.         d = LRFDocument(stream)
  425.         d.parse()
  426.         xml = d.to_xml(write_files = True)
  427.         if options.verbose > 2:
  428.             open('lrs.xml', 'wb').write(xml.encode('utf-8'))
  429.         
  430.         parser = etree.XMLParser(no_network = True, huge_tree = True)
  431.         
  432.         try:
  433.             doc = etree.fromstring(xml, parser = parser)
  434.         except:
  435.             self.log.warn('Failed to parse XML. Trying to recover')
  436.             parser = etree.XMLParser(no_network = True, huge_tree = True, recover = True)
  437.             doc = etree.fromstring(xml, parser = parser)
  438.  
  439.         char_button_map = { }
  440.         for x in doc.xpath('//CharButton[@refobj]'):
  441.             ro = x.get('refobj')
  442.             jump_button = doc.xpath('//*[@objid="%s"]' % ro)
  443.             if jump_button:
  444.                 jump_to = jump_button[0].xpath('descendant::JumpTo[@refpage and @refobj]')
  445.                 if jump_to:
  446.                     char_button_map[ro] = '%s.xhtml#%s' % (jump_to[0].get('refpage'), jump_to[0].get('refobj'))
  447.                 
  448.             jump_to
  449.         
  450.         plot_map = { }
  451.         for x in doc.xpath('//Plot[@refobj]'):
  452.             ro = x.get('refobj')
  453.             image = doc.xpath('//Image[@objid="%s" and @refstream]' % ro)
  454.             if image:
  455.                 imgstr = doc.xpath('//ImageStream[@objid="%s" and @file]' % image[0].get('refstream'))
  456.                 if imgstr:
  457.                     plot_map[ro] = imgstr[0].get('file')
  458.                 
  459.             imgstr
  460.         
  461.         self.log('Converting XML to HTML...')
  462.         styledoc = etree.fromstring(P('templates/lrf.xsl', data = True))
  463.         media_type = MediaType()
  464.         styles = Styles()
  465.         text_block = TextBlock(styles, char_button_map, plot_map, log)
  466.         canvas = Canvas(doc, styles, text_block, log)
  467.         image_block = ImageBlock(canvas)
  468.         ruled_line = RuledLine()
  469.         extensions = {
  470.             ('calibre', 'media-type'): media_type,
  471.             ('calibre', 'text-block'): text_block,
  472.             ('calibre', 'ruled-line'): ruled_line,
  473.             ('calibre', 'styles'): styles,
  474.             ('calibre', 'canvas'): canvas,
  475.             ('calibre', 'image-block'): image_block }
  476.         transform = etree.XSLT(styledoc, extensions = extensions)
  477.         result = transform(doc)
  478.         
  479.         try:
  480.             f = _[1]
  481.             f.write(result)
  482.         finally:
  483.             pass
  484.  
  485.         styles.write()
  486.         return os.path.abspath('content.opf')
  487.  
  488.     
  489.     def preprocess_html(self, options, html):
  490.         self.options = options
  491.         preprocessor = PreProcessor(self.options, log = getattr(self, 'log', None))
  492.         return preprocessor(html)
  493.  
  494.  
  495.