author | rgbecker |
Wed, 25 Oct 2000 08:57:46 +0000 | |
changeset 494 | 54257447cfe9 |
parent 237 | 132245a36067 |
child 760 | 0e51a12a0e39 |
permissions | -rwxr-xr-x |
6 | 1 |
#!/bin/env python |
494 | 2 |
#copyright ReportLab Inc. 2000 |
3 |
#see license.txt for license details |
|
4 |
#history http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/reportlab/pdfgen/test/testpdfgen.py?cvsroot=reportlab |
|
5 |
#$Header: /tmp/reportlab/reportlab/pdfgen/test/Attic/testpdfgen.py,v 1.16 2000/10/25 08:57:45 rgbecker Exp $ |
|
6 |
__version__=''' $Id: testpdfgen.py,v 1.16 2000/10/25 08:57:45 rgbecker Exp $ ''' |
|
16 | 7 |
__doc__='testscript for reportlab.pdfgen' |
0 | 8 |
#tests and documents new low-level canvas |
9 |
import string |
|
10 | 10 |
from reportlab.pdfgen import canvas # gmcm 2000/10/13, pdfgen now a package |
42
ba8c232f544e
Moved inch and cm definitions to reportlab.lib.units and amended all demos
andy_robinson
parents:
16
diff
changeset
|
11 |
from reportlab.lib.units import inch, cm |
43
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
42
diff
changeset
|
12 |
from reportlab.lib import colors |
0 | 13 |
|
14 |
################################################################# |
|
15 |
# |
|
16 |
# first some drawing utilities |
|
17 |
# |
|
18 |
# |
|
19 |
################################################################ |
|
20 |
||
21 |
BASEFONT = ('Times-Roman', 10) |
|
55 | 22 |
def framePageForm(c): |
231 | 23 |
c.beginForm("frame") |
55 | 24 |
c.saveState() |
25 |
# forms can't do non-constant operations |
|
26 |
#canvas.setFont('Times-BoldItalic',20) |
|
27 |
#canvas.drawString(inch, 10.5 * inch, title) |
|
28 |
||
29 |
#c.setFont('Times-Roman',10) |
|
30 |
#c.drawCentredString(4.135 * inch, 0.75 * inch, |
|
31 |
# 'Page %d' % c.getPageNumber()) |
|
32 |
||
33 |
#draw a border |
|
34 |
c.setFillColorRGB(0,0,0.95) |
|
35 |
c.rect(0.3*inch, inch, 0.5*inch, 10*inch, fill=1) |
|
36 |
from reportlab.lib import corp |
|
37 |
c.translate(0.8*inch, 9.6*inch) |
|
38 |
c.rotate(90) |
|
39 |
logo = corp.ReportLabLogo(width=1.3*inch, height=0.5*inch, powered_by=1) |
|
40 |
c.setFillColorRGB(1,1,1) |
|
41 |
c.setStrokeColorRGB(1,1,1) |
|
42 |
logo.draw(c) |
|
43 |
#c.setStrokeColorRGB(1,0,0) |
|
44 |
#c.setLineWidth(5) |
|
45 |
#c.line(0.8 * inch, inch, 0.8 * inch, 10.75 * inch) |
|
46 |
#reset carefully afterwards |
|
47 |
#canvas.setLineWidth(1) |
|
48 |
#canvas.setStrokeColorRGB(0,0,0)\ |
|
49 |
c.restoreState() |
|
231 | 50 |
c.endForm() |
55 | 51 |
|
52 |
titlelist = [] |
|
167
99dd06eb9591
added demonstration of usage of closed outline entries
aaron_watters
parents:
140
diff
changeset
|
53 |
closeit = 0 |
55 | 54 |
|
0 | 55 |
def framePage(canvas, title): |
167
99dd06eb9591
added demonstration of usage of closed outline entries
aaron_watters
parents:
140
diff
changeset
|
56 |
global closeit |
55 | 57 |
titlelist.append(title) |
140
582ff725867b
eliminated canvas._inPage0() (now disallowed)
aaron_watters
parents:
135
diff
changeset
|
58 |
#canvas._inPage0() # do we need this at all? would be good to eliminate it |
55 | 59 |
canvas.saveState() |
0 | 60 |
canvas.setFont('Times-BoldItalic',20) |
55 | 61 |
|
0 | 62 |
canvas.drawString(inch, 10.5 * inch, title) |
231 | 63 |
canvas.bookmarkHorizontalAbsolute(title, 10.8*inch) |
135
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
64 |
#newsection(title) |
231 | 65 |
canvas.addOutlineEntry(title+" section", title, level=0, closed=closeit) |
167
99dd06eb9591
added demonstration of usage of closed outline entries
aaron_watters
parents:
140
diff
changeset
|
66 |
closeit = not closeit # close every other one |
0 | 67 |
canvas.setFont('Times-Roman',10) |
68 |
canvas.drawCentredString(4.135 * inch, 0.75 * inch, |
|
69 |
'Page %d' % canvas.getPageNumber()) |
|
55 | 70 |
canvas.restoreState() |
231 | 71 |
canvas.doForm("frame") |
61 | 72 |
|
135
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
73 |
def makesubsection(canvas, title, horizontal): |
231 | 74 |
canvas.bookmarkHorizontalAbsolute(title, horizontal) |
135
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
75 |
#newsubsection(title) |
231 | 76 |
canvas.addOutlineEntry(title+" subsection", title, level=1) |
61 | 77 |
|
78 |
# outline helpers |
|
135
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
79 |
#outlinenametree = [] |
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
80 |
#def newsection(name): |
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
81 |
# outlinenametree.append(name) |
61 | 82 |
|
135
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
83 |
#def newsubsection(name): |
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
84 |
# from types import TupleType |
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
85 |
# thissection = outlinenametree[-1] |
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
86 |
# if type(thissection) is not TupleType: |
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
87 |
# subsectionlist = [] |
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
88 |
# thissection = outlinenametree[-1] = (thissection, subsectionlist) |
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
89 |
# else: |
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
90 |
# (sectionname, subsectionlist) = thissection |
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
91 |
# subsectionlist.append(name) |
0 | 92 |
|
93 |
class DocBlock: |
|
94 |
"""A DocBlock has a chunk of commentary and a chunk of code. |
|
95 |
It prints the code and commentary, then executes the code, |
|
96 |
which is presumed to draw in a region reserved for it. |
|
97 |
""" |
|
98 |
def __init__(self): |
|
99 |
self.comment1 = "A doc block" |
|
42
ba8c232f544e
Moved inch and cm definitions to reportlab.lib.units and amended all demos
andy_robinson
parents:
16
diff
changeset
|
100 |
self.code = "canvas.setTextOrigin(cm, cm)\ncanvas.textOut('Hello World')" |
0 | 101 |
self.comment2 = "That was a doc block" |
102 |
self.drawHeight = 0 |
|
103 |
||
104 |
def _getHeight(self): |
|
105 |
"splits into lines" |
|
106 |
self.comment1lines = string.split(self.comment1, '\n') |
|
107 |
self.codelines = string.split(self.code, '\n') |
|
108 |
self.comment2lines = string.split(self.comment2, '\n') |
|
109 |
textheight = (len(self.comment1lines) + |
|
110 |
len(self.code) + |
|
111 |
len(self.comment2lines) + |
|
112 |
18) |
|
113 |
return max(textheight, self.drawHeight) |
|
114 |
||
115 |
def draw(self, canvas, x, y): |
|
116 |
#specifies top left corner |
|
117 |
canvas.saveState() |
|
118 |
height = self._getHeight() |
|
119 |
canvas.rect(x, y-height, 6*inch, height) |
|
120 |
#first draw the text |
|
121 |
canvas.setTextOrigin(x + 3 * inch, y - 12) |
|
122 |
canvas.setFont('Times-Roman',10) |
|
123 |
canvas.textLines(self.comment1) |
|
124 |
drawCode(canvas, self.code) |
|
125 |
canvas.textLines(self.comment2) |
|
126 |
||
55 | 127 |
#now a box for the drawing, slightly within rect |
0 | 128 |
canvas.rect(x + 9, y - height + 9, 198, height - 18) |
129 |
#boundary: |
|
130 |
self.namespace = {'canvas':canvas,'cm': cm,'inch':inch} |
|
131 |
canvas.translate(x+9, y - height + 9) |
|
132 |
codeObj = compile(self.code, '<sample>','exec') |
|
133 |
exec codeObj in self.namespace |
|
134 |
||
135 |
canvas.restoreState() |
|
136 |
||
137 |
||
138 |
||
139 |
def drawAxes(canvas, label): |
|
140 |
"""draws a couple of little rulers showing the coords - |
|
141 |
uses points as units so you get an imperial ruler |
|
142 |
one inch on each side""" |
|
143 |
#y axis |
|
144 |
canvas.line(0,0,0,72) |
|
145 |
for y in range(9): |
|
146 |
tenths = (y+1) * 7.2 |
|
147 |
canvas.line(-6,tenths,0,tenths) |
|
148 |
canvas.line(-6, 66, 0, 72) #arrow... |
|
149 |
canvas.line(6, 66, 0, 72) #arrow... |
|
150 |
||
151 |
canvas.line(0,0,72,0) |
|
152 |
for x in range(9): |
|
153 |
tenths = (x+1) * 7.2 |
|
154 |
canvas.line(tenths,-6,tenths, 0) |
|
155 |
canvas.line(66, -6, 72, 0) #arrow... |
|
156 |
canvas.line(66, +6, 72, 0) #arrow... |
|
157 |
||
158 |
canvas.drawString(18, 30, label) |
|
159 |
||
160 |
def drawCrossHairs(canvas, x, y): |
|
161 |
"""just a marker for checking text metrics - blue for fun""" |
|
162 |
||
163 |
canvas.saveState() |
|
164 |
canvas.setStrokeColorRGB(0,1,0) |
|
165 |
canvas.line(x-6,y,x+6,y) |
|
166 |
canvas.line(x,y-6,x,y+6) |
|
167 |
canvas.restoreState() |
|
168 |
||
169 |
def drawCode(canvas, code): |
|
170 |
"""Draws a block of text at current point, indented and in Courier""" |
|
171 |
canvas.addLiteral('36 0 Td') |
|
43
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
42
diff
changeset
|
172 |
canvas.setFillColor(colors.blue) |
0 | 173 |
canvas.setFont('Courier',10) |
174 |
||
175 |
t = canvas.beginText() |
|
176 |
t.textLines(code) |
|
177 |
c.drawText(t) |
|
178 |
||
43
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
42
diff
changeset
|
179 |
canvas.setFillColor(colors.black) |
0 | 180 |
canvas.addLiteral('-36 0 Td') |
181 |
canvas.setFont('Times-Roman',10) |
|
182 |
||
183 |
||
184 |
def run(): |
|
185 |
c = canvas.Canvas('testpdfgen.pdf') |
|
55 | 186 |
framePageForm(c) # define the frame form |
231 | 187 |
c.showOutline() |
0 | 188 |
|
189 |
framePage(c, 'PDFgen graphics API test script') |
|
135
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
190 |
makesubsection(c, "PDFgen and PIDDLE", 10*inch) |
0 | 191 |
|
192 |
||
193 |
t = c.beginText(inch, 10*inch) |
|
237
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
194 |
t.setFont('Times-Roman', 10) |
0 | 195 |
drawCrossHairs(c, t.getX(),t.getY()) |
196 |
t.textLines(""" |
|
237
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
197 |
The ReportLab library permits you to create PDF documents directly from |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
198 |
your Python code. The "pdfgen" subpackage is the lowest level exposed |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
199 |
to the user and lets you directly position test and graphics on the |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
200 |
page, with access to almost the full range of PDF features. |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
201 |
The API is intended to closely mirror the PDF / Postscript imaging |
0 | 202 |
model. There is an almost one to one correspondence between commands |
203 |
and PDF operators. However, where PDF provides several ways to do a job, |
|
237
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
204 |
we have generally only picked one. |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
205 |
The test script attempts to use all of the methods exposed by the Canvas |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
206 |
class, defined in reportlab/pdfgen/canvas.py |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
207 |
First, let's look at text output. There are some basic commands |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
208 |
to draw strings: |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
209 |
- canvas.setFont(fontname, fontsize [, leading]) |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
210 |
- canvas.drawString(x, y, text) |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
211 |
- canvas.drawRightString(x, y, text) |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
212 |
- canvas.drawCentredString(x, y, text) |
0 | 213 |
|
237
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
214 |
The coordinates are in points starting at the bottom left corner of the |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
215 |
page. When setting a font, the leading (i.e. inter-line spacing) |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
216 |
defaults to 1.2 * fontsize if the fontsize is not provided. |
0 | 217 |
|
237
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
218 |
For more sophisticated operations, you can create a Text Object, defined |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
219 |
in reportlab/pdfgen/testobject.py. Text objects produce tighter PDF, run |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
220 |
faster and have many methods for precise control of spacing and position. |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
221 |
Basic usage goes as follows: |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
222 |
- tx = canvas.beginText(x, y) |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
223 |
- tx.textOut('Hello') # this moves the cursor to the right |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
224 |
- tx.textLine('Hello again') # prints a line and moves down |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
225 |
- y = tx.getY() # getX, getY and getCursor track position |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
226 |
- canvas.drawText(tx) # all gets drawn at the end |
0 | 227 |
|
237
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
228 |
The green crosshairs below test whether the text cursor is working |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
229 |
properly. They should appear at the bottom left of each relevant |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
230 |
substring. |
0 | 231 |
""") |
237
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
232 |
|
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
233 |
t.setFillColorRGB(1,0,0) |
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
234 |
t.setTextOrigin(inch, 4*inch) |
0 | 235 |
drawCrossHairs(c, t.getX(),t.getY()) |
236 |
t.textOut('textOut moves across:') |
|
237 |
drawCrossHairs(c, t.getX(),t.getY()) |
|
238 |
t.textOut('textOut moves across:') |
|
239 |
drawCrossHairs(c, t.getX(),t.getY()) |
|
240 |
t.textOut('textOut moves across:') |
|
241 |
drawCrossHairs(c, t.getX(),t.getY()) |
|
242 |
t.textLine('') |
|
243 |
drawCrossHairs(c, t.getX(),t.getY()) |
|
244 |
t.textLine('textLine moves down') |
|
245 |
drawCrossHairs(c, t.getX(),t.getY()) |
|
246 |
t.textLine('textLine moves down') |
|
247 |
drawCrossHairs(c, t.getX(),t.getY()) |
|
248 |
t.textLine('textLine moves down') |
|
249 |
drawCrossHairs(c, t.getX(),t.getY()) |
|
250 |
||
237
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
251 |
t.setTextOrigin(4*inch,3.25*inch) |
0 | 252 |
drawCrossHairs(c, t.getX(),t.getY()) |
253 |
t.textLines('This is a multi-line\nstring with embedded newlines\ndrawn with textLines().\n') |
|
237
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
254 |
drawCrossHairs(c, t.getX(),t.getY()) |
0 | 255 |
t.textLines(['This is a list of strings', |
237
132245a36067
Test script text now bears some resemblance to our code base
andy_robinson
parents:
231
diff
changeset
|
256 |
'drawn with textLines().']) |
0 | 257 |
c.drawText(t) |
258 |
||
259 |
t = c.beginText(2*inch,2*inch) |
|
260 |
t.setFont('Times-Roman',10) |
|
261 |
drawCrossHairs(c, t.getX(),t.getY()) |
|
262 |
t.textOut('Small text.') |
|
263 |
drawCrossHairs(c, t.getX(),t.getY()) |
|
264 |
t.setFont('Courier',14) |
|
265 |
t.textOut('Bigger fixed width text.') |
|
266 |
drawCrossHairs(c, t.getX(),t.getY()) |
|
267 |
t.setFont('Times-Roman',10) |
|
268 |
t.textOut('Small text again.') |
|
269 |
drawCrossHairs(c, t.getX(),t.getY()) |
|
270 |
c.drawText(t) |
|
271 |
||
272 |
#mark the cursor where it stopped |
|
273 |
c.showPage() |
|
274 |
||
275 |
||
276 |
||
277 |
############################################################## |
|
278 |
# |
|
279 |
# page 2 - line styles |
|
280 |
# |
|
281 |
############################################################### |
|
282 |
||
283 |
#page 2 - lines and styles |
|
284 |
framePage(c, 'Line Drawing Styles') |
|
285 |
||
286 |
||
287 |
||
288 |
# three line ends, lines drawn the hard way |
|
289 |
#firt make some vertical end markers |
|
290 |
c.setDash(4,4) |
|
291 |
c.setLineWidth(0) |
|
292 |
c.line(inch,9.2*inch,inch, 7.8*inch) |
|
293 |
c.line(3*inch,9.2*inch,3*inch, 7.8*inch) |
|
294 |
c.setDash() #clears it |
|
295 |
||
296 |
c.setLineWidth(5) |
|
297 |
c.setLineCap(0) |
|
298 |
p = c.beginPath() |
|
299 |
p.moveTo(inch, 9*inch) |
|
300 |
p.lineTo(3*inch, 9*inch) |
|
301 |
c.drawPath(p) |
|
302 |
c.drawString(4*inch, 9*inch, 'the default - butt caps project half a width') |
|
135
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
303 |
makesubsection(c, "caps and joins", 8.5*inch) |
0 | 304 |
|
305 |
c.setLineCap(1) |
|
306 |
p = c.beginPath() |
|
307 |
p.moveTo(inch, 8.5*inch) |
|
308 |
p.lineTo(3*inch, 8.5*inch) |
|
309 |
c.drawPath(p) |
|
310 |
c.drawString(4*inch, 8.5*inch, 'round caps') |
|
311 |
||
312 |
c.setLineCap(2) |
|
313 |
p = c.beginPath() |
|
314 |
p.moveTo(inch, 8*inch) |
|
315 |
p.lineTo(3*inch, 8*inch) |
|
316 |
c.drawPath(p) |
|
317 |
c.drawString(4*inch, 8*inch, 'square caps') |
|
318 |
||
319 |
c.setLineCap(0) |
|
320 |
||
321 |
# three line joins |
|
322 |
c.setLineJoin(0) |
|
323 |
p = c.beginPath() |
|
324 |
p.moveTo(inch, 7*inch) |
|
325 |
p.lineTo(2*inch, 7*inch) |
|
326 |
p.lineTo(inch, 6.7*inch) |
|
327 |
c.drawPath(p) |
|
328 |
c.drawString(4*inch, 6.8*inch, 'Default - mitered join') |
|
329 |
||
330 |
c.setLineJoin(1) |
|
331 |
p = c.beginPath() |
|
332 |
p.moveTo(inch, 6.5*inch) |
|
333 |
p.lineTo(2*inch, 6.5*inch) |
|
334 |
p.lineTo(inch, 6.2*inch) |
|
335 |
c.drawPath(p) |
|
336 |
c.drawString(4*inch, 6.3*inch, 'round join') |
|
337 |
||
338 |
c.setLineJoin(2) |
|
339 |
p = c.beginPath() |
|
340 |
p.moveTo(inch, 6*inch) |
|
341 |
p.lineTo(2*inch, 6*inch) |
|
342 |
p.lineTo(inch, 5.7*inch) |
|
343 |
c.drawPath(p) |
|
344 |
c.drawString(4*inch, 5.8*inch, 'bevel join') |
|
345 |
||
346 |
c.setDash(6,6) |
|
347 |
p = c.beginPath() |
|
348 |
p.moveTo(inch, 5*inch) |
|
349 |
p.lineTo(3*inch, 5*inch) |
|
350 |
c.drawPath(p) |
|
351 |
c.drawString(4*inch, 5*inch, 'dash pattern 6 points on, 3 off- setDash(6,3)') |
|
135
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
352 |
makesubsection(c, "dash patterns", 5*inch) |
0 | 353 |
|
354 |
c.setDash([1,2,3,4,5,6],0) |
|
355 |
p = c.beginPath() |
|
356 |
p.moveTo(inch, 4.5*inch) |
|
357 |
p.lineTo(3*inch, 4.5*inch) |
|
358 |
c.drawPath(p) |
|
359 |
c.drawString(4*inch, 4.5*inch, 'dash pattern lengths growing - setDash([1,2,3,4,5,6],0)') |
|
360 |
||
361 |
c.setDash() |
|
362 |
||
363 |
||
364 |
c.showPage() |
|
365 |
||
366 |
############################################################## |
|
367 |
# |
|
368 |
# higher level shapes |
|
369 |
# |
|
370 |
############################################################### |
|
371 |
framePage(c, 'Shape Drawing Routines') |
|
372 |
||
373 |
||
374 |
t = c.beginText(inch, 10*inch) |
|
375 |
t.textLines(""" |
|
376 |
Rather than making your own paths, you have access to a range of shape routines. |
|
377 |
These are built in pdfgen out of lines and bezier curves, but use the most compact |
|
378 |
set of operators possible. We can add any new ones that are of general use at no |
|
379 |
cost to performance.""") |
|
380 |
t.textLine() |
|
381 |
||
382 |
#line demo |
|
135
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
383 |
makesubsection(c, "lines", 10*inch) |
0 | 384 |
c.line(inch, 8*inch, 3*inch, 8*inch) |
385 |
t.setTextOrigin(4*inch, 8*inch) |
|
386 |
t.textLine('canvas.line(x1, y1, x2, y2)') |
|
387 |
||
388 |
#bezier demo - show control points |
|
135
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
389 |
makesubsection(c, "bezier curves", 7.5*inch) |
0 | 390 |
(x1, y1, x2, y2, x3, y3, x4, y4) = ( |
391 |
inch, 6.5*inch, |
|
392 |
1.2*inch, 7.5 * inch, |
|
393 |
3*inch, 7.5 * inch, |
|
394 |
3.5*inch, 6.75 * inch |
|
395 |
) |
|
396 |
c.bezier(x1, y1, x2, y2, x3, y3, x4, y4) |
|
397 |
c.setDash(3,3) |
|
398 |
c.line(x1,y1,x2,y2) |
|
399 |
c.line(x3,y3,x4,y4) |
|
400 |
c.setDash() |
|
401 |
t.setTextOrigin(4*inch, 7 * inch) |
|
402 |
t.textLine('canvas.bezier(x1, y1, x2, y2, x3, y3, x4, y4)') |
|
403 |
||
404 |
||
405 |
#rectangle |
|
135
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
406 |
makesubsection(c, "rectangles", 7*inch) |
0 | 407 |
c.rect(inch, 5.25 * inch, 2 * inch, 0.75 * inch) |
408 |
t.setTextOrigin(4*inch, 5.5 * inch) |
|
409 |
t.textLine('canvas.rect(x, y, width, height) - x,y is lower left') |
|
410 |
||
411 |
#wedge |
|
135
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
412 |
makesubsection(c, "wedges", 5*inch) |
0 | 413 |
c.wedge(inch, 5*inch, 3*inch, 4*inch, 0, 315) |
414 |
t.setTextOrigin(4*inch, 4.5 * inch) |
|
415 |
t.textLine('canvas.wedge(x1, y1, x2, y2, startDeg, extentDeg)') |
|
416 |
t.textLine('Note that this is an elliptical arc, not just circular!') |
|
417 |
||
418 |
#wedge the other way |
|
419 |
c.wedge(inch, 4*inch, 3*inch, 3*inch, 0, -45) |
|
420 |
t.setTextOrigin(4*inch, 3.5 * inch) |
|
421 |
t.textLine('Use a negative extent to go clockwise') |
|
422 |
||
423 |
#circle |
|
135
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
424 |
makesubsection(c, "circles", 3.5*inch) |
0 | 425 |
c.circle(1.5*inch, 2*inch, 0.5 * inch) |
426 |
c.circle(3*inch, 2*inch, 0.5 * inch) |
|
427 |
t.setTextOrigin(4*inch, 2 * inch) |
|
428 |
t.textLine('canvas.circle(x, y, radius)') |
|
429 |
c.drawText(t) |
|
430 |
############################################################## |
|
431 |
# |
|
432 |
# Page 4 - fonts |
|
433 |
# |
|
434 |
############################################################### |
|
435 |
||
436 |
||
437 |
c.showPage() |
|
438 |
framePage(c, "Font Control") |
|
439 |
||
440 |
c.drawString(inch, 10*inch, 'Listing available fonts...') |
|
441 |
||
442 |
y = 9.5*inch |
|
443 |
for fontname in c.getAvailableFonts(): |
|
444 |
c.setFont(fontname,24) |
|
445 |
c.drawString(inch, y, 'This should be %s' % fontname) |
|
446 |
y = y - 28 |
|
135
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
447 |
makesubsection(c, "fonts and colors", 4*inch) |
0 | 448 |
|
449 |
c.setFont('Times-Roman', 12) |
|
450 |
t = c.beginText(inch, 4*inch) |
|
451 |
t.textLines("""Now we'll look at the color functions and how they interact |
|
452 |
with the text. In theory, a word is just a shape; so setFillColorRGB() |
|
453 |
determines most of what you see. If you specify other text rendering |
|
454 |
modes, an outline color could be defined by setStrokeColorRGB() too""") |
|
455 |
c.drawText(t) |
|
456 |
||
457 |
||
458 |
t = c.beginText(inch, 2.75 * inch) |
|
459 |
t.setFont('Times-Bold',36) |
|
43
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
42
diff
changeset
|
460 |
t.setFillColor(colors.green) #green |
0 | 461 |
t.textLine('Green fill, no stroke') |
462 |
||
43
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
42
diff
changeset
|
463 |
#t.setStrokeColorRGB(1,0,0) #ou can do this in a text object, or the canvas. |
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
42
diff
changeset
|
464 |
t.setStrokeColor(colors.red) #ou can do this in a text object, or the canvas. |
0 | 465 |
t.setTextRenderMode(2) # fill and stroke |
466 |
t.textLine('Green fill, red stroke - yuk!') |
|
467 |
||
468 |
t.setTextRenderMode(0) # back to default - fill only |
|
469 |
t.setFillColorRGB(0,0,0) #back to default |
|
470 |
t.setStrokeColorRGB(0,0,0) #ditto |
|
471 |
c.drawText(t) |
|
472 |
||
473 |
||
474 |
||
475 |
######################################################################### |
|
476 |
# |
|
477 |
# Page 5 - coord transforms |
|
478 |
# |
|
479 |
######################################################################### |
|
480 |
c.showPage() |
|
481 |
framePage(c, "Coordinate Transforms") |
|
482 |
c.setFont('Times-Roman', 12) |
|
483 |
t = c.beginText(inch, 10 * inch) |
|
484 |
t.textLines("""This shows coordinate transformations. We draw a set of axes, |
|
485 |
moving down the page and transforming space before each one. |
|
486 |
You can use saveState() and restoreState() to unroll transformations. |
|
487 |
Note that functions which track the text cursor give the cursor position |
|
488 |
in the current coordinate system; so if you set up a 6 inch high frame |
|
489 |
2 inches down the page to draw text in, and move the origin to its top |
|
490 |
left, you should stop writing text after six inches and not eight.""") |
|
491 |
c.drawText(t) |
|
492 |
||
493 |
drawAxes(c, "0. at origin") |
|
494 |
c.addLiteral('%about to translate space') |
|
495 |
c.translate(2*inch, 7 * inch) |
|
496 |
drawAxes(c, '1. translate near top of page') |
|
497 |
||
498 |
c.saveState() |
|
499 |
c.translate(1*inch, -2 * inch) |
|
500 |
drawAxes(c, '2. down 2 inches, across 1') |
|
501 |
c.restoreState() |
|
502 |
||
503 |
c.saveState() |
|
504 |
c.translate(0, -3 * inch) |
|
505 |
c.scale(2, -1) |
|
506 |
drawAxes(c, '3. down 3 from top, scale (2, -1)') |
|
507 |
c.restoreState() |
|
508 |
||
509 |
c.saveState() |
|
510 |
c.translate(0, -5 * inch) |
|
511 |
c.rotate(-30) |
|
512 |
drawAxes(c, "4. down 5, rotate 30' anticlockwise") |
|
513 |
c.restoreState() |
|
514 |
||
515 |
c.saveState() |
|
516 |
c.translate(3 * inch, -5 * inch) |
|
517 |
c.skew(0,30) |
|
518 |
drawAxes(c, "5. down 5, 3 across, skew beta 30") |
|
519 |
c.restoreState() |
|
520 |
||
521 |
||
522 |
######################################################################### |
|
523 |
# |
|
524 |
# Page 6 - clipping |
|
525 |
# |
|
526 |
######################################################################### |
|
527 |
c.showPage() |
|
528 |
framePage(c, "Clipping") |
|
529 |
c.setFont('Times-Roman', 12) |
|
530 |
t = c.beginText(inch, 10 * inch) |
|
531 |
t.textLines("""This shows clipping at work. We draw a chequerboard of rectangles |
|
532 |
into a path object, and clip it. This then forms a mask which limits the region of |
|
533 |
the page on which one can draw. This paragraph was drawn after setting the clipping |
|
534 |
path, and so you should only see part of the text.""") |
|
535 |
c.drawText(t) |
|
536 |
||
537 |
c.saveState() |
|
538 |
#c.setFillColorRGB(0,0,1) |
|
539 |
p = c.beginPath() |
|
540 |
#make a chesboard effect, 1 cm squares |
|
541 |
for i in range(14): |
|
42
ba8c232f544e
Moved inch and cm definitions to reportlab.lib.units and amended all demos
andy_robinson
parents:
16
diff
changeset
|
542 |
x0 = (3 + i) * cm |
0 | 543 |
for j in range(7): |
42
ba8c232f544e
Moved inch and cm definitions to reportlab.lib.units and amended all demos
andy_robinson
parents:
16
diff
changeset
|
544 |
y0 = (16 + j) * cm |
ba8c232f544e
Moved inch and cm definitions to reportlab.lib.units and amended all demos
andy_robinson
parents:
16
diff
changeset
|
545 |
p.rect(x0, y0, 0.85*cm, 0.85*cm) |
0 | 546 |
c.addLiteral('%Begin clip path') |
547 |
c.clipPath(p) |
|
548 |
c.addLiteral('%End clip path') |
|
42
ba8c232f544e
Moved inch and cm definitions to reportlab.lib.units and amended all demos
andy_robinson
parents:
16
diff
changeset
|
549 |
t = c.beginText(3 * cm, 22.5 * cm) |
0 | 550 |
t.textLines("""This shows clipping at work. We draw a chequerboard of rectangles |
551 |
into a path object, and clip it. This then forms a mask which limits the region of |
|
552 |
the page on which one can draw. This paragraph was drawn after setting the clipping |
|
553 |
path, and so you should only see part of the text. |
|
554 |
This shows clipping at work. We draw a chequerboard of rectangles |
|
555 |
into a path object, and clip it. This then forms a mask which limits the region of |
|
556 |
the page on which one can draw. This paragraph was drawn after setting the clipping |
|
557 |
path, and so you should only see part of the text. |
|
558 |
This shows clipping at work. We draw a chequerboard of rectangles |
|
559 |
into a path object, and clip it. This then forms a mask which limits the region of |
|
560 |
the page on which one can draw. This paragraph was drawn after setting the clipping |
|
561 |
path, and so you should only see part of the text.""") |
|
562 |
c.drawText(t) |
|
563 |
||
564 |
c.restoreState() |
|
565 |
||
566 |
||
567 |
t = c.beginText(inch, 5 * inch) |
|
568 |
t.textLines("""You can also use text as an outline for clipping with the text render mode. |
|
569 |
The API is not particularly clean on this and one has to follow the right sequence; |
|
570 |
this can be optimized shortly.""") |
|
571 |
c.drawText(t) |
|
572 |
||
573 |
#first the outline |
|
574 |
c.saveState() |
|
575 |
t = c.beginText(inch, 3.0 * inch) |
|
576 |
t.setFont('Helvetica-BoldOblique',108) |
|
577 |
t.setTextRenderMode(5) #stroke and add to path |
|
578 |
t.textLine('Python!') |
|
579 |
t.setTextRenderMode(0) |
|
580 |
c.drawText(t) #this will make a clipping mask |
|
581 |
||
582 |
#now some small stuff which wil be drawn into the current clip mask |
|
583 |
t = c.beginText(inch, 4 * inch) |
|
584 |
t.setFont('Times-Roman',6) |
|
585 |
t.textLines((('spam ' * 40) + '\n') * 15) |
|
586 |
c.drawText(t) |
|
587 |
||
588 |
#now reset canvas to get rid of the clipping mask |
|
589 |
c.restoreState() |
|
590 |
||
591 |
||
592 |
||
593 |
######################################################################### |
|
594 |
# |
|
595 |
# Page 7 - images |
|
596 |
# |
|
597 |
######################################################################### |
|
598 |
c.showPage() |
|
599 |
framePage(c, "Images") |
|
600 |
c.setFont('Times-Roman', 12) |
|
601 |
t = c.beginText(inch, 10 * inch) |
|
602 |
try: |
|
603 |
import Image |
|
604 |
except: |
|
605 |
t.textOut("Python Imaging Library not found! You need it to see images.") |
|
606 |
c.save() |
|
607 |
return |
|
608 |
||
609 |
||
610 |
t.textLines("""This shows image capabilities. If I've done things |
|
611 |
right, the bitmap should have its bottom left corner aligned |
|
612 |
with the crosshairs.""") |
|
613 |
t.textLines("""PDFgen uses the Python Imaging Library to process |
|
614 |
a very wide variety of image formats. Although some processing |
|
615 |
is required, cached versions of the image are prepared and |
|
616 |
stored in the project directory, so that subsequent builds of |
|
617 |
an image-rich document are very fast indeed.""") |
|
618 |
||
619 |
c.drawText(t) |
|
620 |
||
621 |
c.drawInlineImage('PythonPowered.gif',2*inch, 7*inch) |
|
622 |
c.line(1.5*inch, 7*inch, 4*inch, 7*inch) |
|
623 |
c.line(2*inch, 6.5*inch, 2*inch, 8*inch) |
|
624 |
c.drawString(4.5 * inch, 7.25*inch, 'image drawn at natural size') |
|
625 |
||
626 |
c.drawInlineImage('PythonPowered.gif',2*inch, 4*inch, inch, inch) |
|
627 |
c.line(1.5*inch, 4*inch, 4*inch, 4*inch) |
|
628 |
c.line(2*inch, 3.5*inch, 2*inch, 5*inch) |
|
629 |
c.drawString(4.5 * inch, 4.25*inch, 'image distorted to fit box') |
|
55 | 630 |
|
631 |
||
632 |
||
633 |
######################################################################### |
|
634 |
# |
|
635 |
# Page 8 - Forms and simple links |
|
636 |
# |
|
637 |
######################################################################### |
|
638 |
c.showPage() |
|
639 |
framePage(c, "Forms and Links") |
|
640 |
c.setFont('Times-Roman', 12) |
|
641 |
t = c.beginText(inch, 10 * inch) |
|
642 |
t.textLines("""Forms are sequences of text or graphics operations |
|
643 |
which are stored only once in a PDF file and used as many times |
|
644 |
as desired. The blue logo bar to the left is an example of a form |
|
645 |
in this document. See the function framePageForm in this demo script |
|
646 |
for an example of how to use canvas.beginForm(name, ...) ... canvas.endForm(). |
|
647 |
||
648 |
Documents can also contain cross references where (for example) a rectangle |
|
649 |
on a page may be bound to a position on another page. If the user clicks |
|
650 |
on the rectangle the PDF viewer moves to the bound position on the other |
|
651 |
page. There are many other types of annotations and links supported by PDF. |
|
652 |
||
653 |
For example there is a bookmark to each page in this document and below |
|
654 |
is a browsable index that jumps to those pages. |
|
655 |
""") |
|
656 |
c.drawText(t) |
|
657 |
||
658 |
nentries = len(titlelist) |
|
659 |
xmargin = 3*inch |
|
660 |
xmax = 7*inch |
|
661 |
ystart = 6.54*inch |
|
662 |
ydelta = 0.4*inch |
|
663 |
for i in range(nentries): |
|
664 |
yposition = ystart - i*ydelta |
|
665 |
title = titlelist[i] |
|
666 |
c.drawString(xmargin, yposition, title) |
|
231 | 667 |
c.linkAbsolute(title, title, (xmargin-ydelta/4, yposition-ydelta/4, xmax, yposition+ydelta/2)) |
61 | 668 |
### now do stuff for the outline |
669 |
#for x in outlinenametree: print x |
|
670 |
#stop |
|
135
6f634b913387
added demonstration of new AddOutlineEntry0 api
aaron_watters
parents:
63
diff
changeset
|
671 |
#apply(c.setOutlineNames0, tuple(outlinenametree)) |
0 | 672 |
c.save() |
673 |
||
674 |
||
675 |
||
676 |
def pageShapes(c): |
|
677 |
"""Demonstrates the basic lines and shapes""" |
|
678 |
c.showPage() |
|
679 |
framePage(c, "Basic line and shape routines""") |
|
680 |
c.setTextOrigin(inch, 10 * inch) |
|
681 |
c.setFont('Times-Roman', 12) |
|
682 |
c.textLines("""pdfgen provides some basic routines for drawing straight and curved lines, |
|
683 |
and also for solid shapes.""") |
|
684 |
||
685 |
y = 9 * inch |
|
686 |
d = DocBlock() |
|
687 |
d.comment1 = 'Lesson one' |
|
688 |
d.code = "canvas.textOut('hello, world')" |
|
689 |
print d.code |
|
690 |
||
691 |
d.comment2 = 'Lesson two' |
|
692 |
||
693 |
d.draw(c, inch, 9 * inch) |
|
694 |
||
695 |
if __name__ == "__main__": |
|
6 | 696 |
run() |