def tabela(self, largura, altura, dados, colWidths=None, rowHeights=None, style=None, repeatRows=0, repeatCols=0, splitByRow=1, emptyTableAction=None, ident=None, hAlign=None, vAlign=None): # Escape dados str ou unicode dados = [[escape(d) if isinstance(d, (str, unicode)) else d for d in l] for l in dados] # Renderizar 1 linha tabela = Table(dados[:1], colWidths, rowHeights, style, repeatRows, repeatCols, splitByRow, emptyTableAction, ident, hAlign, vAlign) l, a = tabela.wrapOn(self.canvas, largura, altura) # Quantas linhas dessa altura cabem linhas = int(altura/a) # Renderizar linhas tabela = Table(dados[:linhas], colWidths, rowHeights, style, repeatRows, repeatCols, splitByRow, emptyTableAction, ident, hAlign, vAlign) l, a = tabela.wrapOn(self.canvas, largura, altura) # Se não couber, vou tirando de 1 em 1 if a > altura: for i in range(linhas, 0, -1): tabela = Table(dados[:i], colWidths, rowHeights, style, repeatRows, repeatCols, splitByRow, emptyTableAction, ident, hAlign, vAlign) l, a = tabela.wrapOn(self.canvas, largura, altura) if a <= altura: break return (tabela, i, a) # Se couber, vou colocando de 1 em 1 i = linhas for i in range(linhas, len(dados)): tabela = Table(dados[:i], colWidths, rowHeights, style, repeatRows, repeatCols, splitByRow, emptyTableAction, ident, hAlign, vAlign) l, a = tabela.wrapOn(self.canvas, largura, altura) if a > altura: break i -= 1 tabela = Table(dados[:i], colWidths, rowHeights, style, repeatRows, repeatCols, splitByRow, emptyTableAction, ident, hAlign, vAlign) l, a = tabela.wrapOn(self.canvas, largura, altura) return (tabela, i, a)
def draw_contract_nb_table(self, canvas): data = [ ('Contract NB', self.transmittal.contract_number), ('Phase', ''), ] table = Table(data, hAlign='LEFT', colWidths=[25 * mm, 25 * mm]) table.setStyle(self.get_table_style()) table.wrapOn(canvas, 50 * mm, 50 * mm) table.drawOn(canvas, *self.coord(145, 55))
def tabela(self, largura, altura, dados, colWidths=None, rowHeights=None, style=None, repeatRows=0, repeatCols=0, splitByRow=1, emptyTableAction=None, ident=None, hAlign=None, vAlign=None): # Escape dados str ou unicode dados = [[ escape(d) if isinstance(d, (str, unicode)) else d for d in l ] for l in dados] # Renderizar 1 linha tabela = Table(dados[:1], colWidths, rowHeights, style, repeatRows, repeatCols, splitByRow, emptyTableAction, ident, hAlign, vAlign) l, a = tabela.wrapOn(self.canvas, largura, altura) # Quantas linhas dessa altura cabem linhas = int(altura / a) # Renderizar linhas tabela = Table(dados[:linhas], colWidths, rowHeights, style, repeatRows, repeatCols, splitByRow, emptyTableAction, ident, hAlign, vAlign) l, a = tabela.wrapOn(self.canvas, largura, altura) # Se não couber, vou tirando de 1 em 1 if a > altura: for i in range(linhas, 0, -1): tabela = Table(dados[:i], colWidths, rowHeights, style, repeatRows, repeatCols, splitByRow, emptyTableAction, ident, hAlign, vAlign) l, a = tabela.wrapOn(self.canvas, largura, altura) if a <= altura: break return (tabela, i, a) # Se couber, vou colocando de 1 em 1 i = linhas for i in range(linhas, len(dados)): tabela = Table(dados[:i], colWidths, rowHeights, style, repeatRows, repeatCols, splitByRow, emptyTableAction, ident, hAlign, vAlign) l, a = tabela.wrapOn(self.canvas, largura, altura) if a > altura: break i -= 1 tabela = Table(dados[:i], colWidths, rowHeights, style, repeatRows, repeatCols, splitByRow, emptyTableAction, ident, hAlign, vAlign) l, a = tabela.wrapOn(self.canvas, largura, altura) return (tabela, i, a)
def cabecera(self, request, fecha, pdf): usuario = request.user.get_full_name() #Utilizamos el archivo logo_django.png que está guardado en la carpeta media/imagenes archivo_imagen = settings.MEDIA_ROOT + 'Logo.png' #Definimos el tamaño de la imagen a cargar y las coordenadas correspondientes pdf.drawImage(archivo_imagen, 30, 700, 120, 90, preserveAspectRatio=True ) pdf.setFont("Helvetica", 9) # pdf.drawString(550, 770, u"%s" %time.strftime("%x")) pdf.drawString(500, 760, u"Fecha: %s/%s/%s" %(fecha.day, fecha.month, fecha.year) ) pdf.drawString(500, 750, u"Hora: %s:%s" %(fecha.hour, fecha.minute) ) #Creamos una tupla de encabezados para neustra tabla encabezados = ['Estado de Cuenta'.upper()] #Creamos una lista de tuplas que van a contener a las personas detalles = [ ('%s, Edificio %s, Apartamento %s' %(usuario, p.edificio, p.no_apartamento)) for p in Residente.objects.filter(id=request.user.id) ] #Establecemos el tamaño de cada una de las columnas de la tabla detalle_orden = Table([encabezados] + [detalles], rowHeights=50, colWidths=[575] ) #Aplicamos estilos a las celdas de la tabla detalle_orden.setStyle( TableStyle( [ #La primera fila(encabezados) va a estar centrada ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), ('ALIGN', (0, 0), (0, -1), 'CENTER'), ('FONTSIZE', (0, 0), (-1, -1), 12), ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), ('ALIGN', (0, 0), (0, 0), 'CENTER'), ('FONTSIZE', (0, 0), (-1, 0), 16), ('TEXTCOLOR', (0, 1), (-1, -1), colors.black), ] ) ) #Establecemos el tamaño de la hoja que ocupará la tabla detalle_orden.wrapOn(pdf, 1000, 800) #Definimos la coordenada donde se dibujará la tabla detalle_orden.drawOn(pdf, 15, 660)
def tabla(self, datos, c): encabezados = [["Nombre", "Primer Apellido", "Sergundo Apellido", "Correo", "Nombre Mascota", "Tipo", "Peso"]] width, height = A4 tabla = Table(encabezados+datos, colWidths=30*mm) tabla.setStyle([("VALIGN", (0,0), (-1,-1), "MIDDLE"), ("ALIGN", (0,0), (-1,-1), "CENTER"), ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('FONT', (0,0), (-1,0), 'Times-Bold'), ('FONTSIZE', (0,0),(-1,-1), 10)]) tabla.wrapOn(c, width, height) tabla.drawOn(c, 0, 520)
def set_common_per_page(self, canvas, doc): PAGE_WIDTH, PAGE_HEIGHT = pagesizes.A4 PDF_HEADER_FONT_SIZE = 8 canvas.saveState() # header string = self.set_header_string() canvas.setFont(self.FONT_MEIRYO, PDF_HEADER_FONT_SIZE) canvas.drawCentredString((PAGE_WIDTH / 2.0), (PAGE_HEIGHT - 20), string) # footer string = self.set_footer_string() canvas.setFont(self.FONT_MEIRYO, PDF_HEADER_FONT_SIZE) canvas.drawCentredString((PAGE_WIDTH / 2.0), 20, string) # 左上: アイコン image_path = django_settings.PDF_IMAGE_DIR + 'apple-icon-180x180.png' canvas.drawImage(image_path, 10*mm, 285*mm, width=10*mm, height=10*mm, preserveAspectRatio=True, mask=[0, 0, 0, 0, 0, 0]) # 右上: TLP表記 string = 'TLP: %s' % (self.feed.tlp.upper()) # Tableにて実装 data = [[string], ] table = Table(data) if self.feed.tlp.upper() == 'RED': color = '#FF0033' elif self.feed.tlp.upper() == 'AMBER': color = '#FFC000' elif self.feed.tlp.upper() == 'GREEN': color = '#33FF00' else: color = '#FFFFFF' table.setStyle(TableStyle([ # 背景色は黒 ('BACKGROUND', (0, 0), (-1, -1), colors.black), # テキスト色はTLPによって異なる ('TEXTCOLOR', (0, 0), (-1, -1), color), # 表で使うフォントとそのサイズを設定 ('FONT', (0, 0), (-1, -1), self.FONT_MEIRYO, 9), # ('FONT', (0, 0), (-1, -1), 'CJK', 9), # 四角に罫線を引いて、0.5の太さで、色は黒 ('BOX', (0, 0), (-1, -1), 1, colors.black), # 四角の内側に格子状の罫線を引いて、0.25の太さで、色は赤 ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black), # セルの縦文字位置を、TOPにする ('VALIGN', (0, 0), (-1, -1), 'TOP'), ])) # 配置位置 table.wrapOn(canvas, 180*mm, 287*mm) table.drawOn(canvas, 180*mm, 287*mm) canvas.restoreState()
def razas(self, pdf): #Se crea una lista de tuplas que van a contener los datos de todos los animales encabezados = ('Codigo', 'Nombre') parametros = [(p.id, p.nombre) for p in Raza.objects.all()] t = Table([encabezados] + parametros) t.setStyle( TableStyle([('GRID', (0, 0), (3, -1), 1, colors.dodgerblue), ('LINEBELOW', (0, 0), (-1, 0), 2, colors.darkblue), ('BACKGROUND', (0, 0), (-1, 0), colors.green)])) #Establecemos el tamaño de la hoja que ocupará la tabla t.wrapOn(pdf, 640, 480) #Definimos la coordenada donde se dibujará la tabla t.drawOn(pdf, 200, 200)
def tabla(self, pdf): #Se crea una lista de tuplas que van a contener los datos de todos los animales encabezados = ('Nombre', 'Fecha nacimiento', 'Raza', 'Tipo de Rodeo') parametros = [(p.nombre, p.fechanacimiento, p.raza, p.tipo) for p in Animal.objects.all()] t = Table([encabezados] + parametros) t.setStyle( TableStyle([('GRID', (0, 0), (3, -1), 1, colors.dodgerblue), ('LINEBELOW', (0, 0), (-1, 0), 2, colors.darkblue), ('BACKGROUND', (0, 0), (-1, 0), colors.green)])) #Establecemos el tamaño de la hoja que ocupará la tabla t.wrapOn(pdf, 50, 80) #Definimos la coordenada donde se dibujará la tabla t.drawOn(pdf, 140, 280)
def tabla(self, pdf, y): encabezados = ('Nombre', 'Placa', 'Dia', 'Valor') model = Alquiler detalles = [(persona.idcliente, persona.idcar, persona.Fecha_Salida, persona.valor) for persona in model.objects.filter()] detalle_orden = Table([encabezados] + detalles, colWidths=[2 * cm, 5 * cm, 5 * cm, 5 * cm]) detalle_orden.setStyle( TableStyle([ ('ALIGN', (0, 0), (3, 0), 'CENTER'), ('GRID', (0, 0), (-1, -1), 1, colors.black), ('FONTSIZE', (0, 0), (-1, -1), 10), ])) detalle_orden.wrapOn(pdf, 800, 600) detalle_orden.drawOn(pdf, 60, y)
def pdf_drawTable(self, table_data, table_style=[], x=45, y=800, table_width=2460, table_height=300, font_size=50, colWidths=[]): ''' @example: table_data = [] table_data.append(['Rank','Total Entries','Occupancy','Exit_number','Percenty']) table_data.append(["1",'11','555','1251','22']) self.pdf_drawTable(table_data) ''' if len(colWidths) == 0: colWidths = self.get_table_column_width_list( table_data, table_width) try: rowHeights = int(table_height / (len(table_data))) except ZeroDivisionError as e: raise e return table_object = Table(table_data, colWidths, rowHeights) # (column,row) table_basic_stylesheet = [ ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.white), ('TEXTCOLOR', (0, 0), (-1, 0), colors.white), ('ALIGN', (0, 0), (-1, -1), 'CENTRE'), ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), ('BOTTOMPADDING', (0, 0), (-1, -1), 55), ('FONT', (0, 0), (-1, 0), FONTBLOD), ('FONT', (0, 1), (-1, -1), FONT), ('FONTSIZE', (0, 0), (-1, -1), font_size), ('BACKGROUND', (0, 0), (-1, 0), HexColor(0X4472c4)), ('BACKGROUND', (0, 1), (-1, -1), HexColor(0xE9ECF6)), ] for i in table_style: table_basic_stylesheet.append(i) table_stylesheet = TableStyle(table_basic_stylesheet) table_object.setStyle(table_stylesheet) table_object.wrapOn(self.pdf_page_object, 0, 0) y = self.pdf_config_object.pdf_height - y table_object.drawOn(self.pdf_page_object, x, y)
def tabla(self, request, pago, pdf, y): #Creamos una tupla de encabezados para neustra tabla encabezados = ('FECHA', 'PAGO', 'CONCEPTO', 'PENDIENTE', 'RECARGO', 'CONCEPTO RECARGO') #Creamos una lista de tuplas que van a contener a las personas detalles = [(p.fecha, 'RD$%s%s' %(p.pagos, '.00'), p.concepto, 'RD$%s%s' %(p.deuda_pendiente, '.00'), 'RD$%s%s' %(p.recargo, '.00'), p.concepto_deuda) for p in pago ] #Establecemos el tamaño de cada una de las columnas de la tabla detalle_orden = Table( [encabezados] + detalles, rowHeights=15, colWidths= [ 12 * 5, 15 * 5, 30 * 5, 15 * 5, 15 * 5, 30 * 5 ] ) #Aplicamos estilos a las celdas de la tabla detalle_orden.setStyle(TableStyle( [ #La primera fila(encabezados) va a estar centrada ('ALIGN', (0, 0), (0, 0), 'CENTER'), #Los bordes de todas las celdas serán de color negro y con un grosor de 1 ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black), ('BOX', (0, 0), (-1, -1), 0.75, colors.black), #El tamaño de las letras de cada una de las celdas será de 10 ('BACKGROUND', (0, 0), (8, 0), colors.lightblue), ('ALIGN', (0, 0), (-5, -1), 'CENTER'), ('ALIGN', (4, 0), (-2, -1), 'CENTER'), ('FONTSIZE', (0, 0), (-1, -1), 7), ('ALIGN', (0, 0), (-1, 0), 'CENTER'), ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), ('FONTSIZE', (0, 0), (-1, 0), 9), ] )) #Establecemos el tamaño de la hoja que ocupará la tabla detalle_orden.wrapOn(pdf, 1000, 800) #Definimos la coordenada donde se dibujará la tabla detalle_orden.drawOn(pdf, 15, y)
class PmlTableOfContents(TableOfContents): def wrap(self, availWidth, availHeight): "All table properties should be known by now." widths = (availWidth - self.rightColumnWidth, self.rightColumnWidth) # makes an internal table which does all the work. # we draw the LAST RUN's entries! If there are # none, we make some dummy data to keep the table # from complaining if len(self._lastEntries) == 0: _tempEntries = [(0, 'Placeholder for table of contents', 0)] else: _tempEntries = self._lastEntries i = 0 lastMargin = 0 tableData = [] tableStyle = [ ('VALIGN', (0, 0), (- 1, - 1), 'TOP'), ('LEFTPADDING', (0, 0), (- 1, - 1), 0), ('RIGHTPADDING', (0, 0), (- 1, - 1), 0), ('TOPPADDING', (0, 0), (- 1, - 1), 0), ('BOTTOMPADDING', (0, 0), (- 1, - 1), 0), ] for entry in _tempEntries: level, text, pageNum = entry[:3] leftColStyle = self.levelStyles[level] if i: # Not for first element tableStyle.append(( 'TOPPADDING', (0, i), (- 1, i), max(lastMargin, leftColStyle.spaceBefore))) # print leftColStyle.leftIndent lastMargin = leftColStyle.spaceAfter #right col style is right aligned rightColStyle = ParagraphStyle(name='leftColLevel%d' % level, parent=leftColStyle, leftIndent=0, alignment=TA_RIGHT) leftPara = Paragraph(text, leftColStyle) rightPara = Paragraph(str(pageNum), rightColStyle) tableData.append([leftPara, rightPara]) i += 1 self._table = Table( tableData, colWidths=widths, style=TableStyle(tableStyle)) self.width, self.height = self._table.wrapOn(self.canv, availWidth, availHeight) return (self.width, self.height)
def totales(self, request, pago, pdf, y): #Creamos una tupla de encabezados para neustra tabla encabezados = ['TOTALES'] #Creamos una lista de tuplas que van a contener a las personas deuda = 0 deuda_pendiente = 0 total_pagado = 0 for p in pago: deuda += p.recargo deuda_pendiente = (p.deuda_pendiente + p.recargo) total_pagado += p.pagos detalles = [ ['Total Deuda RD$%s.00' %deuda], ['Total Deuda Por Recargo RD$%s.00' %deuda_pendiente], ['Total Pagado RD$%s.00' %total_pagado] ] #Establecemos el tamaño de cada una de las columnas de la tabla detalle_orden = Table([encabezados] + detalles, rowHeights=15, colWidths=[43 * 5]) #Aplicamos estilos a las celdas de la tabla detalle_orden.setStyle( TableStyle( [ ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), ('BACKGROUND', (0, 0), (8, 0), colors.lightblue), ('INNERGRID', (0, 0), (0, 0), 0.25, colors.black), ('ALIGN', (0, 0), (-1, -1), 'LEFT'), ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), ('ALIGN', (0, 0), (0, 0), 'CENTER'), ('TEXTCOLOR', (0, 1), (-1, -1), colors.black), ] ) ) #Establecemos el tamaño de la hoja que ocupará la tabla detalle_orden.wrapOn(pdf, 1000, 800) #Definimos la coordenada donde se dibujará la tabla detalle_orden.drawOn(pdf, 380, 50)
def genera_copertina(citazione): sfondo = settings.IMG_DIR + 'coperchio_bomboniera2.jpg' img_for_print = utils.ImageReader(sfondo) print(citazione['canzone']) path_file = '%s/copertine/cop_%s%s.pdf' % (settings.DOCDIR, citazione['id_frase'], citazione['canzone']) dimensione = (19*units.cm, 27*units.cm) c = canvas.Canvas(path_file, pagesize=dimensione) c.setFontSize(10) c.drawImage(img_for_print, 0, 10, dimensione[0], dimensione[1]) tabella_testo = [ [ par_nero('...{citazione}...'.format(**citazione), font=citazione['font'], lead=citazione['lead'], fontName='mvboli', align=TA_CENTER) ], [ par_nero("<i></i>".format(**citazione), font=15, align=TA_RIGHT, lead= 15) ], [ par_nero("<i>{canzone}</i>".format(**citazione), font=15, align=TA_RIGHT, lead= 15) ], [ par_nero("{autore}".format(**citazione), font=15, align=TA_RIGHT, lead= 15) ], ] style_row = TableStyle([]) #style_row.add('LINEABOVE', (0, 0), (-1, 0), 0.25, colors.grey) #style_row.add('LINEBELOW', (0, 0), (-1, 0), 0.25, colors.grey) #style_row.add('LINEAFTER', (-1, 0), (-1, 0), 0.25, colors.grey) #style_row.add('LINEBEFORE', (0, 0), (0, 0), 0.25, colors.grey) table = Table(tabella_testo, colWidths=11.5*units.cm, style=style_row) table.wrapOn(c, citazione['margin_left']*units.cm, citazione['margin_bottom']*units.cm) table.drawOn(c, citazione['margin_left']*units.cm, citazione['margin_bottom']*units.cm) c.save()
def body_1(start, end,event_time): #Body data= [['No.', 'Name', 'Cat II', 'Cat III']] for i in range(start,end): #Generate Transaction Id transaction_id = str(event_id)+event_date+event_time+str(i) transaction_id = filter(str.isalnum, str(transaction_id)) luhn = generate(transaction_id) transaction_id = str(transaction_id)+luhn data.append([str(i)+','+luhn,'','','']) ##### tstyle = [('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0,0), (-1,-1), 0.25, colors.black),] t = Table(data, colWidths=(3*cm, 4*cm, 6*cm, 6*cm)) t.setStyle(TableStyle(tstyle)) t.wrapOn(c, 1*cm, 0*cm) t.drawOn(c, 1*cm, 1*cm) c.showPage()
class SimpleIndex(IndexingFlowable): """Creates multi level indexes. The styling can be cutomized and alphabetic headers turned on and off. """ def __init__(self, **kwargs): """ Constructor of SimpleIndex. Accepts the same arguments as the setup method. """ #keep stuff in a dictionary while building self._entries = {} self._lastEntries = {} self._flowable = None self.setup(**kwargs) def getFormatFunc(self, format): try: D = {} exec( 'from reportlab.lib.sequencer import _format_%s as formatFunc' % format, D) return D['formatFunc'] except ImportError: raise ValueError('Unknown format %r' % format) def setup(self, style=None, dot=None, tableStyle=None, headers=True, name=None, format='123', offset=0): """ This method makes it possible to change styling and other parameters on an existing object. style is the paragraph style to use for index entries. dot can either be None or a string. If it's None, entries are immediatly followed by their corresponding page numbers. If it's a string, page numbers are aligned on the right side of the document and the gap filled with a repeating sequence of the string. tableStyle is the style used by the table which the index uses to draw itself. Use this to change properties like spacing between elements. headers is a boolean. If it is True, alphabetic headers are displayed in the Index when the first letter changes. If False, we just output some extra space before the next item name makes it possible to use several indexes in one document. If you want this use this parameter to give each index a unique name. You can then index a term by refering to the name of the index which it should appear in: <index item="term" name="myindex" /> format can be 'I', 'i', '123', 'ABC', 'abc' """ if style is None: style = ParagraphStyle(name='index', fontName=_baseFontName, fontSize=11) self.textStyle = style self.tableStyle = tableStyle or defaultTableStyle self.dot = dot self.headers = headers if name is None: from reportlab.platypus.paraparser import DEFAULT_INDEX_NAME as name self.name = name self.formatFunc = self.getFormatFunc(format) self.offset = offset def __call__(self, canv, kind, label): label = asNative(label, 'latin1') try: terms, format, offset = decode_label(label) except: terms = label format = offset = None if format is None: formatFunc = self.formatFunc else: formatFunc = self.getFormatFunc(format) if offset is None: offset = self.offset terms = commasplit(terms) cPN = canv.getPageNumber() pns = formatFunc(cPN - offset) key = 'ix_%s_%s_p_%s' % (self.name, label, pns) info = canv._curr_tx_info canv.bookmarkHorizontal(key, info['cur_x'], info['cur_y'] + info['leading']) self.addEntry(terms, (cPN, pns), key) def getCanvasMaker(self, canvasmaker=canvas.Canvas): def newcanvasmaker(*args, **kwargs): from reportlab.pdfgen import canvas c = canvasmaker(*args, **kwargs) setattr(c, self.name, self) return c return newcanvasmaker def isIndexing(self): return 1 def isSatisfied(self): return (self._entries == self._lastEntries) def beforeBuild(self): # keep track of the last run self._lastEntries = self._entries.copy() self.clearEntries() def clearEntries(self): self._entries = {} def notify(self, kind, stuff): """The notification hook called to register all kinds of events. Here we are interested in 'IndexEntry' events only. """ if kind == 'IndexEntry': text, pageNum = stuff self.addEntry(text, (self._canv.getPageNumber(), pageNum)) def addEntry(self, text, pageNum, key=None): """Allows incremental buildup""" self._entries.setdefault(makeTuple(text), set([])).add((pageNum, key)) def split(self, availWidth, availHeight): """At this stage we do not care about splitting the entries, we will just return a list of platypus tables. Presumably the calling app has a pointer to the original TableOfContents object; Platypus just sees tables. """ return self._flowable.splitOn(self.canv, availWidth, availHeight) def _getlastEntries(self, dummy=[(['Placeholder for index'], enumerate((None, ) * 3))]): '''Return the last run's entries! If there are none, returns dummy.''' lE = self._lastEntries or self._entries if not lE: return dummy return list(sorted(lE.items())) def _build(self, availWidth, availHeight): _tempEntries = [(tuple(asUnicode(t) for t in texts), pageNumbers) for texts, pageNumbers in self._getlastEntries()] def getkey(seq): return [ ''.join((c for c in unicodedata.normalize('NFD', x.upper()) if unicodedata.category(c) != 'Mn')) for x in seq[0] ] _tempEntries.sort(key=getkey) leveloffset = self.headers and 1 or 0 def drawIndexEntryEnd(canvas, kind, label): '''Callback to draw dots and page numbers after each entry.''' style = self.getLevelStyle(leveloffset) pages = [(p[1], k) for p, k in sorted(decode_label(label))] drawPageNumbers(canvas, style, pages, availWidth, availHeight, self.dot) self.canv.drawIndexEntryEnd = drawIndexEntryEnd alpha = '' tableData = [] lastTexts = [] alphaStyle = self.getLevelStyle(0) for texts, pageNumbers in _tempEntries: texts = list(texts) #track when the first character changes; either output some extra #space, or the first letter on a row of its own. We cannot do #widow/orphan control, sadly. nalpha = ''.join( (c for c in unicodedata.normalize('NFD', texts[0][0].upper()) if unicodedata.category(c) != 'Mn')) if alpha != nalpha: alpha = nalpha if self.headers: header = alpha else: header = ' ' tableData.append([ Spacer(1, alphaStyle.spaceBefore), ]) tableData.append([ Paragraph(header, alphaStyle), ]) tableData.append([ Spacer(1, alphaStyle.spaceAfter), ]) i, diff = listdiff(lastTexts, texts) if diff: lastTexts = texts texts = texts[i:] label = encode_label(list(pageNumbers)) texts[-1] = '%s<onDraw name="drawIndexEntryEnd" label="%s"/>' % ( texts[-1], label) for text in texts: #Platypus and RML differ on how parsed XML attributes are escaped. #e.g. <index item="M&S"/>. The only place this seems to bite us is in #the index entries so work around it here. text = escapeOnce(text) style = self.getLevelStyle(i + leveloffset) para = Paragraph(text, style) if style.spaceBefore: tableData.append([ Spacer(1, style.spaceBefore), ]) tableData.append([ para, ]) i += 1 self._flowable = Table(tableData, colWidths=[availWidth], style=self.tableStyle) def wrap(self, availWidth, availHeight): "All table properties should be known by now." self._build(availWidth, availHeight) self.width, self.height = self._flowable.wrapOn( self.canv, availWidth, availHeight) return self.width, self.height def drawOn(self, canvas, x, y, _sW=0): """Don't do this at home! The standard calls for implementing draw(); we are hooking this in order to delegate ALL the drawing work to the embedded table object. """ self._flowable.drawOn(canvas, x, y, _sW) def draw(self): t = self._flowable ocanv = getattr(t, 'canv', None) if not ocanv: t.canv = self.canv try: t.draw() finally: if not ocanv: del t.canv def getLevelStyle(self, n): '''Returns the style for level n, generating and caching styles on demand if not present.''' if not hasattr(self.textStyle, '__iter__'): self.textStyle = [self.textStyle] try: return self.textStyle[n] except IndexError: self.textStyle = list(self.textStyle) prevstyle = self.getLevelStyle(n - 1) self.textStyle.append( ParagraphStyle(name='%s-%d-indented' % (prevstyle.name, n), parent=prevstyle, firstLineIndent=prevstyle.firstLineIndent + .2 * cm, leftIndent=prevstyle.leftIndent + .2 * cm)) return self.textStyle[n]
class TableOfContents(IndexingFlowable): """This creates a formatted table of contents. It presumes a correct block of data is passed in. The data block contains a list of (level, text, pageNumber) triplets. You can supply a paragraph style for each level (starting at zero). Set dotsMinLevel to determine from which level on a line of dots should be drawn between the text and the page number. If dotsMinLevel is set to a negative value, no dotted lines are drawn. """ def __init__(self, **kwds): self.rightColumnWidth = kwds.pop('rightColumnWidth', 72) self.levelStyles = kwds.pop('levelStyles', defaultLevelStyles) self.tableStyle = kwds.pop('tableStyle', defaultTableStyle) self.dotsMinLevel = kwds.pop('dotsMinLevel', 1) self.formatter = kwds.pop('formatter', None) if kwds: raise ValueError('unexpected keyword arguments %s' % ', '.join(kwds.keys())) self._table = None self._entries = [] self._lastEntries = [] def beforeBuild(self): # keep track of the last run self._lastEntries = self._entries[:] self.clearEntries() def isIndexing(self): return 1 def isSatisfied(self): return (self._entries == self._lastEntries) def notify(self, kind, stuff): """The notification hook called to register all kinds of events. Here we are interested in 'TOCEntry' events only. """ if kind == 'TOCEntry': self.addEntry(*stuff) def clearEntries(self): self._entries = [] def getLevelStyle(self, n): '''Returns the style for level n, generating and caching styles on demand if not present.''' try: return self.levelStyles[n] except IndexError: prevstyle = self.getLevelStyle(n - 1) self.levelStyles.append( ParagraphStyle(name='%s-%d-indented' % (prevstyle.name, n), parent=prevstyle, firstLineIndent=prevstyle.firstLineIndent + delta, leftIndent=prevstyle.leftIndent + delta)) return self.levelStyles[n] def addEntry(self, level, text, pageNum, key=None): """Adds one entry to the table of contents. This allows incremental buildup by a doctemplate. Requires that enough styles are defined.""" assert type(level) == type(1), "Level must be an integer" self._entries.append((level, text, pageNum, key)) def addEntries(self, listOfEntries): """Bulk creation of entries in the table of contents. If you knew the titles but not the page numbers, you could supply them to get sensible output on the first run.""" for entryargs in listOfEntries: self.addEntry(*entryargs) def wrap(self, availWidth, availHeight): "All table properties should be known by now." # makes an internal table which does all the work. # we draw the LAST RUN's entries! If there are # none, we make some dummy data to keep the table # from complaining if len(self._lastEntries) == 0: _tempEntries = [(0, 'Placeholder for table of contents', 0, None)] else: _tempEntries = self._lastEntries def drawTOCEntryEnd(canvas, kind, label): '''Callback to draw dots and page numbers after each entry.''' label = label.split(',') page, level, key = int(label[0]), int(label[1]), eval(label[2], {}) style = self.getLevelStyle(level) if self.dotsMinLevel >= 0 and level >= self.dotsMinLevel: dot = ' . ' else: dot = '' if self.formatter: page = self.formatter(page) drawPageNumbers(canvas, style, [(page, key)], availWidth, availHeight, dot) self.canv.drawTOCEntryEnd = drawTOCEntryEnd tableData = [] for (level, text, pageNum, key) in _tempEntries: style = self.getLevelStyle(level) if key: text = '<a href="#%s">%s</a>' % (key, text) keyVal = repr(key).replace(',', '\\x2c').replace('"', '\\x2c') else: keyVal = None para = Paragraph( '%s<onDraw name="drawTOCEntryEnd" label="%d,%d,%s"/>' % (text, pageNum, level, keyVal), style) if style.spaceBefore: tableData.append([ Spacer(1, style.spaceBefore), ]) tableData.append([ para, ]) self._table = Table(tableData, colWidths=(availWidth, ), style=self.tableStyle) self.width, self.height = self._table.wrapOn(self.canv, availWidth, availHeight) return (self.width, self.height) def split(self, availWidth, availHeight): """At this stage we do not care about splitting the entries, we will just return a list of platypus tables. Presumably the calling app has a pointer to the original TableOfContents object; Platypus just sees tables. """ return self._table.splitOn(self.canv, availWidth, availHeight) def drawOn(self, canvas, x, y, _sW=0): """Don't do this at home! The standard calls for implementing draw(); we are hooking this in order to delegate ALL the drawing work to the embedded table object. """ self._table.drawOn(canvas, x, y, _sW)
def pdf(group, username, list, show_header=True, show_footer=True): """PDF version of list""" content = BytesIO() columns = list.column_set.all() accounts = list.accounts() margin = 0.5 * cm font_name = "Times-Roman" font_name_bold = "Times-Bold" font_size = 12 font_size_small = 10 font_size_min = 8 head_height = 30 # pt foot_height = 15 # pt logo_height = 25 # pt font_size_name = font_size_small font_size_short_name = font_size_small font_size_balance = font_size_small if list.orientation == list.LANDSCAPE: height, width = A4 else: width, height = A4 grid_style = TableStyle(parent=GRID_STYLE) # Create canvas for page and set fonts p = canvas.Canvas(content, (width, height)) show_logo = bool(group.logo and group.logo.storage.exists(group.logo.path)) if show_logo: # Find scaling ratio ratio = group.logo.width / group.logo.height # Load logo with correct scaling logo = Image( group.logo.path, width=logo_height * ratio, height=logo_height ) def draw_header(): if not show_header: return if show_logo: logo.drawOn( p, width - margin - logo_height * ratio, height - margin - logo_height, ) # Setup rest of header p.setFont(font_name, font_size) p.drawString( margin, height - margin - font_size, f"{group}: {list.name}" ) p.setFont(font_name, font_size_small) p.drawString( margin, height - margin - font_size - font_size + 2, "%s: %s %s %s" % (_("Printed"), str(date.today()), _("by"), username), ) footer = [] if group.email: footer.append(group.email) if group.account_number: footer.append(group.get_account_number_display()) if list.comment.strip(): footer.append(list.comment.replace("\n", " ").replace("\r", " ")) def draw_footer(): if not show_footer: return p.drawString(margin, margin, " - ".join(footer)) blacklisted_note = _("Blacklisted accounts are marked with: ") p.drawRightString(width - margin - 10, margin, blacklisted_note) p.setFillColor(BLACKLISTED_COLOR) p.rect(width - margin - 10, margin, 8, 8, fill=1, stroke=0) p.setFont(font_name, font_size) if not accounts: no_accounts_message = _("Sorry, this list is empty.") draw_header() p.drawString( margin, height - font_size - margin - head_height, no_accounts_message, ) draw_footer() p.save() return content elif not columns: no_columns_message = _( "Sorry, this list isn't set up correctly, " "please add some columns." ) draw_header() p.drawString( margin, height - font_size - margin - head_height, no_columns_message, ) draw_footer() p.save() return content # Store col widths col_width = [] header = [_("Name")] if list.account_width: col_width.append(list.account_width) if list.short_name_width: col_width.append(list.short_name_width) if list.account_width and list.short_name_width: header.append("") if list.balance_width: header.append(_("Balance")) col_width.append(list.balance_width) if list.short_name_width > 0 and list.account_width > 0: grid_style.add("SPAN", (0, 0), (1, 0)) base_x = len(header) for c in columns: header.append(c.name) col_width.append(c.width) # Calculate relative col widths over to absolute points for i, w in enumerate(col_width): col_width[i] = ( float(w) / float( (list.listcolumn_width or 0) + list.balance_width + (list.account_width or 0) + (list.short_name_width or 0) ) * (width - 2 * margin) ) # Intialise table with header data = [header] for i, a in enumerate(accounts): color = ALTERNATE_COLORS[(i + 1) % len(ALTERNATE_COLORS)] if list.double: i *= 2 extra_row_height = 1 else: extra_row_height = 0 i += 1 grid_style.add("BACKGROUND", (0, i), (-1, i + extra_row_height), color) row = [] if list.account_width: row.append(a.name) # Check if we need to reduce col font size while ( col_width[len(row) - 1] < p.stringWidth(row[-1], font_name, font_size_name) + 12 and font_size_name > font_size_min ): font_size_name -= 1 if list.short_name_width: short_name = a.short_name if not short_name and a.owner: short_name = a.owner.username row.append(short_name or a.name) # Check if we need to reduce col font size while ( col_width[len(row) - 1] < p.stringWidth(row[-1], font_name, font_size_name) + 12 and font_size_short_name > font_size_min ): font_size_short_name -= 1 if list.balance_width: row.append("%d" % a.normal_balance()) # XXX: currently warnings are only shown if balance is shown, this # if needs to be moved if you want to change that if a.needs_warning(): grid_style.add( "FONTNAME", (0, i), (base_x - 1, i), font_name_bold ) grid_style.add( "TEXTCOLOR", (base_x - 1, i), (base_x - 1, i), WARN_TEXT_COLOR, ) # Check if we need to reduce col font size while ( col_width[len(row) - 1] < p.stringWidth(str(row[-1]), font_name, font_size_balance) + 12 and font_size_balance > font_size_min ): font_size_balance -= 1 if a.is_blocked(): if list.balance_width: grid_style.add( "TEXTCOLOR", (base_x - 1, i), (base_x - 1, i), BLACKLISTED_TEXT_COLOR, ) grid_style.add( "FONTNAME", (0, i), (base_x - 1, i), font_name_bold ) grid_style.add( "BACKGROUND", (base_x, i), (-1, i + extra_row_height), BLACKLISTED_COLOR, ) row.extend([""] * len(header[base_x:])) else: row.extend(header[base_x:]) data.append(row) if list.double: data.append([""] * len(row)) grid_style.add("SPAN", (0, i), (0, i + extra_row_height)) if list.balance_width: grid_style.add("SPAN", (1, i), (1, i + extra_row_height)) grid_style.add("FONTSIZE", (0, 0), (-1, -1), font_size_small) # Set font size for names grid_style.add("FONTSIZE", (0, 1), (0, -1), font_size_name) grid_style.add("ALIGN", (0, 0), (-1, -1), "LEFT") grid_style.add("ALIGN", (base_x, 0), (-1, -1), "RIGHT") grid_style.add("FONTNAME", (0, 0), (-1, 0), font_name_bold) # Set font size for balance if list.balance_width: grid_style.add( "FONTSIZE", (base_x - 1, 1), (base_x - 1, -1), font_size_balance ) grid_style.add("ALIGN", (base_x - 1, 1), (base_x - 1, -1), "RIGHT") grid_style.add("TEXTCOLOR", (base_x, 1), (-1, -1), FAINT_COLOR) if list.double: grid_style.add("TOPPADDING", (base_x, 1), (-1, -1), 2) grid_style.add("BOTTOMPADDING", (base_x, 1), (-1, -1), 2) grid_style.add("VALIGN", (0, 1), (-1, -1), "TOP") grid_style.add("GRID", (0, 0), (-1, -1), 0.25, BORDER_COLOR) # Create table t = Table(data, colWidths=col_width, style=grid_style, repeatRows=1) rest = None avail_w = width - 2 * margin avail_h = height - 2 * margin - head_height - foot_height while t: # Figure out how big table will be t_width, t_height = t.wrapOn(p, avail_w, avail_h) if not rest and t_height > height - 2 * margin - head_height: t, rest = t.split(avail_w, avail_h) continue # Draw on canvas draw_header() t.drawOn(p, margin, height - t_height - margin - head_height) draw_footer() if rest: # set t to the second table and reset rest t, rest = (rest, None) # Show new page p.showPage() else: # Leave loop break p.save() return content
data.append(aux[:max_page]) aux = aux[max_page:] data.append(aux) for d in data: table_height = (len(d) * rowHeight) table = Table(thead, colWidths=colWidth, rowHeights=20) table.setStyle( TableStyle([ ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.red), ('BOX', (0, 0), (-1, -1), 0.25, colors.black), ('ALIGN', (0, 0), (-1, -1), 'CENTER'), ('TEXTCOLOR', (0, 0), (-1, 0), colors.red), ])) table.wrapOn(c, width, height) table.drawOn(c, 0, 200 * mm - 20) table = Table(d, colWidths=colWidth, rowHeights=rowHeight) table.setStyle( TableStyle([ ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black), ('BOX', (0, 0), (-1, -1), 0.25, colors.black), ('ALIGN', (0, 0), (-1, -1), 'CENTER'), ('TEXTCOLOR', (0, 0), (-1, 0), colors.red), ])) table.wrapOn(c, height, width) table.drawOn(c, 0, 200 * mm - table_height - 20) c.drawString(2 * mm, 205 * mm, "Welcome to Reportlab!")
class TableOfContents(IndexingFlowable): """This creates a formatted table of contents. It presumes a correct block of data is passed in. The data block contains a list of (level, text, pageNumber) triplets. You can supply a paragraph style for each level (starting at zero). Set dotsMinLevel to determine from which level on a line of dots should be drawn between the text and the page number. If dotsMinLevel is set to a negative value, no dotted lines are drawn. """ def __init__(self): self.rightColumnWidth = 72 self.levelStyles = [levelZeroParaStyle, levelOneParaStyle, levelTwoParaStyle, levelThreeParaStyle, levelFourParaStyle] self.tableStyle = defaultTableStyle self.dotsMinLevel = 1 self._table = None self._entries = [] self._lastEntries = [] def beforeBuild(self): # keep track of the last run self._lastEntries = self._entries[:] self.clearEntries() def isIndexing(self): return 1 def isSatisfied(self): return (self._entries == self._lastEntries) def notify(self, kind, stuff): """The notification hook called to register all kinds of events. Here we are interested in 'TOCEntry' events only. """ if kind == 'TOCEntry': self.addEntry(*stuff) def clearEntries(self): self._entries = [] def addEntry(self, level, text, pageNum, key=None): """Adds one entry to the table of contents. This allows incremental buildup by a doctemplate. Requires that enough styles are defined.""" assert type(level) == type(1), "Level must be an integer" assert level < len(self.levelStyles), \ "Table of contents must have a style defined " \ "for paragraph level %d before you add an entry" % level self._entries.append((level, text, pageNum, key)) def addEntries(self, listOfEntries): """Bulk creation of entries in the table of contents. If you knew the titles but not the page numbers, you could supply them to get sensible output on the first run.""" for entryargs in listOfEntries: self.addEntry(*entryargs) def wrap(self, availWidth, availHeight): "All table properties should be known by now." # makes an internal table which does all the work. # we draw the LAST RUN's entries! If there are # none, we make some dummy data to keep the table # from complaining if len(self._lastEntries) == 0: _tempEntries = [(0,'Placeholder for table of contents',0,None)] else: _tempEntries = self._lastEntries def drawTOCEntryEnd(canvas, kind, label): '''Callback to draw dots and page numbers after each entry.''' page, level = [ int(x) for x in label.split(',') ] x, y = canvas._curr_tx_info['cur_x'], canvas._curr_tx_info['cur_y'] style = self.levelStyles[level] pagew = stringWidth(' %d' % page, style.fontName, style.fontSize) if self.dotsMinLevel >= 0 and level >= self.dotsMinLevel: dotw = stringWidth(' . ', style.fontName, style.fontSize) dotsn = int((availWidth-x-pagew)/dotw) else: dotsn = dotw = 0 tx = canvas.beginText(availWidth-pagew-dotsn*dotw, y) tx.setFont(style.fontName, style.fontSize) tx.textLine('%s %d' % (dotsn * ' . ', page)) canvas.drawText(tx) self.canv.drawTOCEntryEnd = drawTOCEntryEnd tableData = [] for (level, text, pageNum, key) in _tempEntries: style = self.levelStyles[level] if key: text = '<a href="#%s">%s</a>' % (key, text) para = Paragraph('%s<onDraw name="drawTOCEntryEnd" label="%d,%d"/>' % (text, pageNum, level), style) if style.spaceBefore: tableData.append([Spacer(1, style.spaceBefore),]) tableData.append([para,]) self._table = Table(tableData, colWidths=(availWidth,), style=self.tableStyle) self.width, self.height = self._table.wrapOn(self.canv,availWidth, availHeight) return (self.width, self.height) def split(self, availWidth, availHeight): """At this stage we do not care about splitting the entries, we will just return a list of platypus tables. Presumably the calling app has a pointer to the original TableOfContents object; Platypus just sees tables. """ return self._table.splitOn(self.canv,availWidth, availHeight) def drawOn(self, canvas, x, y, _sW=0): """Don't do this at home! The standard calls for implementing draw(); we are hooking this in order to delegate ALL the drawing work to the embedded table object. """ self._table.drawOn(canvas, x, y, _sW)
class SimpleIndex(IndexingFlowable): """Creates multi level indexes. The styling can be cutomized and alphabetic headers turned on and off. """ def __init__(self, **kwargs): """ Constructor of SimpleIndex. Accepts the same arguments as the setup method. """ #keep stuff in a dictionary while building self._entries = {} self._lastEntries = {} self._flowable = None self.setup(**kwargs) def getFormatFunc(self,format): try: D = {} exec('from reportlab.lib.sequencer import _format_%s as formatFunc' % format, D) return D['formatFunc'] except ImportError: raise ValueError('Unknown format %r' % format) def setup(self, style=None, dot=None, tableStyle=None, headers=True, name=None, format='123', offset=0): """ This method makes it possible to change styling and other parameters on an existing object. style is the paragraph style to use for index entries. dot can either be None or a string. If it's None, entries are immediatly followed by their corresponding page numbers. If it's a string, page numbers are aligned on the right side of the document and the gap filled with a repeating sequence of the string. tableStyle is the style used by the table which the index uses to draw itself. Use this to change properties like spacing between elements. headers is a boolean. If it is True, alphabetic headers are displayed in the Index when the first letter changes. If False, we just output some extra space before the next item name makes it possible to use several indexes in one document. If you want this use this parameter to give each index a unique name. You can then index a term by refering to the name of the index which it should appear in: <index item="term" name="myindex" /> format can be 'I', 'i', '123', 'ABC', 'abc' """ if style is None: style = ParagraphStyle(name='index', fontName=_baseFontName, fontSize=11) self.textStyle = style self.tableStyle = tableStyle or defaultTableStyle self.dot = dot self.headers = headers if name is None: from reportlab.platypus.paraparser import DEFAULT_INDEX_NAME as name self.name = name self.formatFunc = self.getFormatFunc(format) self.offset = offset def __call__(self,canv,kind,label): try: terms, format, offset = decode_label(label) except: terms = label format = offset = None if format is None: formatFunc = self.formatFunc else: formatFunc = self.getFormatFunc(format) if offset is None: offset = self.offset terms = commasplit(terms) pns = formatFunc(canv.getPageNumber()-offset) key = 'ix_%s_%s_p_%s' % (self.name, label, pns) info = canv._curr_tx_info canv.bookmarkHorizontal(key, info['cur_x'], info['cur_y'] + info['leading']) self.addEntry(terms, pns, key) def getCanvasMaker(self, canvasmaker=canvas.Canvas): def newcanvasmaker(*args, **kwargs): from reportlab.pdfgen import canvas c = canvasmaker(*args, **kwargs) setattr(c,self.name,self) return c return newcanvasmaker def isIndexing(self): return 1 def isSatisfied(self): return (self._entries == self._lastEntries) def beforeBuild(self): # keep track of the last run self._lastEntries = self._entries.copy() self.clearEntries() def clearEntries(self): self._entries = {} def notify(self, kind, stuff): """The notification hook called to register all kinds of events. Here we are interested in 'IndexEntry' events only. """ if kind == 'IndexEntry': (text, pageNum) = stuff self.addEntry(text, pageNum) def addEntry(self, text, pageNum, key=None): """Allows incremental buildup""" self._entries.setdefault(makeTuple(text),set([])).add((pageNum, key)) def split(self, availWidth, availHeight): """At this stage we do not care about splitting the entries, we will just return a list of platypus tables. Presumably the calling app has a pointer to the original TableOfContents object; Platypus just sees tables. """ return self._flowable.splitOn(self.canv,availWidth, availHeight) def _getlastEntries(self, dummy=[(['Placeholder for index'],enumerate((None,)*3))]): '''Return the last run's entries! If there are none, returns dummy.''' if not self._lastEntries: if self._entries: return list(self._entries.items()) return dummy return list(self._lastEntries.items()) def _build(self,availWidth,availHeight): _tempEntries = self._getlastEntries() def getkey(seq): return [x.upper() for x in seq[0]] _tempEntries.sort(key=getkey) leveloffset = self.headers and 1 or 0 def drawIndexEntryEnd(canvas, kind, label): '''Callback to draw dots and page numbers after each entry.''' style = self.getLevelStyle(leveloffset) pages = decode_label(label) drawPageNumbers(canvas, style, pages, availWidth, availHeight, self.dot) self.canv.drawIndexEntryEnd = drawIndexEntryEnd alpha = '' tableData = [] lastTexts = [] alphaStyle = self.getLevelStyle(0) for texts, pageNumbers in _tempEntries: texts = list(texts) #track when the first character changes; either output some extra #space, or the first letter on a row of its own. We cannot do #widow/orphan control, sadly. nalpha = texts[0][0].upper() if alpha != nalpha: alpha = nalpha if self.headers: header = alpha else: header = ' ' tableData.append([Spacer(1, alphaStyle.spaceBefore),]) tableData.append([Paragraph(header, alphaStyle),]) tableData.append([Spacer(1, alphaStyle.spaceAfter),]) i, diff = listdiff(lastTexts, texts) if diff: lastTexts = texts texts = texts[i:] label = encode_label(list(pageNumbers)) texts[-1] = '%s<onDraw name="drawIndexEntryEnd" label="%s"/>' % (texts[-1], label) for text in texts: #Platypus and RML differ on how parsed XML attributes are escaped. #e.g. <index item="M&S"/>. The only place this seems to bite us is in #the index entries so work around it here. text = escapeOnce(text) style = self.getLevelStyle(i+leveloffset) para = Paragraph(text, style) if style.spaceBefore: tableData.append([Spacer(1, style.spaceBefore),]) tableData.append([para,]) i += 1 self._flowable = Table(tableData, colWidths=[availWidth], style=self.tableStyle) def wrap(self, availWidth, availHeight): "All table properties should be known by now." self._build(availWidth,availHeight) self.width, self.height = self._flowable.wrapOn(self.canv,availWidth, availHeight) return self.width, self.height def drawOn(self, canvas, x, y, _sW=0): """Don't do this at home! The standard calls for implementing draw(); we are hooking this in order to delegate ALL the drawing work to the embedded table object. """ self._flowable.drawOn(canvas, x, y, _sW) def draw(self): t = self._flowable ocanv = getattr(t,'canv',None) if not ocanv: t.canv = self.canv try: t.draw() finally: if not ocanv: del t.canv def getLevelStyle(self, n): '''Returns the style for level n, generating and caching styles on demand if not present.''' if not hasattr(self.textStyle, '__iter__'): self.textStyle = [self.textStyle] try: return self.textStyle[n] except IndexError: self.textStyle = list(self.textStyle) prevstyle = self.getLevelStyle(n-1) self.textStyle.append(ParagraphStyle( name='%s-%d-indented' % (prevstyle.name, n), parent=prevstyle, firstLineIndent = prevstyle.firstLineIndent+.2*cm, leftIndent = prevstyle.leftIndent+.2*cm)) return self.textStyle[n]
def transferencia_pdf(request): # Create the HttpResponse object with the appropriate PDF headers. response = HttpResponse(content_type='application/pdf') # Para descargar directo #response['Content-Disposition'] = 'attachment; filename=reporte.pdf' # Create the PDF object, using the response object as its "file." buffer = BytesIO() p = canvas.Canvas(buffer, A4) # Instanciar Cuenta tipoCuenta = request.GET['tipocuenta'] cuentaNumero = request.GET['cuentanumero'] apellidos = request.GET['apellidosA'] nombres = request.GET['nombresA'] direccion = request.GET['direccion'] telefono = request.GET['telefono'] fechaTransaccion = request.GET['fecha'] montoAux = request.GET['monto'] numCuentaDestinatario = request.GET['numb'] nombresDestinatario = request.GET['nomb'] apellidosDestinatario = request.GET['apellb'] # HEADER p.setLineWidth(.3) p.setFont('Helvetica', 10) p.drawString(180, 800, "COOPERATIVA DE AHORRO Y CREDITO") p.setFont('Helvetica-Bold', 17) p.drawString(160, 780, "COOPERATIVA JONNATHAN") p.setFont('Helvetica', 15) p.drawString(180, 762, "CUENTA TIPO: " + tipoCuenta) p.setFont('Helvetica-Bold', 12) p.drawString(30, 730, "Oficina:") p.setFont('Helvetica', 12) p.drawString(95, 730, "Loja") p.setFont('Helvetica-Bold', 12) p.drawString(325, 730, "N. de Cuenta: ") p.setFont('Helvetica', 12) p.drawString(425, 730, cuentaNumero) p.line(420, 727, 560, 727)#start X, height end y , height p.setFont('Helvetica-Bold', 12) p.drawString(30, 710, "Nombres:") p.setFont('Helvetica', 12) p.drawString(95, 710, apellidos + ' ' + nombres) p.setFont('Helvetica-Bold', 12) p.drawString(30, 690, "Domicilio:") p.setFont('Helvetica', 12) p.drawString(95, 690, direccion) p.setFont('Helvetica-Bold', 12) p.drawString(348, 690, "Telefono:") p.setFont('Helvetica', 12) p.drawString(425, 690, telefono) # Table header styles = getSampleStyleSheet() styleBH = styles["Normal"] styleBH.alignment = TA_CENTER styleBH.fontSize = 10 fecha = Paragraph('''Fecha Emision''', styleBH) cuentaDestino = Paragraph('''Numero de Cuenta''', styleBH) destinatario = Paragraph('''Destinatario''', styleBH) tipo = Paragraph('''Tipo Operacion''', styleBH) monto = Paragraph('''Monto''', styleBH) data = [] data.append([fecha, cuentaDestino, destinatario, tipo, monto]) data.append([fechaTransaccion, numCuentaDestinatario, nombresDestinatario + apellidosDestinatario, "transferencia",montoAux]) # Table body styleN = styles["BodyText"] styleN.alignment = TA_CENTER styleN.fontSize = 7 high = 640 # Table size table = Table(data, colWidths=[4.6 * cm, 2.5 * cm, 7 * cm, 3 * cm, 2.3 * cm]) table.setStyle(TableStyle([# estilos de la tabla ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0,0), (-1,-1), 0.25, colors.black), ])) # pdf size width, height = A4 table.wrapOn(p, width, height) table.drawOn(p, 30, high) # Close the PDF object cleanly, and we're done. p.showPage()# save page p.save() # save pdf # get the value of BytesIO buffer and write response pdf = buffer.getvalue() buffer.close() response.write(pdf) return response
class TableOfContents(IndexingFlowable): """This creates a formatted table of contents. It presumes a correct block of data is passed in. The data block contains a list of (level, text, pageNumber) triplets. You can supply a paragraph style for each level (starting at zero). """ def __init__(self): self.entries = [] self.rightColumnWidth = 72 self.levelStyles = [levelZeroParaStyle, levelOneParaStyle, levelTwoParaStyle, levelThreeParaStyle, levelFourParaStyle] self.tableStyle = defaultTableStyle self._table = None self._entries = [] self._lastEntries = [] def beforeBuild(self): # keep track of the last run self._lastEntries = self._entries[:] self.clearEntries() def isIndexing(self): return 1 def isSatisfied(self): return (self._entries == self._lastEntries) def notify(self, kind, stuff): """The notification hook called to register all kinds of events. Here we are interested in 'TOCEntry' events only. """ if kind == 'TOCEntry': (level, text, pageNum) = stuff self.addEntry(level, text, pageNum) def clearEntries(self): self._entries = [] def addEntry(self, level, text, pageNum): """Adds one entry to the table of contents. This allows incremental buildup by a doctemplate. Requires that enough styles are defined.""" assert type(level) == type(1), "Level must be an integer" assert level < len(self.levelStyles), \ "Table of contents must have a style defined " \ "for paragraph level %d before you add an entry" % level self._entries.append((level, text, pageNum)) def addEntries(self, listOfEntries): """Bulk creation of entries in the table of contents. If you knew the titles but not the page numbers, you could supply them to get sensible output on the first run.""" for (level, text, pageNum) in listOfEntries: self.addEntry(level, text, pageNum) def wrap(self, availWidth, availHeight): "All table properties should be known by now." widths = (availWidth - self.rightColumnWidth, self.rightColumnWidth) # makes an internal table which does all the work. # we draw the LAST RUN's entries! If there are # none, we make some dummy data to keep the table # from complaining if len(self._lastEntries) == 0: _tempEntries = [(0,'Placeholder for table of contents',0)] else: _tempEntries = self._lastEntries tableData = [] for (level, text, pageNum) in _tempEntries: leftColStyle = self.levelStyles[level] #right col style is right aligned rightColStyle = ParagraphStyle(name='leftColLevel%d' % level, parent=leftColStyle, leftIndent=0, alignment=enums.TA_RIGHT) leftPara = Paragraph(text, leftColStyle) rightPara = Paragraph(str(pageNum), rightColStyle) tableData.append([leftPara, rightPara]) self._table = Table(tableData, colWidths=widths, style=self.tableStyle) self.width, self.height = self._table.wrapOn(self.canv,availWidth, availHeight) return (self.width, self.height) def split(self, availWidth, availHeight): """At this stage we do not care about splitting the entries, we will just return a list of platypus tables. Presumably the calling app has a pointer to the original TableOfContents object; Platypus just sees tables. """ return self._table.splitOn(self.canv,availWidth, availHeight) def drawOn(self, canvas, x, y, _sW=0): """Don't do this at home! The standard calls for implementing draw(); we are hooking this in order to delegate ALL the drawing work to the embedded table object. """ self._table.drawOn(canvas, x, y, _sW)
def save(self): self.draw_header() self.canvas.drawCentredString(cm(10.5), cm(19), "REFUND NOTE {0} FOR INVOICE NUMBER {1}".format(self.refundid, self.invoicenum)) self.canvas.drawString(cm(2), cm(18), "Reason for refund: {0}".format(self.reason)) tblpaid = [ ["Amount paid"], ["Item", "Amount"], ["Amount", "{0:.2f} {1}".format(self.invoiceamount, settings.CURRENCY_SYMBOL)], ] tblrefunded = [ ["Amount refunded"], ["Item", "Amount"], ["Amount", "{0:.2f} {1}".format(self.refundamount, settings.CURRENCY_SYMBOL)], ] tblprevious = [ ["Amount previously refunded"], ["Item", "Amount"], ["Amount", "{0:.2f} {1}".format(self.previousamount, settings.CURRENCY_SYMBOL)], ] if self.invoicevat: tblpaid.extend([ ["VAT", "{0:.2f} {1}".format(self.invoicevat, settings.CURRENCY_SYMBOL)], ["", "{0:.2f} {1}".format(self.invoiceamount + self.invoicevat, settings.CURRENCY_SYMBOL)], ]) tblrefunded.extend([ ["VAT", "{0:.2f} {1}".format(self.refundvat, settings.CURRENCY_SYMBOL)], ["", "{0:.2f} {1}".format(self.refundamount + self.refundvat, settings.CURRENCY_SYMBOL)], ]) tblprevious .extend([ ["VAT", "{0:.2f} {1}".format(self.previousvat, settings.CURRENCY_SYMBOL)], ["", "{0:.2f} {1}".format(self.previousamount + self.previousvat, settings.CURRENCY_SYMBOL)], ]) style = [ ('SPAN', (0, 0), (1, 0)), ('BACKGROUND', (0, 0), (-1, 0), colors.lightgrey), ('ALIGN', (0, 0), (0, 0), 'CENTER'), ('ALIGN', (1, 1), (1, -1), 'RIGHT'), ('LINEBELOW', (0, 1), (-1, 1), 1, colors.black), ('OUTLINE', (0, 0), (-1, -1), 1, colors.black), ] if self.invoicevat: style.append( ('LINEABOVE', (-1, -1), (-1, -1), 2, colors.black), ) t = Table(tblpaid, [cm(10.5), cm(2.5), cm(1.5), cm(2.5)]) t.setStyle(TableStyle(style)) w, h = t.wrapOn(self.canvas, cm(10), cm(10)) t.drawOn(self.canvas, (self.canvas._pagesize[0] - w) // 2, cm(17) - h) if self.previousamount: t = Table(tblprevious, [cm(10.5), cm(2.5), cm(1.5), cm(2.5)]) t.setStyle(TableStyle(style)) w, h = t.wrapOn(self.canvas, cm(10), cm(10)) t.drawOn(self.canvas, (self.canvas._pagesize[0] - w) // 2, cm(17) - h * 2 - cm(1)) extraofs = h + cm(1) else: extraofs = 0 t = Table(tblrefunded, [cm(10.5), cm(2.5), cm(1.5), cm(2.5)]) t.setStyle(TableStyle(style)) w, h = t.wrapOn(self.canvas, cm(10), cm(10)) t.drawOn(self.canvas, (self.canvas._pagesize[0] - w) // 2, cm(17) - h * 2 - cm(1) - extraofs) self.canvas.drawCentredString(cm(10.5), cm(16.3) - h * 2 - cm(2) - extraofs, "This refund was issued {0}".format(timezone.localtime(self.refunddate).strftime("%B %d, %Y"))) if self.paymentmethod: self.canvas.drawCentredString(cm(10.5), cm(16.3) - h * 2 - cm(3) - extraofs, "Refunded to the original form of payment: {0}.".format(self.paymentmethod)) self.canvas.showPage() self.canvas.save() return self.pdfdata
def save(self): # We can fit ROWS_PER_PAGE rows on one page. We might want to do something # cute to avoid a single row on it's own page in the future, but # for now, just split it evenly. for pagenum in range(0, (len(self.rows) - 1) // self.ROWS_PER_PAGE + 1): self.draw_header() islastpage = (pagenum == (len(self.rows) - 1) // self.ROWS_PER_PAGE) if len(self.rows) > self.ROWS_PER_PAGE: suffix = " (page %s/%s)" % (pagenum + 1, len(self.rows) // self.ROWS_PER_PAGE + 1) else: suffix = '' self.canvas.setFont('DejaVu Serif Bold', 12) self.canvas.setFillColor(colors.black) # Center between 2 and 19 is 10.5 self.canvas.drawCentredString(cm(10.5), cm(19), self.title) self.canvas.setFont('DejaVu Serif', 9) if self.invoicenum: if self.receipt: self.canvas.drawCentredString(cm(10.5), cm(18.5), "Receipt for invoice number %s%s" % (self.invoicenum, suffix)) else: self.canvas.drawCentredString(cm(10.5), cm(18.5), "Invoice number %s - %s%s" % (self.invoicenum, timezone.localtime(self.invoicedate).strftime("%B %d, %Y"), suffix)) self.canvas.setFont('DejaVu Serif Bold', 10) if self.receipt: self.canvas.drawString(cm(15), cm(28), "Receipt #%s" % self.invoicenum) else: self.canvas.drawString(cm(15), cm(28), "Invoice #%s" % self.invoicenum) if self.bankinfo: self.canvas.setFont('DejaVu Serif Bold', 8) self.canvas.drawString(cm(15), cm(27.5), "Payment ref: %s" % self.paymentref) else: self.canvas.drawCentredString(cm(10.5), cm(18.5), "Receipt - %s%s" % (timezone.localtime(self.invoicedate).strftime("%B %d, %Y"), suffix)) if pagenum == 0: firstcol = "Item" else: firstcol = "Item - continued from page %s" % pagenum if settings.EU_VAT: tbldata = [[firstcol, "Quantity", "Ex VAT", "VAT", "Incl VAT"]] else: tbldata = [[firstcol, "Quantity", "Price", "Total"]] tblcols = len(tbldata[0]) if settings.EU_VAT: tbldata.extend([(self.trimstring(title, cm(9.5), "DejaVu Serif", 8), count, "%.2f %s" % (cost, settings.CURRENCY_SYMBOL), vatrate and vatrate.shortstr or "No VAT", "%.2f %s" % ((cost * count) * (1 + (vatpercent / Decimal(100))), settings.CURRENCY_SYMBOL)) for title, cost, count, vatrate, vatpercent in self.rows[pagenum * self.ROWS_PER_PAGE:(pagenum + 1) * self.ROWS_PER_PAGE]]) else: tbldata.extend([(self.trimstring(title, cm(9.5), "DejaVu Serif", 8), count, "%.2f %s" % (cost, settings.CURRENCY_SYMBOL), "%.2f %s" % ((cost * count), settings.CURRENCY_SYMBOL)) for title, cost, count, vatrate, vatpercent in self.rows[pagenum * self.ROWS_PER_PAGE:(pagenum + 1) * self.ROWS_PER_PAGE]]) style = [ # Set global font size ('FONTSIZE', (0, 0), (-1, -1), 8), # Right-align all columnsexcept the first one (item name) ('ALIGN', (1, 0), (tblcols - 1, -1), 'RIGHT'), # Draw header line background in light gray and line under it ('BACKGROUND', (0, 0), (tblcols - 1, 0), colors.lightgrey), ('LINEBELOW', (0, 0), (-1, 0), 2, colors.black), # Draw an outline around the whole table ('OUTLINE', (0, 0), (-1, -1), 1, colors.black), ] if islastpage: totalexcl = sum([cost * count for title, cost, count, vatrate, vatpercent in self.rows]) if settings.EU_VAT: # When EU vat enabled, calculate total fields both with and without VAT, # and special-case the reverse-VAT situation. totalvat = sum([(cost * count * (vatpercent / Decimal(100))).quantize(Decimal('0.01')) for title, cost, count, vatrate, vatpercent in self.rows]) totalincl = sum([(cost * count * (1 + vatpercent / Decimal(100))).quantize(Decimal('0.01')) for title, cost, count, vatrate, vatpercent in self.rows]) if self.totalvat > 0 and totalvat != self.totalvat: raise Exception("Specified total VAT {0} does not match calculated VAT {1}".format(self.totalvat, totalvat)) if self.reverse_vat: if totalvat != 0: raise Exception("Can't use reverse VAT and specified VAT at the same time!") vathdr = 'Total VAT *' vatstr = "0 %s *" % (settings.CURRENCY_SYMBOL, ) else: vathdr = 'Total VAT' vatstr = '%.2f %s' % (totalvat, settings.CURRENCY_SYMBOL) tbldata.extend([ ('Total excl VAT', '', '', '', '%.2f %s' % (totalexcl, settings.CURRENCY_SYMBOL)), (vathdr, '', '', '', vatstr), ('Total incl VAT', '', '', '', '%.2f %s' % (totalincl, settings.CURRENCY_SYMBOL)), ]) style.extend([ # For the tree "total excl", "cat", "total incl" lines, span the # cells together and alight right, and draw a line above them. ('SPAN', (0, -3), (3, -3)), ('SPAN', (0, -2), (3, -2)), ('SPAN', (0, -1), (3, -1)), ('ALIGN', (0, -3), (0, -1), 'RIGHT'), ('LINEABOVE', (-4, -3), (-1, -3), 2, colors.black), ]) else: # No EU vat, so just a simple total tbldata.extend([ ('Total', '', '', '%.2f %s' % (totalexcl, settings.CURRENCY_SYMBOL)), ]) # Merge the cells of the total line together, right-align them, and # draw a line above them. style.extend([ ('SPAN', (0, -1), (2, -1)), ('ALIGN', (0, -1), (0, -1), 'RIGHT'), ('LINEABOVE', (-3, -1), (-1, -1), 2, colors.black), ]) else: tbldata.append([' Continued on page %s' % (pagenum + 2), '', '', '']) style.append(('ALIGN', (0, -1), (-1, -1), 'CENTER')) style.append(('FONT', (0, -1), (-1, -1), 'DejaVu Serif Italic')) t = Table(tbldata, [cm(9.5), cm(1.5), cm(2.5), cm(2), cm(2.5)]) t.setStyle(TableStyle(style)) w, h = t.wrapOn(self.canvas, cm(10), cm(10)) t.drawOn(self.canvas, cm(2), cm(18) - h) self.canvas.setFont('DejaVu Serif Bold', 10) if self.receipt: self.canvas.drawCentredString(cm(10.5), cm(17.3) - h, "This invoice was paid %s" % timezone.localtime(self.duedate).strftime("%B %d, %Y")) else: self.canvas.drawCentredString(cm(10.5), cm(17.3) - h, "This invoice is due: %s" % timezone.localtime(self.duedate).strftime("%B %d, %Y")) if self.bankinfo: self.canvas.setFont('DejaVu Serif', 8) self.canvas.drawCentredString(cm(10.5), cm(16.8) - h, "If paying with bank transfer, use payment reference %s" % self.paymentref) if islastpage: self.draw_footer() # Finish this page off, and optionally loop to another one self.canvas.showPage() # Last page is finished, flush the PDF output self.canvas.save() return self.pdfdata
def makeRampart(fire, days, dates, maps, sim_output, scores): """! Make summary page for RamPART and risk @param fire Fire name to use @param days Array of days simulation created output for @param dates Array of dates simulation created output for @param maps List of maps to use for cover page thumbnails @param sim_output Array of simulation output, by line @param scores Array of scores for simulation output dates @return Path of RamPART summary page PDF """ size = float( find_line(sim_output, 'Fire starting with size', 'size ')[:-2]) sizes = find_lines(sim_output, ' size at end of day') confirmed = find_line(sim_output, 'Initialized WxShield with date')[-16:] numSims = int(find_line(sim_output, 'simulations', 'Ran ').split(' ')[0]) showSims = "{:,}".format(numSims) score = scores[-1] showScore = score lat_find = "Using ignition point (" lat_long = find_line(sim_output, lat_find, lat_find)[:-1].split(',') lat = float(lat_long[0].strip()) lon = float(lat_long[1].strip()) loc_find = 'UTM coordinates are: ' location = find_line(sim_output, loc_find, loc_find) runTime = sim_output[1][1:20] startup = find_lines(sim_output, 'Startup indices ') startup = startup[0] if ( len(startup) > 0) else "Startup indices are not valid" txtStartup = startup[startup.find("Startup indices "):] rampart = os.path.join(os.path.dirname(maps[0]), fire + "_rampart.pdf") title = "{} - {}".format(fire, dates[0]) # c = canvas.Canvas(rampart, LANDSCAPE) c.rect(MARGIN / 3, MARGIN / 3, PAGE_WIDTH - 2 * MARGIN / 3, PAGE_HEIGHT - 2 * MARGIN / 3, fill=0) c.setFillColor(colors.white) c.rect(MARGIN / 2, PAGE_HEIGHT - MARGIN, 220, 20, fill=1) c.setFillColor(colors.black) c.setFont(NORMAL, 20) c.drawString(MARGIN, PAGE_HEIGHT - MARGIN, 'Part 2: Impact & Risk') c.setFont(BOLD, 36) c.drawCentredString(IMAGE_WIDTH / 2, PAGE_HEIGHT - 3 * MARGIN, title) c.drawInlineImage(r'C:\FireGUARD\mapping\logo_all.png', MARGIN / 2, PAGE_HEIGHT - (3.5 * MARGIN + LOGO_HEIGHT), LOGO_WIDTH, LOGO_HEIGHT) c.setFont(BOLD, 20) c.drawCentredString(MARGIN + 1.4 * LOGO_WIDTH, PAGE_HEIGHT - (5 * MARGIN), 'Total Risk') c.setFont(BOLD, 12) c.drawCentredString(MARGIN + 1.4 * LOGO_WIDTH, PAGE_HEIGHT - (6 * MARGIN), '(on day 14)') c.setFont(BOLD, 36) c.drawCentredString(MARGIN + 1.4 * LOGO_WIDTH, PAGE_HEIGHT - (9 * MARGIN), showScore) # c.setFont(BOLD, 12) t = Table([['Simulation Start', confirmed], ['Location', location], ['Initial size (ha)', "{:,}".format(size)], ['Model run', runTime], ['Simulations', showSims]]) t.setStyle( TableStyle([ ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black), ('BOX', (0, 0), (-1, -1), 0.25, colors.black), ])) # w, h = t.wrapOn(c, 0, 0) t.drawOn(c, 2 * LOGO_WIDTH + MARGIN, PAGE_HEIGHT - (9.7 * MARGIN)) c.drawInlineImage(maps[1], MARGIN + IMAGE_WIDTH, MARGIN + 2 * IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_HEIGHT) c.drawInlineImage(maps[0], MARGIN + 2 * IMAGE_WIDTH, MARGIN + 2 * IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_HEIGHT) c.drawInlineImage(maps[2], MARGIN + IMAGE_WIDTH, MARGIN + IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_HEIGHT) c.drawInlineImage(maps[4], MARGIN + 2 * IMAGE_WIDTH, MARGIN + IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_HEIGHT) c.drawInlineImage(maps[3], MARGIN + IMAGE_WIDTH, MARGIN, IMAGE_WIDTH, IMAGE_HEIGHT) c.drawInlineImage(maps[5], MARGIN + 2 * IMAGE_WIDTH, MARGIN, IMAGE_WIDTH, IMAGE_HEIGHT) # c.setFont(BOLD, 20) c.drawString(MARGIN, 630, 'Check:') def mkPoint(title, text, y): c.setFont(BOLD, 10) c.drawString(MARGIN, y, "- " + title) c.setFont(NORMAL, 10) c.drawString(110, y, text) mkPoint("Burn Probability", "Is it accurate? Does it make sense? What were the assumptions?", 615) mkPoint("ARs", 'Can they be burnt? Are they located in areas of "non-fuel"?', 600) c.setFont(BOLD, 20) c.drawString(MARGIN, 580, "Product Description:") mkPoint("Potential Impact", "What would happen if the entire area were to burn with 100%", 565) c.drawString(110, 550, "certainty at a high fire intensity?") mkPoint("Total Risk", "The sum of the risk per cell for the entire area.", 535) mkPoint( "Risk Map", "The impact (adjusted for different fire intensities) times the likelihood", 520) c.drawString(110, 505, "that a cell is burnt, giving the risk per cell.") c.setFont(BOLD, 20) c.drawString(MARGIN, 485, "Terminology:") # mkPoint( "Risk", 'Is impact times likelihood, literally the "average" loss, as if the', 470) c.drawString(110, 455, "situation was repeated many times.") mkPoint( "ARs", 'Assests and Resources (ARs) are physical things on the landscape.', 440) mkPoint("Resources", 'Are biological and other natural elements.', 425) mkPoint("Assets", 'Are objects built by people.', 410) mkPoint( "Fire Effects", 'Are the physical, biological, and ecological changes to ARs and their', 395) c.drawString( 110, 380, 'functioning caused by fire. Only "direct" effects happening') c.drawString( 110, 365, 'immediately or soon after the passage of fire are considered.') mkPoint( "Fire Impacts", 'Are the changes in worth, as judged by people, that are caused by', 350) c.drawString( 110, 335, 'fire effects. Impact represents loss and positive impacts are not') c.drawString( 110, 320, 'considered. There are three impact types that make up total impact:') c.drawString(110, 305, 'Social, Economic, and Emergency Response.') c.drawInlineImage(r'C:\FireGUARD\mapping\impact_flow.png', MARGIN, 200, IMAGE_WIDTH, 366.0 / 1435 * IMAGE_WIDTH) c.drawString(MARGIN, 185, 'Q: What is the impact and risk scale?') c.drawString( MARGIN, 170, 'A: Staff scored impacts on a 1-10 scale for each of 52 different ARs.' ) data = [ ['', 'Total Potential Impact', 'Risk (average loss)', ''], ['', '(HFI 4000+ kW/m)', '50% prob', '90% prob'], ['1 structure', '6.6', '3.3', '5.9'], ['100 ha of timber', '5.9', '3.0', '5.3'], ['1 km of hydro line', '7.0', '3.5', '6.3'], [ 'Example sum in 1 ha (3 structures,\n50 m of hydro line, 1 ha of timber)', '20.2', '10.1', '18.2' ] ] t = Table(data, colWidths=[170, 105, 60, 60]) t.setStyle( TableStyle([ ('GRID', (0, 0), (-1, -1), 0.25, colors.black), ('FONTNAME', (0, 0), (-1, 1), BOLD), ('FONTSIZE', (0, 0), (-1, -1), 10), ('ALIGN', (1, 0), (-1, 1), 'CENTER'), ('SPAN', (-2, 0), (-1, 0)), ])) # w, h = t.wrapOn(c, 0, 0) t.drawOn(c, MARGIN, 45) c.setFont(BOLD, 10) c.drawString(MARGIN, 30, 'Interpretation:') c.setFont(NORMAL, 10) c.drawString( MARGIN, 15, 'A risk of 10 is "like" the loss of 200 ha of timber, or worse than the loss of a structure.' ) c.drawCentredString(PAGE_WIDTH / 2, 5, Settings.ACTIVE_OFFER) c.save() return rampart
def save(self): # We can fit 15 rows on one page. We might want to do something # cute to avoid a single row on it's own page in the future, but # for now, just split it evenly. for pagenum in range(0, (len(self.rows)-1)/15+1): self._pageheader() islastpage = (pagenum == (len(self.rows)-1)/15) if len(self.rows) > 15: suffix = " (page %s/%s)" % (pagenum+1, len(self.rows)/15+1) else: suffix = '' # Center between 2 and 19 is 10.5 if self.invoicenum: if self.receipt: self.canvas.drawCentredString(10.5*cm,19*cm, "RECEIPT FOR INVOICE NUMBER %s%s" % (self.invoicenum, suffix)) else: self.canvas.drawCentredString(10.5*cm,19*cm, "INVOICE NUMBER %s - %s%s" % (self.invoicenum, self.invoicedate.strftime("%B %d, %Y"),suffix)) else: self.canvas.drawCentredString(10.5*cm,19*cm, "RECEIPT - %s%s" % (self.invoicedate.strftime("%B %d, %Y"), suffix)) if pagenum == 0: tbldata = [["Item", "Price", "Count", "Amount"], ] else: tbldata = [["Item - continued from page %s" % pagenum, "Price", "count", "amount"], ] tbldata.extend([(self.trimstring(title, 10.5*cm, "Times-Roman", 10), "%.2f %s" % (cost, self.currency), count, "%.2f %s" % ((cost * count), self.currency)) for title,cost, count in self.rows[pagenum*15:(pagenum+1)*15]]) style = [ ('BACKGROUND',(0,0),(3,0),colors.lightgrey), ('ALIGN',(1,0),(3,-1),'RIGHT'), ('LINEBELOW',(0,0),(-1,0), 2, colors.black), ('OUTLINE', (0,0), (-1, -1), 1, colors.black), ] if islastpage: tbldata.append(['','','Total',"%.2f %s" % (sum([cost*count for title,cost,count in self.rows]),self.currency)]) style.append(('LINEABOVE', (-2,-1), (-1, -1), 2, colors.black)) else: tbldata.append([' Continued on page %s' % (pagenum + 2), '', '', '']) style.append(('ALIGN', (0, -1), (-1, -1), 'CENTER')) style.append(('FONT', (0, -1), (-1, -1), 'Times-Italic')) t = Table(tbldata, [10.5*cm, 2.5*cm, 1.5*cm, 2.5*cm]) t.setStyle(TableStyle(style)) w,h = t.wrapOn(self.canvas,10*cm,10*cm) t.drawOn(self.canvas, 2*cm, 18*cm-h) if self.receipt: self.canvas.drawCentredString(10.5*cm,17.3*cm-h, "This invoice was paid %s" % self.duedate.strftime("%B %d, %Y")) else: self.canvas.drawCentredString(10.5*cm,17.3*cm-h, "This invoice is due: %s" % self.duedate.strftime("%B %d, %Y")) t = self.canvas.beginText() t.setTextOrigin(2*cm, 5*cm) t.setFont("Times-Italic", 10) t.textLine("PostgreSQL Europe is a French non-profit under the French 1901 Law. The association is not VAT registered.") t.textLine("") if islastpage and self.bankinfo: t.setFont("Times-Bold", 10) t.textLine("Bank references / Références bancaires / Bankverbindungen / Referencias bancarias") t.setFont("Times-Roman", 8) t.textLines("""CCM PARIS 1-2 LOUVRE MONTORGUEIL 28 RUE ETIENNE MARCEL 75002 PARIS FRANCE IBAN: FR76 1027 8060 3100 0205 2290 114 BIC: CMCIFR2A """) self.canvas.drawText(t) # Finish this page off, and optionally loop to another one self.canvas.showPage() # Last page is finished, flush the PDF output self.canvas.save() return self.pdfdata
def makeCover(fire, days, dates, maps, sim_output, scores): """! Make cover page pdf summarizing FireSTARR results @param fire Fire name to use @param days Array of days simulation created output for @param dates Array of dates simulation created output for @param maps List of maps to use for cover page thumbnails @param sim_output Array of simulation output, by line @param scores Array of scores for simulation output dates @return Path of cover page PDF """ size = float( find_line(sim_output, 'Fire starting with size', 'size ')[:-2]) sizes = find_lines(sim_output, ' size at end of day') confirmed = find_line(sim_output, 'Initialized WxShield with date')[-16:] numSims = int(find_line(sim_output, 'simulations', 'Ran ').split(' ')[0]) showSims = "{:,}".format(numSims) score = scores[-1] showScore = score lat_find = "Using ignition point (" lat_long = find_line(sim_output, lat_find, lat_find)[:-1].split(',') lat = float(lat_long[0].strip()) lon = float(lat_long[1].strip()) loc_find = 'UTM coordinates are: ' location = find_line(sim_output, loc_find, loc_find) runTime = sim_output[1][1:20] startup = find_lines(sim_output, 'Startup indices ') startup = startup[0] if ( len(startup) > 0) else "Startup indices are not valid" txtStartup = startup[startup.find("Startup indices "):] cover = os.path.join(os.path.dirname(maps[0]), fire + "_cover.pdf") title = "{} - {}".format(fire, dates[0]) # c = canvas.Canvas(cover, LANDSCAPE) c.rect(MARGIN / 3, MARGIN / 3, PAGE_WIDTH - 2 * MARGIN / 3, PAGE_HEIGHT - 2 * MARGIN / 3, fill=0) c.setFillColor(colors.white) c.rect(MARGIN / 2, PAGE_HEIGHT - MARGIN, 220, 20, fill=1) c.setFillColor(colors.black) c.setFont(NORMAL, 20) c.drawString(MARGIN, PAGE_HEIGHT - MARGIN, 'Part 1: Burn Probability') c.setFont(BOLD, 36) c.drawCentredString(IMAGE_WIDTH / 2, PAGE_HEIGHT - 3 * MARGIN, title) c.drawInlineImage(r'C:\FireGUARD\mapping\logo_all.png', MARGIN / 2, PAGE_HEIGHT - (3.5 * MARGIN + LOGO_HEIGHT), LOGO_WIDTH, LOGO_HEIGHT) c.setFont(BOLD, 20) c.drawCentredString(MARGIN + 1.4 * LOGO_WIDTH, PAGE_HEIGHT - (5 * MARGIN), 'Total Risk') c.setFont(BOLD, 12) c.drawCentredString(MARGIN + 1.4 * LOGO_WIDTH, PAGE_HEIGHT - (6 * MARGIN), '(on day 14)') c.setFont(BOLD, 36) c.drawCentredString(MARGIN + 1.4 * LOGO_WIDTH, PAGE_HEIGHT - (9 * MARGIN), showScore) # c.setFont(BOLD, 12) t = Table([['Simulation Start', confirmed], ['Location', location], ['Initial size (ha)', "{:,}".format(size)], ['Model run', runTime], ['Simulations', showSims]]) t.setStyle( TableStyle([ ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black), ('BOX', (0, 0), (-1, -1), 0.25, colors.black), ])) # w, h = t.wrapOn(c, 0, 0) t.drawOn(c, 2 * LOGO_WIDTH + MARGIN, PAGE_HEIGHT - (9.7 * MARGIN)) c.drawInlineImage(maps[1], MARGIN + IMAGE_WIDTH, MARGIN + 2 * IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_HEIGHT) c.drawInlineImage(maps[0], MARGIN + 2 * IMAGE_WIDTH, MARGIN + 2 * IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_HEIGHT) c.drawInlineImage(maps[2], MARGIN + IMAGE_WIDTH, MARGIN + IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_HEIGHT) c.drawInlineImage(maps[4], MARGIN + 2 * IMAGE_WIDTH, MARGIN + IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_HEIGHT) c.drawInlineImage(maps[3], MARGIN + IMAGE_WIDTH, MARGIN, IMAGE_WIDTH, IMAGE_HEIGHT) c.drawInlineImage(maps[5], MARGIN + 2 * IMAGE_WIDTH, MARGIN, IMAGE_WIDTH, IMAGE_HEIGHT) # c.setFont(BOLD, 10) c.drawCentredString(MARGIN + IMAGE_WIDTH / 2, 630, txtStartup) data = [['Simulated fire statistics', '', '', '', '', '', ''], ['', 'Date', 'Size (ha)', '', '', '', 'Total Risk'], [ 'Day*', '(23:59 local)', 'Min', 'Average', 'Median**', 'Max', '(Avg Loss)' ]] for i in xrange(len(days)): sizeline = 'size at end of day ' + str(days[i]) + ': ' size = [x for x in sizes if -1 != x.find(sizeline)] size_split = size[0][(size[0].find(sizeline) + len(sizeline)):].split(' ') size_min = "{:,}".format(int(round(float(size_split[0])))) size_max = "{:,}".format(int(round(float(size_split[3])))) size_median = "{:,}".format(int(round(float(size_split[9])))) size_mean = "{:,}".format(int(round(float(size_split[6])))) risk = scores[i] data.append([ str(days[i]), dates[i], size_min, size_mean, size_median, size_max, risk ]) t = Table(data, colWidths=[40, 65, 55, 55, 55, 55, 55]) t.setStyle( TableStyle([ ('GRID', (0, 0), (-1, -1), 0.25, colors.black), ('FONTNAME', (0, 0), (-1, 2), BOLD), ('ALIGN', (0, 0), (-1, -1), 'CENTER'), ('SPAN', (2, 1), (-2, 1)), ('SPAN', (0, 0), (-1, 0)), ])) # w, h = t.wrapOn(c, 0, 0) t.drawOn(c, MARGIN, 470) c.setFont(NORMAL, 10) c.drawString(MARGIN, 460, '* Day 1 is the simulation start date') c.drawString( MARGIN, 450, '** Half of the fires are smaller than and larger than the median size' ) # form = c.acroForm # c.setFont(NORMAL, 12) def addQuestion(q, y): global question c.drawString(MARGIN, y + 8, q) group = 'radio' + str(question) form.radio(name=group, tooltip='Field radio1', value='yes', selected=False, x=170, y=y, buttonStyle='circle', borderStyle='solid', shape='circle') form.radio(name=group, tooltip='Field radio1', value='no', selected=False, x=195, y=y, buttonStyle='circle', borderStyle='solid', shape='circle') form.textfield(name='reason' + str(question), tooltip='Explanation', x=225, y=y, borderStyle='inset', borderColor=colors.black, fillColor=colors.white, width=180, height=20, textColor=colors.black, forceBorder=True) question = question + 1 c.drawString(170, 425, 'Yes No') addQuestion('Start location accurate', 400) addQuestion('Start size correct', 380) addQuestion('Perimeter most recent', 360) addQuestion('Fuel map accurate', 340) addQuestion('Startup indices appropriate', 320) addQuestion('Spread matches weather', 300) addQuestion('Projection is reasonable', 280) c.drawString( MARGIN, 260, 'If no to any question, explain why this is still operationally useful:' ) form.textfield(name='notes', tooltip='Notes', x=MARGIN, y=235, borderStyle='inset', borderColor=colors.black, fillColor=colors.white, width=405 - MARGIN, height=20, textColor=colors.black, forceBorder=True) # c.setFont(BOLD, 20) c.drawString(MARGIN, 215, 'Reviewed by:') form.textfield(name='reviewer', tooltip='Reviewed by', x=145, y=213, borderStyle='inset', borderColor=colors.black, fillColor=colors.white, width=260, height=20, textColor=colors.black, forceBorder=True) # c.setFont(BOLD, 13) c.drawString(MARGIN, 195, 'Interpreting the burn probability maps:') c.setFont(NORMAL, 12) c.drawString( MARGIN, 180, 'Fire growth is simulated for thousands of individual weather and fire' ) c.drawString( MARGIN, 164, 'behaviour scenarios. The burn probability is the fraction of scenarios in' ) c.drawString( MARGIN, 148, 'which each cell burned. It is extremely unlikely that the whole coloured' ) c.drawString(MARGIN, 132, 'area burned in a single scenario.') # c.setFont(BOLD, 13) c.drawString(MARGIN, 116, 'Warning - Experimental Model') c.setFont(NORMAL, 12) c.drawString( MARGIN, 100, 'Any operational use should only be done with caution and awareness of' ) c.drawString( MARGIN, 84, 'the assumptions and simplifications. The model spreads over a virtual grid' ) c.drawString( MARGIN, 68, 'of 1 ha cells derived from Ontario\'s FBP Fuel Model. Assumes no') c.drawString( MARGIN, 52, 'suppression. Does not represent fine scale barriers (small creeks, etc.) or' ) c.drawString( MARGIN, 36, 'long-range spotting. This model is under continuous development, and can' ) c.drawString(MARGIN, 20, 'change at any time.') c.setFont(BOLD, 10) c.drawCentredString(PAGE_WIDTH / 2, 5, Settings.ACTIVE_OFFER) c.save() return cover
stylesTable = fontsize = 7 # Inicializa altura para empezar a escribir high = 650 # Se declaran las ventas ventas = [ {'id' : '1', 'name' : 'Tupper', 'price' : '$130', 'quantity' : '3'}, {'id' : '2', 'name' : 'Cuchara', 'price' : '$10', 'quantity' : '2'}, {'id' : '2', 'name' : 'Vaso', 'price' : '$40', 'quantity' : '4'}, ] # Se agrega la informacion de las ventas a la lista for venta in ventas: this_venta = [venta['id'], venta['name'], venta['price'], venta['quantity']] ticket.append(this_venta) high = high - 18 # Se dibuja el contorno de la tabla width, heigth = A4 table = Table(ticket, colWidths = [1.9 * cm, 9.5 * cm, 1.9 * cm, 1.9 * cm]) table.setStyle(TableStyle([ ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black), ('BOX', (0, 0), (-1, -1), 0.25, colors.black), ])) table.wrapOn(c, width, heigth) table.drawOn(c, 30, high) c.showPage() # Save PDF c.save()
def reporte_pdf(request): # Create the HttpResponse object with the appropriate PDF headers. response = HttpResponse(content_type='application/pdf') # Para descargar directo #response['Content-Disposition'] = 'attachment; filename=reporte.pdf' # Create the PDF object, using the response object as its "file." buffer = BytesIO() p = canvas.Canvas(buffer, A4) # Instanciar Cuenta num = request.GET['numero'] cuent = Cuenta.objects.get(numero = num) #Instanciar Lista de transacciones listTransaccion = Transaccion.objects.all().filter(cuenta = cuent).order_by('fecha') # HEADER p.setLineWidth(.3) p.setFont('Helvetica', 10) p.drawString(180, 800, "COOPERATIVA DE AHORRO Y CREDITO") p.setFont('Helvetica-Bold', 17) p.drawString(160, 780, "COOPERATIVA JONNATHAN") p.setFont('Helvetica', 15) p.drawString(180, 762, "CUENTA TIPO: " + cuent.tipoCuenta) p.setFont('Helvetica-Bold', 12) p.drawString(30, 730, "Oficina:") p.setFont('Helvetica', 12) p.drawString(95, 730, "Loja") p.setFont('Helvetica-Bold', 12) p.drawString(325, 730, "N. de Cuenta: ") p.setFont('Helvetica', 12) p.drawString(425, 730, cuent.numero) p.line(420, 727, 560, 727)#start X, height end y , height p.setFont('Helvetica-Bold', 12) p.drawString(30, 710, "Nombres:") p.setFont('Helvetica', 12) p.drawString(95, 710, cuent.cliente.apellidos + ' ' + cuent.cliente.nombres) p.setFont('Helvetica-Bold', 12) p.drawString(30, 690, "Domicilio:") p.setFont('Helvetica', 12) p.drawString(95, 690, cuent.cliente.direccion) p.setFont('Helvetica-Bold', 12) p.drawString(348, 690, "Telefono:") p.setFont('Helvetica', 12) p.drawString(425, 690, cuent.cliente.telefono) # Cliente table transacciones = [] transacciones.append({'fecha':cuent.fechaApertura, 'name':"Apertura", 'b1':cuent.saldoApertura, 'b2':cuent.saldoApertura}) for ltr in listTransaccion: transacciones.append({'fecha':ltr.fecha, 'name':ltr.tipo, 'b1':ltr.valor, 'b2':ltr.saldoFinal}) #transacciones = [{'fecha':'1','name':'Jonnathan', 'b1':'3.4', 'b2':'3.5'}] # Table header styles = getSampleStyleSheet() styleBH = styles["Normal"] styleBH.alignment = TA_CENTER styleBH.fontSize = 10 fecha = Paragraph('''Fecha''', styleBH) tipo = Paragraph('''Tipo Operacion''', styleBH) monto = Paragraph('''Monto''', styleBH) saldo = Paragraph('''Saldo''', styleBH) data = [] data.append([fecha, tipo, monto, saldo]) # Table body styleN = styles["BodyText"] styleN.alignment = TA_CENTER styleN.fontSize = 7 high = 640 for t in transacciones: this_t = [t['fecha'], t['name'], t['b1'], t['b2']] data.append(this_t) high = high - 18 # Table size table = Table(data, colWidths=[6 * cm, 6.4 * cm, 3 * cm, 3 * cm]) table.setStyle(TableStyle([# estilos de la tabla ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0,0), (-1,-1), 0.25, colors.black), ])) # pdf size width, height = A4 table.wrapOn(p, width, height) table.drawOn(p, 30, high) # Close the PDF object cleanly, and we're done. p.showPage()# save page p.save() # save pdf # get the value of BytesIO buffer and write response pdf = buffer.getvalue() buffer.close() response.write(pdf) return response
class TableOfContents(IndexingFlowable): """This creates a formatted table of contents. It presumes a correct block of data is passed in. The data block contains a list of (level, text, pageNumber) triplets. You can supply a paragraph style for each level (starting at zero). """ def __init__(self): self.entries = [] self.rightColumnWidth = 72 self.levelStyles = [ levelZeroParaStyle, levelOneParaStyle, levelTwoParaStyle, levelThreeParaStyle, levelFourParaStyle ] self.tableStyle = defaultTableStyle self._table = None self._entries = [] self._lastEntries = [] def beforeBuild(self): # keep track of the last run self._lastEntries = self._entries[:] self.clearEntries() def isIndexing(self): return 1 def isSatisfied(self): return (self._entries == self._lastEntries) def notify(self, kind, stuff): """The notification hook called to register all kinds of events. Here we are interested in 'TOCEntry' events only. """ if kind == 'TOCEntry': (level, text, pageNum) = stuff self.addEntry(level, text, pageNum) def clearEntries(self): self._entries = [] def addEntry(self, level, text, pageNum): """Adds one entry to the table of contents. This allows incremental buildup by a doctemplate. Requires that enough styles are defined.""" assert type(level) == type(1), "Level must be an integer" assert level < len(self.levelStyles), \ "Table of contents must have a style defined " \ "for paragraph level %d before you add an entry" % level self._entries.append((level, text, pageNum)) def addEntries(self, listOfEntries): """Bulk creation of entries in the table of contents. If you knew the titles but not the page numbers, you could supply them to get sensible output on the first run.""" for (level, text, pageNum) in listOfEntries: self.addEntry(level, text, pageNum) def wrap(self, availWidth, availHeight): "All table properties should be known by now." widths = (availWidth - self.rightColumnWidth, self.rightColumnWidth) # makes an internal table which does all the work. # we draw the LAST RUN's entries! If there are # none, we make some dummy data to keep the table # from complaining if len(self._lastEntries) == 0: _tempEntries = [(0, 'Placeholder for table of contents', 0)] else: _tempEntries = self._lastEntries tableData = [] for (level, text, pageNum) in _tempEntries: leftColStyle = self.levelStyles[level] #right col style is right aligned rightColStyle = ParagraphStyle(name='leftColLevel%d' % level, parent=leftColStyle, leftIndent=0, alignment=enums.TA_RIGHT) leftPara = Paragraph(text, leftColStyle) rightPara = Paragraph(str(pageNum), rightColStyle) tableData.append([leftPara, rightPara]) self._table = Table(tableData, colWidths=widths, style=self.tableStyle) self.width, self.height = self._table.wrapOn(self.canv, availWidth, availHeight) return (self.width, self.height) def split(self, availWidth, availHeight): """At this stage we do not care about splitting the entries, we will just return a list of platypus tables. Presumably the calling app has a pointer to the original TableOfContents object; Platypus just sees tables. """ return self._table.splitOn(self.canv, availWidth, availHeight) def drawOn(self, canvas, x, y, _sW=0): """Don't do this at home! The standard calls for implementing draw(); we are hooking this in order to delegate ALL the drawing work to the embedded table object. """ self._table.drawOn(canvas, x, y, _sW)
class TableOfContents(IndexingFlowable): """This creates a formatted table of contents. It presumes a correct block of data is passed in. The data block contains a list of (level, text, pageNumber) triplets. You can supply a paragraph style for each level (starting at zero). Set dotsMinLevel to determine from which level on a line of dots should be drawn between the text and the page number. If dotsMinLevel is set to a negative value, no dotted lines are drawn. """ def __init__(self): self.rightColumnWidth = 72 self.levelStyles = defaultLevelStyles self.tableStyle = defaultTableStyle self.dotsMinLevel = 1 self._table = None self._entries = [] self._lastEntries = [] def beforeBuild(self): # keep track of the last run self._lastEntries = self._entries[:] self.clearEntries() def isIndexing(self): return 1 def isSatisfied(self): return (self._entries == self._lastEntries) def notify(self, kind, stuff): """The notification hook called to register all kinds of events. Here we are interested in 'TOCEntry' events only. """ if kind == 'TOCEntry': self.addEntry(*stuff) def clearEntries(self): self._entries = [] def getLevelStyle(self, n): '''Returns the style for level n, generating and caching styles on demand if not present.''' try: return self.levelStyles[n] except IndexError: prevstyle = self.getLevelStyle(n-1) self.levelStyles.append(ParagraphStyle( name='%s-%d-indented' % (prevstyle.name, n), parent=prevstyle, firstLineIndent = prevstyle.firstLineIndent+delta, leftIndent = prevstyle.leftIndent+delta)) return self.levelStyles[n] def addEntry(self, level, text, pageNum, key=None): """Adds one entry to the table of contents. This allows incremental buildup by a doctemplate. Requires that enough styles are defined.""" assert type(level) == type(1), "Level must be an integer" self._entries.append((level, text, pageNum, key)) def addEntries(self, listOfEntries): """Bulk creation of entries in the table of contents. If you knew the titles but not the page numbers, you could supply them to get sensible output on the first run.""" for entryargs in listOfEntries: self.addEntry(*entryargs) def wrap(self, availWidth, availHeight): "All table properties should be known by now." # makes an internal table which does all the work. # we draw the LAST RUN's entries! If there are # none, we make some dummy data to keep the table # from complaining if len(self._lastEntries) == 0: _tempEntries = [(0,'Placeholder for table of contents',0,None)] else: _tempEntries = self._lastEntries def drawTOCEntryEnd(canvas, kind, label): '''Callback to draw dots and page numbers after each entry.''' label = label.split(',') page, level, key = int(label[0]), int(label[1]), eval(label[2],{}) style = self.getLevelStyle(level) if self.dotsMinLevel >= 0 and level >= self.dotsMinLevel: dot = ' . ' else: dot = '' drawPageNumbers(canvas, style, [(page, key)], availWidth, availHeight, dot) self.canv.drawTOCEntryEnd = drawTOCEntryEnd tableData = [] for (level, text, pageNum, key) in _tempEntries: style = self.getLevelStyle(level) if key: text = '<a href="#%s">%s</a>' % (key, text) keyVal = repr(key).replace(',','\\x2c').replace('"','\\x2c') else: keyVal = None para = Paragraph('%s<onDraw name="drawTOCEntryEnd" label="%d,%d,%s"/>' % (text, pageNum, level, keyVal), style) if style.spaceBefore: tableData.append([Spacer(1, style.spaceBefore),]) tableData.append([para,]) self._table = Table(tableData, colWidths=(availWidth,), style=self.tableStyle) self.width, self.height = self._table.wrapOn(self.canv,availWidth, availHeight) return (self.width, self.height) def split(self, availWidth, availHeight): """At this stage we do not care about splitting the entries, we will just return a list of platypus tables. Presumably the calling app has a pointer to the original TableOfContents object; Platypus just sees tables. """ return self._table.splitOn(self.canv,availWidth, availHeight) def drawOn(self, canvas, x, y, _sW=0): """Don't do this at home! The standard calls for implementing draw(); we are hooking this in order to delegate ALL the drawing work to the embedded table object. """ self._table.drawOn(canvas, x, y, _sW)
def account_to_pdf_export(request, account_id): label = 'Информация о счете:' item = get_account_data(account_id) import datetime buffer = io.BytesIO() p = canvas.Canvas(buffer) datetime_now = datetime.datetime.now() datetime_str = datetime.datetime.strftime(datetime_now, '%d.%m.%Y %H:%M:%S') pdfmetrics.registerFont(TTFont('Arial', 'Arial.ttf')) p.setFont('Arial', 16) p.drawString( 100, 770, 'Выписка по счету: "{}" на {}'.format(str(item['info'].name), datetime_str)) p.setFont('Arial', 12) p.drawString(100, 700, 'Валюта: {}'.format(str(item['info'].currency))) p.drawString( 100, 680, 'Дата создания счета: {}'.format( datetime.datetime.strftime(item['info'].datetime, '%H:%M:%S %d.%m.%Y'))) p.drawString(100, 660, 'Начальный баланс: {}'.format(str(item['info'].amount))) p.drawString(100, 640, 'Текущий баланс: {}'.format(str(item['total']))) p.drawString(100, 620, 'Таблица операций со счетом:') p.setFont('Arial', 8) data = [] data.append(('Категория:', 'Тип операции', 'Дата добавления:', 'Сумма:')) data.append(('создание счета', 'начальный баланс', '{}'.format( datetime.datetime.strftime(item['info'].datetime, '%d.%m.%Y %H:%M:%S')), str(item['info'].amount))) for data_item in item['data']: data.append(( data_item.category, 'зачисление' if data_item.prefix == 'income' else 'cписание', datetime.datetime.strftime(data_item.datetime, '%d.%m.%Y %H:%M:%S'), data_item.amount, )) data.append(('', '', 'Итого:', str(item['total']))) data_length = len(data) width = 300 height = 100 x = 100 y = 500 - data_length * 5 f = Table(data) f.setStyle( TableStyle([('FONTNAME', (0, 0), (-1, -1), 'Arial'), ('BOX', (0, 0), (-1, -1), .5, colors.black), ('GRID', (0, 0), (-1, 0), .5, colors.black), ('LINEBEFORE', (0, 0), (-1, -1), .5, colors.black), ('LINEAFTER', (-1, 0), (-1, -1), .5, colors.black), ('LINEBELOW', (0, 'splitlast'), (-1, 'splitlast'), .5, colors.black)])) f.wrapOn(p, width, height) f.drawOn(p, x, y) # <td> # {% if data_item.type_of %} # {% if data_item.type_of == '+' %} # <span style="color: green"> # {% else %} # <span style="color: red"> # {% endif %} # {{ data_item.type_of}}{{ data_item.amount}}</span> # {% else %} # {{ data_item.type_of}}{{ data_item.amount}} # {% endif %} p.showPage() p.save() buffer.seek(0) feliename = 'Отчет_на_{}.pdf'.format( datetime.datetime.strftime(datetime_now, '%d%m%Y_%H%M%S')) return FileResponse(buffer, as_attachment=True, filename=feliename)
def body(): # Body size_y = 0.62 data = [["Sold", "Cash", "Card", "Contingent", "Reserved", "Expected", "Unsold Reserv."]] for cat, value in report_result_dict.iteritems(): size_y = size_y + 1.86 """ if cat == 'all': report_cat_name = 'All' else: report_cat_name = self.report_cat_list[event_id][cat] """ if cat == "all": categorie_name = "All" else: categorie_name = cat_name[cat] p = Paragraph('<para alignment="center"><b>' + categorie_name + "</b></para>", styles["Normal"]) data.append([p, "", "", "", "", "", ""]) if cat == "all": data_for_pie = [ value["a_total_sold"], value["a_sold_cash"], value["a_sold_card"], value["a_sold_conti"], value["a_reserved"], value["a_not_visited"], ] data.append( [ value["a_total_sold"], value["a_sold_cash"], value["a_sold_card"], value["a_sold_conti"], value["a_reserved"], value["a_total_pre"], value["a_not_visited"], ] ) data.append( [ str(value["m_total_sold"]) + unichr(8364), str(value["m_sold_cash"]) + unichr(8364), str(value["m_sold_card"]) + unichr(8364), "-", str(value["m_reserved"]) + unichr(8364), str(value["m_total_pre"]) + unichr(8364), str(value["m_not_visited"]) + unichr(8364), ] ) tstyle = [ ("INNERGRID", (0, 0), (-1, -1), 0.25, colors.grey), ("BOX", (0, 0), (-1, -1), 0.25, colors.black), ("ALIGN", (0, 1), (-1, -1), "RIGHT"), ( "COLBACKGROUNDS", (0, 0), (-1, -1), [ colors.lightpink, colors.lightpink, colors.lightpink, colors.lightpink, colors.lightyellow, colors.lightgrey, colors.lightyellow, ], ), ("ROWBACKGROUNDS", (0, 1), (-1, -1), [colors.lightslategray, None, None]), ] t = Table(data) t.setStyle(TableStyle(tstyle)) t.wrapOn(c, 19 * cm, 0 * cm) pos_y = 26.5 - size_y t.drawOn(c, 1 * cm, pos_y * cm) # Price Details # size_y = 0.62 pdata = [] for cat, value in report_result_dict.iteritems(): size_y = size_y + 1.86 if cat == "all": pass else: categorie_name = cat_name[cat] p = Paragraph('<para alignment="center"><b>' + categorie_name + "</b></para>", styles["Normal"]) pdata.append([p]) data_price_titles = [] data_price_amount = [] data_price_total = [] for prow in p_result: if cat == "cat_" + str(prow["cat_id"]): data_price_titles.append(prow["name"]) try: data_price_amount.append(str(value["a_prices"][str(prow["id"])])) except KeyError: data_price_amount.append("0") try: data_price_total.append(str(value["m_prices"][str(prow["id"])]) + unichr(8364)) except KeyError: data_price_total.append("0" + unichr(8364)) print data_price_titles pdata.append(data_price_titles) pdata.append(data_price_amount) pdata.append(data_price_total) tstyle = [ ("INNERGRID", (0, 0), (-1, -1), 0.25, colors.grey), ("BOX", (0, 0), (-1, -1), 0.25, colors.black), ("ALIGN", (0, 1), (-1, -1), "RIGHT"), ("COLBACKGROUNDS", (0, 0), (-1, -1), [colors.lightgrey, colors.whitesmoke]), ("ROWBACKGROUNDS", (0, 0), (-1, -1), [colors.lightslategray, None, None, None]), ] t = Table(pdata) t.setStyle(TableStyle(tstyle)) t.wrapOn(c, 19 * cm, 0 * cm) pos_y = 25 - size_y t.drawOn(c, 1 * cm, pos_y * cm) """ #Pie Chart d = Drawing(500, 500) pc = Pie() pc.x = 65 pc.y = 15 pc.width = 200 pc.height = 200 pc.data = data_for_pie pc.labels = ['Sold','Cash','Card','Contingent','Reserved','Unsold Reserv.'] pc.slices.strokeWidth=0.5 pc.slices[0].popout = 10 #pc.slices[0].strokeWidth = 2 #pc.slices[0].strokeDashArray = [2,2] pc.slices[0].labelRadius = 1.3 pc.slices[0].fontColor = colors.red pc.slices[0].fillColor = colors.lightpink pc.slices[1].fillColor = colors.lightpink pc.slices[2].fillColor = colors.lightpink pc.slices[3].fillColor = colors.lightpink pc.slices[4].fillColor = colors.lightyellow pc.slices[5].fillColor = colors.lightyellow d.add(pc) d.wrapOn(c, 5*cm, 5*cm) d.drawOn(c, 1*cm, 1*cm) """ if event_date == "all": data = [] sold = [] reserved = [] unsold_reserved = [] sold_contingent = [] for key, value in sorted(report_date_dict.iteritems(), key=lambda report_date_dict: report_date_dict[0]): date_day_dt = dt.datetime.strptime(key, "%Y-%m-%d") date_day = date_day_dt.strftime("%Y%m%d") sold.append((int(date_day), value["sold"])) reserved.append((int(date_day), value["reserved"])) unsold_reserved.append((int(date_day), value["unsold_reserved"])) sold_contingent.append((int(date_day), value["sold_contingent"])) data.append(sold) data.append(reserved) data.append(unsold_reserved) data.append(sold_contingent) print data # sample data _colors = ( Color(0.90, 0, 0), Color(0.801961, 0.801961, 0), Color(0.380392, 0.380392, 0), Color(0.580392, 0, 0), ) _catNames = "Sold", "Reserved", "Unsold Reserved", "Contingents" d = Drawing(400, 200) # adding the actual chart here. plot = GridLinePlot() plot.y = 50 plot.x = 15 plot.width = 525 plot.height = 125 plot.xValueAxis.xLabelFormat = "{ddd} {dd}. {mm}." plot.lineLabels.fontSize = 6 plot.lineLabels.boxStrokeWidth = 0.5 plot.lineLabels.visible = 1 plot.lineLabels.boxAnchor = "c" plot.lineLabels.angle = 0 plot.lineLabelNudge = 10 plot.joinedLines = 1 plot.lines.strokeWidth = 1.5 plot.lines[0].strokeColor = _colors[0] plot.lines[1].strokeColor = _colors[1] plot.lines[2].strokeColor = _colors[2] plot.lines[3].strokeColor = _colors[3] # sample data plot.data = data """ plot.data = [[(20010630, 1000), (20011231, 101), (20020630, 100.05), (20021231, 102), (20030630, 103), (20031230, 104), (20040630, 99.200000000000003), (20041231, 99.099999999999994)], [(20010630, 100.8), (20011231, 100.90000000000001), (20020630, 100.2), (20021231, 100.09999999999999), (20030630, 100), (20031230, 100.05), (20040630, 99.900000000000006), (20041231, 99.799999999999997)], [(20010630, 99.700000000000003), (20011231, 99.799999999999997), (20020630, 100), (20021231, 100.01000000000001), (20030630, 95), (20031230, 90), (20040630, 85), (20041231, 80)]] """ # y axis plot.yValueAxis.tickRight = 0 plot.yValueAxis.maximumTicks = 10 # plot.yValueAxis.leftAxisPercent = 0 plot.yValueAxis.tickLeft = 5 plot.yValueAxis.valueMax = None plot.yValueAxis.valueMin = None plot.yValueAxis.rangeRound = "both" plot.yValueAxis.requiredRange = 30 plot.yValueAxis.valueSteps = None plot.yValueAxis.valueStep = None plot.yValueAxis.forceZero = 0 plot.yValueAxis.labels.fontSize = 7 plot.yValueAxis.labels.dy = 0 plot.yValueAxis.avoidBoundFrac = 0.1 # x axis plot.xValueAxis.labels.fontName = "Helvetica" plot.xValueAxis.labels.fontSize = 7 plot.xValueAxis.valueSteps = None plot.xValueAxis.dailyFreq = 0 plot.xValueAxis.gridStrokeWidth = 0.25 plot.xValueAxis.labels.angle = 90 plot.xValueAxis.maximumTicks = 20 plot.xValueAxis.tickDown = 3 plot.xValueAxis.dailyFreq = 0 plot.xValueAxis.bottomAxisLabelSlack = 0 plot.xValueAxis.minimumTickSpacing = 10 plot.xValueAxis.visibleGrid = 0 plot.xValueAxis.gridEnd = 0 plot.xValueAxis.gridStart = 0 plot.xValueAxis.labels.angle = 45 plot.xValueAxis.labels.boxAnchor = "e" plot.xValueAxis.labels.dx = 0 plot.xValueAxis.labels.dy = -5 # adding legend legend = LineLegend() legend.boxAnchor = "sw" legend.x = 20 legend.y = -2 legend.columnMaximum = 1 legend.yGap = 0 legend.deltax = 50 legend.deltay = 0 legend.dx = 10 legend.dy = 1.5 legend.fontSize = 7 legend.alignment = "right" legend.dxTextSpace = 5 legend.colorNamePairs = [(_colors[i], _catNames[i]) for i in xrange(len(plot.data))] d.add(plot) d.add(legend) d.wrapOn(c, 18 * cm, 5 * cm) d.drawOn(c, 1 * cm, 1 * cm) c.showPage()
class MyTableOfContents(TableOfContents): """ Subclass of reportlab.platypus.tableofcontents.TableOfContents which supports hyperlinks to corresponding sections. """ def __init__(self, *args, **kwargs): # The parent argument is to define the locality of # the TOC. If it's none, it's a global TOC and # any heading it's notified about is accepted. # If it's a node, then the heading needs to be "inside" # that node. This can be figured out because # the heading flowable keeps a reference to the title # node it was creatd from. # # Yes, this is gross. self.parent = kwargs.pop('parent') TableOfContents.__init__(self, *args, **kwargs) # reference ids for which this TOC should be notified self.refids = [] # revese lookup table from (level, text) to refid self.refid_lut = {} self.linkColor = "#0000ff" def notify(self, kind, stuff): # stuff includes (level, text, pagenum, label) level, text, pageNum, label, node = stuff rlabel = '-'.join(label.split('-')[:-1]) def islocal(_node): """See if this node is "local enough" for this TOC. This is for Issue 196""" if self.parent is None: return True while _node.parent: if _node.parent == self.parent: return True _node = _node.parent return False if rlabel in self.refids and islocal(node): self.addEntry(level, text, pageNum) self.refid_lut[(level, text, pageNum)] = label def wrap(self, availWidth, availHeight): """Adds hyperlink to toc entry.""" widths = (availWidth - self.rightColumnWidth, self.rightColumnWidth) # makes an internal table which does all the work. # we draw the LAST RUN's entries! If there are # none, we make some dummy data to keep the table # from complaining if len(self._lastEntries) == 0: _tempEntries = [(0, 'Placeholder for table of contents', 0, None)] else: _tempEntries = self._lastEntries if _tempEntries: base_level = _tempEntries[0][0] else: base_level = 0 tableData = [] for entry in _tempEntries: level, text, pageNum = entry[:3] left_col_level = level - base_level leftColStyle = self.getLevelStyle(left_col_level) label = self.refid_lut.get((level, text, pageNum), None) if label: pre = u'<a href="#%s" color="%s">' % (label, self.linkColor) post = u'</a>' if isinstance(text, bytes): text = text.decode('utf-8') text = pre + text + post else: pre = '' post = '' # right col style is right aligned rightColStyle = ParagraphStyle( name='leftColLevel%d' % left_col_level, parent=leftColStyle, leftIndent=0, alignment=TA_RIGHT, ) leftPara = Paragraph(text, leftColStyle) rightPara = Paragraph(pre + str(pageNum) + post, rightColStyle) tableData.append([leftPara, rightPara]) self._table = Table(tableData, colWidths=widths, style=self.tableStyle) self.width, self.height = self._table.wrapOn(self.canv, availWidth, availHeight) return self.width, self.height def split(self, aW, aH): # Make sure _table exists before splitting. # This was only triggered in rare cases using sphinx. if not self._table: self.wrap(aW, aH) return TableOfContents.split(self, aW, aH) def isSatisfied(self): if self._entries == self._lastEntries: log.debug('Table Of Contents is stable') return True else: if len(self._entries) != len(self._lastEntries): log.info('Number of items in TOC changed ' 'from %d to %d, not satisfied' % (len(self._lastEntries), len(self._entries))) return False log.info('TOC entries that moved in this pass:') for i in range(len(self._entries)): if self._entries[i] != self._lastEntries[i]: log.info(str(self._entries[i])) log.info(str(self._lastEntries[i])) return False
class SimpleIndex(IndexingFlowable): """This creates a very simple index. Entries have a string key, and appear with a page number on the right. Prototype for more sophisticated multi-level index.""" def __init__(self): #keep stuff in a dictionary while building self._entries = {} self._lastEntries = {} self._table = None self.textStyle = ParagraphStyle(name='index', fontName='Times-Roman', fontSize=12) def isIndexing(self): return 1 def isSatisfied(self): return (self._entries == self._lastEntries) def beforeBuild(self): # keep track of the last run self._lastEntries = self._entries.copy() self.clearEntries() def clearEntries(self): self._entries = {} def notify(self, kind, stuff): """The notification hook called to register all kinds of events. Here we are interested in 'IndexEntry' events only. """ if kind == 'IndexEntry': (text, pageNum) = stuff self.addEntry(text, pageNum) def addEntry(self, text, pageNum): """Allows incremental buildup""" if self._entries.has_key(text): self._entries[text].append(str(pageNum)) else: self._entries[text] = [pageNum] def split(self, availWidth, availHeight): """At this stage we do not care about splitting the entries, we will just return a list of platypus tables. Presumably the calling app has a pointer to the original TableOfContents object; Platypus just sees tables. """ return self._table.splitOn(self.canv,availWidth, availHeight) def wrap(self, availWidth, availHeight): "All table properties should be known by now." # makes an internal table which does all the work. # we draw the LAST RUN's entries! If there are # none, we make some dummy data to keep the table # from complaining if len(self._lastEntries) == 0: _tempEntries = [('Placeholder for index',[0,1,2])] else: _tempEntries = self._lastEntries.items() _tempEntries.sort() tableData = [] for (text, pageNumbers) in _tempEntries: #right col style is right aligned allText = text + ': ' + string.join(map(str, pageNumbers), ', ') para = Paragraph(allText, self.textStyle) tableData.append([para]) self._table = Table(tableData, colWidths=[availWidth]) self.width, self.height = self._table.wrapOn(self.canv,availWidth, availHeight) return (self.width, self.height) def drawOn(self, canvas, x, y, _sW=0): """Don't do this at home! The standard calls for implementing draw(); we are hooking this in order to delegate ALL the drawing work to the embedded table object. """ self._table.drawOn(canvas, x, y, _sW)
def pdf(group, list, show_header=True, show_footer=True): """PDF version of list""" content = StringIO() columns = list.column_set.all() accounts = list.accounts() margin = 0.5*cm font_name = 'Times-Roman' font_name_bold = 'Times-Bold' font_size = 12 font_size_small = 10 font_size_min = 8 head_height = 30 # pt foot_height = 15 # pt logo_height = 25 # pt font_size_name = font_size_small font_size_short_name = font_size_small font_size_balance = font_size_small if list.orientation == list.LANDSCAPE: height, width = A4 else: width, height = A4 # Create canvas for page and set fonts p = canvas.Canvas(content, (width, height)) show_logo = bool(group.logo and group.logo.storage.exists(group.logo.path)) if show_logo: # Find scaling ratio ratio = group.logo.width / group.logo.height # Load logo with correct scaling logo = Image( group.logo.path, width=logo_height*ratio, height=logo_height) def draw_header(): if not show_header: return if show_logo: logo.drawOn( p, width - margin - logo_height*ratio, height - margin - logo_height) # Setup rest of header p.setFont(font_name, font_size) p.drawString( margin, height - margin - font_size, u'%s: %s' % (group, list.name)) p.setFont(font_name, font_size_small) p.drawString( margin, height - margin - font_size - font_size + 2, u'%s: %s' % (_('Printed'), str(date.today()))) footer = [] if group.email: footer.append(group.email) if group.account_number: footer.append(group.get_account_number_display()) if list.comment.strip(): footer.append(list.comment.replace('\n', ' ').replace('\r', ' ')) def draw_footer(): if not show_footer: return p.drawString(margin, margin, u' - '.join(footer)) blacklisted_note = _(u'Blacklisted accounts are marked with: ') p.drawRightString(width - margin - 10, margin, blacklisted_note) p.setFillColor(BLACKLISTED_COLOR) p.rect(width - margin - 10, margin, 8, 8, fill=1, stroke=0) p.setFont(font_name, font_size) if not accounts: no_accounts_message = _(u"Sorry, this list is empty.") draw_header() p.drawString( margin, height - font_size - margin - head_height, no_accounts_message) draw_footer() p.save() return content elif not columns: no_columns_message = _( u"Sorry, this list isn't set up correctly, " u"please add some columns.") draw_header() p.drawString( margin, height - font_size - margin - head_height, no_columns_message) draw_footer() p.save() return content # Store col widths col_width = [] header = [_(u'Name')] if list.account_width: col_width.append(list.account_width) if list.short_name_width: col_width.append(list.short_name_width) if list.account_width and list.short_name_width: header.append('') if list.balance_width: header.append(_(u'Balance')) col_width.append(list.balance_width) if list.short_name_width > 0 and list.account_width > 0: GRID_STYLE.add('SPAN', (0, 0), (1, 0)) base_x = len(header) for c in columns: header.append(c.name) col_width.append(c.width) # Calculate relative col widths over to absolute points for i, w in enumerate(col_width): col_width[i] = float(w) / float( (list.listcolumn_width or 0) + list.balance_width + (list.account_width or 0) + (list.short_name_width or 0) ) * (width - 2 * margin) # Intialise table with header data = [header] for i, a in enumerate(accounts): color = ALTERNATE_COLORS[(i+1) % len(ALTERNATE_COLORS)] if list.double: i *= 2 extra_row_height = 1 else: extra_row_height = 0 i += 1 GRID_STYLE.add('BACKGROUND', (0, i), (-1, i+extra_row_height), color) row = [] if list.account_width: row.append(a.name) # Check if we need to reduce col font size while ( col_width[len(row)-1] < p.stringWidth(row[-1], font_name, font_size_name) + 12 and font_size_name > font_size_min): font_size_name -= 1 if list.short_name_width: short_name = a.short_name if not short_name and a.owner: short_name = a.owner.username row.append(short_name or a.name) # Check if we need to reduce col font size while ( col_width[len(row)-1] < p.stringWidth(row[-1], font_name, font_size_name) + 12 and font_size_short_name > font_size_min): font_size_short_name -= 1 if list.balance_width: row.append('%d' % a.normal_balance()) # XXX: currently warnings are only shown if balance is shown, this # if needs to be moved if you want to change that if a.needs_warning(): GRID_STYLE.add( 'FONTNAME', (0, i), (base_x - 1, i), font_name_bold) GRID_STYLE.add( 'TEXTCOLOR', (base_x - 1, i), (base_x - 1, i), WARN_TEXT_COLOR) # Check if we need to reduce col font size while ( col_width[len(row)-1] < p.stringWidth(str(row[-1]), font_name, font_size_balance) + 12 and font_size_balance > font_size_min): font_size_balance -= 1 if a.is_blocked(): if list.balance_width: GRID_STYLE.add( 'TEXTCOLOR', (base_x - 1, i), (base_x - 1, i), BLACKLISTED_TEXT_COLOR) GRID_STYLE.add( 'FONTNAME', (0, i), (base_x - 1, i), font_name_bold) GRID_STYLE.add( 'BACKGROUND', (base_x, i), (-1, i + extra_row_height), BLACKLISTED_COLOR) row.extend([''] * len(header[base_x:])) else: row.extend(header[base_x:]) data.append(row) if list.double: data.append([''] * len(row)) GRID_STYLE.add('SPAN', (0, i), (0, i + extra_row_height)) if list.balance_width: GRID_STYLE.add('SPAN', (1, i), (1, i + extra_row_height)) GRID_STYLE.add('FONTSIZE', (0, 0), (-1, -1), font_size_small) # Set font size for names GRID_STYLE.add('FONTSIZE', (0, 1), (0, -1), font_size_name) GRID_STYLE.add('ALIGN', (0, 0), (-1, -1), 'LEFT') GRID_STYLE.add('ALIGN', (base_x, 0), (-1, -1), 'RIGHT') GRID_STYLE.add('FONTNAME', (0, 0), (-1, 0), font_name_bold) # Set font size for balance if list.balance_width: GRID_STYLE.add( 'FONTSIZE', (base_x - 1, 1), (base_x - 1, -1), font_size_balance) GRID_STYLE.add('ALIGN', (base_x - 1, 1), (base_x - 1, -1), 'RIGHT') GRID_STYLE.add('TEXTCOLOR', (base_x, 1), (-1, -1), FAINT_COLOR) if list.double: GRID_STYLE.add('TOPPADDING', (base_x, 1), (-1, -1), 2) GRID_STYLE.add('BOTTOMPADDING', (base_x, 1), (-1, -1), 2) GRID_STYLE.add('VALIGN', (0, 1), (-1, -1), 'TOP') GRID_STYLE.add('GRID', (0, 0), (-1, -1), 0.25, BORDER_COLOR) # Create table t = Table(data, colWidths=col_width, style=GRID_STYLE, repeatRows=1) rest = None avail_w = width-2*margin avail_h = height - 2*margin - head_height - foot_height while t: # Figure out how big table will be t_width, t_height = t.wrapOn(p, avail_w, avail_h) if not rest and t_height > height - 2*margin - head_height: t, rest = t.split(avail_w, avail_h) continue # Draw on canvas draw_header() t.drawOn(p, margin, height - t_height - margin - head_height) draw_footer() if rest: # set t to the second table and reset rest t, rest = (rest, None) # Show new page p.showPage() else: # Leave loop break p.save() return content
def pdf(request, guid): import settings import reportlab.pdfgen.canvas from reportlab.lib import pagesizes, units, colors, utils from reportlab.platypus import Paragraph, Image from reportlab.platypus.tables import Table, TableStyle from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet from django.contrib.humanize.templatetags.humanize import intcomma company = fact.models.Slot.company() invoice = get_object_or_404(fact.models.Invoice, pk=guid) if not invoice.date_posted or not invoice.date_due: return redirect(reverse('fact.views.detailed', kwargs={'guid':guid})) response = HttpResponse(mimetype='application/pdf') response['Content-Disposition'] = 'attachment; filename=' + _('invoice') + '-' + invoice.id + '.pdf' p = reportlab.pdfgen.canvas.Canvas(response, pagesize=pagesizes.A4) width, height = pagesizes.A4 font = 'Helvetica' # Load options and payment text options = fact.models.Option.opt_list(request.LANGUAGE_CODE) for key, value in options.iteritems(): options['payment_text'] = options['payment_text'].replace('%' + key + '%', value) options['payment_text'] = options['payment_text'].replace('\n', '<br/>') # Right-hand stuff x = units.cm * 14; p.setFont(font + '-Bold', 18) p.drawString(x, height-(units.cm*4.5), _('Invoice %s') % invoice.id) p.setFont(font, 10) p.drawString(x, height-(units.cm*5.5), _('Invoice date: %s') % invoice.date_invoice.strftime('%d.%m.%Y')) p.drawString(x, height-(units.cm*6), _('Due date: %s') % invoice.date_due.strftime('%d.%m.%Y')) # Logo img = utils.ImageReader(settings.FACT_LOGO) iw, ih = img.getSize() aspect = ih / float(iw) img = Image(settings.FACT_LOGO, width=units.cm*4, height=units.cm*4*aspect) img.drawOn(p, x+(units.cm*1), height-(units.cm*2.25)) # Left-hand header stuff x = units.cm * 2; p.setFont(font + '-Oblique', 8) p.drawString(x, height-(units.cm*1.25), company['name']) address = company['address'].split("\n") base = 1.65 for a in address: p.drawString(x, height-(units.cm*base), a) base += 0.4 # Recipient name and address y = units.cm*4.5 base = 0.5 customer = invoice.customer p.setFont(font, 10) p.drawString(x, height-y, customer.addr_name); y += units.cm*base p.drawString(x, height-y, customer.addr_addr1); y += units.cm*base p.drawString(x, height-y, customer.addr_addr2); y += units.cm*base p.drawString(x, height-y, customer.addr_addr3); y += units.cm*base p.drawString(x, height-y, customer.addr_addr4); y += units.cm*base y += units.cm*2 # Main p.setFont(font + '-Bold', 14) p.drawString(x, height-y, _('Specification')) y += units.cm*1 p.setFont(font, 10) fmt = '{0:.2f}' # Get our invoice entries, headers, etc style = TableStyle() invoice_entries = [] headers = [_('Description'), _('Amount'), _('Type'), _('Unit price'), _('VAT'), _('Net')] style.add('FONT', (0,0), (-1,0), font + '-Bold') style.add('LINEBELOW', (0,0), (-1,0), 1, colors.black) for entry in invoice.entries: invoice_entries.append([ entry.description, intcomma(fmt.format(entry.quantity)), _(entry.action), intcomma(fmt.format(entry.unitprice)), intcomma(fmt.format(entry.tax_percent)) + '%', intcomma(fmt.format(entry.net)) ]) style.add('LINEBELOW', (0, len(invoice_entries)), (-1, len(invoice_entries)), 1, colors.black) sums = [] sums.append([_('Net'), '', '', '', '', intcomma(fmt.format(invoice.net))]) sums.append([_('VAT'), '', '', '', '', intcomma(fmt.format(invoice.tax))]) if invoice.payments.count() > 0: sums.append([_('Subtotal'), '', '', '', '', intcomma(fmt.format(invoice.gross))]) style.add('LINEBELOW', (0, len(invoice_entries)+3), (-1, len(invoice_entries)+3), 1, colors.black) for payment in invoice.payments.all(): sums.append([_('Paid %s') + payment.post_date.strftime('%d.%m.%Y'), '', '', '', '', intcomma(fmt.format(payment.amount))]) ln = len(invoice_entries) + len(sums) style.add('LINEBELOW', (0, ln), (-1, ln), 1, colors.black) else: style.add('LINEBELOW', (0, len(invoice_entries)+2), (-1, len(invoice_entries)+2), 1, colors.black) sums.append([_('Amount due'), '', '', '', '', intcomma(fmt.format(invoice.due))]) ln = len(invoice_entries) + len(sums) style.add('BACKGROUND', (0, ln), (-1, ln), colors.wheat) style.add('FONT', (0, ln), (-1, ln), font + '-Bold') style.add('LINEBELOW', (0, ln), (-1, ln), 2, colors.black) # Draw the table t = Table([headers] + invoice_entries + sums, ([units.cm*6.5, units.cm*1.75, units.cm*2, units.cm*2.5, units.cm*2, units.cm*2.25]) ) t.setStyle(style) w, h = t.wrapOn(p, units.cm*19, units.cm*8) y += h t.drawOn(p, x, height-y) # Bank account number stylesheet = getSampleStyleSheet() if invoice.notes: txt = invoice.notes + '<br/><br/>' else: txt = '' txt += options['payment_text'] pr = Paragraph(txt, stylesheet['BodyText']) w, h = pr.wrapOn(p, units.cm*17, units.cm*6) y += pr.height + (units.cm*1) pr.drawOn(p, x, height-y) # Footer stuff p.setFont(font + '-BoldOblique', 8) p.drawString(x, units.cm*2.8, company['name']) p.setFont(font + '-Oblique', 8) p.drawString(x, units.cm*2.4, address[0]) p.drawString(x, units.cm*2, address[1]) p.drawString(units.cm*8, units.cm*2.4, 'Web: ' + company['url']) p.drawString(units.cm*8, units.cm*2, 'E-post: ' + company['email']) p.drawString(units.cm*14, units.cm*2.4, 'Telefon: ' + company['phone']) p.drawString(units.cm*14, units.cm*2, 'Org.nr: ' + company['id']) # Close the PDF object cleanly, and we're done. p.showPage() p.save() return response
class PmlTableOfContents(TableOfContents): def wrap(self, availWidth, availHeight): "All table properties should be known by now." # makes an internal table which does all the work. # we draw the LAST RUN's entries! If there are # none, we make some dummy data to keep the table # from complaining if len(self._lastEntries) == 0: _tempEntries = [(0, 'Placeholder for table of contents', 0, None)] else: _tempEntries = self._lastEntries def drawTOCEntryEnd(canvas, kind, label): '''Callback to draw dots and page numbers after each entry.''' label = label.split(',') page, level, key = int(label[0]), int(label[1]), literal_eval( label[2]) if level == 2: return style = self.getLevelStyle(level) if level <= 1: dot = ' . ' else: dot = '' if self.formatter: page = self.formatter(page) drawPageNumbers(canvas, style, [(page, key)], availWidth, availHeight, dot) self.canv.drawTOCEntryEnd = drawTOCEntryEnd tableData = [] for (level, text, pageNum, key) in _tempEntries: style = self.getLevelStyle(level) if key: text = '<a href="#%s">%s</a>' % (key, text) keyVal = repr(key).replace(',', '\\x2c').replace('"', '\\x2c') else: keyVal = None para = TocParagraph( '%s<onDraw name="drawTOCEntryEnd" label="%d,%d,%s"/>' % (text, pageNum, level, keyVal), style, level=level) # import ipdb; ipdb.set_trace() if style.spaceBefore: tableData.append([ Spacer(1, style.spaceBefore), ]) tableData.append([ para, ]) self._table = Table(tableData, colWidths=(availWidth, ), style=self.tableStyle) self.width, self.height = self._table.wrapOn(self.canv, availWidth, availHeight) return (self.width, self.height)