def _ellipse(self, node): x1 = utils.unit_get(node.get('x')) x2 = utils.unit_get(node.get('width')) y1 = utils.unit_get(node.get('y')) y2 = utils.unit_get(node.get('height')) self.canvas.ellipse(x1,y1,x2,y2, **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'}))
def __init__(self, node, localcontext, styles, self2): self.localcontext = (localcontext or {}).copy() self.node = node self.styles = styles self.width = utils.unit_get(node.get('width')) self.height = utils.unit_get(node.get('height')) self.self2 = self2
def __init__(self, node, style, localcontext={}): self.localcontext = localcontext self.posx = utils.unit_get(node.get('x')) self.posy = utils.unit_get(node.get('y')) aligns = { 'drawString': 'left', 'drawRightString': 'right', 'drawCentredString': 'center' } align = aligns[node.tag] self.pos = [(self.posx, self.posy, align, utils._process_text(self, node.text), style.get('td'), style.font_size_get('td'))]
def _tag_table(self, node): new_node = copy.deepcopy(node) for child in new_node: new_node.remove(child) new_node.tag = 'table' def process(node, new_node): for child in utils._child_get(node, self): new_child = copy.deepcopy(child) new_node.append(new_child) if len(child): for n in new_child: new_child.remove(n) process(child, new_child) else: new_child.text = utils._process_text(self, child.text) new_child.tag = 'p' try: if new_child.get('style').find('terp_tblheader') != -1: new_node.tag = 'th' except Exception: pass process(node, new_node) if new_node.get('colWidths', False): sizes = map(lambda x: utils.unit_get(x), new_node.get('colWidths').split(',')) tr = etree.SubElement(new_node, 'tr') for s in sizes: etree.SubElement(tr, 'td', width=str(s)) return etree.tostring(new_node)
def _lines(self, node): line_str = node.text.split() lines = [] while len(line_str)>3: lines.append([utils.unit_get(l) for l in line_str[0:4]]) line_str = line_str[4:] self.canvas.lines(lines)
def __init__(self, template, localcontext=None): self.frame_pos = -1 self.localcontext = localcontext self.frames = [] self.template_order = [] self.page_template = {} self.loop = 0 self._tags = { 'drawString': _rml_tmpl_draw_string, 'drawRightString': _rml_tmpl_draw_string, 'drawCentredString': _rml_tmpl_draw_string, 'lines': _rml_tmpl_draw_lines } self.style = _rml_draw_style() rc = 'data:image/png;base64,' self.data = '' for pt in template.findall('pageTemplate'): frames = {} id = pt.get('id') self.template_order.append(id) for tmpl in pt.findall('frame'): posy = int(utils.unit_get(tmpl.get('y1'))) posx = int(utils.unit_get(tmpl.get('x1'))) frames[(posy, posx, tmpl.get('id'))] = _rml_tmpl_frame( posx, utils.unit_get(tmpl.get('width'))) for tmpl in pt.findall('pageGraphics'): for n in tmpl: if n.tag == 'image': self.data = rc + utils._process_text(self, n.text) if n.tag in self._tags: t = self._tags[n.tag](n, self.style, self.localcontext) frames[(t.posy, t.posx, n.tag)] = t else: self.style.update(n) keys = frames.keys() keys.sort() keys.reverse() self.page_template[id] = [] for key in range(len(keys)): if key > 0 and keys[key - 1][0] == keys[key][0]: if type(self.page_template[id][-1]) == type( frames[keys[key]]): if self.page_template[id][-1].tag_mergeable(): self.page_template[id][-1].merge(frames[keys[key]]) continue self.page_template[id].append(frames[keys[key]]) self.template = self.template_order[0]
def _line_mode(self, node): ljoin = {'round':1, 'mitered':0, 'bevelled':2} lcap = {'default':0, 'round':1, 'square':2} if node.get('width'): self.canvas.setLineWidth(utils.unit_get(node.get('width'))) if node.get('join'): self.canvas.setLineJoin(ljoin[node.get('join')]) if node.get('cap'): self.canvas.setLineCap(lcap[node.get('cap')]) if node.get('miterLimit'): self.canvas.setDash(utils.unit_get(node.get('miterLimit'))) if node.get('dash'): dashes = node.get('dash').split(',') for x in range(len(dashes)): dashes[x]=utils.unit_get(dashes[x]) self.canvas.setDash(node.get('dash').split(','))
def __init__(self, node, style, localcontext={}): self.localcontext = localcontext coord = [ utils.unit_get(x) for x in utils._process_text(self, node.text).split(' ') ] self.ok = False self.posx = coord[0] self.posy = coord[1] self.width = coord[2] - coord[0] self.ok = coord[1] == coord[3] self.style = style self.style = style.get('hr')
def setFont(self, node): fontname = node.get('name') if fontname not in pdfmetrics.getRegisteredFontNames()\ or fontname not in pdfmetrics.standardFonts: # let reportlab attempt to find it try: pdfmetrics.getFont(fontname) except Exception: _logger.debug('Could not locate font %s, substituting default: %s', fontname, self.canvas._fontname) fontname = self.canvas._fontname return self.canvas.setFont(fontname, utils.unit_get(node.get('size')))
def _path(self, node): self.path = self.canvas.beginPath() self.path.moveTo(**utils.attr_get(node, ['x','y'])) for n in utils._child_get(node, self): if not n.text : if n.tag=='moveto': vals = utils.text_get(n).split() self.path.moveTo(utils.unit_get(vals[0]), utils.unit_get(vals[1])) elif n.tag=='curvesto': vals = utils.text_get(n).split() while len(vals)>5: pos=[] while len(pos)<6: pos.append(utils.unit_get(vals.pop(0))) self.path.curveTo(*pos) elif n.text: data = n.text.split() # Not sure if I must merge all TEXT_NODE ? while len(data)>1: x = utils.unit_get(data.pop(0)) y = utils.unit_get(data.pop(0)) self.path.lineTo(x,y) if (not node.get('close')) or utils.bool_get(node.get('close')): self.path.close() self.canvas.drawPath(self.path, **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'}))
def _para_style_update(self, node): data = {} for attr in ['textColor', 'backColor', 'bulletColor', 'borderColor']: if node.get(attr): data[attr] = color.get(node.get(attr)) for attr in ['fontName', 'bulletFontName', 'bulletText']: if node.get(attr): data[attr] = node.get(attr) for attr in ['fontSize', 'leftIndent', 'rightIndent', 'spaceBefore', 'spaceAfter', 'firstLineIndent', 'bulletIndent', 'bulletFontSize', 'leading', 'borderWidth','borderPadding','borderRadius']: if node.get(attr): data[attr] = utils.unit_get(node.get(attr)) if node.get('alignment'): align = { 'right':reportlab.lib.enums.TA_RIGHT, 'center':reportlab.lib.enums.TA_CENTER, 'justify':reportlab.lib.enums.TA_JUSTIFY } data['alignment'] = align.get(node.get('alignment').lower(), reportlab.lib.enums.TA_LEFT) return data
def __init__(self, localcontext, stylesheet, doc): self.doc = doc self.localcontext = localcontext self.attrs = {} self._tags = { 'fontSize': lambda x: ('font-size', str(utils.unit_get(x) + 5.0) + 'px'), 'alignment': lambda x: ('text-align', str(x)) } result = '' for ps in stylesheet.findall('paraStyle'): attr = {} attrs = ps.attrib for key, val in attrs.items(): attr[key] = val attrs = [] for a in attr: if a in self._tags: attrs.append('%s:%s' % self._tags[a](attr[a])) if len(attrs): result += 'p.' + attr['name'] + ' {' + '; '.join(attrs) + '}\n' self.result = result
def _table_style_get(self, style_node): styles = [] for node in style_node: start = utils.tuple_int_get(node, 'start', (0,0) ) stop = utils.tuple_int_get(node, 'stop', (-1,-1) ) if node.tag=='blockValign': styles.append(('VALIGN', start, stop, str(node.get('value')))) elif node.tag=='blockFont': styles.append(('FONT', start, stop, str(node.get('name')))) elif node.tag=='blockTextColor': styles.append(('TEXTCOLOR', start, stop, color.get(str(node.get('colorName'))))) elif node.tag=='blockLeading': styles.append(('LEADING', start, stop, utils.unit_get(node.get('length')))) elif node.tag=='blockAlignment': styles.append(('ALIGNMENT', start, stop, str(node.get('value')))) elif node.tag=='blockSpan': styles.append(('SPAN', start, stop)) elif node.tag=='blockLeftPadding': styles.append(('LEFTPADDING', start, stop, utils.unit_get(node.get('length')))) elif node.tag=='blockRightPadding': styles.append(('RIGHTPADDING', start, stop, utils.unit_get(node.get('length')))) elif node.tag=='blockTopPadding': styles.append(('TOPPADDING', start, stop, utils.unit_get(node.get('length')))) elif node.tag=='blockBottomPadding': styles.append(('BOTTOMPADDING', start, stop, utils.unit_get(node.get('length')))) elif node.tag=='blockBackground': styles.append(('BACKGROUND', start, stop, color.get(node.get('colorName')))) if node.get('size'): styles.append(('FONTSIZE', start, stop, utils.unit_get(node.get('size')))) elif node.tag=='lineStyle': kind = node.get('kind') kind_list = [ 'GRID', 'BOX', 'OUTLINE', 'INNERGRID', 'LINEBELOW', 'LINEABOVE','LINEBEFORE', 'LINEAFTER' ] assert kind in kind_list thick = 1 if node.get('thickness'): thick = float(node.get('thickness')) styles.append((kind, start, stop, thick, color.get(node.get('colorName')))) return platypus.tables.TableStyle(styles)
def _image(self, node): import urllib import urlparse from reportlab.lib.utils import ImageReader nfile = node.get('file') if not nfile: if node.get('name'): image_data = self.images[node.get('name')] _logger.debug("Image %s used", node.get('name')) s = StringIO(image_data) else: newtext = node.text if self.localcontext: res = utils._regex.findall(newtext) for key in res: newtext = eval(key, {}, self.localcontext) or '' image_data = None if newtext: image_data = base64.decodestring(newtext) if image_data: s = StringIO(image_data) else: _logger.debug("No image data!") return False else: if nfile in self.images: s = StringIO(self.images[nfile]) else: try: up = urlparse.urlparse(str(nfile)) except ValueError: up = False if up and up.scheme: # RFC: do we really want to open external URLs? # Are we safe from cross-site scripting or attacks? _logger.debug("Retrieve image from %s", nfile) u = urllib.urlopen(str(nfile)) s = StringIO(u.read()) else: _logger.debug("Open image file %s ", nfile) s = _open_image(nfile, path=self.path) try: img = ImageReader(s) (sx,sy) = img.getSize() _logger.debug("Image is %dx%d", sx, sy) args = { 'x': 0.0, 'y': 0.0, 'mask': 'auto'} for tag in ('width','height','x','y'): if node.get(tag): args[tag] = utils.unit_get(node.get(tag)) if ('width' in args) and (not 'height' in args): args['height'] = sy * args['width'] / sx elif ('height' in args) and (not 'width' in args): args['width'] = sx * args['height'] / sy elif ('width' in args) and ('height' in args): if (float(args['width'])/args['height'])>(float(sx)>sy): args['width'] = sx * args['height'] / sy else: args['height'] = sy * args['width'] / sx self.canvas.drawImage(img, **args) finally: s.close()
def _tag_spacer(self, node): length = 1 + int(utils.unit_get(node.get('length'))) / 35 return "<br/>" * length
def _circle(self, node): self.canvas.circle(x_cen=utils.unit_get(node.get('x')), y_cen=utils.unit_get(node.get('y')), r=utils.unit_get(node.get('radius')), **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'}))
def _translate(self, node): dx = utils.unit_get(node.get('dx')) or 0 dy = utils.unit_get(node.get('dy')) or 0 self.canvas.translate(dx,dy)
def _grid(self, node): xlist = [utils.unit_get(s) for s in node.get('xs').split(',')] ylist = [utils.unit_get(s) for s in node.get('ys').split(',')] self.canvas.grid(xlist, ylist)
def draw(self): self.canv.beginForm("pageCount%d" % self.story_count) self.canv.setFont("Helvetica", utils.unit_get(str(8))) self.canv.drawString(0, 0, str(self.canv.getPageNumber())) self.canv.endForm()
def font_size_get(self, tag): size = utils.unit_get(self.style.get('td', {}).get('font-size', '16')) return size
def _table(self, node): children = utils._child_get(node,self,'tr') if not children: return None length = 0 colwidths = None rowheights = None data = [] styles = [] posy = 0 for tr in children: paraStyle = None if tr.get('style'): st = copy.deepcopy(self.styles.table_styles[tr.get('style')]) for si in range(len(st._cmds)): s = list(st._cmds[si]) s[1] = (s[1][0],posy) s[2] = (s[2][0],posy) st._cmds[si] = tuple(s) styles.append(st) if tr.get('paraStyle'): paraStyle = self.styles.styles[tr.get('paraStyle')] data2 = [] posx = 0 for td in utils._child_get(tr, self,'td'): if td.get('style'): st = copy.deepcopy(self.styles.table_styles[td.get('style')]) for s in st._cmds: s[1][1] = posy s[2][1] = posy s[1][0] = posx s[2][0] = posx styles.append(st) if td.get('paraStyle'): # TODO: merge styles paraStyle = self.styles.styles[td.get('paraStyle')] posx += 1 flow = [] for n in utils._child_get(td, self): if n.tag == etree.Comment: n.text = '' continue fl = self._flowable(n, extra_style=paraStyle) if isinstance(fl,list): flow += fl else: flow.append( fl ) if not len(flow): flow = self._textual(td) data2.append( flow ) if len(data2)>length: length=len(data2) for ab in data: while len(ab)<length: ab.append('') while len(data2)<length: data2.append('') data.append( data2 ) posy += 1 if node.get('colWidths'): assert length == len(node.get('colWidths').split(',')) colwidths = [utils.unit_get(f.strip()) for f in node.get('colWidths').split(',')] if node.get('rowHeights'): rowheights = [utils.unit_get(f.strip()) for f in node.get('rowHeights').split(',')] if len(rowheights) == 1: rowheights = rowheights[0] table = platypus.LongTable(data = data, colWidths=colwidths, rowHeights=rowheights, **(utils.attr_get(node, ['splitByRow'] ,{'repeatRows':'int','repeatCols':'int'}))) if node.get('style'): table.setStyle(self.styles.table_styles[node.get('style')]) for s in styles: table.setStyle(s) return table
def _rect(self, node): if node.get('round'): self.canvas.roundRect(radius=utils.unit_get(node.get('round')), **utils.attr_get(node, ['x','y','width','height'], {'fill':'bool','stroke':'bool'})) else: self.canvas.rect(**utils.attr_get(node, ['x','y','width','height'], {'fill':'bool','stroke':'bool'}))
def _flowable(self, node, extra_style=None): if node.tag=='pto': return self._pto(node) if node.tag=='para': style = self.styles.para_style_get(node) if extra_style: style.__dict__.update(extra_style) result = [] for i in self._textual(node).split('\n'): result.append(platypus.Paragraph(i, style, **(utils.attr_get(node, [], {'bulletText':'str'})))) return result elif node.tag=='barCode': try: from reportlab.graphics.barcode import code128 from reportlab.graphics.barcode import code39 from reportlab.graphics.barcode import code93 from reportlab.graphics.barcode import common from reportlab.graphics.barcode import fourstate from reportlab.graphics.barcode import usps from reportlab.graphics.barcode import createBarcodeDrawing except ImportError: _logger.warning("Cannot use barcode renderers:", exc_info=True) return None args = utils.attr_get(node, [], {'ratio':'float','xdim':'unit','height':'unit','checksum':'int','quiet':'int','width':'unit','stop':'bool','bearers':'int','barWidth':'float','barHeight':'float'}) codes = { 'codabar': lambda x: common.Codabar(x, **args), 'code11': lambda x: common.Code11(x, **args), 'code128': lambda x: code128.Code128(str(x), **args), 'standard39': lambda x: code39.Standard39(str(x), **args), 'standard93': lambda x: code93.Standard93(str(x), **args), 'i2of5': lambda x: common.I2of5(x, **args), 'extended39': lambda x: code39.Extended39(str(x), **args), 'extended93': lambda x: code93.Extended93(str(x), **args), 'msi': lambda x: common.MSI(x, **args), 'fim': lambda x: usps.FIM(x, **args), 'postnet': lambda x: usps.POSTNET(x, **args), 'ean13': lambda x: createBarcodeDrawing('EAN13', value=str(x), **args), 'qrcode': lambda x: createBarcodeDrawing('QR', value=x, **args), } code = 'code128' if node.get('code'): code = node.get('code').lower() return codes[code](self._textual(node)) elif node.tag=='name': self.styles.names[ node.get('id')] = node.get('value') return None elif node.tag=='xpre': style = self.styles.para_style_get(node) return platypus.XPreformatted(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str','dedent':'int','frags':'int'}))) elif node.tag=='pre': style = self.styles.para_style_get(node) return platypus.Preformatted(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str','dedent':'int'}))) elif node.tag=='illustration': return self._illustration(node) elif node.tag=='blockTable': return self._table(node) elif node.tag=='title': styles = reportlab.lib.styles.getSampleStyleSheet() style = styles['Title'] return platypus.Paragraph(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str'}))) elif re.match('^h([1-9]+[0-9]*)$', (node.tag or '')): styles = reportlab.lib.styles.getSampleStyleSheet() style = styles['Heading'+str(node.tag[1:])] return platypus.Paragraph(self._textual(node), style, **(utils.attr_get(node, [], {'bulletText':'str'}))) elif node.tag=='image': image_data = False if not node.get('file'): if node.get('name'): if node.get('name') in self.doc.images: _logger.debug("Image %s read ", node.get('name')) image_data = self.doc.images[node.get('name')].read() else: _logger.warning("Image %s not defined", node.get('name')) return False else: import base64 newtext = node.text if self.localcontext: newtext = utils._process_text(self, node.text or '') image_data = base64.decodestring(newtext) if not image_data: _logger.debug("No inline image data") return False image = StringIO(image_data) else: _logger.debug("Image get from file %s", node.get('file')) image = _open_image(node.get('file'), path=self.doc.path) return platypus.Image(image, mask=(250,255,250,255,250,255), **(utils.attr_get(node, ['width','height']))) elif node.tag=='spacer': if node.get('width'): width = utils.unit_get(node.get('width')) else: width = utils.unit_get('1cm') length = utils.unit_get(node.get('length')) return platypus.Spacer(width=width, height=length) elif node.tag=='section': return self.render(node) elif node.tag == 'pageNumberReset': return PageReset() elif node.tag in ('pageBreak', 'nextPage'): return platypus.PageBreak() elif node.tag=='condPageBreak': return platypus.CondPageBreak(**(utils.attr_get(node, ['height']))) elif node.tag=='setNextTemplate': return platypus.NextPageTemplate(str(node.get('name'))) elif node.tag=='nextFrame': return platypus.CondPageBreak(1000) # TODO: change the 1000 ! elif node.tag == 'setNextFrame': from reportlab.platypus.doctemplate import NextFrameFlowable return NextFrameFlowable(str(node.get('name'))) elif node.tag == 'currentFrame': from reportlab.platypus.doctemplate import CurrentFrameFlowable return CurrentFrameFlowable(str(node.get('name'))) elif node.tag == 'frameEnd': return EndFrameFlowable() elif node.tag == 'hr': width_hr=node.get('width') or '100%' color_hr=node.get('color') or 'black' thickness_hr=node.get('thickness') or 1 lineCap_hr=node.get('lineCap') or 'round' return platypus.flowables.HRFlowable(width=width_hr,color=color.get(color_hr),thickness=float(thickness_hr),lineCap=str(lineCap_hr)) else: sys.stderr.write('Warning: flowable not yet implemented: %s !\n' % (node.tag,)) return None
def _curves(self, node): line_str = node.text.split() lines = [] while len(line_str)>7: self.canvas.bezier(*[utils.unit_get(l) for l in line_str[0:8]]) line_str = line_str[8:]