ReportLabExample

ReportLab (PDF generation)

Hello World

Source code:

   1 #copyright ReportLab Inc. 2000
   2 #see license.txt for license details
   3 #history http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/reportlab/pdfgen/test/test_hello.py?cvsroot=reportlab
   4 #$Header: /cvsroot/reportlab/reportlab/test/test_hello.py,v 1.3 2002/07/24 19:56:38 andy_robinson Exp $
   5 __version__=''' $Id'''
   6 __doc__="""most basic test possible that makes a PDF.
   7 
   8 Useful if you want to test that a really minimal PDF is healthy,
   9 since the output is about the smallest thing we can make."""
  10 
  11 from reportlab.test import unittest
  12 from reportlab.test.utils import makeSuiteForClasses
  13 from reportlab.pdfgen.canvas import Canvas
  14 
  15 import sys
  16 
  17 class HelloTestCase(unittest.TestCase):
  18     "Simplest test that makes PDF"
  19 
  20     def test(self):
  21         c = Canvas('sys$output')
  22         c.setFont('Helvetica-Bold', 36)
  23         c.drawString(100,700, 'Hello World')
  24         print 'Content-Type: application/pdf\n'
  25         sys.stdout.flush()
  26         c.save()
  27         sys.stdout.flush()
  28 
  29 def makeSuite():
  30     return makeSuiteForClasses(HelloTestCase)
  31 
  32 
  33 #noruntests
  34 unittest.TextTestRunner().run(makeSuite())

Result:

pdfgen_hello.pdf

General demonstration

