febrero 17, 2014

ReportLab: Platypus - Canvas como Flowable, ejemplo resumen (13)

En la entrada anterior, vimos como trabajan los niveles de platypus, sin embargo no se vio el paso directo entre el nivel 1 (canvas) y el nivel 2 (flowables), ya que los dibujos creados en el nivel 1 fueron del tipo No-Flowables, usados como pie de página y encabezado.

En este ejemplo veremos el uso de la clase Flowable, en la que heredaremos sus atributos y crear nosotros nuestros propios dibujos con canvas:


 



#-*- coding:utf-8 -*-
import os

#Librerias reportlab a usar:
from reportlab.platypus import (BaseDocTemplate, PageTemplate, 
NextPageTemplate, PageBreak, Frame, FrameBreak, Flowable, Paragraph, 
Image, Spacer)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY
from reportlab.lib.pagesizes import A4, landscape
from reportlab.lib.units import inch

#CREAMOS EL DOCTEMPLATE
#======================
doc = BaseDocTemplate('test.pdf', pagesize=A4) #landscape(A4) para Horizontal

#CREAMOS LOS CANVAS
#==================
def encabezado(canvas,doc):
    canvas.saveState()
    canvas.setFont('Times-Roman', 9)
    canvas.drawString(inch, A4[1] - 50, "Ejemplo de DocTemplate y PageTemplate")
    canvas.line(inch, A4[1] - 60, A4[0] - 65, A4[1] - 60)
    canvas.restoreState()
    
def piePagina(canvas,doc):
    canvas.saveState()
    canvas.setFont('Times-Roman',9)
    canvas.drawString(inch, 0.75 * inch, "Página %d" % doc.page)
    canvas.restoreState()
    
#Creamos nuestro flowable. Se tiene que tener al menos un método wrap y draw    
class Rectangulo(Flowable):
    def __init__(self, ancho=206, alto=100):
        self.ancho = ancho
        self.alto = alto
    
    def wrap(self, *args):
        """Provee el tamaño del área de dibujo"""
        return (self.ancho, self.alto)

    def draw(self):
        canvas = self.canv  # El atributo que permite dibujar en canvas
        canvas.saveState()
        canvas.setLineWidth(1)
        canvas.rect(0, 0, self.ancho, self.alto, fill=0)
        canvas.restoreState()

#Modifiquemos un flowable existente
class RotarImagen(Image):
    def wrap(self, availWidth, availHeight):
        self.w, self.h = Image.wrap(self, availWidth, availHeight)
        return self.w, self.h

    def draw(self):
        self.canv.translate(0,self.h)
        self.canv.rotate(-90)
        Image.draw(self)

#CREAMOS LOS FRAMES
#==================
#Frame (x1, y1, ancho, alto, leftPadding=6, bottomPadding=6, rightPadding=6,
#topPadding=6, id=None, showBoundary=0)

frame0 = Frame(doc.leftMargin, doc.bottomMargin, 
                doc.width, doc.height, showBoundary=1, id='normalBorde')
frame1 = Frame(doc.leftMargin, doc.bottomMargin, 
                doc.width, doc.height / 2, id='capitulo')
frame2 = Frame(doc.leftMargin, doc.bottomMargin, 
                doc.width /2 - 6, doc.height, id='col1')
frame3 = Frame(doc.leftMargin + doc.width / 2 + 6, doc.bottomMargin, 
                doc.width / 2 - 6, doc.height, id='col2')

#CREAMOS LOS PAGETEMPLATE
#========================
#PageTemplate(id=None,frames=[],onPage=_doNothing,onPageEnd=_doNothing)

doc.addPageTemplates([
    PageTemplate(id='caratula', frames=frame0),
    PageTemplate(id='capitulos', frames=frame1),
    PageTemplate(id='contenido', frames=[frame2, frame3], 
                 onPage = encabezado, onPageEnd=piePagina),
                    ])

#CREAMOS LOS FLOWABLES
#=====================
#Creamos la hoja de Estilo
estilo=getSampleStyleSheet()
estilo.add(ParagraphStyle(name = "Titulo",  alignment=TA_CENTER, fontSize=20,
           fontName="Helvetica-BoldOblique"))
           
#Iniciamos el platypus story
story=[]

#Creamos la carátula:
story.append(Spacer(0,200))
story.append(Image("Tux2.png", width=150, height=200))
story.append(Spacer(0,20))
titulo = Paragraph("Ejemplo PageTemplate-DocTemplate", estilo['Titulo'])
story.append(titulo)

#Creamos el contenido en general
story.append(NextPageTemplate('capitulos'))
story.append(PageBreak())
story.append(Paragraph("Capítulo I: Conociendo ReportLab", estilo['Heading1']))
  
story.append(NextPageTemplate('contenido'))
story.append(PageBreak())
story.append(Paragraph("Contenido del Capítulo I. " * 300, estilo['Normal']))
                
