Locked History Attachments

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)
 344     c.drawString(4*inch, 6.8*inch, 'Default - mitered join')
 345 
 346     c.setLineJoin(1)
 347     p = c.beginPath()
 348     p.moveTo(inch, 6.5*inch)
 349     p.lineTo(2*inch, 6.5*inch)
 350     p.lineTo(inch, 6.2*inch)
 351     c.drawPath(p)
 352     c.drawString(4*inch, 6.3*inch, 'round join')
 353 
 354     c.setLineJoin(2)
 355     p = c.beginPath()
 356     p.moveTo(inch, 6*inch)
 357     p.lineTo(2*inch, 6*inch)
 358     p.lineTo(inch, 5.7*inch)
 359     c.drawPath(p)
 360     c.drawString(4*inch, 5.8*inch, 'bevel join')
 361 
 362     c.setDash(6,6)
 363     p = c.beginPath()
 364     p.moveTo(inch, 5*inch)
 365     p.lineTo(3*inch, 5*inch)
 366     c.drawPath(p)
 367     c.drawString(4*inch, 5*inch, 'dash 6 points on, 6 off- setDash(6,6) setLineCap(0)')
 368     makesubsection(c, "dash patterns", 5*inch)
 369 
 370     c.setLineCap(1)
 371     p = c.beginPath()
 372     p.moveTo(inch, 4.5*inch)
 373     p.lineTo(3*inch, 4.5*inch)
 374     c.drawPath(p)
 375     c.drawString(4*inch, 4.5*inch, 'dash 6 points on, 6 off- setDash(6,6) setLineCap(1)')
 376 
 377     c.setLineCap(0)
 378     c.setDash([1,2,3,4,5,6],0)
 379     p = c.beginPath()
 380     p.moveTo(inch, 4.0*inch)
 381     p.lineTo(3*inch, 4.0*inch)
 382     c.drawPath(p)
 383     c.drawString(4*inch, 4*inch, 'dash growing - setDash([1,2,3,4,5,6],0) setLineCap(0)')
 384 
 385     c.setLineCap(1)
 386     c.setLineJoin(1)
 387     c.setDash(32,12)
 388     p = c.beginPath()
 389     p.moveTo(inch, 3.0*inch)
 390     p.lineTo(2.5*inch, 3.0*inch)
 391     p.lineTo(inch, 2*inch)
 392     c.drawPath(p)
 393     c.drawString(4*inch, 3*inch, 'dash pattern, join and cap style interacting - ')
 394     c.drawString(4*inch, 3*inch - 12, 'round join & miter results in sausages')
 395 
 396     c.showPage()
 397 
 398 
 399 ##############################################################
 400 #
 401 # higher level shapes
 402 #
 403 ###############################################################
 404     framePage(c, 'Shape Drawing Routines')
 405 
 406     t = c.beginText(inch, 10*inch)
 407     t.textLines("""
 408 Rather than making your own paths, you have access to a range of shape routines.
 409 These are built in pdfgen out of lines and bezier curves, but use the most compact
 410 set of operators possible.  We can add any new ones that are of general use at no
 411 cost to performance.""")
 412     t.textLine()
 413 
 414     #line demo
 415     makesubsection(c, "lines", 10*inch)
 416     c.line(inch, 8*inch, 3*inch, 8*inch)
 417     t.setTextOrigin(4*inch, 8*inch)
 418     t.textLine('canvas.line(x1, y1, x2, y2)')
 419 
 420     #bezier demo - show control points
 421     makesubsection(c, "bezier curves", 7.5*inch)
 422     (x1, y1, x2, y2, x3, y3, x4, y4) = (
 423                         inch, 6.5*inch,
 424                         1.2*inch, 7.5 * inch,
 425                         3*inch, 7.5 * inch,
 426                         3.5*inch, 6.75 * inch
 427                         )
 428     c.bezier(x1, y1, x2, y2, x3, y3, x4, y4)
 429     c.setDash(3,3)
 430     c.line(x1,y1,x2,y2)
 431     c.line(x3,y3,x4,y4)
 432     c.setDash()
 433     t.setTextOrigin(4*inch, 7 * inch)
 434     t.textLine('canvas.bezier(x1, y1, x2, y2, x3, y3, x4, y4)')
 435 
 436     #rectangle
 437     makesubsection(c, "rectangles", 7*inch)
 438     c.rect(inch, 5.25 * inch, 2 * inch, 0.75 * inch)
 439     t.setTextOrigin(4*inch, 5.5 * inch)
 440     t.textLine('canvas.rect(x, y, width, height) - x,y is lower left')
 441 
 442     #wedge
 443     makesubsection(c, "wedges", 5*inch)
 444     c.wedge(inch, 5*inch, 3*inch, 4*inch, 0, 315)
 445     t.setTextOrigin(4*inch, 4.5 * inch)
 446     t.textLine('canvas.wedge(x1, y1, x2, y2, startDeg, extentDeg)')
 447     t.textLine('Note that this is an elliptical arc, not just circular!')
 448 
 449     #wedge the other way
 450     c.wedge(inch, 4*inch, 3*inch, 3*inch, 0, -45)
 451     t.setTextOrigin(4*inch, 3.5 * inch)
 452     t.textLine('Use a negative extent to go clockwise')
 453 
 454     #circle
 455     makesubsection(c, "circles", 3.5*inch)
 456     c.circle(1.5*inch, 2*inch, 0.5 * inch)
 457     c.circle(3*inch, 2*inch, 0.5 * inch)
 458     t.setTextOrigin(4*inch, 2 * inch)
 459     t.textLine('canvas.circle(x, y, radius)')
 460     c.drawText(t)
 461 
 462     c.showPage()
 463 
 464 ##############################################################
 465 #
 466 # Page 4 - fonts
 467 #
 468 ###############################################################
 469     framePage(c, "Font Control")
 470 
 471     c.drawString(inch, 10*inch, 'Listing available fonts...')
 472 
 473     y = 9.5*inch
 474     for fontname in c.getAvailableFonts():
 475         c.setFont(fontname,24)
 476         c.drawString(inch, y, 'This should be %s' % fontname)
 477         y = y - 28
 478     makesubsection(c, "fonts and colors", 4*inch)
 479 
 480     c.setFont('Times-Roman', 12)
 481     t = c.beginText(inch, 4*inch)
 482     t.textLines("""Now we'll look at the color functions and how they interact
 483     with the text.  In theory, a word is just a shape; so setFillColorRGB()
 484     determines most of what you see.  If you specify other text rendering
 485     modes, an outline color could be defined by setStrokeColorRGB() too""")
 486     c.drawText(t)
 487 
 488     t = c.beginText(inch, 2.75 * inch)
 489     t.setFont('Times-Bold',36)
 490     t.setFillColor(colors.green)  #green
 491     t.textLine('Green fill, no stroke')
 492 
 493     #t.setStrokeColorRGB(1,0,0)  #ou can do this in a text object, or the canvas.
 494     t.setStrokeColor(colors.red)  #ou can do this in a text object, or the canvas.
 495     t.setTextRenderMode(2)   # fill and stroke
 496     t.textLine('Green fill, red stroke - yuk!')
 497 
 498     t.setTextRenderMode(0)   # back to default - fill only
 499     t.setFillColorRGB(0,0,0)   #back to default
 500     t.setStrokeColorRGB(0,0,0) #ditto
 501     c.drawText(t)
 502     c.showPage()
 503 
 504 #########################################################################
 505 #
 506 #  Page 5 - coord transforms
 507 #
 508 #########################################################################
 509     framePage(c, "Coordinate Transforms")
 510     c.setFont('Times-Roman', 12)
 511     t = c.beginText(inch, 10 * inch)
 512     t.textLines("""This shows coordinate transformations.  We draw a set of axes,
 513     moving down the page and transforming space before each one.
 514     You can use saveState() and restoreState() to unroll transformations.
 515     Note that functions which track the text cursor give the cursor position
 516     in the current coordinate system; so if you set up a 6 inch high frame
 517     2 inches down the page to draw text in, and move the origin to its top
 518     left, you should stop writing text after six inches and not eight.""")
 519     c.drawText(t)
 520 
 521     drawAxes(c, "0.  at origin")
 522     c.addLiteral('%about to translate space')
 523     c.translate(2*inch, 7 * inch)
 524     drawAxes(c, '1. translate near top of page')
 525 
 526     c.saveState()
 527     c.translate(1*inch, -2 * inch)
 528     drawAxes(c, '2. down 2 inches, across 1')
 529     c.restoreState()
 530 
 531     c.saveState()
 532     c.translate(0, -3 * inch)
 533     c.scale(2, -1)
 534     drawAxes(c, '3. down 3 from top, scale (2, -1)')
 535     c.restoreState()
 536 
 537     c.saveState()
 538     c.translate(0, -5 * inch)
 539     c.rotate(-30)
 540     drawAxes(c, "4. down 5, rotate 30' anticlockwise")
 541     c.restoreState()
 542 
 543     c.saveState()
 544     c.translate(3 * inch, -5 * inch)
 545     c.skew(0,30)
 546     drawAxes(c, "5. down 5, 3 across, skew beta 30")
 547     c.restoreState()
 548 
 549     c.showPage()
 550 
 551 #########################################################################
 552 #
 553 #  Page 6 - clipping
 554 #
 555 #########################################################################
 556     framePage(c, "Clipping")
 557     c.setFont('Times-Roman', 12)
 558     t = c.beginText(inch, 10 * inch)
 559     t.textLines("""This shows clipping at work. We draw a chequerboard of rectangles
 560     into a path object, and clip it.  This then forms a mask which limits the region of
 561     the page on which one can draw.  This paragraph was drawn after setting the clipping
 562     path, and so you should only see part of the text.""")
 563     c.drawText(t)
 564 
 565     c.saveState()
 566     #c.setFillColorRGB(0,0,1)
 567     p = c.beginPath()
 568     #make a chesboard effect, 1 cm squares
 569     for i in range(14):
 570         x0 = (3 + i) * cm
 571         for j in range(7):
 572             y0 = (16 + j) * cm
 573             p.rect(x0, y0, 0.85*cm, 0.85*cm)
 574     c.addLiteral('%Begin clip path')
 575     c.clipPath(p)
 576     c.addLiteral('%End clip path')
 577     t = c.beginText(3 * cm, 22.5 * cm)
 578     t.textLines("""This shows clipping at work.  We draw a chequerboard of rectangles
 579     into a path object, and clip it.  This then forms a mask which limits the region of
 580     the page on which one can draw.  This paragraph was drawn after setting the clipping
 581     path, and so you should only see part of the text.
 582         This shows clipping at work.  We draw a chequerboard of rectangles
 583     into a path object, and clip it.  This then forms a mask which limits the region of
 584     the page on which one can draw.  This paragraph was drawn after setting the clipping
 585     path, and so you should only see part of the text.
 586         This shows clipping at work.  We draw a chequerboard of rectangles
 587     into a path object, and clip it.  This then forms a mask which limits the region of
 588     the page on which one can draw.  This paragraph was drawn after setting the clipping
 589     path, and so you should only see part of the text.""")
 590     c.drawText(t)
 591 
 592     c.restoreState()
 593 
 594     t = c.beginText(inch, 5 * inch)
 595     t.textLines("""You can also use text as an outline for clipping with the text render mode.
 596         The API is not particularly clean on this and one has to follow the right sequence;
 597         this can be optimized shortly.""")
 598     c.drawText(t)
 599 
 600     #first the outline
 601     c.saveState()
 602     t = c.beginText(inch, 3.0 * inch)
 603     t.setFont('Helvetica-BoldOblique',108)
 604     t.setTextRenderMode(5)  #stroke and add to path
 605     t.textLine('Python!')
 606     t.setTextRenderMode(0)
 607     c.drawText(t)    #this will make a clipping mask
 608 
 609     #now some small stuff which wil be drawn into the current clip mask
 610     t = c.beginText(inch, 4 * inch)
 611     t.setFont('Times-Roman',6)
 612     t.textLines((('spam ' * 40) + '\n') * 15)
 613     c.drawText(t)
 614 
 615     #now reset canvas to get rid of the clipping mask
 616     c.restoreState()
 617 
 618     c.showPage()
 619 
 620 
 621 #########################################################################
 622 #
 623 #  Page 7 - images
 624 #
 625 #########################################################################
 626     framePage(c, "Images")
 627     c.setFont('Times-Roman', 12)
 628     t = c.beginText(inch, 10 * inch)
 629     if not haveImages:
 630         c.drawString(inch, 11*inch,
 631                      "Python or Java Imaging Library not found! Below you see rectangles instead of images.")
 632 
 633     t.textLines("""PDFgen uses the Python Imaging Library (or, under Jython, java.awt.image and javax.imageio)
 634         to process a very wide variety of image formats.
 635         This page shows image capabilities.  If I've done things right, the bitmap should have
 636         its bottom left corner aligned with the crosshairs.
 637         There are two methods for drawing images.  The recommended use is to call drawImage.
 638         This produces the smallest PDFs and the fastest generation times as each image's binary data is
 639         only embedded once in the file.  Also you can use advanced features like transparency masks.
 640         You can also use drawInlineImage, which puts images in the page stream directly.
 641         This is slightly faster for Acrobat to render or for very small images, but wastes
 642         space if you use images more than once.""")
 643 
 644     c.drawText(t)
 645 
 646     if haveImages:
 647         c.drawInlineImage('pythonpowered.gif',2*inch, 7*inch)
 648     else:
 649         c.rect(2*inch, 7*inch, 110, 44)
 650 
 651     c.line(1.5*inch, 7*inch, 4*inch, 7*inch)
 652     c.line(2*inch, 6.5*inch, 2*inch, 8*inch)
 653     c.drawString(4.5 * inch, 7.25*inch, 'inline image drawn at natural size')
 654 
 655     if haveImages:
 656         c.drawInlineImage('pythonpowered.gif',2*inch, 5*inch, inch, inch)
 657     else:
 658         c.rect(2*inch, 5*inch, inch, inch)
 659 
 660     c.line(1.5*inch, 5*inch, 4*inch, 5*inch)
 661     c.line(2*inch, 4.5*inch, 2*inch, 6*inch)
 662     c.drawString(4.5 * inch, 5.25*inch, 'inline image distorted to fit box')
 663 
 664     c.drawString(1.5 * inch, 4*inch, 'Image XObjects can be defined once in the file and drawn many times.')
 665     c.drawString(1.5 * inch, 3.75*inch, 'This results in faster generation and much smaller files.')
 666 
 667     for i in range(5):
 668         if haveImages:
 669             (w, h) = c.drawImage('pythonpowered.gif', (1.5 + i)*inch, 3*inch)
 670         else:
 671             c.rect((1.5 + i)*inch, 3*inch, 110, 44)
 672 
 673     myMask = [254,255,222,223,0,1]
 674     c.drawString(1.5 * inch, 2.5*inch, "The optional 'mask' parameter lets you define transparent colors. We used a color picker")
 675     c.drawString(1.5 * inch, 2.3*inch, "to determine that the yellow in the image above is RGB=(225,223,0).  We then define a mask")
 676     c.drawString(1.5 * inch, 2.1*inch, "spanning these RGB values:  %s.  The background vanishes!!" % myMask)
 677     c.drawString(2.5*inch, 1.2*inch, 'This would normally be obscured')
 678     if haveImages:
 679         c.drawImage('pythonpowered.gif', 3*inch, 1.2*inch, w, h, mask=myMask)
 680     else:
 681         c.rect(3*inch, 1.2*inch, 110, 44)
 682 
 683     c.showPage()
 684 
 685 
 686 #########################################################################
 687 #
 688 #  Page 8 - Forms and simple links
 689 #
 690 #########################################################################
 691     framePage(c, "Forms and Links")
 692     c.setFont('Times-Roman', 12)
 693     t = c.beginText(inch, 10 * inch)
 694     t.textLines("""Forms are sequences of text or graphics operations
 695       which are stored only once in a PDF file and used as many times
 696       as desired.  The blue logo bar to the left is an example of a form
 697       in this document.  See the function framePageForm in this demo script
 698       for an example of how to use canvas.beginForm(name, ...) ... canvas.endForm().
 699 
 700       Documents can also contain cross references where (for example) a rectangle
 701       on a page may be bound to a position on another page.  If the user clicks
 702       on the rectangle the PDF viewer moves to the bound position on the other
 703       page.  There are many other types of annotations and links supported by PDF.
 704 
 705       For example, there is a bookmark to each page in this document and below
 706       is a browsable index that jumps to those pages. In addition we show two
 707       URL hyperlinks; for these, you specify a rectangle but must draw the contents
 708       or any surrounding rectangle yourself.
 709       """)
 710     c.drawText(t)
 711 
 712     nentries = len(titlelist)
 713     xmargin = 3*inch
 714     xmax = 7*inch
 715     ystart = 6.54*inch
 716     ydelta = 0.4*inch
 717     for i in range(nentries):
 718         yposition = ystart - i*ydelta
 719         title = titlelist[i]
 720         c.drawString(xmargin, yposition, title)
 721         c.linkAbsolute(title, title, (xmargin-ydelta/4, yposition-ydelta/4, xmax, yposition+ydelta/2))
 722 
 723 
 724     # test URLs
 725     r1 = (inch, 3*inch, 5*inch, 3.25*inch) # this is x1,y1,x2,y2
 726     c.linkURL('http://www.reportlab.com/', r1, thickness=1, color=colors.green)
 727     c.drawString(inch+3, 3*inch+6, 'Hyperlink to www.reportlab.com, with green border')
 728 
 729     r1 = (inch, 2.5*inch, 5*inch, 2.75*inch) # this is x1,y1,x2,y2
 730     c.linkURL('mailto:reportlab-users@egroups.com', r1) #, border=0)
 731     c.drawString(inch+3, 2.5*inch+6, 'mailto: hyperlink, without border')
 732 
 733     r1 = (inch, 2*inch, 5*inch, 2.25*inch) # this is x1,y1,x2,y2
 734     c.linkURL('http://www.reportlab.com/', r1,
 735                       thickness=2,
 736                       dashArray=[2,4],
 737                       color=colors.magenta)
 738     c.drawString(inch+3, 2*inch+6, 'Hyperlink with custom border style')
 739 
 740     ### now do stuff for the outline
 741     #for x in outlinenametree: print x
 742     #stop
 743     #apply(c.setOutlineNames0, tuple(outlinenametree))
 744     return c
 745 
 746 
 747 def run(filename):
 748     c = makeDocument(filename)
 749     data = c.getpdfdata()
 750     print 'Content-Type: application/pdf\n'
 751     sys.stdout.flush()
 752     sys.stdout.write(data)
 753     sys.stdout.flush()
 754 
 755 def pageShapes(c):
 756     """Demonstrates the basic lines and shapes"""
 757 
 758     c.showPage()
 759     framePage(c, "Basic line and shape routines""")
 760     c.setTextOrigin(inch, 10 * inch)
 761     c.setFont('Times-Roman', 12)
 762     c.textLines("""pdfgen provides some basic routines for drawing straight and curved lines,
 763     and also for solid shapes.""")
 764 
 765     y = 9 * inch
 766     d = DocBlock()
 767     d.comment1 = 'Lesson one'
 768     d.code = "canvas.textOut('hello, world')"
 769     print d.code
 770 
 771     d.comment2 = 'Lesson two'
 772 
 773     d.draw(c, inch, 9 * inch)
 774 
 775 
 776 class PdfgenTestCase(unittest.TestCase):
 777     "Make documents with lots of Pdfgen features"
 778 
 779     def test0(self):
 780         "Make a PDFgen document with most graphics features"
 781         run('test_pdfgen_general.pdf')
 782 
 783 
 784 def makeSuite():
 785     return makeSuiteForClasses(PdfgenTestCase)
 786 
 787 
 788 #noruntests
 789 unittest.TextTestRunner().run(makeSuite())

Result: pdfgen_general.pdf