author | aaron_watters |
Sun, 26 Mar 2000 20:45:01 +0000 | |
changeset 54 | 9f1cadbf9728 |
parent 52 | 3bbe0067a2dc |
child 60 | 5b97da0315d3 |
permissions | -rwxr-xr-x |
6 | 1 |
############################################################################### |
2 |
# |
|
3 |
# ReportLab Public License Version 1.0 |
|
4 |
# |
|
5 |
# Except for the change of names the spirit and intention of this |
|
6 |
# license is the same as that of Python |
|
7 |
# |
|
8 |
# (C) Copyright ReportLab Inc. 1998-2000. |
|
9 |
# |
|
10 |
# |
|
11 |
# All Rights Reserved |
|
12 |
# |
|
13 |
# Permission to use, copy, modify, and distribute this software and its |
|
14 |
# documentation for any purpose and without fee is hereby granted, provided |
|
15 |
# that the above copyright notice appear in all copies and that both that |
|
16 |
# copyright notice and this permission notice appear in supporting |
|
7 | 17 |
# documentation, and that the name of ReportLab not be used |
6 | 18 |
# in advertising or publicity pertaining to distribution of the software |
19 |
# without specific, written prior permission. |
|
20 |
# |
|
21 |
# |
|
22 |
# Disclaimer |
|
23 |
# |
|
24 |
# ReportLab Inc. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS |
|
25 |
# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, |
|
26 |
# IN NO EVENT SHALL ReportLab BE LIABLE FOR ANY SPECIAL, INDIRECT |
|
27 |
# OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS |
|
28 |
# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR |
|
29 |
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
|
30 |
# PERFORMANCE OF THIS SOFTWARE. |
|
31 |
# |
|
32 |
############################################################################### |
|
33 |
# $Log: canvas.py,v $ |
|
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
34 |
# Revision 1.18 2000/03/26 20:45:01 aaron_watters |
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
35 |
# added beginForm..endForm and fixed some naming convention issues. |
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
36 |
# |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
37 |
# Revision 1.17 2000/03/24 21:02:21 aaron_watters |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
38 |
# added support for destinations, forms, linkages |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
39 |
# |
45 | 40 |
# Revision 1.15 2000/03/10 21:46:04 andy_robinson |
41 |
# fixed typo in setDash |
|
48 | 42 |
# |
43
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
43 |
# Revision 1.14 2000/03/08 13:40:03 andy_robinson |
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
44 |
# Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor) |
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
45 |
# which accepts color objects directly. |
45 | 46 |
# |
36 | 47 |
# Revision 1.13 2000/03/06 20:06:36 rgbecker |
48 |
# Typo self._currentPageHasImages = 1 |
|
43
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
49 |
# |
33 | 50 |
# Revision 1.12 2000/03/02 12:58:58 rgbecker |
51 |
# Remove over officious import checks Imag/zlib |
|
36 | 52 |
# |
28 | 53 |
# Revision 1.11 2000/03/02 10:28:54 rgbecker |
54 |
# [].extend illegal in 1.5.1 |
|
33 | 55 |
# |
27
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
56 |
# Revision 1.10 2000/02/24 17:28:13 andy_robinson |
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
57 |
# Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1 |
28 | 58 |
# |
26
ee96702d3008
Removed some constants which are no longer used.
andy_robinson
parents:
21
diff
changeset
|
59 |
# Revision 1.9 2000/02/24 09:12:55 andy_robinson |
27
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
60 |
# |
26
ee96702d3008
Removed some constants which are no longer used.
andy_robinson
parents:
21
diff
changeset
|
61 |
# Removed some constants which are no longer used. |
27
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
62 |
# |
21 | 63 |
# Revision 1.8 2000/02/20 14:43:27 rgbecker |
64 |
# _currentPageHasImages = 0 in init |
|
26
ee96702d3008
Removed some constants which are no longer used.
andy_robinson
parents:
21
diff
changeset
|
65 |
# |
20 | 66 |
# Revision 1.7 2000/02/20 11:08:56 rgbecker |
67 |
# Canvas.setPageSize fix |
|
21 | 68 |
# |
18 | 69 |
# Revision 1.6 2000/02/17 15:26:28 rgbecker |
70 |
# Change page compression default |
|
20 | 71 |
# |
16 | 72 |
# Revision 1.5 2000/02/17 02:08:04 rgbecker |
73 |
# Docstring & other fixes |
|
18 | 74 |
# |
10 | 75 |
# Revision 1.4 2000/02/16 09:42:50 rgbecker |
76 |
# Conversion to reportlab package |
|
16 | 77 |
# |
7 | 78 |
# Revision 1.3 2000/02/15 17:55:59 rgbecker |
79 |
# License text fixes |
|
10 | 80 |
# |
6 | 81 |
# Revision 1.2 2000/02/15 15:47:09 rgbecker |
82 |
# Added license, __version__ and Logi comment |
|
7 | 83 |
# |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
84 |
__version__=''' $Id: canvas.py,v 1.18 2000/03/26 20:45:01 aaron_watters Exp $ ''' |
16 | 85 |
__doc__=""" |
0 | 86 |
PDFgen is a library to generate PDF files containing text and graphics. It is the |
87 |
foundation for a complete reporting solution in Python. It is also the |
|
88 |
foundation for piddlePDF, the PDF back end for PIDDLE. |
|
89 |
||
90 |
Documentation is a little slim right now; run then look at testpdfgen.py |
|
91 |
to get a clue. |
|
92 |
||
6 | 93 |
Progress Reports: |
94 |
8.83, 2000-01-13, gmcm: |
|
95 |
Packagizing: |
|
96 |
renamed from pdfgen.py to canvas.py |
|
97 |
broke out PDFTextObject to textobject.py |
|
98 |
broke out PDFPathObject to pathobject.py |
|
0 | 99 |
placed all three in a package directory named pdfgen |
100 |
0.82, 1999-10-27, AR: |
|
101 |
Fixed some bugs on printing to Postscript. Added 'Text Object' |
|
102 |
analogous to Path Object to control entry and exit from text mode. |
|
103 |
Much simpler clipping API. All verified to export Postscript and |
|
104 |
redistill. |
|
105 |
One limitation still - clipping to text paths is fine in Acrobat |
|
106 |
but not in Postscript (any level) |
|
107 |
||
108 |
0.81,1999-10-13, AR: |
|
109 |
Adding RoundRect; changed all format strings to use %0.2f instead of %s, |
|
110 |
so we don't get exponentials in the output. |
|
111 |
0.8,1999-10-07, AR: all changed! |
|
112 |
""" |
|
113 |
## 0.81 1999-10-13: |
|
114 |
## |
|
115 |
## |
|
116 |
## |
|
117 |
import os |
|
118 |
import sys |
|
119 |
import string |
|
120 |
import time |
|
121 |
import tempfile |
|
122 |
import cStringIO |
|
123 |
from types import * |
|
124 |
from math import sin, cos, tan, pi, ceil |
|
125 |
||
10 | 126 |
from reportlab.pdfbase import pdfutils |
127 |
from reportlab.pdfbase import pdfdoc |
|
128 |
from reportlab.pdfbase import pdfmetrics |
|
16 | 129 |
from reportlab.pdfgen import pdfgeom, pathobject, textobject |
43
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
130 |
from reportlab.lib import colors |
0 | 131 |
|
132 |
# Robert Kern |
|
133 |
# Constants for closing paths. |
|
134 |
# May be useful if one changes 'arc' and 'rect' to take a |
|
135 |
# default argument that tells how to close the path. |
|
136 |
# That way we can draw filled shapes. |
|
137 |
||
138 |
FILL_EVEN_ODD = 0 |
|
139 |
FILL_NON_ZERO = 1 |
|
140 |
#this is used by path-closing routines. |
|
141 |
#map stroke, fill, fillmode -> operator |
|
142 |
# fillmode: 1 = non-Zero (obviously), 0 = evenOdd |
|
143 |
PATH_OPS = {(0, 0, FILL_EVEN_ODD) : 'n', #no op |
|
144 |
(0, 0, FILL_NON_ZERO) : 'n', #no op |
|
145 |
(1, 0, FILL_EVEN_ODD) : 'S', #stroke only |
|
146 |
(1, 0, FILL_NON_ZERO) : 'S', #stroke only |
|
147 |
(0, 1, FILL_EVEN_ODD) : 'f*', #Fill only |
|
148 |
(0, 1, FILL_NON_ZERO) : 'f', #Fill only |
|
149 |
(1, 1, FILL_EVEN_ODD) : 'B*', #Stroke and Fill |
|
150 |
(1, 1, FILL_NON_ZERO) : 'B', #Stroke and Fill |
|
151 |
} |
|
152 |
||
153 |
class Canvas: |
|
154 |
"""This is a low-level interface to the PDF file format. The plan is to |
|
155 |
expose the whole pdfgen API through this. Its drawing functions should have a |
|
156 |
one-to-one correspondence with PDF functionality. Unlike PIDDLE, it thinks |
|
157 |
in terms of RGB values, Postscript font names, paths, and a 'current graphics |
|
158 |
state'. Just started development at 5/9/99, not in use yet. |
|
159 |
||
160 |
""" |
|
18 | 161 |
def __init__(self,filename,pagesize=(595.27,841.89), bottomup = 1, pageCompression=0 ): |
0 | 162 |
"""Most of the attributes are private - we will use set/get methods |
163 |
as the preferred interface. Default page size is A4.""" |
|
164 |
self._filename = filename |
|
165 |
self._doc = pdfdoc.PDFDocument() |
|
166 |
self._pagesize = pagesize |
|
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
167 |
#self._currentPageHasImages = 0 |
0 | 168 |
self._pageTransitionString = '' |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
169 |
self._destinations = {} # dictionary of destinations for cross indexing. |
0 | 170 |
|
21 | 171 |
self._pageCompression = pageCompression #off by default - turn on when we're happy! |
0 | 172 |
self._pageNumber = 1 # keep a count |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
173 |
#self._code = [] #where the current page's marking operators accumulate |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
174 |
self._restartAccumulators() # restart all accumulation state (generalized, arw) |
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
175 |
self._annotationCount = 0 |
0 | 176 |
|
177 |
#PostScript has the origin at bottom left. It is easy to achieve a top- |
|
178 |
#down coord system by translating to the top of the page and setting y |
|
179 |
#scale to -1, but then text is inverted. So self.bottomup is used |
|
180 |
#to also set the text matrix accordingly. You can now choose your |
|
181 |
#drawing coordinates. |
|
182 |
self.bottomup = bottomup |
|
20 | 183 |
self._make_preamble() |
0 | 184 |
|
185 |
#initial graphics state |
|
186 |
self._x = 0 |
|
187 |
self._y = 0 |
|
188 |
self._fontname = 'Times-Roman' |
|
189 |
self._fontsize = 12 |
|
190 |
self._textMode = 0 #track if between BT/ET |
|
191 |
self._leading = 14.4 |
|
192 |
self._currentMatrix = (1., 0., 0., 1., 0., 0.) |
|
193 |
self._fillMode = 0 #even-odd |
|
194 |
||
195 |
#text state |
|
196 |
self._charSpace = 0 |
|
197 |
self._wordSpace = 0 |
|
198 |
self._horizScale = 100 |
|
199 |
self._textRenderMode = 0 |
|
200 |
self._rise = 0 |
|
201 |
self._textLineMatrix = (1., 0., 0., 1., 0., 0.) |
|
202 |
self._textMatrix = (1., 0., 0., 1., 0., 0.) |
|
203 |
||
204 |
# line drawing |
|
205 |
self._lineCap = 0 |
|
206 |
self._lineJoin = 0 |
|
207 |
self._lineDash = None #not done |
|
208 |
self._lineWidth = 0 |
|
209 |
self._mitreLimit = 0 |
|
210 |
||
211 |
self._fillColorRGB = (0,0,0) |
|
212 |
self._strokeColorRGB = (0,0,0) |
|
213 |
||
20 | 214 |
def _make_preamble(self): |
215 |
if self.bottomup: |
|
216 |
#set initial font |
|
217 |
#self._preamble = 'BT /F9 12 Tf 14.4 TL ET' |
|
218 |
self._preamble = '1 0 0 1 0 0 cm BT /F9 12 Tf 14.4 TL ET' |
|
219 |
else: |
|
220 |
#switch coordinates, flip text and set font |
|
221 |
#self._preamble = '1 0 0 -1 0 %0.2f cm BT /F9 12 Tf 14.4 TL ET' % self._pagesize[1] |
|
222 |
self._preamble = '1 0 0 -1 0 %0.2f cm BT /F9 12 Tf 14.4 TL ET' % self._pagesize[1] |
|
223 |
||
0 | 224 |
def _escape(self, s): |
225 |
"""PDF escapes are like Python ones, but brackets need slashes before them too. |
|
226 |
Use Python's repr function and chop off the quotes first""" |
|
227 |
s = repr(s)[1:-1] |
|
228 |
s = string.replace(s, '(','\(') |
|
229 |
s = string.replace(s, ')','\)') |
|
230 |
return s |
|
231 |
||
232 |
#info functions - non-standard |
|
233 |
def setAuthor(self, author): |
|
234 |
self._doc.setAuthor(author) |
|
235 |
||
236 |
def setTitle(self, title): |
|
237 |
self._doc.setTitle(title) |
|
238 |
||
239 |
def setSubject(self, subject): |
|
240 |
self._doc.setSubject(subject) |
|
241 |
||
242 |
def pageHasData(self): |
|
243 |
"Info function - app can call it after showPage to see if it needs a save" |
|
244 |
return len(self._code) == 0 |
|
245 |
||
246 |
def showPage(self): |
|
247 |
"""This is where the fun happens""" |
|
248 |
page = pdfdoc.PDFPage() |
|
249 |
page.pagewidth = self._pagesize[0] |
|
250 |
page.pageheight = self._pagesize[1] |
|
251 |
page.hasImages = self._currentPageHasImages |
|
252 |
page.pageTransitionString = self._pageTransitionString |
|
253 |
page.setCompression(self._pageCompression) |
|
254 |
#print stream |
|
255 |
page.setStream([self._preamble] + self._code) |
|
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
256 |
self._setXObjects(page) |
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
257 |
self._setAnnotations(page) |
0 | 258 |
self._doc.addPage(page) |
259 |
||
260 |
#now get ready for the next one |
|
261 |
self._pageNumber = self._pageNumber + 1 |
|
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
262 |
self._restartAccumulators() |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
263 |
|
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
264 |
def _setAnnotations(self,page): |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
265 |
page.Annots = self._annotationrefs |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
266 |
|
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
267 |
def _setXObjects(self, thing): |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
268 |
"""for pages and forms, define the XObject dictionary for resources, if needed""" |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
269 |
forms = self._formsinuse |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
270 |
if forms: |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
271 |
xobjectsdict = self._doc.xobjDict(forms) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
272 |
thing.XObjects = xobjectsdict |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
273 |
else: |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
274 |
thing.XObjects = None |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
275 |
|
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
276 |
def _bookmarkReference(self, name): |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
277 |
"""get a reference to a (possibly undefined, possibly unbound) bookmark""" |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
278 |
d = self._destinations |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
279 |
try: |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
280 |
return d[name] |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
281 |
except: |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
282 |
result = d[name] = pdfdoc.Destination(name) # newly defined, unbound |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
283 |
return result |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
284 |
|
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
285 |
def bookmarkPage(self, name): |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
286 |
"""bind a bookmark (destination) to the current page""" |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
287 |
# XXXX there are a lot of other ways a bookmark destination can be bound: should be implemented. |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
288 |
# XXXX the other ways require tracking of the graphics state.... |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
289 |
dest = self._bookmarkReference(name) |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
290 |
pageref = self._doc.thisPageRef() |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
291 |
dest.fit() |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
292 |
dest.setPageRef(pageref) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
293 |
return dest |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
294 |
|
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
295 |
def bookmarkHorizontalAbsolute(self, name, yhorizontal): |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
296 |
"""bind a bookmark (destination to the current page at a horizontal position""" |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
297 |
dest = self._bookmarkReference(name) |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
298 |
pageref = self._doc.thisPageRef() |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
299 |
dest.fith(yhorizontal) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
300 |
dest.setPageRef(pageref) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
301 |
return dest |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
302 |
|
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
303 |
def inPage(self): |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
304 |
"""declare a page, enable page features""" |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
305 |
self._doc.inPage() |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
306 |
|
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
307 |
def inForm(self): |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
308 |
"deprecated in favore of beginForm...endForm" |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
309 |
self._doc.inForm() |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
310 |
|
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
311 |
def doForm(self, name): |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
312 |
"""use a form XObj in current operation stream""" |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
313 |
internalname = self._doc.hasForm(name) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
314 |
if not internalname: |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
315 |
raise ValueError, "form is not defined %s" % name |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
316 |
self._code.append("/%s Do" % internalname) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
317 |
self._formsinuse.append(name) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
318 |
|
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
319 |
def _restartAccumulators(self): |
0 | 320 |
self._code = [] # ready for more... |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
321 |
self._currentPageHasImages = 1 # for safety... |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
322 |
self._formsinuse = [] |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
323 |
self._annotationrefs = [] |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
324 |
self._formData = None |
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
325 |
|
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
326 |
def beginForm(self, name, lowerx=0, lowery=0, upperx=None, uppery=None): |
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
327 |
"declare the current graphics stream to be a form" |
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
328 |
self._formData = (name, lowerx, lowery, upperx, uppery) |
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
329 |
self.inForm() |
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
330 |
|
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
331 |
def endForm(self): |
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
332 |
(name, lowerx, lowery, upperx, uppery) = self._formData |
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
333 |
self.makeForm(name, lowerx, lowery, upperx, uppery) |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
334 |
|
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
335 |
def makeForm(self, name, lowerx=0, lowery=0, upperx=None, uppery=None): |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
336 |
"""Like showpage, but make a form using accumulated operations instead""" |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
337 |
# deprecated in favor or beginForm(...)... endForm() |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
338 |
(w,h) = self._pagesize |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
339 |
if upperx is None: upperx=w |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
340 |
if uppery is None: uppery=h |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
341 |
form = pdfdoc.PDFFormXObject(lowerx=lowerx, lowery=lowery, upperx=upperx, uppery=uppery) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
342 |
form.compression = self._pageCompression |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
343 |
form.setStreamList([self._preamble] + self._code) # ??? minus preamble (seems to be needed!) |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
344 |
self._setXObjects(form) |
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
345 |
self._setAnnotations(form) |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
346 |
self._doc.addForm(name, form) |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
347 |
self._restartAccumulators() |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
348 |
|
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
349 |
def textAnnotation(self, contents, Rect=None, addtopage=1, name=None, **kw): |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
350 |
if not Rect: |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
351 |
(w,h) = self._pagesize# default to whole page (?) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
352 |
Rect = (0,0,w,h) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
353 |
annotation = apply(pdfdoc.TextAnnotation, (Rect, contents), kw) |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
354 |
self._addAnnotation(annotation, name, addtopage) |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
355 |
|
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
356 |
def inkAnnotation(self, contents, InkList=None, Rect=None, addtopage=1, name=None, **kw): |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
357 |
"not working?" |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
358 |
(w,h) = self._pagesize |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
359 |
if not Rect: |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
360 |
Rect = (0,0,w,h) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
361 |
if not InkList: |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
362 |
InkList = ( (100,100,100,h-100,w-100,h-100,w-100,100), ) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
363 |
annotation = apply(pdfdoc.InkAnnotation, (Rect, contents, InkList), kw) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
364 |
self.addAnnotation(annotation, name, addtopage) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
365 |
|
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
366 |
def linkAbsolute(self, contents, destinationname, Rect=None, addtopage=1, name=None, **kw): |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
367 |
"""link annotation positioned wrt the default user space""" |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
368 |
destination = self._bookmarkReference(destinationname) # permitted to be undefined... must bind later... |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
369 |
(w,h) = self._pagesize |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
370 |
if not Rect: |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
371 |
Rect = (0,0,w,h) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
372 |
kw["Rect"] = Rect |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
373 |
kw["Contents"] = contents |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
374 |
kw["Destination"] = destination |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
375 |
annotation = apply(pdfdoc.LinkAnnotation, (), kw) |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
376 |
self._addAnnotation(annotation, name, addtopage) |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
377 |
|
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
378 |
def _addAnnotation(self, annotation, name=None, addtopage=1): |
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
379 |
count = self._annotationCount = self._annotationCount+1 |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
380 |
if not name: name="NUMBER"+repr(count) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
381 |
self._doc.addAnnotation(name, annotation) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
382 |
if addtopage: |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
383 |
self._annotatePage(name) |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
384 |
|
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
385 |
def _annotatePage(self, name): |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
386 |
ref = self._doc.refAnnotation(name) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
387 |
self._annotationrefs.append(ref) |
0 | 388 |
|
389 |
def getPageNumber(self): |
|
390 |
return self._pageNumber |
|
391 |
||
392 |
def save(self): |
|
393 |
"""Saves the file. If holding data, do |
|
394 |
a showPage() to save them having to.""" |
|
395 |
if len(self._code): |
|
396 |
self.showPage() |
|
397 |
self._doc.SaveToFile(self._filename) |
|
398 |
print 'saved', self._filename |
|
399 |
||
400 |
def setPageSize(self, size): |
|
401 |
"""accepts a 2-tuple in points for paper size for this |
|
402 |
and subsequent pages""" |
|
403 |
self._pagesize = size |
|
20 | 404 |
self._make_preamble() |
0 | 405 |
|
406 |
def addLiteral(self, s, escaped=1): |
|
407 |
if escaped==0: |
|
408 |
s = self._escape(s) |
|
409 |
self._code.append(s) |
|
410 |
||
411 |
||
412 |
###################################################################### |
|
413 |
# |
|
414 |
# coordinate transformations |
|
415 |
# |
|
416 |
###################################################################### |
|
417 |
||
418 |
||
419 |
def transform(self, a,b,c,d,e,f): |
|
420 |
"""How can Python track this?""" |
|
421 |
a0,b0,c0,d0,e0,f0 = self._currentMatrix |
|
422 |
self._currentMatrix = (a0*a+c0*b, b0*a+d0*b, |
|
423 |
a0*c+c0*d, b0*c+d0*d, |
|
424 |
a0*e+c0*f+e0, b0*e+d0*f+f0) |
|
425 |
self._code.append('%0.2f %0.2f %0.2f %0.2f %0.2f %0.2f cm' % (a,b,c,d,e,f)) |
|
426 |
||
427 |
def translate(self, dx, dy): |
|
428 |
self.transform(1,0,0,1,dx,dy) |
|
429 |
||
430 |
def scale(self, x, y): |
|
431 |
self.transform(x,0,0,y,0,0) |
|
432 |
||
433 |
def rotate(self, theta): |
|
434 |
"""Canvas.rotate(theta) |
|
435 |
||
436 |
theta is in degrees.""" |
|
437 |
c = cos(theta * pi / 180) |
|
438 |
s = sin(theta * pi / 180) |
|
439 |
self.transform(c, s, -s, c, 0, 0) |
|
440 |
||
441 |
def skew(self, alpha, beta): |
|
442 |
tanAlpha = tan(alpha * pi / 180) |
|
443 |
tanBeta = tan(beta * pi / 180) |
|
444 |
self.transform(1, tanAlpha, tanBeta, 1, 0, 0) |
|
445 |
||
446 |
###################################################################### |
|
447 |
# |
|
448 |
# graphics state management |
|
449 |
# |
|
450 |
###################################################################### |
|
451 |
||
452 |
||
453 |
||
454 |
def saveState(self): |
|
455 |
"""These need expanding to save/restore Python's state tracking too""" |
|
456 |
self._code.append('q') |
|
457 |
||
458 |
def restoreState(self): |
|
459 |
"""These need expanding to save/restore Python's state tracking too""" |
|
460 |
self._code.append('Q') |
|
461 |
||
462 |
############################################################### |
|
463 |
# |
|
464 |
# Drawing methods. These draw things directly without |
|
465 |
# fiddling around with Path objects. We can add any geometry |
|
466 |
# methods we wish as long as their meaning is precise and |
|
467 |
# they are of general use. |
|
468 |
# |
|
469 |
# In general there are two patterns. Closed shapes |
|
470 |
# have the pattern shape(self, args, stroke=1, fill=0); |
|
471 |
# by default they draw an outline only. Line segments come |
|
472 |
# in three flavours: line, bezier, arc (which is a segment |
|
473 |
# of an elliptical arc, approximated by up to four bezier |
|
474 |
# curves, one for each quadrant. |
|
475 |
# |
|
476 |
# In the case of lines, we provide a 'plural' to unroll |
|
477 |
# the inner loop; it is useful for drawing big grids |
|
478 |
################################################################ |
|
479 |
||
480 |
||
481 |
#--------first the line drawing methods----------------------- |
|
482 |
def line(self, x1,y1, x2,y2): |
|
483 |
"As it says" |
|
484 |
self._code.append('n %0.2f %0.2f m %0.2f %0.2f l S' % (x1, y1, x2, y2)) |
|
485 |
||
486 |
def lines(self, linelist): |
|
487 |
"""As line(), but slightly more efficient for lots of them - |
|
488 |
one stroke operation and one less function call""" |
|
489 |
self._code.append('n') |
|
490 |
for (x1,y1,x2,y2) in linelist: |
|
491 |
self._code.append('%0.2f %0.2f m %0.2f %0.2f l' % (x1, y1, x2, y2)) |
|
492 |
self._code.append('S') |
|
493 |
||
494 |
def grid(self, xlist, ylist): |
|
495 |
"""Lays out a grid in current line style. Suuply list of |
|
496 |
x an y positions.""" |
|
497 |
assert len(xlist) > 1, "x coordinate list must have 2+ items" |
|
498 |
assert len(ylist) > 1, "y coordinate list must have 2+ items" |
|
499 |
lines = [] |
|
500 |
y0, y1 = ylist[0], ylist[-1] |
|
501 |
x0, x1 = xlist[0], xlist[-1] |
|
502 |
for x in xlist: |
|
503 |
lines.append(x,y0,x,y1) |
|
504 |
for y in ylist: |
|
505 |
lines.append(x0,y,x1,y) |
|
506 |
self.lines(lines) |
|
507 |
||
508 |
def bezier(self, x1, y1, x2, y2, x3, y3, x4, y4): |
|
509 |
"Bezier curve with the four given control points" |
|
510 |
self._code.append('n %0.2f %0.2f m %0.2f %0.2f %0.2f %0.2f %0.2f %0.2f c S' % |
|
511 |
(x1, y1, x2, y2, x3, y3, x4, y4) |
|
512 |
) |
|
513 |
def arc(self, x1,y1, x2,y2, startAng=0, extent=90): |
|
514 |
"""Contributed to piddlePDF by Robert Kern, 28/7/99. |
|
515 |
Trimmed down by AR to remove color stuff for pdfgen.canvas and |
|
516 |
revert to positive coordinates. |
|
517 |
||
518 |
Draw a partial ellipse inscribed within the rectangle x1,y1,x2,y2, |
|
519 |
starting at startAng degrees and covering extent degrees. Angles |
|
520 |
start with 0 to the right (+x) and increase counter-clockwise. |
|
521 |
These should have x1<x2 and y1<y2. |
|
522 |
||
523 |
The algorithm is an elliptical generalization of the formulae in |
|
524 |
Jim Fitzsimmon's TeX tutorial <URL: http://www.tinaja.com/bezarc1.pdf>.""" |
|
525 |
||
526 |
pointList = pdfgeom.bezierArc(x1,y1, x2,y2, startAng, extent) |
|
527 |
#move to first point |
|
528 |
self._code.append('n %0.2f %0.2f m' % pointList[0][:2]) |
|
529 |
for curve in pointList: |
|
530 |
self._code.append('%0.2f %0.2f %0.2f %0.2f %0.2f %0.2f c' % curve[2:]) |
|
531 |
# stroke |
|
532 |
self._code.append('S') |
|
533 |
||
534 |
#--------now the shape drawing methods----------------------- |
|
535 |
def rect(self, x, y, width, height, stroke=1, fill=0): |
|
536 |
"draws a rectangle" |
|
537 |
self._code.append('n %0.2f %0.2f %0.2f %0.2f re ' % (x, y, width, height) |
|
538 |
+ PATH_OPS[stroke, fill, self._fillMode]) |
|
539 |
||
540 |
||
541 |
def ellipse(self, x1, y1, x2, y2, stroke=1, fill=0): |
|
542 |
"""Uses bezierArc, which conveniently handles 360 degrees - |
|
543 |
nice touch Robert""" |
|
544 |
pointList = pdfgeom.bezierArc(x1,y1, x2,y2, 0, 360) |
|
545 |
#move to first point |
|
546 |
self._code.append('n %0.2f %0.2f m' % pointList[0][:2]) |
|
547 |
for curve in pointList: |
|
548 |
self._code.append('%0.2f %0.2f %0.2f %0.2f %0.2f %0.2f c' % curve[2:]) |
|
549 |
#finish |
|
550 |
self._code.append(PATH_OPS[stroke, fill, self._fillMode]) |
|
551 |
||
552 |
||
553 |
def wedge(self, x1,y1, x2,y2, startAng, extent, stroke=1, fill=0): |
|
554 |
"""Like arc, but connects to the centre of the ellipse. |
|
555 |
Most useful for pie charts and PacMan!""" |
|
556 |
||
557 |
x_cen = (x1+x2)/2. |
|
558 |
y_cen = (y1+y2)/2. |
|
559 |
pointList = pdfgeom.bezierArc(x1,y1, x2,y2, startAng, extent) |
|
560 |
||
561 |
self._code.append('n %0.2f %0.2f m' % (x_cen, y_cen)) |
|
562 |
# Move the pen to the center of the rectangle |
|
563 |
self._code.append('%0.2f %0.2f l' % pointList[0][:2]) |
|
564 |
for curve in pointList: |
|
565 |
self._code.append('%0.2f %0.2f %0.2f %0.2f %0.2f %0.2f c' % curve[2:]) |
|
566 |
# finish the wedge |
|
567 |
self._code.append('%0.2f %0.2f l ' % (x_cen, y_cen)) |
|
568 |
# final operator |
|
569 |
self._code.append(PATH_OPS[stroke, fill, self._fillMode]) |
|
570 |
||
571 |
def circle(self, x_cen, y_cen, r, stroke=1, fill=0): |
|
572 |
"""special case of ellipse""" |
|
573 |
||
574 |
x1 = x_cen - r |
|
575 |
x2 = x_cen + r |
|
576 |
y1 = y_cen - r |
|
577 |
y2 = y_cen + r |
|
578 |
self.ellipse(x1, y1, x2, y2, stroke, fill) |
|
579 |
||
580 |
def roundRect(self, x, y, width, height, radius, stroke=1, fill=0): |
|
581 |
"""Draws a rectangle with rounded corners. The corners are |
|
582 |
approximately quadrants of a circle, with the given radius.""" |
|
583 |
#use a precomputed set of factors for the bezier approximation |
|
584 |
#to a circle. There are six relevant points on the x axis and y axis. |
|
585 |
#sketch them and it should all make sense! |
|
586 |
t = 0.4472 * radius |
|
587 |
||
588 |
x0 = x |
|
589 |
x1 = x0 + t |
|
590 |
x2 = x0 + radius |
|
591 |
x3 = x0 + width - radius |
|
592 |
x4 = x0 + width - t |
|
593 |
x5 = x0 + width |
|
594 |
||
595 |
y0 = y |
|
596 |
y1 = y0 + t |
|
597 |
y2 = y0 + radius |
|
598 |
y3 = y0 + height - radius |
|
599 |
y4 = y0 + height - t |
|
600 |
y5 = y0 + height |
|
601 |
||
602 |
self._code.append('n %0.2f %0.2f m' % (x2, y0)) |
|
603 |
self._code.append('%0.2f %0.2f l' % (x3, y0)) # bottom row |
|
604 |
self._code.append('%0.2f %0.2f %0.2f %0.2f %0.2f %0.2f c' |
|
605 |
% (x4, y0, x5, y1, x5, y2)) # bottom right |
|
606 |
||
607 |
self._code.append('%0.2f %0.2f l' % (x5, y3)) # right edge |
|
608 |
self._code.append('%0.2f %0.2f %0.2f %0.2f %0.2f %0.2f c' |
|
609 |
% (x5, y4, x4, y5, x3, y5)) # top right |
|
610 |
||
611 |
self._code.append('%0.2f %0.2f l' % (x2, y5)) # top row |
|
612 |
self._code.append('%0.2f %0.2f %0.2f %0.2f %0.2f %0.2f c' |
|
613 |
% (x1, y5, x0, y4, x0, y3)) # top left |
|
614 |
||
615 |
self._code.append('%0.2f %0.2f l' % (x0, y2)) # left edge |
|
616 |
self._code.append('%0.2f %0.2f %0.2f %0.2f %0.2f %0.2f c' |
|
617 |
% (x0, y1, x1, y0, x2, y0)) # bottom left |
|
618 |
||
619 |
self._code.append('h') #close off, although it should be where it started anyway |
|
620 |
||
621 |
||
622 |
self._code.append(PATH_OPS[stroke, fill, self._fillMode]) |
|
623 |
################################################## |
|
624 |
# |
|
625 |
# Text methods |
|
626 |
# |
|
627 |
# As with graphics, a separate object ensures that |
|
628 |
# everything is bracketed between text operators. |
|
629 |
# The methods below are a high-level convenience. |
|
630 |
# use PDFTextObject for multi-line text. |
|
631 |
################################################## |
|
632 |
||
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
633 |
|
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
634 |
def setFillColorCMYK(self, c, m, y, k): |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
635 |
"""Takes 4 arguments between 0.0 and 1.0""" |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
636 |
self._fillColorCMYK = (c, m, y, k) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
637 |
self._code.append('%0.2f %0.2f %0.2f %0.2f k' % (c, m, y, k)) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
638 |
|
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
639 |
def setStrokeColorCMYK(self, c, m, y, k): |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
640 |
"""Takes 4 arguments between 0.0 and 1.0""" |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
641 |
self._strokeColorCMYK = (c, m, y, k) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
642 |
self._code.append('%0.2f %0.2f %0.2f %0.2f K' % (c, m, y, k)) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
643 |
|
0 | 644 |
def drawString(self, x, y, text): |
645 |
"""Draws a string in the current text styles.""" |
|
646 |
#we could inline this for speed if needed |
|
647 |
t = self.beginText(x, y) |
|
648 |
t.textLine(text) |
|
649 |
self.drawText(t) |
|
650 |
||
651 |
def drawRightString(self, x, y, text): |
|
652 |
"""Draws a string right-aligned with the y coordinate""" |
|
653 |
width = self.stringWidth(text, self._fontname, self._fontsize) |
|
654 |
t = self.beginText(x - width, y) |
|
655 |
t.textLine(text) |
|
656 |
self.drawText(t) |
|
657 |
||
658 |
def drawCentredString(self, x, y, text): |
|
659 |
"""Draws a string right-aligned with the y coordinate. I |
|
660 |
am British so the spelling is correct, OK?""" |
|
661 |
width = self.stringWidth(text, self._fontname, self._fontsize) |
|
662 |
t = self.beginText(x - 0.5*width, y) |
|
663 |
t.textLine(text) |
|
664 |
self.drawText(t) |
|
665 |
||
666 |
def getAvailableFonts(self): |
|
667 |
"""Returns the list of PostScript font names available. |
|
668 |
Standard set now, but may grow in future with font embedding.""" |
|
669 |
fontnames = self._doc.getAvailableFonts() |
|
670 |
fontnames.sort() |
|
671 |
return fontnames |
|
672 |
||
673 |
def setFont(self, psfontname, size, leading = None): |
|
674 |
"""Sets the font. If leading not specified, defaults to 1.2 x |
|
675 |
font size. Raises a readable exception if an illegal font |
|
676 |
is supplied. Font names are case-sensitive! Keeps track |
|
677 |
of font anme and size for metrics.""" |
|
678 |
self._fontname = psfontname |
|
679 |
self._fontsize = size |
|
680 |
pdffontname = self._doc.getInternalFontName(psfontname) |
|
681 |
if leading is None: |
|
682 |
leading = size * 1.2 |
|
683 |
self._leading = leading |
|
684 |
self._code.append('BT %s %0.1f Tf %0.1f TL ET' % (pdffontname, size, leading)) |
|
685 |
||
686 |
def stringWidth(self, text, fontname, fontsize): |
|
687 |
"gets width of a string in the given font and size" |
|
688 |
return pdfmetrics.stringwidth(text, fontname) * 0.001 * fontsize |
|
689 |
||
690 |
# basic graphics modes |
|
691 |
def setLineWidth(self, width): |
|
692 |
self._lineWidth = width |
|
693 |
self._code.append('%0.2f w' % width) |
|
694 |
||
695 |
def setLineCap(self, mode): |
|
696 |
"""0=butt,1=round,2=square""" |
|
697 |
assert mode in (0,1,2), "Line caps allowed: 0=butt,1=round,2=square" |
|
698 |
self._lineCap = mode |
|
699 |
self._code.append('%d J' % mode) |
|
700 |
||
701 |
def setLineJoin(self, mode): |
|
702 |
"""0=mitre, 1=round, 2=bevel""" |
|
703 |
assert mode in (0,1,2), "Line Joins allowed: 0=mitre, 1=round, 2=bevel" |
|
704 |
self._lineJoin = mode |
|
705 |
self._code.append('%d j' % mode) |
|
706 |
||
707 |
def setMiterLimit(self, limit): |
|
708 |
self._miterLimit = limit |
|
709 |
self._code.append('%0.2f M' % limit) |
|
710 |
||
711 |
def setDash(self, array=[], phase=0): |
|
712 |
"""Two notations. pass two numbers, or an array and phase""" |
|
713 |
if type(array) == IntType or type(array) == FloatType: |
|
714 |
self._code.append('[%s %s] 0 d' % (array, phase)) |
|
45 | 715 |
elif type(array) == ListType or type(array) == TupleType: |
0 | 716 |
assert phase <= len(array), "setDash phase must be l.t.e. length of array" |
717 |
textarray = string.join(map(str, array)) |
|
718 |
self._code.append('[%s] %s d' % (textarray, phase)) |
|
719 |
||
720 |
def setFillColorRGB(self, r, g, b): |
|
43
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
721 |
"""Takes 3 arguments between 0.0 and 1.0""" |
0 | 722 |
self._fillColorRGB = (r, g, b) |
723 |
self._code.append('%0.2f %0.2f %0.2f rg' % (r,g,b)) |
|
724 |
||
725 |
def setStrokeColorRGB(self, r, g, b): |
|
43
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
726 |
"""Takes 3 arguments between 0.0 and 1.0""" |
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
727 |
self._strokeColorRGB = (r, g, b) |
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
728 |
self._code.append('%0.2f %0.2f %0.2f RG' % (r,g,b)) |
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
729 |
|
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
730 |
def setFillColor(self, aColor): |
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
731 |
"""Takes a color object, allowing colors to be referred to by name""" |
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
732 |
r, g, b = aColor.red, aColor.green, aColor.blue |
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
733 |
self._strokeColorRGB = (r, g, b) |
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
734 |
self._code.append('%0.2f %0.2f %0.2f rg' % (r,g,b)) |
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
735 |
|
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
736 |
def setStrokeColor(self, aColor): |
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
737 |
"""Takes a color object, allowing colors to be referred to by name""" |
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
738 |
r, g, b = aColor.red, aColor.green, aColor.blue |
0 | 739 |
self._strokeColorRGB = (r, g, b) |
740 |
self._code.append('%0.2f %0.2f %0.2f RG' % (r,g,b)) |
|
27
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
741 |
|
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
742 |
def setFillGray(self, gray): |
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
743 |
"""Sets the gray level; 0.0=black, 1.0=white""" |
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
744 |
self._fillColorRGB = (gray, gray, gray) |
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
745 |
self._code.append('%0.2f g' % gray) |
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
746 |
|
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
747 |
def setStrokeGray(self, gray): |
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
748 |
"""Sets the gray level; 0.0=black, 1.0=white""" |
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
749 |
self._strokeColorRGB = (gray, gray, gray) |
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
750 |
self._code.append('%0.2f G' % gray) |
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
751 |
|
0 | 752 |
|
753 |
# path stuff - the separate path object builds it |
|
754 |
def beginPath(self): |
|
755 |
"""Returns a fresh path object""" |
|
756 |
return pathobject.PDFPathObject() |
|
757 |
||
758 |
def drawPath(self, aPath, stroke=1, fill=0): |
|
759 |
"Draw in the mode indicated" |
|
760 |
op = PATH_OPS[stroke, fill, self._fillMode] |
|
761 |
self._code.append(aPath.getCode() + ' ' + op) |
|
762 |
||
763 |
def clipPath(self, aPath, stroke=1, fill=0): |
|
764 |
"clip as well as drawing" |
|
765 |
op = PATH_OPS[stroke, fill, self._fillMode] |
|
766 |
self._code.append(aPath.getCode() + ' W ' + op) |
|
767 |
||
768 |
def beginText(self, x=0, y=0): |
|
769 |
"""Returns a fresh text object""" |
|
770 |
return textobject.PDFTextObject(self, x, y) |
|
771 |
||
772 |
def drawText(self, aTextObject): |
|
773 |
"""Draws a text object""" |
|
774 |
self._code.append(aTextObject.getCode()) |
|
775 |
||
776 |
###################################################### |
|
777 |
# |
|
778 |
# Image routines |
|
779 |
# |
|
780 |
###################################################### |
|
781 |
def drawInlineImage(self, image, x,y, width=None,height=None): |
|
33 | 782 |
"""Draw an Image into the specified rectangle. If width and |
0 | 783 |
height are omitted, they are calculated from the image size. |
784 |
Also allow file names as well as images. This allows a |
|
785 |
caching mechanism""" |
|
786 |
||
36 | 787 |
self._currentPageHasImages = 1 |
0 | 788 |
|
789 |
if type(image) == StringType: |
|
790 |
if os.path.splitext(image)[1] in ['.jpg', '.JPG']: |
|
33 | 791 |
#directly process JPEG files |
792 |
#open file, needs some error handling!! |
|
0 | 793 |
imageFile = open(image, 'rb') |
794 |
info = self.readJPEGInfo(imageFile) |
|
795 |
imgwidth, imgheight = info[0], info[1] |
|
796 |
if info[2] == 1: |
|
797 |
colorSpace = 'DeviceGray' |
|
798 |
elif info[2] == 3: |
|
799 |
colorSpace = 'DeviceRGB' |
|
800 |
else: #maybe should generate an error, is this right for CMYK? |
|
801 |
colorSpace = 'DeviceCMYK' |
|
802 |
imageFile.seek(0) #reset file pointer |
|
803 |
imagedata = [] |
|
804 |
imagedata.append('BI') # begin image |
|
805 |
# this describes what is in the image itself |
|
806 |
imagedata.append('/Width %0.2f /Height %0.2f' %(info[0], info[1])) |
|
807 |
imagedata.append('/BitsPerComponent 8') |
|
808 |
imagedata.append('/ColorSpace /%s' % colorSpace) |
|
809 |
imagedata.append('/Filter [ /ASCII85Decode /DCTDecode]') |
|
810 |
imagedata.append('ID') |
|
811 |
#write in blocks of (??) 60 characters per line to a list |
|
812 |
compressed = imageFile.read() |
|
813 |
encoded = pdfutils._AsciiBase85Encode(compressed) |
|
814 |
outstream = cStringIO.StringIO(encoded) |
|
815 |
dataline = outstream.read(60) |
|
816 |
while dataline <> "": |
|
817 |
imagedata.append(dataline) |
|
818 |
dataline = outstream.read(60) |
|
819 |
imagedata.append('EI') |
|
820 |
else: |
|
821 |
if not pdfutils.cachedImageExists(image): |
|
33 | 822 |
try: |
823 |
import Image |
|
824 |
except ImportError: |
|
825 |
print 'Python Imaging Library not available' |
|
826 |
return |
|
827 |
try: |
|
828 |
import zlib |
|
829 |
except ImportError: |
|
830 |
print 'zlib not available' |
|
831 |
return |
|
0 | 832 |
pdfutils.cacheImageFile(image) |
33 | 833 |
|
0 | 834 |
#now we have one cached, slurp it in |
835 |
cachedname = os.path.splitext(image)[0] + '.a85' |
|
836 |
imagedata = open(cachedname,'rb').readlines() |
|
837 |
#trim off newlines... |
|
838 |
imagedata = map(string.strip, imagedata) |
|
839 |
||
840 |
#parse line two for width, height |
|
841 |
words = string.split(imagedata[1]) |
|
842 |
imgwidth = string.atoi(words[1]) |
|
843 |
imgheight = string.atoi(words[3]) |
|
844 |
else: |
|
845 |
#PIL Image |
|
846 |
#work out all dimensions |
|
33 | 847 |
try: |
848 |
import zlib |
|
849 |
except ImportError: |
|
850 |
print 'zlib not available' |
|
851 |
return |
|
0 | 852 |
myimage = image.convert('RGB') |
853 |
imgwidth, imgheight = myimage.size |
|
854 |
imagedata = [] |
|
855 |
imagedata.append('BI') # begin image |
|
856 |
||
857 |
# this describes what is in the image itself |
|
858 |
imagedata.append('/W %0.2f /H %0.2f /BPC 8 /CS /RGB /F [/A85 /Fl]' % (imgwidth, imgheight)) |
|
859 |
imagedata.append('ID') |
|
860 |
||
861 |
#use a flate filter and Ascii Base 85 to compress |
|
862 |
raw = myimage.tostring() |
|
863 |
assert(len(raw) == imgwidth * imgheight, "Wrong amount of data for image") |
|
864 |
compressed = zlib.compress(raw) #this bit is very fast... |
|
865 |
encoded = pdfutils._AsciiBase85Encode(compressed) #...sadly this isn't |
|
866 |
||
867 |
#write in blocks of (??) 60 characters per line to a list |
|
868 |
outstream = cStringIO.StringIO(encoded) |
|
869 |
dataline = outstream.read(60) |
|
870 |
while dataline <> "": |
|
871 |
imagedata.append(dataline) |
|
872 |
dataline = outstream.read(60) |
|
873 |
imagedata.append('EI') |
|
874 |
||
875 |
#now build the PDF for the image. |
|
876 |
if not width: |
|
877 |
width = imgwidth |
|
878 |
if not height: |
|
879 |
height = imgheight |
|
880 |
||
881 |
# this says where and how big to draw it |
|
882 |
#self._code.append('ET') |
|
883 |
#self._code.append('q %0.2f 0 0 %0.2f %0.2f %0.2f cm' % (width, height, x, y+height)) |
|
884 |
if self.bottomup: |
|
885 |
self._code.append('q %0.2f 0 0 %0.2f %0.2f %0.2f cm' % (width, height, x, y)) |
|
886 |
else: |
|
887 |
self._code.append('q %0.2f 0 0 %0.2f %0.2f %0.2f cm' % (width, height, x, y+height)) |
|
28 | 888 |
|
889 |
# self._code.extend(imagedata) if >=python-1.5.2 |
|
890 |
for line in imagedata: |
|
891 |
self._code.append(line) |
|
892 |
||
0 | 893 |
self._code.append('Q') |
894 |
#self._code.append('BT') |
|
895 |
||
896 |
######################################################################### |
|
897 |
# |
|
898 |
# JPEG processing code - contributed by Eric Johnson |
|
899 |
# |
|
900 |
######################################################################### |
|
901 |
||
902 |
# Read data from the JPEG file. We should probably be using PIL to |
|
903 |
# get this information for us -- but this way is more fun! |
|
904 |
# Returns (width, height, color components) as a triple |
|
905 |
# This is based on Thomas Merz's code from GhostScript (viewjpeg.ps) |
|
906 |
def readJPEGInfo(self, image): |
|
907 |
"Read width, height and number of components from JPEG file" |
|
908 |
import struct |
|
909 |
||
910 |
#Acceptable JPEG Markers: |
|
911 |
# SROF0=baseline, SOF1=extended sequential or SOF2=progressive |
|
912 |
validMarkers = [0xC0, 0xC1, 0xC2] |
|
913 |
||
914 |
#JPEG markers without additional parameters |
|
915 |
noParamMarkers = \ |
|
916 |
[ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0x01 ] |
|
917 |
||
918 |
#Unsupported JPEG Markers |
|
919 |
unsupportedMarkers = \ |
|
920 |
[ 0xC3, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCD, 0xCE, 0xCF ] |
|
921 |
||
922 |
#read JPEG marker segments until we find SOFn marker or EOF |
|
923 |
done = 0 |
|
924 |
while not done: |
|
925 |
x = struct.unpack('B', image.read(1)) |
|
926 |
if x[0] == 0xFF: #found marker |
|
927 |
x = struct.unpack('B', image.read(1)) |
|
928 |
#print "Marker: ", '%0.2x' % x[0] |
|
929 |
#check marker type is acceptable and process it |
|
930 |
if x[0] in validMarkers: |
|
931 |
image.seek(2, 1) #skip segment length |
|
932 |
x = struct.unpack('B', image.read(1)) #data precision |
|
933 |
if x[0] != 8: |
|
934 |
raise 'PDFError', ' JPEG must have 8 bits per component' |
|
935 |
y = struct.unpack('BB', image.read(2)) |
|
936 |
height = (y[0] << 8) + y[1] |
|
937 |
y = struct.unpack('BB', image.read(2)) |
|
938 |
width = (y[0] << 8) + y[1] |
|
939 |
y = struct.unpack('B', image.read(1)) |
|
940 |
color = y[0] |
|
941 |
return width, height, color |
|
942 |
done = 1 |
|
943 |
elif x[0] in unsupportedMarkers: |
|
944 |
raise 'PDFError', ' Unsupported JPEG marker: %0.2x' % x[0] |
|
945 |
elif x[0] not in noParamMarkers: |
|
946 |
#skip segments with parameters |
|
947 |
#read length and skip the data |
|
948 |
x = struct.unpack('BB', image.read(2)) |
|
949 |
image.seek( (x[0] << 8) + x[1] - 2, 1) |
|
950 |
||
951 |
def setPageCompression(self, onoff=1): |
|
952 |
"""Possible values 1 or 0 (1 for 'on' is the default). |
|
953 |
If on, the page data will be compressed, leading to much |
|
954 |
smaller files, but takes a little longer to create the files. |
|
955 |
This applies to all subsequent pages, or until setPageCompression() |
|
956 |
is next called.""" |
|
957 |
self._pageCompression = onoff |
|
958 |
||
959 |
||
960 |
def setPageTransition(self, effectname=None, duration=1, |
|
961 |
direction=0,dimension='H',motion='I'): |
|
962 |
"""PDF allows page transition effects for use when giving |
|
963 |
presentations. There are six possible effects. You can |
|
964 |
just guive the effect name, or supply more advanced options |
|
965 |
to refine the way it works. There are three types of extra |
|
966 |
argument permitted, and here are the allowed values: |
|
967 |
direction_arg = [0,90,180,270] |
|
968 |
dimension_arg = ['H', 'V'] |
|
969 |
motion_arg = ['I','O'] (start at inside or outside) |
|
970 |
||
971 |
This table says which ones take which arguments: |
|
972 |
||
973 |
PageTransitionEffects = { |
|
974 |
'Split': [direction_arg, motion_arg], |
|
975 |
'Blinds': [dimension_arg], |
|
976 |
'Box': [motion_arg], |
|
977 |
'Wipe' : [direction_arg], |
|
978 |
'Dissolve' : [], |
|
979 |
'Glitter':[direction_arg] |
|
980 |
} |
|
981 |
Have fun! |
|
982 |
""" |
|
983 |
if not effectname: |
|
984 |
self._pageTransitionString = '' |
|
985 |
return |
|
986 |
||
987 |
#first check each optional argument has an allowed value |
|
988 |
if direction in [0,90,180,270]: |
|
989 |
direction_arg = '/Di /%d' % direction |
|
990 |
else: |
|
991 |
raise 'PDFError', ' directions allowed are 0,90,180,270' |
|
992 |
||
993 |
if dimension in ['H', 'V']: |
|
994 |
dimension_arg = '/Dm /%s' % dimension |
|
995 |
else: |
|
996 |
raise'PDFError','dimension values allowed are H and V' |
|
997 |
||
998 |
if motion in ['I','O']: |
|
999 |
motion_arg = '/M /%s' % motion |
|
1000 |
else: |
|
1001 |
raise'PDFError','motion values allowed are I and O' |
|
1002 |
||
1003 |
||
1004 |
# this says which effects require which argument types from above |
|
1005 |
PageTransitionEffects = { |
|
1006 |
'Split': [direction_arg, motion_arg], |
|
1007 |
'Blinds': [dimension_arg], |
|
1008 |
'Box': [motion_arg], |
|
1009 |
'Wipe' : [direction_arg], |
|
1010 |
'Dissolve' : [], |
|
1011 |
'Glitter':[direction_arg] |
|
1012 |
} |
|
1013 |
||
1014 |
try: |
|
1015 |
args = PageTransitionEffects[effectname] |
|
1016 |
except KeyError: |
|
1017 |
raise 'PDFError', 'Unknown Effect Name "%s"' % effectname |
|
1018 |
self._pageTransitionString = '' |
|
1019 |
return |
|
1020 |
||
1021 |
||
1022 |
self._pageTransitionString = (('/Trans <</D %d /S /%s ' % (duration, effectname)) + |
|
1023 |
string.join(args, ' ') + ' >>') |
|
1024 |
||
1025 |
if __name__ == '__main__': |
|
1026 |
print 'For test scripts, run testpdfgen.py' |