story.append(NextPageTemplate('capitulos'))
story.append(PageBreak())
story.append(Paragraph("Capítulo II: Sobre Platypus", estilo['Heading1']))

story.append(NextPageTemplate('contenido'))
story.append(PageBreak())
story.append(Paragraph("Contenido de la columna I ", estilo['Title']))
story.append(Paragraph("Lorem ipsum "*140, estilo['BodyText']))
story.append(FrameBreak()) #Se mueve al siguiente frame del pagetemplate
story.append(Paragraph("Contenido de la columna II", estilo['Title']))
story.append(Paragraph("Domine Sanctus "*50, estilo['BodyText']))
story.append(Paragraph("Veamos un rectángulo:", estilo['BodyText']))
story.append(Rectangulo())
story.append(Paragraph("Veamos un cuadrado:", estilo['BodyText']))
story.append(Rectangulo(50, 50))

I = RotarImagen("tuxito.png")
I.hAlign = "CENTER"
story.append(I)
                      
#CONSTRUIMOS EL PDF
#==================
doc.build(story)

os.system("test.pdf")

3 comentarios:

  1. cual es el formato para que la hoja del pdf sea horizontal??
    # -*- coding:utf-8 -*-
    from reportlab.pdfgen import canvas
    from reportlab.lib.pagesizes import A4,B4, cm
    from reportlab.lib.styles import getSampleStyleSheet
    from reportlab.platypus import Paragraph, Table, TableStyle
    from reportlab.lib.enums import TA_JUSTIFY, TA_LEFT, TA_CENTER
    from reportlab.lib import colors

    #creando tabla

    width, height = B4
    styles = getSampleStyleSheet()
    styleN = styles["BodyText"]
    styleN.alignment = TA_LEFT
    styleBH = styles["Normal"]
    styleBH.alignment = TA_CENTER

    def coord(x, y, unit=1):
    x, y = x * unit, height - y * unit
    return x, y

    # Headers
    hdescrpcion = Paragraph('''descrpcion''', styleBH)
    hpartida = Paragraph('''partida''', styleBH)
    hcandidad = Paragraph('''candidad''', styleBH)
    hprecio_unitario = Paragraph('''precio_unitario''', styleBH)
    hprecio_total = Paragraph('''precio_total''', styleBH)

    # Texts
    descrpcion = Paragraph('long paragraph', styleN)
    partida = Paragraph('1', styleN)
    candidad = Paragraph('120', styleN)
    precio_unitario = Paragraph('$52.00', styleN)
    precio_total = Paragraph('$6240.00', styleN)

    data= [[hdescrpcion, hcandidad,hcandidad, hprecio_unitario, hprecio_total],
    [partida, candidad, descrpcion, precio_unitario, precio_total]]

    table = Table(data, colWidths=[2.05 * cm, 2.7 * cm, 5 * cm,
    3* cm, 3 * 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, height)
    table.drawOn(c, *coord(1.8, 9.6, cm))
    c.save()

    ResponderEliminar
  2. como puedo colocar la pagina de mi pdf en horizontal??

    # -*- coding:utf-8 -*-
    from reportlab.pdfgen import canvas
    from reportlab.lib.pagesizes import A4,B4, cm
    from reportlab.lib.styles import getSampleStyleSheet
    from reportlab.platypus import Paragraph, Table, TableStyle
    from reportlab.lib.enums import TA_JUSTIFY, TA_LEFT, TA_CENTER
    from reportlab.lib import colors

    #creando tabla

    width, height = B4
    styles = getSampleStyleSheet()
    styleN = styles["BodyText"]
    styleN.alignment = TA_LEFT
    styleBH = styles["Normal"]
    styleBH.alignment = TA_CENTER

    def coord(x, y, unit=1):
    x, y = x * unit, height - y * unit
    return x, y

    # Headers
    hdescrpcion = Paragraph('''descrpcion''', styleBH)
    hpartida = Paragraph('''partida''', styleBH)
    hcandidad = Paragraph('''candidad''', styleBH)
    hprecio_unitario = Paragraph('''precio_unitario''', styleBH)
    hprecio_total = Paragraph('''precio_total''', styleBH)

    # Texts
    descrpcion = Paragraph('long paragraph', styleN)
    partida = Paragraph('1', styleN)
    candidad = Paragraph('120', styleN)
    precio_unitario = Paragraph('$52.00', styleN)
    precio_total = Paragraph('$6240.00', styleN)

    data= [[hdescrpcion, hcandidad,hcandidad, hprecio_unitario, hprecio_total],
    [partida, candidad, descrpcion, precio_unitario, precio_total]]

    table = Table(data, colWidths=[2.05 * cm, 2.7 * cm, 5 * cm,
    3* cm, 3 * 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, height)
    table.drawOn(c, *coord(1.8, 9.6, cm))
    c.save()

    ResponderEliminar
  3. Exte ejemplo es claro y efectivo, de como mezclar canvas con doc... recomendado

    ResponderEliminar