zephir.utils.trml2pdf.trml2pdf

Package zephir :: Package utils :: Package trml2pdf :: Module trml2pdf |
[frames] | no frames]

# Source Code for Module zephir.utils.trml2pdf.trml2pdf

      1  #!/usr/bin/python
      2  # -*- coding: UTF-8 -*-
      3
      4  # trml2pdf - An RML to PDF converter
      5  # Copyright (C) 2003, Fabien Pinckaers, UCL, FSA
      6  # Contributors
      7  #     Richard Waid <richard@iopen.net>
      8  #
      9  # This library is free software; you can redistribute it and/or
     10  # modify it under the terms of the GNU Lesser General Public
     11  # License as published by the Free Software Foundation; either
     12  # version 2.1 of the License, or (at your option) any later version.
     13  #
     14  # This library is distributed in the hope that it will be useful,
     15  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17  # Lesser General Public License for more details.
     18  #
     19  # You should have received a copy of the GNU Lesser General Public
     20  # License along with this library; if not, write to the Free Software
     21  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     22
     23  import sys
     24  # Eole: utilisation de cStringIO
     25  import cStringIO as StringIO
     26  import xml.dom.minidom
     27  import copy
     28  import locale
     29
     30  import reportlab
     31  from reportlab.pdfgen import canvas
     32  from reportlab import platypus
     33
     34  import utils
     35  import color
     36
     37  #
     38  # Change this to UTF-8 if you plan tu use Reportlab's UTF-8 support
     39  #
     40  try:
     41      from zephir.config import charset
     42      encoding = charset
     43  except:
     44      encoding = locale.getpreferredencoding()
     45
     46
     47 -def _child_get(node, childs):
     48          clds = []
     49          for n in node.childNodes:
     50                  if (n.nodeType==n.ELEMENT_NODE) and (n.localName==childs):
     51                          clds.append(n)
     52          return clds
     53
     54 -class _rml_styles(object):
     55 -        def __init__(self, nodes):
     56                  self.styles = {}
     57                  self.names = {}
     58                  self.table_styles = {}
     59                  for node in nodes:
     60                          for style in node.getElementsByTagName('blockTableStyle'):
     61                                  self.table_styles[style.getAttribute('id')] = self._table_style_get(style)
     62                          for style in node.getElementsByTagName('paraStyle'):
     63                                  self.styles[style.getAttribute('name')] = self._para_style_get(style)
     64                          for variable in node.getElementsByTagName('initialize'):
     65                                  for name in variable.getElementsByTagName('name'):
     66                                          self.names[ name.getAttribute('id')] = name.getAttribute('value')
     67
     68 -        def _para_style_update(self, style, node):
     69                  for attr in ['textColor', 'backColor', 'bulletColor']:
     70                          if node.hasAttribute(attr):
     71                                  style.__dict__[attr] = color.get(node.getAttribute(attr))
     72                  for attr in ['fontName', 'bulletFontName', 'bulletText']:
     73                          if node.hasAttribute(attr):
     74                                  style.__dict__[attr] = node.getAttribute(attr)
     75                  for attr in ['fontSize', 'leftIndent', 'rightIndent', 'spaceBefore', 'spaceAfter', 'firstLineIndent', 'bulletIndent', 'bulletFontSize', 'leading']:
     76                          if node.hasAttribute(attr):
     77                                  style.__dict__[attr] = utils.unit_get(node.getAttribute(attr))
     78                  if node.hasAttribute('alignment'):
     79                          align = {
     80                                  'right':reportlab.lib.enums.TA_RIGHT,
     81                                  'center':reportlab.lib.enums.TA_CENTER,
     82                                  'justify':reportlab.lib.enums.TA_JUSTIFY
     83                          }
     84                          style.alignment = align.get(node.getAttribute('alignment').lower(), reportlab.lib.enums.TA_LEFT)
     85                  return style
     86
     87 -        def _table_style_get(self, style_node):
     88                  styles = []
     89                  for node in style_node.childNodes:
     90                          if node.nodeType==node.ELEMENT_NODE:
     91                                  start = utils.tuple_int_get(node, 'start', (0,0) )
     92                                  stop = utils.tuple_int_get(node, 'stop', (-1,-1) )
     93                                  if node.localName=='blockValign':
     94                                          styles.append(('VALIGN', start, stop, str(node.getAttribute('value'))))
     95                                  elif node.localName=='blockFont':
     96                                          styles.append(('FONT', start, stop, str(node.getAttribute('name'))))
     97                                  elif node.localName=='blockTextColor':
     98                                          styles.append(('TEXTCOLOR', start, stop, color.get(str(node.getAttribute('colorName')))))
     99                                  elif node.localName=='blockLeading':
    100                                          styles.append(('LEADING', start, stop, utils.unit_get(node.getAttribute('length'))))
    101                                  elif node.localName=='blockAlignment':
    102                                          styles.append(('ALIGNMENT', start, stop, str(node.getAttribute('value'))))
    103                                  elif node.localName=='blockLeftPadding':
    104                                          styles.append(('LEFTPADDING', start, stop, utils.unit_get(node.getAttribute('length'))))
    105                                  elif node.localName=='blockRightPadding':
    106                                          styles.append(('RIGHTPADDING', start, stop, utils.unit_get(node.getAttribute('length'))))
    107                                  elif node.localName=='blockTopPadding':
    108                                          styles.append(('TOPPADDING', start, stop, utils.unit_get(node.getAttribute('length'))))
    109                                  elif node.localName=='blockBottomPadding':
    110                                          styles.append(('BOTTOMPADDING', start, stop, utils.unit_get(node.getAttribute('length'))))
    111                                  elif node.localName=='blockBackground':
    112                                          styles.append(('BACKGROUND', start, stop, color.get(node.getAttribute('colorName'))))
    113                                  if node.hasAttribute('size'):
    114                                          styles.append(('FONTSIZE', start, stop, utils.unit_get(node.getAttribute('size'))))
    115                                  elif node.localName=='lineStyle':
    116                                          kind = node.getAttribute('kind')
    117                                          kind_list = [ 'GRID', 'BOX', 'OUTLINE', 'INNERGRID', 'LINEBELOW', 'LINEABOVE','LINEBEFORE', 'LINEAFTER' ]
    118                                          assert kind in kind_list
    119                                          thick = 1
    120                                          if node.hasAttribute('thickness'):
    121                                                  thick = float(node.getAttribute('thickness'))
    122                                          styles.append((kind, start, stop, thick,  color.get(node.getAttribute('colorName'))))
    123                  return platypus.tables.TableStyle(styles)
    124
    125 -        def _para_style_get(self, node):
    126                  styles = reportlab.lib.styles.getSampleStyleSheet()
    127                  style = copy.deepcopy(styles["Normal"])
    128                  self._para_style_update(style, node)
    129                  return style
    130
    131 -        def para_style_get(self, node):
    132                  style = False
    133                  if node.hasAttribute('style'):
    134                          if node.getAttribute('style') in self.styles:
    135                                  style = copy.deepcopy(self.styles[node.getAttribute('style')])
    136                          else:
    137                                  sys.stderr.write('Warning: style not found, %s - setting default!\n' % (node.getAttribute('style'),) )
    138                  if not style:
    139                          styles = reportlab.lib.styles.getSampleStyleSheet()
    140                          style = copy.deepcopy(styles['Normal'])
    141                  return self._para_style_update(style, node)
    142
    143 -class _rml_doc(object):
    144 -        def __init__(self, data):
    145                  self.dom = xml.dom.minidom.parseString(data)
    146                  self.filename = self.dom.documentElement.getAttribute('filename')
    147
    148 -        def docinit(self, els):
    149                  from reportlab.lib.fonts import addMapping
    150                  from reportlab.pdfbase import pdfmetrics
    151                  from reportlab.pdfbase.ttfonts import TTFont
    152
    153                  for node in els:
    154                          for font in node.getElementsByTagName('registerFont'):
    155                                  name = font.getAttribute('fontName').encode('ascii')
    156                                  fname = font.getAttribute('fontFile').encode('ascii')
    157                                  pdfmetrics.registerFont(TTFont(name, fname ))
    158                                  addMapping(name, 0, 0, name)    #normal
    159                                  addMapping(name, 0, 1, name)    #italic
    160                                  addMapping(name, 1, 0, name)    #bold
    161                                  addMapping(name, 1, 1, name)    #italic and bold
    162
    163 -        def render(self, out):
    164                  el = self.dom.documentElement.getElementsByTagName('docinit')
    165                  if el:
    166                          self.docinit(el)
    167
    168                  el = self.dom.documentElement.getElementsByTagName('stylesheet')
    169                  self.styles = _rml_styles(el)
    170
    171                  el = self.dom.documentElement.getElementsByTagName('template')
    172                  if len(el):
    173                          pt_obj = _rml_template(out, el[0], self)
    174                          pt_obj.render(self.dom.documentElement.getElementsByTagName('story')[0])
    175                  else:
    176                          self.canvas = canvas.Canvas(out)
    177                          pd = self.dom.documentElement.getElementsByTagName('pageDrawing')[0]
    178                          pd_obj = _rml_canvas(self.canvas, None, self)
    179                          pd_obj.render(pd)
    180                          self.canvas.showPage()
    181                          self.canvas.save()
    182
    183 -class _rml_canvas(object):
    184 -        def __init__(self, canvas, doc_tmpl=None, doc=None):
    185                  self.canvas = canvas
    186                  self.styles = doc.styles
    187                  self.doc_tmpl = doc_tmpl
    188                  self.doc = doc
    189
    190 -        def _textual(self, node):
    191                  rc = ''
    192                  for n in node.childNodes:
    193                          if n.nodeType == n.ELEMENT_NODE:
    194                                  if n.localName=='pageNumber':
    195                                          rc += str(self.canvas.getPageNumber())
    196                          elif (n.nodeType == node.CDATA_SECTION_NODE):
    197                                  rc += n.data
    198                          elif (n.nodeType == node.TEXT_NODE):
    199                                  rc += n.data
    200                  return rc.encode(encoding)
    201
    202 -        def _drawString(self, node):
    203                  self.canvas.drawString(text=self._textual(node), **utils.attr_get(node, ['x','y']))
    204 -        def _drawCenteredString(self, node):
    205                  self.canvas.drawCentredString(text=self._textual(node), **utils.attr_get(node, ['x','y']))
    206 -        def _drawRightString(self, node):
    207                  self.canvas.drawRightString(text=self._textual(node), **utils.attr_get(node, ['x','y']))
    208 -        def _rect(self, node):
    209                  if node.hasAttribute('round'):
    210                          self.canvas.roundRect(radius=utils.unit_get(node.getAttribute('round')), **utils.attr_get(node, ['x','y','width','height'], {'fill':'bool','stroke':'bool'}))
    211                  else:
    212                          self.canvas.rect(**utils.attr_get(node, ['x','y','width','height'], {'fill':'bool','stroke':'bool'}))
    213 -        def _ellipse(self, node):
    214                  x1 = utils.unit_get(node.getAttribute('x'))
    215                  x2 = utils.unit_get(node.getAttribute('width'))
    216                  y1 = utils.unit_get(node.getAttribute('y'))
    217                  y2 = utils.unit_get(node.getAttribute('height'))
    218                  self.canvas.ellipse(x1,y1,x2,y2, **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'}))
    219 -        def _curves(self, node):
    220                  line_str = utils.text_get(node).split()
    221                  lines = []
    222                  while len(line_str)>7:
    223                          self.canvas.bezier(*[utils.unit_get(l) for l in line_str[0:8]])
    224                          line_str = line_str[8:]
    225 -        def _lines(self, node):
    226                  line_str = utils.text_get(node).split()
    227                  lines = []
    228                  while len(line_str)>3:
    229                          lines.append([utils.unit_get(l) for l in line_str[0:4]])
    230                          line_str = line_str[4:]
    231                  self.canvas.lines(lines)
    232 -        def _grid(self, node):
    233                  xlist = [utils.unit_get(s) for s in node.getAttribute('xs').split(',')]
    234                  ylist = [utils.unit_get(s) for s in node.getAttribute('ys').split(',')]
    235                  self.canvas.grid(xlist, ylist)
    236 -        def _translate(self, node):
    237                  dx = 0
    238                  dy = 0
    239                  if node.hasAttribute('dx'):
    240                          dx = utils.unit_get(node.getAttribute('dx'))
    241                  if node.hasAttribute('dy'):
    242                          dy = utils.unit_get(node.getAttribute('dy'))
    243                  self.canvas.translate(dx,dy)
    244
    245 -        def _circle(self, node):
    246                  self.canvas.circle(x_cen=utils.unit_get(node.getAttribute('x')), y_cen=utils.unit_get(node.getAttribute('y')), r=utils.unit_get(node.getAttribute('radius')), **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'}))
    247
    248 -        def _place(self, node):
    249                  flows = _rml_flowable(self.doc).render(node)
    250                  infos = utils.attr_get(node, ['x','y','width','height'])
    251
    252                  infos['y']+=infos['height']
    253                  for flow in flows:
    254                          w,h = flow.wrap(infos['width'], infos['height'])
    255                          if w<=infos['width'] and h<=infos['height']:
    256                                  infos['y']-=h
    257                                  flow.drawOn(self.canvas,infos['x'],infos['y'])
    258                                  infos['height']-=h
    259                          else:
    260                                  raise ValueError, "Not enough space"
    261
    262 -        def _line_mode(self, node):
    263                  ljoin = {'round':1, 'mitered':0, 'bevelled':2}
    264                  lcap = {'default':0, 'round':1, 'square':2}
    265                  if node.hasAttribute('width'):
    266                          self.canvas.setLineWidth(utils.unit_get(node.getAttribute('width')))
    267                  if node.hasAttribute('join'):
    268                          self.canvas.setLineJoin(ljoin[node.getAttribute('join')])
    269                  if node.hasAttribute('cap'):
    270                          self.canvas.setLineCap(lcap[node.getAttribute('cap')])
    271                  if node.hasAttribute('miterLimit'):
    272                          self.canvas.setDash(utils.unit_get(node.getAttribute('miterLimit')))
    273                  if node.hasAttribute('dash'):
    274                          dashes = node.getAttribute('dash').split(',')
    275                          for x in range(len(dashes)):
    276                                  dashes[x]=utils.unit_get(dashes[x])
    277                          self.canvas.setDash(node.getAttribute('dash').split(','))
    278
    279 -        def _image(self, node):
    280                  import urllib
    281                  from reportlab.lib.utils import ImageReader
    282                  u = urllib.urlopen(str(node.getAttribute('file')))
    283                  s = StringIO.StringIO()
    284                  s.write(u.read())
    285                  s.seek(0)
    286                  img = ImageReader(s)
    287                  (sx,sy) = img.getSize()
    288
    289                  args = {}
    290                  for tag in ('width','height','x','y'):
    291                          if node.hasAttribute(tag):
    292                                  args[tag] = utils.unit_get(node.getAttribute(tag))
    293                  if ('width' in args) and (not 'height' in args):
    294                          args['height'] = sy * args['width'] / sx
    295                  elif ('height' in args) and (not 'width' in args):
    296                          args['width'] = sx * args['height'] / sy
    297                  elif ('width' in args) and ('height' in args):
    298                          if (float(args['width'])/args['height'])>(float(sx)>sy):
    299                                  args['width'] = sx * args['height'] / sy
    300                          else:
    301                                  args['height'] = sy * args['width'] / sx
    302                  self.canvas.drawImage(img, **args)
    303
    304 -        def _path(self, node):
    305                  self.path = self.canvas.beginPath()
    306                  self.path.moveTo(**utils.attr_get(node, ['x','y']))
    307                  for n in node.childNodes:
    308                          if n.nodeType == node.ELEMENT_NODE:
    309                                  if n.localName=='moveto':
    310                                          vals = utils.text_get(n).split()
    311                                          self.path.moveTo(utils.unit_get(vals[0]), utils.unit_get(vals[1]))
    312                                  elif n.localName=='curvesto':
    313                                          vals = utils.text_get(n).split()
    314                                          while len(vals)>5:
    315                                                  pos=[]
    316                                                  while len(pos)<6:
    317                                                          pos.append(utils.unit_get(vals.pop(0)))
    318                                                  self.path.curveTo(*pos)
    319                          elif (n.nodeType == node.TEXT_NODE):
    320                                  data = n.data.split()               # Not sure if I must merge all TEXT_NODE ?
    321                                  while len(data)>1:
    322                                          x = utils.unit_get(data.pop(0))
    323                                          y = utils.unit_get(data.pop(0))
    324                                          self.path.lineTo(x,y)
    325                  if (not node.hasAttribute('close')) or utils.bool_get(node.getAttribute('close')):
    326                          self.path.close()
    327                  self.canvas.drawPath(self.path, **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'}))
    328
    329 -        def render(self, node):
    330                  tags = {
    331                          'drawCentredString': self._drawCenteredString,
    332                          'drawRightString': self._drawRightString,
    333                          'drawString': self._drawString,
    334                          'rect': self._rect,
    335                          'ellipse': self._ellipse,
    336                          'lines': self._lines,
    337                          'grid': self._grid,
    338                          'curves': self._curves,
    339                          'fill': lambda node: self.canvas.setFillColor(color.get(node.getAttribute('color'))),
    340                          'stroke': lambda node: self.canvas.setStrokeColor(color.get(node.getAttribute('color'))),
    341                          'setFont': lambda node: self.canvas.setFont(node.getAttribute('name'), utils.unit_get(node.getAttribute('size'))),
    342                          'place': self._place,
    343                          'circle': self._circle,
    344                          'lineMode': self._line_mode,
    345                          'path': self._path,
    346                          'rotate': lambda node: self.canvas.rotate(float(node.getAttribute('degrees'))),
    347                          'translate': self._translate,
    348                          'image': self._image
    349                  }
    350                  for nd in node.childNodes:
    351                          if nd.nodeType==nd.ELEMENT_NODE:
    352                                  for tag in tags:
    353                                          if nd.localName==tag:
    354                                                  tags[tag](nd)
    355                                                  break
    356
    357 -class _rml_draw(object):
    358 -        def __init__(self, node, styles):
    359                  self.node = node
    360                  self.styles = styles
    361                  self.canvas = None
    362
    363 -        def render(self, canvas, doc):
    364                  canvas.saveState()
    365                  cnv = _rml_canvas(canvas, doc, self.styles)
    366                  cnv.render(self.node)
    367                  canvas.restoreState()
    368
    369 -class _rml_flowable(object):
    370 -        def __init__(self, doc):
    371                  self.doc = doc
    372                  self.styles = doc.styles
    373
    374 -        def _textual(self, node):
    375                  rc = ''
    376                  for n in node.childNodes:
    377                          if n.nodeType == node.ELEMENT_NODE:
    378                                  if n.localName=='getName':
    379                                          newNode = self.doc.dom.createTextNode(self.styles.names.get(n.getAttribute('id'),'Unknown name'))
    380                                          node.insertBefore(newNode, n)
    381                                          node.removeChild(n)
    382                                  if n.localName=='pageNumber':
    383                                          rc+='<pageNumber/>'            # TODO: change this !
    384                                  else:
    385                                          self._textual(n)
    386                                  rc += n.toxml()
    387                          elif (n.nodeType == node.CDATA_SECTION_NODE):
    388                                  rc += n.data
    389                          elif (n.nodeType == node.TEXT_NODE):
    390                                  rc += n.data
    391                  return rc.encode(encoding)
    392
    393 -        def _table(self, node):
    394                  length = 0
    395                  colwidths = None
    396                  rowheights = None
    397                  data = []
    398                  for tr in _child_get(node,'tr'):
    399                          data2 = []
    400                          for td in _child_get(tr, 'td'):
    401                                  flow = []
    402                                  for n in td.childNodes:
    403                                          if n.nodeType==node.ELEMENT_NODE:
    404                                                  flow.append( self._flowable(n) )
    405                                  if not len(flow):
    406                                          flow = self._textual(td)
    407                                  data2.append( flow )
    408                          if len(data2)>length:
    409                                  length=len(data2)
    410                                  for ab in data:
    411                                          while len(ab)<length:
    412                                                  ab.append('')
    413                          while len(data2)<length:
    414                                  data2.append('')
    415                          data.append( data2 )
    416                  if node.hasAttribute('colWidths'):
    417                          assert length == len(node.getAttribute('colWidths').split(','))
    418                          colwidths = [utils.unit_get(f.strip()) for f in node.getAttribute('colWidths').split(',')]
    419                  if node.hasAttribute('rowHeights'):
    420                          rowheights = [utils.unit_get(f.strip()) for f in node.getAttribute('rowHeights').split(',')]
    421                  table = platypus.Table(data = data, colWidths=colwidths, rowHeights=rowheights, **(utils.attr_get(node, ['splitByRow'] ,{'repeatRows':'int','repeatCols':'int'})))
    422                  if node.hasAttribute('style'):
    423                          table.setStyle(self.styles.table_styles[node.getAttribute('style')])
    424                  return table
    425
    426 -        def _illustration(self, node):
    427                  class Illustration(platypus.flowables.Flowable):
    428                          def __init__(self, node, styles):
    429                                  self.node = node
    430                                  self.styles = styles
    431                                  self.width = utils.unit_get(node.getAttribute('width'))
    432                                  self.height = utils.unit_get(node.getAttribute('height'))
    433                          def wrap(self, *args):
    434                                  return (self.width, self.height)
    435                          def draw(self):
    436                                  canvas = self.canv
    437                                  drw = _rml_draw(self.node, self.styles)
    438                                  drw.render(self.canv, None)
    439                  return Illustration(node, self.styles)
    440
    441 -        def _flowable(self, node):
    442                  if node.localName=='para':
    443                          style = self.styles.para_style_get(node)
    444                          return platypus.Paragraph(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str'})))
    445                  elif node.localName=='name':
    446                          self.styles.names[ node.getAttribute('id')] = node.getAttribute('value')
    447                          return None
    448                  elif node.localName=='xpre':
    449                          style = self.styles.para_style_get(node)
    450                          return platypus.XPreformatted(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str','dedent':'int','frags':'int'})))
    451                  elif node.localName=='pre':
    452                          style = self.styles.para_style_get(node)
    453                          return platypus.Preformatted(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str','dedent':'int'})))
    454                  elif node.localName=='illustration':
    455                          return  self._illustration(node)
    456                  elif node.localName=='blockTable':
    457                          return  self._table(node)
    458                  elif node.localName=='title':
    459                          styles = reportlab.lib.styles.getSampleStyleSheet()
    460                          style = styles['Title']
    461                          return platypus.Paragraph(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str'})))
    462                  elif node.localName=='h1':
    463                          styles = reportlab.lib.styles.getSampleStyleSheet()
    464                          style = styles['Heading1']
    465                          return platypus.Paragraph(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str'})))
    466                  elif node.localName=='h2':
    467                          styles = reportlab.lib.styles.getSampleStyleSheet()
    468                          style = styles['Heading2']
    469                          return platypus.Paragraph(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str'})))
    470                  elif node.localName=='h3':
    471                          styles = reportlab.lib.styles.getSampleStyleSheet()
    472                          style = styles['Heading3']
    473                          return platypus.Paragraph(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str'})))
    474                  elif node.localName=='image':
    475                          return platypus.Image(node.getAttribute('file'), mask=(250,255,250,255,250,255), **(utils.attr_get(node, ['width','height'])))
    476                  elif node.localName=='spacer':
    477                          if node.hasAttribute('width'):
    478                                  width = utils.unit_get(node.getAttribute('width'))
    479                          else:
    480                                  width = utils.unit_get('1cm')
    481                          length = utils.unit_get(node.getAttribute('length'))
    482                          return platypus.Spacer(width=width, height=length)
    483                  elif node.localName=='pageBreak':
    484                          return platypus.PageBreak()
    485                  elif node.localName=='condPageBreak':
    486                          return platypus.CondPageBreak(**(utils.attr_get(node, ['height'])))
    487                  elif node.localName=='setNextTemplate':
    488                          return platypus.NextPageTemplate(str(node.getAttribute('name')))
    489                  elif node.localName=='nextFrame':
    490                          return platypus.CondPageBreak(1000)           # TODO: change the 1000 !
    491                  else:
    492                          sys.stderr.write('Warning: flowable not yet implemented: %s !\n' % (node.localName,))
    493                          return None
    494
    495 -        def render(self, node_story):
    496                  story = []
    497                  node = node_story.firstChild
    498                  while node:
    499                          if node.nodeType == node.ELEMENT_NODE:
    500                                  flow = self._flowable(node)
    501                                  if flow:
    502                                          story.append(flow)
    503                          node = node.nextSibling
    504                  return story
    505
    506 -class _rml_template(object):
    507 -        def __init__(self, out, node, doc):
    508                  if not node.hasAttribute('pageSize'):
    509                          pageSize = (utils.unit_get('21cm'), utils.unit_get('29.7cm'))
    510                  else:
    511                          ps = map(lambda x:x.strip(), node.getAttribute('pageSize').replace(')', '').replace('(', '').split(','))
    512                          pageSize = ( utils.unit_get(ps[0]),utils.unit_get(ps[1]) )
    513                  cm = reportlab.lib.units.cm
    514                  self.doc_tmpl = platypus.BaseDocTemplate(out, pagesize=pageSize, **utils.attr_get(node, ['leftMargin','rightMargin','topMargin','bottomMargin'], {'allowSplitting':'int','showBoundary':'bool','title':'str','author':'str'}))
    515                  self.page_templates = []
    516                  self.styles = doc.styles
    517                  self.doc = doc
    518                  pts = node.getElementsByTagName('pageTemplate')
    519                  for pt in pts:
    520                          frames = []
    521                          for frame_el in pt.getElementsByTagName('frame'):
    522                                  frame = platypus.Frame( **(utils.attr_get(frame_el, ['x1','y1', 'width','height', 'leftPadding', 'rightPadding', 'bottomPadding', 'topPadding'], {'id':'text', 'showBoundary':'bool'})) )
    523                                  frames.append( frame )
    524                          gr = pt.getElementsByTagName('pageGraphics')
    525                          if len(gr):
    526                                  drw = _rml_draw(gr[0], self.doc)
    527                                  self.page_templates.append( platypus.PageTemplate(frames=frames, onPage=drw.render, **utils.attr_get(pt, [], {'id':'str'}) ))
    528                          else:
    529                                  self.page_templates.append( platypus.PageTemplate(frames=frames, **utils.attr_get(pt, [], {'id':'str'}) ))
    530                  self.doc_tmpl.addPageTemplates(self.page_templates)
    531
    532 -        def render(self, node_story):
    533                  r = _rml_flowable(self.doc)
    534                  fis = r.render(node_story)
    535                  self.doc_tmpl.build(fis)
    536
    537 -def parseString(data, fout=None):
    538          r = _rml_doc(data)
    539          if fout:
    540                  fp = file(fout,'wb')
    541                  r.render(fp)
    542                  fp.close()
    543                  return fout
    544          else:
    545                  fp = StringIO.StringIO()
    546                  r.render(fp)
    547                  return fp.getvalue()
    548
    549 -def trml2pdf_help():
    550          print 'Usage: trml2pdf input.rml >output.pdf'
    551          print 'Render the standard input (RML) and output a PDF file'
    552          sys.exit(0)
    553
    554  if __name__=="__main__":
    555          if len(sys.argv)>1:
    556                  if sys.argv[1]=='--help':
    557                          trml2pdf_help()
    558                  print parseString(file(sys.argv[1], 'r').read()),
    559          else:
    560                  print 'Usage: trml2pdf input.rml >output.pdf'
    561                  print 'Try \'trml2pdf --help\' for more information.'
    562