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:
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)