Source code:

   1 #copyright ReportLab Inc. 2000
   2 #see license.txt for license details
   3 #history http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/reportlab/pdfgen/test/testpdfgen.py?cvsroot=reportlab
   4 #$Header: /cvsroot/reportlab/reportlab/test/test_pdfgen_general.py,v 1.19 2003/09/08 16:09:51 rgbecker Exp $
   5 __version__=''' $Id: test_pdfgen_general.py,v 1.19 2003/09/08 16:09:51 rgbecker Exp $ '''
   6 __doc__='testscript for reportlab.pdfgen'
   7 #tests and documents new low-level canvas
   8 
   9 import string
  10 
  11 from reportlab.test import unittest
  12 from reportlab.test.utils import makeSuiteForClasses
  13 
  14 from reportlab.pdfgen import canvas   # gmcm 2000/10/13, pdfgen now a package
  15 from reportlab.lib.units import inch, cm
  16 from reportlab.lib import colors
  17 from reportlab.lib.utils import haveImages
  18 
  19 import sys
  20 
  21 #################################################################
  22 #
  23 #  first some drawing utilities
  24 #
  25 #
  26 ################################################################
  27 
  28 BASEFONT = ('Times-Roman', 10)
  29 def framePageForm(c):
  30     c.beginForm("frame")
  31     c.saveState()
  32     # forms can't do non-constant operations
  33     #canvas.setFont('Times-BoldItalic',20)
  34     #canvas.drawString(inch, 10.5 * inch, title)
  35 
  36     #c.setFont('Times-Roman',10)
  37     #c.drawCentredString(4.135 * inch, 0.75 * inch,
  38     #                        'Page %d' % c.getPageNumber())
  39 
  40     #draw a border
  41     c.setFillColor(colors.ReportLabBlue)
  42     c.rect(0.3*inch, inch, 0.5*inch, 10*inch, fill=1)
  43     from reportlab.lib import corp
  44     c.translate(0.8*inch, 9.6*inch)
  45     c.rotate(90)
  46     logo = corp.ReportLabLogo(width=1.3*inch, height=0.5*inch, powered_by=1)
  47     c.setFillColorRGB(1,1,1)
  48     c.setStrokeColorRGB(1,1,1)
  49     logo.draw(c)
  50     #c.setStrokeColorRGB(1,0,0)
  51     #c.setLineWidth(5)
  52     #c.line(0.8 * inch, inch, 0.8 * inch, 10.75 * inch)
  53     #reset carefully afterwards
  54     #canvas.setLineWidth(1)
  55     #canvas.setStrokeColorRGB(0,0,0)\
  56     c.restoreState()
  57     c.endForm()
  58 
  59 def framePage(canvas, title):
  60     global closeit
  61     titlelist.append(title)
  62     #canvas._inPage0()  # do we need this at all?  would be good to eliminate it
  63     canvas.saveState()
  64     canvas.setFont('Times-BoldItalic',20)
  65 
  66     canvas.drawString(inch, 10.5 * inch, title)
  67     canvas.bookmarkHorizontalAbsolute(title, 10.8*inch)
  68     #newsection(title)
  69     canvas.addOutlineEntry(title+" section", title, level=0, closed=closeit)
  70     closeit = not closeit # close every other one
  71     canvas.setFont('Times-Roman',10)
  72     canvas.drawCentredString(4.135 * inch, 0.75 * inch,
  73                             'Page %d' % canvas.getPageNumber())
  74     canvas.restoreState()
  75     canvas.doForm("frame")
  76 
  77 
  78 def makesubsection(canvas, title, horizontal):
  79     canvas.bookmarkHorizontalAbsolute(title, horizontal)
  80     #newsubsection(title)
  81     canvas.addOutlineEntry(title+" subsection", title, level=1)
  82 
  83 
  84 # outline helpers
  85 #outlinenametree = []
  86 #def newsection(name):
  87 #    outlinenametree.append(name)
  88 
  89 
  90 #def newsubsection(name):
  91 #    from types import TupleType
  92 #    thissection = outlinenametree[-1]
  93 #    if type(thissection) is not TupleType:
  94 #        subsectionlist = []
  95 #        thissection = outlinenametree[-1] = (thissection, subsectionlist)
  96 #    else:
  97 #        (sectionname, subsectionlist) = thissection
  98 #    subsectionlist.append(name)
  99 
 100 
 101 class DocBlock:
 102     """A DocBlock has a chunk of commentary and a chunk of code.
 103     It prints the code and commentary, then executes the code,
 104     which is presumed to draw in a region reserved for it.
 105     """
 106     def __init__(self):
 107         self.comment1 = "A doc block"
 108         self.code = "canvas.setTextOrigin(cm, cm)\ncanvas.textOut('Hello World')"
 109         self.comment2 = "That was a doc block"
 110         self.drawHeight = 0
 111 
 112     def _getHeight(self):
 113         "splits into lines"
 114         self.comment1lines = string.split(self.comment1, '\n')
 115         self.codelines = string.split(self.code, '\n')
 116         self.comment2lines = string.split(self.comment2, '\n')
 117         textheight = (len(self.comment1lines) +
 118                 len(self.code) +
 119                 len(self.comment2lines) +
 120                 18)
 121         return max(textheight, self.drawHeight)
 122 
 123     def draw(self, canvas, x, y):
 124         #specifies top left corner
 125         canvas.saveState()
 126         height = self._getHeight()
 127         canvas.rect(x, y-height, 6*inch, height)
 128         #first draw the text
 129         canvas.setTextOrigin(x + 3 * inch, y - 12)
 130         canvas.setFont('Times-Roman',10)
 131         canvas.textLines(self.comment1)
 132         drawCode(canvas, self.code)
 133         canvas.textLines(self.comment2)
 134 
 135         #now a box for the drawing, slightly within rect
 136         canvas.rect(x + 9, y - height + 9, 198, height - 18)
 137         #boundary:
 138         self.namespace = {'canvas':canvas,'cm': cm,'inch':inch}
 139         canvas.translate(x+9, y - height + 9)
 140         codeObj = compile(self.code, '<sample>','exec')
 141         exec codeObj in self.namespace
 142 
 143         canvas.restoreState()
 144 
 145 
 146 def drawAxes(canvas, label):
 147     """draws a couple of little rulers showing the coords -
 148     uses points as units so you get an imperial ruler
 149     one inch on each side"""
 150     #y axis
 151     canvas.line(0,0,0,72)
 152     for y in range(9):
 153         tenths = (y+1) * 7.2
 154         canvas.line(-6,tenths,0,tenths)
 155     canvas.line(-6, 66, 0, 72)  #arrow...
 156     canvas.line(6, 66, 0, 72)  #arrow...
 157 
 158     canvas.line(0,0,72,0)
 159     for x in range(9):
 160         tenths = (x+1) * 7.2
 161         canvas.line(tenths,-6,tenths, 0)
 162     canvas.line(66, -6, 72, 0)  #arrow...
 163     canvas.line(66, +6, 72, 0)  #arrow...
 164 
 165     canvas.drawString(18, 30, label)
 166 
 167 
 168 def drawCrossHairs(canvas, x, y):
 169     """just a marker for checking text metrics - blue for fun"""
 170 
 171     canvas.saveState()
 172     canvas.setStrokeColorRGB(0,1,0)
 173     canvas.line(x-6,y,x+6,y)
 174     canvas.line(x,y-6,x,y+6)
 175     canvas.restoreState()
 176 
 177 
 178 def drawCode(canvas, code):
 179     """Draws a block of text at current point, indented and in Courier"""
 180     canvas.addLiteral('36 0 Td')
 181     canvas.setFillColor(colors.blue)
 182     canvas.setFont('Courier',10)
 183 
 184     t = canvas.beginText()
 185     t.textLines(code)
 186     c.drawText(t)
 187 
 188     canvas.setFillColor(colors.black)
 189     canvas.addLiteral('-36 0 Td')
 190     canvas.setFont('Times-Roman',10)
 191 
 192 
 193 def makeDocument(filename, pageCallBack=None):
 194     #the extra arg is a hack added later, so other
 195     #tests can get hold of the canvas just before it is
 196     #saved
 197     global titlelist, closeit
 198     titlelist = []
 199     closeit = 0
 200 
 201     c = canvas.Canvas(filename)
 202     c.setPageCompression(0)
 203     c.setPageCallBack(pageCallBack)
 204     framePageForm(c) # define the frame form
 205     c.showOutline()
 206 
 207     framePage(c, 'PDFgen graphics API test script')
 208     makesubsection(c, "PDFgen", 10*inch)
 209 
 210     t = c.beginText(inch, 10*inch)
 211     t.setFont('Times-Roman', 10)
 212     drawCrossHairs(c, t.getX(),t.getY())
 213     t.textLines("""
 214 The ReportLab library permits you to create PDF documents directly from
 215 your Python code. The "pdfgen" subpackage is the lowest level exposed
 216 to the user and lets you directly position test and graphics on the
 217 page, with access to almost the full range of PDF features.
 218   The API is intended to closely mirror the PDF / Postscript imaging
 219 model.  There is an almost one to one correspondence between commands
 220 and PDF operators.  However, where PDF provides several ways to do a job,
 221 we have generally only picked one.
 222   The test script attempts to use all of the methods exposed by the Canvas
 223 class, defined in reportlab/pdfgen/canvas.py
 224   First, let's look at text output.  There are some basic commands
 225 to draw strings:
 226 -    canvas.setFont(fontname, fontsize [, leading])
 227 -    canvas.drawString(x, y, text)
 228 -    canvas.drawRightString(x, y, text)
 229 -    canvas.drawCentredString(x, y, text)
 230 
 231 The coordinates are in points starting at the bottom left corner of the
 232 page.  When setting a font, the leading (i.e. inter-line spacing)
 233 defaults to 1.2 * fontsize if the fontsize is not provided.
 234 
 235 For more sophisticated operations, you can create a Text Object, defined
 236 in reportlab/pdfgen/testobject.py.  Text objects produce tighter PDF, run
 237 faster and have many methods for precise control of spacing and position.
 238 Basic usage goes as follows:
 239 -   tx = canvas.beginText(x, y)
 240 -   tx.textOut('Hello')    # this moves the cursor to the right
 241 -   tx.textLine('Hello again') # prints a line and moves down
 242 -   y = tx.getY()       # getX, getY and getCursor track position
 243 -   canvas.drawText(tx)  # all gets drawn at the end
 244 
 245 The green crosshairs below test whether the text cursor is working
 246 properly.  They should appear at the bottom left of each relevant
 247 substring.
 248 """)
 249 
 250     t.setFillColorRGB(1,0,0)
 251     t.setTextOrigin(inch, 4*inch)
 252     drawCrossHairs(c, t.getX(),t.getY())
 253     t.textOut('textOut moves across:')
 254     drawCrossHairs(c, t.getX(),t.getY())
 255     t.textOut('textOut moves across:')
 256     drawCrossHairs(c, t.getX(),t.getY())
 257     t.textOut('textOut moves across:')
 258     drawCrossHairs(c, t.getX(),t.getY())
 259     t.textLine('')
 260     drawCrossHairs(c, t.getX(),t.getY())
 261     t.textLine('textLine moves down')
 262     drawCrossHairs(c, t.getX(),t.getY())
 263     t.textLine('textLine moves down')
 264     drawCrossHairs(c, t.getX(),t.getY())
 265     t.textLine('textLine moves down')
 266     drawCrossHairs(c, t.getX(),t.getY())
 267 
 268     t.setTextOrigin(4*inch,3.25*inch)
 269     drawCrossHairs(c, t.getX(),t.getY())
 270     t.textLines('This is a multi-line\nstring with embedded newlines\ndrawn with textLines().\n')
 271     drawCrossHairs(c, t.getX(),t.getY())
 272     t.textLines(['This is a list of strings',
 273                 'drawn with textLines().'])
 274     c.drawText(t)
 275 
 276     t = c.beginText(2*inch,2*inch)
 277     t.setFont('Times-Roman',10)
 278     drawCrossHairs(c, t.getX(),t.getY())
 279     t.textOut('Small text.')
 280     drawCrossHairs(c, t.getX(),t.getY())
 281     t.setFont('Courier',14)
 282     t.textOut('Bigger fixed width text.')
 283     drawCrossHairs(c, t.getX(),t.getY())
 284     t.setFont('Times-Roman',10)
 285     t.textOut('Small text again.')
 286     drawCrossHairs(c, t.getX(),t.getY())
 287     c.drawText(t)
 288 
 289     #mark the cursor where it stopped
 290     c.showPage()
 291 
 292 
 293     ##############################################################
 294     #
 295     # page 2 - line styles
 296     #
 297     ###############################################################
 298 
 299     #page 2 - lines and styles
 300     framePage(c, 'Line Drawing Styles')
 301 
 302 
 303 
 304     # three line ends, lines drawn the hard way
 305     #firt make some vertical end markers
 306     c.setDash(4,4)
 307     c.setLineWidth(0)
 308     c.line(inch,9.2*inch,inch, 7.8*inch)
 309     c.line(3*inch,9.2*inch,3*inch, 7.8*inch)
 310     c.setDash() #clears it
 311 
 312     c.setLineWidth(5)
 313     c.setLineCap(0)
 314     p = c.beginPath()
 315     p.moveTo(inch, 9*inch)
 316     p.lineTo(3*inch, 9*inch)
 317     c.drawPath(p)
 318     c.drawString(4*inch, 9*inch, 'the default - butt caps project half a width')
 319     makesubsection(c, "caps and joins", 8.5*inch)
 320 
 321     c.setLineCap(1)
 322     p = c.beginPath()
 323     p.moveTo(inch, 8.5*inch)
 324     p.lineTo(3*inch, 8.5*inch)
 325     c.drawPath(p)
 326     c.drawString(4*inch, 8.5*inch, 'round caps')
 327 
 328     c.setLineCap(2)
 329     p = c.beginPath()
 330     p.moveTo(inch, 8*inch)
 331     p.lineTo(3*inch, 8*inch)
 332     c.drawPath(p)
 333     c.drawString(4*inch, 8*inch, 'square caps')
 334 
 335     c.setLineCap(0)
 336 
 337     # three line joins
 338     c.setLineJoin(0)
 339     p = c.beginPath()
 340     p.moveTo(inch, 7*inch)
 341     p.lineTo(2*inch, 7*inch)
 342     p.lineTo(inch, 6.7*inch)
 343     c.drawPath(p)