author | rgbecker |
Mon, 04 Sep 2000 08:06:15 +0000 | |
changeset 457 | d5c142f601c0 |
parent 455 | 3eb389710433 |
child 479 | e37604e2fcf9 |
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 $ |
|
457 | 34 |
# Revision 1.51 2000/09/04 08:06:15 rgbecker |
35 |
# Fix spurious comment reference to layout |
|
36 |
# |
|
455 | 37 |
# Revision 1.50 2000/09/01 12:13:26 rgbecker |
38 |
# Improved optimisation checks |
|
457 | 39 |
# |
453 | 40 |
# Revision 1.49 2000/08/31 23:34:36 rgbecker |
41 |
# Fix transform optimisation |
|
455 | 42 |
# |
437 | 43 |
# Revision 1.48 2000/08/20 21:39:50 andy_robinson |
44 |
# Changed an argument syntax for clarity |
|
453 | 45 |
# |
434
257af3109bf4
Various brutal changes to paragraph, canvas and textobject for speed/size
rgbecker
parents:
418
diff
changeset
|
46 |
# Revision 1.47 2000/08/17 15:50:36 rgbecker |
257af3109bf4
Various brutal changes to paragraph, canvas and textobject for speed/size
rgbecker
parents:
418
diff
changeset
|
47 |
# Various brutal changes to paragraph, canvas and textobject for speed/size |
437 | 48 |
# |
418 | 49 |
# Revision 1.46 2000/08/01 11:28:33 rgbecker |
50 |
# Converted to using fp_str |
|
434
257af3109bf4
Various brutal changes to paragraph, canvas and textobject for speed/size
rgbecker
parents:
418
diff
changeset
|
51 |
# |
411 | 52 |
# Revision 1.45 2000/07/31 12:03:23 rgbecker |
53 |
# B Herzog fix to dimension formats |
|
418 | 54 |
# |
409 | 55 |
# Revision 1.44 2000/07/28 00:00:41 rgbecker |
56 |
# Bernhard herzog inspired fixes |
|
411 | 57 |
# |
313 | 58 |
# Revision 1.43 2000/06/30 15:27:55 rgbecker |
59 |
# Allow for non-caching of images |
|
409 | 60 |
# |
305 | 61 |
# Revision 1.42 2000/06/26 15:58:22 rgbecker |
62 |
# Simple fix to widths problem |
|
313 | 63 |
# |
262 | 64 |
# Revision 1.41 2000/06/09 16:18:19 andy_robinson |
65 |
# Doc strings, sequencer |
|
305 | 66 |
# |
260 | 67 |
# Revision 1.40 2000/06/09 01:45:22 aaron_watters |
68 |
# Lots of documentation additions and changes. |
|
262 | 69 |
# |
253 | 70 |
# Revision 1.39 2000/06/01 15:23:06 rgbecker |
71 |
# Platypus re-organisation |
|
260 | 72 |
# |
247 | 73 |
# Revision 1.38 2000/05/26 09:44:40 rgbecker |
74 |
# generalised colors slightly |
|
253 | 75 |
# |
240
022c939a6d55
Preformatted objects now know how to split themselves.
andy_robinson
parents:
232
diff
changeset
|
76 |
# Revision 1.37 2000/05/23 14:06:45 andy_robinson |
022c939a6d55
Preformatted objects now know how to split themselves.
andy_robinson
parents:
232
diff
changeset
|
77 |
# Preformatted objects now know how to split themselves. |
247 | 78 |
# |
232
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
79 |
# Revision 1.36 2000/05/18 17:11:12 aaron_watters |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
80 |
# removed 0's on stable linkage and outline operations. |
240
022c939a6d55
Preformatted objects now know how to split themselves.
andy_robinson
parents:
232
diff
changeset
|
81 |
# |
228 | 82 |
# Revision 1.35 2000/05/18 09:05:08 andy_robinson |
83 |
# Resynchronization |
|
232
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
84 |
# |
181
62d7a443cbc4
Added font encoding support and changed default encoding to WinAnsi
andy_robinson
parents:
179
diff
changeset
|
85 |
# Revision 1.34 2000/04/28 17:33:44 andy_robinson |
62d7a443cbc4
Added font encoding support and changed default encoding to WinAnsi
andy_robinson
parents:
179
diff
changeset
|
86 |
# Added font encoding support and changed default encoding to WinAnsi |
228 | 87 |
# |
179 | 88 |
# Revision 1.33 2000/04/28 14:18:16 rgbecker |
89 |
# Use str(filename) not '<Unknown>' |
|
181
62d7a443cbc4
Added font encoding support and changed default encoding to WinAnsi
andy_robinson
parents:
179
diff
changeset
|
90 |
# |
177
13d1fe68a5ce
Fix verbose filename print when it's actually a file type object
rgbecker
parents:
176
diff
changeset
|
91 |
# Revision 1.32 2000/04/28 13:37:40 rgbecker |
13d1fe68a5ce
Fix verbose filename print when it's actually a file type object
rgbecker
parents:
176
diff
changeset
|
92 |
# Fix verbose filename print when it's actually a file type object |
179 | 93 |
# |
176 | 94 |
# Revision 1.31 2000/04/28 09:10:20 rgbecker |
95 |
# Changed zlib error handling |
|
177
13d1fe68a5ce
Fix verbose filename print when it's actually a file type object
rgbecker
parents:
176
diff
changeset
|
96 |
# |
166 | 97 |
# Revision 1.30 2000/04/25 20:20:13 aaron_watters |
98 |
# Added support for closed outline entries |
|
176 | 99 |
# |
139
6369f06cf280
eliminated inForm/inPage apis in favor of only beginForm..endForm
aaron_watters
parents:
136
diff
changeset
|
100 |
# Revision 1.29 2000/04/18 19:52:35 aaron_watters |
6369f06cf280
eliminated inForm/inPage apis in favor of only beginForm..endForm
aaron_watters
parents:
136
diff
changeset
|
101 |
# eliminated inForm/inPage apis in favor of only beginForm..endForm |
6369f06cf280
eliminated inForm/inPage apis in favor of only beginForm..endForm
aaron_watters
parents:
136
diff
changeset
|
102 |
# (page mode is automatically inferred when page-only operations are |
6369f06cf280
eliminated inForm/inPage apis in favor of only beginForm..endForm
aaron_watters
parents:
136
diff
changeset
|
103 |
# attempted...) |
166 | 104 |
# |
136 | 105 |
# Revision 1.28 2000/04/15 14:58:32 aaron_watters |
106 |
# Completed addOutlineEntry0 api |
|
139
6369f06cf280
eliminated inForm/inPage apis in favor of only beginForm..endForm
aaron_watters
parents:
136
diff
changeset
|
107 |
# |
127
44912033ce1b
Removed illegal append statement usage in canvas.grid()
andy_robinson
parents:
117
diff
changeset
|
108 |
# Revision 1.27 2000/04/14 11:28:32 andy_robinson |
44912033ce1b
Removed illegal append statement usage in canvas.grid()
andy_robinson
parents:
117
diff
changeset
|
109 |
# Removed illegal append statement usage in canvas.grid() |
136 | 110 |
# |
117 | 111 |
# Revision 1.26 2000/04/12 16:26:51 rgbecker |
112 |
# XML Tagged Paragraph parser changes |
|
127
44912033ce1b
Removed illegal append statement usage in canvas.grid()
andy_robinson
parents:
117
diff
changeset
|
113 |
# |
100
b98a1487daad
Color methods in textobject and canvas now synchronised.
andy_robinson
parents:
77
diff
changeset
|
114 |
# Revision 1.25 2000/04/10 09:21:21 andy_robinson |
b98a1487daad
Color methods in textobject and canvas now synchronised.
andy_robinson
parents:
77
diff
changeset
|
115 |
# Color methods in textobject and canvas now synchronised. |
b98a1487daad
Color methods in textobject and canvas now synchronised.
andy_robinson
parents:
77
diff
changeset
|
116 |
# Added 'verbosity' keyword to allow hiding of 'save myfile.pdf' messages. |
117 | 117 |
# |
77
a5d452cb7a5d
Removed some old comments; tweaks to experimental Outline methods.
andy_robinson
parents:
70
diff
changeset
|
118 |
# Revision 1.24 2000/04/06 09:52:02 andy_robinson |
a5d452cb7a5d
Removed some old comments; tweaks to experimental Outline methods.
andy_robinson
parents:
70
diff
changeset
|
119 |
# Removed some old comments; tweaks to experimental Outline methods. |
100
b98a1487daad
Color methods in textobject and canvas now synchronised.
andy_robinson
parents:
77
diff
changeset
|
120 |
# |
70 | 121 |
# Revision 1.23 2000/04/05 16:26:36 rgbecker |
122 |
# Fixes to setFill/StrokeColor |
|
77
a5d452cb7a5d
Removed some old comments; tweaks to experimental Outline methods.
andy_robinson
parents:
70
diff
changeset
|
123 |
# |
69 | 124 |
# Revision 1.22 2000/04/05 16:21:02 rgbecker |
125 |
# Added _SeqTypes for efficiency |
|
70 | 126 |
# |
68 | 127 |
# Revision 1.21 2000/04/05 16:15:11 rgbecker |
128 |
# Made setFill/StrokeColor polymorphic |
|
69 | 129 |
# |
64
568049c4a12f
Using trailing zero convention for new form and link API
andy_robinson
parents:
60
diff
changeset
|
130 |
# Revision 1.20 2000/04/03 09:36:15 andy_robinson |
568049c4a12f
Using trailing zero convention for new form and link API
andy_robinson
parents:
60
diff
changeset
|
131 |
# Using trailing zero convention for new form and link API |
68 | 132 |
# |
60 | 133 |
# Revision 1.19 2000/04/02 02:53:49 aaron_watters |
134 |
# added support for outline trees |
|
64
568049c4a12f
Using trailing zero convention for new form and link API
andy_robinson
parents:
60
diff
changeset
|
135 |
# |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
136 |
# 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
|
137 |
# added beginForm..endForm and fixed some naming convention issues. |
60 | 138 |
# |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
139 |
# Revision 1.17 2000/03/24 21:02:21 aaron_watters |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
140 |
# added support for destinations, forms, linkages |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
141 |
# |
45 | 142 |
# Revision 1.15 2000/03/10 21:46:04 andy_robinson |
143 |
# fixed typo in setDash |
|
48 | 144 |
# |
43
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
145 |
# 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
|
146 |
# 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
|
147 |
# which accepts color objects directly. |
45 | 148 |
# |
36 | 149 |
# Revision 1.13 2000/03/06 20:06:36 rgbecker |
150 |
# Typo self._currentPageHasImages = 1 |
|
43
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
151 |
# |
33 | 152 |
# Revision 1.12 2000/03/02 12:58:58 rgbecker |
153 |
# Remove over officious import checks Imag/zlib |
|
36 | 154 |
# |
28 | 155 |
# Revision 1.11 2000/03/02 10:28:54 rgbecker |
156 |
# [].extend illegal in 1.5.1 |
|
33 | 157 |
# |
27
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
158 |
# 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
|
159 |
# Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1 |
28 | 160 |
# |
26
ee96702d3008
Removed some constants which are no longer used.
andy_robinson
parents:
21
diff
changeset
|
161 |
# 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
|
162 |
# |
26
ee96702d3008
Removed some constants which are no longer used.
andy_robinson
parents:
21
diff
changeset
|
163 |
# 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
|
164 |
# |
21 | 165 |
# Revision 1.8 2000/02/20 14:43:27 rgbecker |
166 |
# _currentPageHasImages = 0 in init |
|
26
ee96702d3008
Removed some constants which are no longer used.
andy_robinson
parents:
21
diff
changeset
|
167 |
# |
20 | 168 |
# Revision 1.7 2000/02/20 11:08:56 rgbecker |
169 |
# Canvas.setPageSize fix |
|
21 | 170 |
# |
18 | 171 |
# Revision 1.6 2000/02/17 15:26:28 rgbecker |
172 |
# Change page compression default |
|
20 | 173 |
# |
16 | 174 |
# Revision 1.5 2000/02/17 02:08:04 rgbecker |
175 |
# Docstring & other fixes |
|
18 | 176 |
# |
10 | 177 |
# Revision 1.4 2000/02/16 09:42:50 rgbecker |
178 |
# Conversion to reportlab package |
|
16 | 179 |
# |
7 | 180 |
# Revision 1.3 2000/02/15 17:55:59 rgbecker |
181 |
# License text fixes |
|
10 | 182 |
# |
6 | 183 |
# Revision 1.2 2000/02/15 15:47:09 rgbecker |
184 |
# Added license, __version__ and Logi comment |
|
7 | 185 |
# |
457 | 186 |
__version__=''' $Id: canvas.py,v 1.51 2000/09/04 08:06:15 rgbecker Exp $ ''' |
16 | 187 |
__doc__=""" |
0 | 188 |
PDFgen is a library to generate PDF files containing text and graphics. It is the |
189 |
foundation for a complete reporting solution in Python. It is also the |
|
190 |
foundation for piddlePDF, the PDF back end for PIDDLE. |
|
191 |
||
192 |
Documentation is a little slim right now; run then look at testpdfgen.py |
|
193 |
to get a clue. |
|
194 |
||
6 | 195 |
Progress Reports: |
196 |
8.83, 2000-01-13, gmcm: |
|
197 |
Packagizing: |
|
198 |
renamed from pdfgen.py to canvas.py |
|
199 |
broke out PDFTextObject to textobject.py |
|
200 |
broke out PDFPathObject to pathobject.py |
|
0 | 201 |
placed all three in a package directory named pdfgen |
202 |
0.82, 1999-10-27, AR: |
|
203 |
Fixed some bugs on printing to Postscript. Added 'Text Object' |
|
204 |
analogous to Path Object to control entry and exit from text mode. |
|
205 |
Much simpler clipping API. All verified to export Postscript and |
|
206 |
redistill. |
|
207 |
One limitation still - clipping to text paths is fine in Acrobat |
|
208 |
but not in Postscript (any level) |
|
209 |
||
210 |
0.81,1999-10-13, AR: |
|
211 |
Adding RoundRect; changed all format strings to use %0.2f instead of %s, |
|
212 |
so we don't get exponentials in the output. |
|
213 |
0.8,1999-10-07, AR: all changed! |
|
214 |
""" |
|
215 |
## 0.81 1999-10-13: |
|
216 |
## |
|
217 |
## |
|
218 |
## |
|
219 |
import os |
|
220 |
import sys |
|
221 |
import string |
|
222 |
import time |
|
223 |
import tempfile |
|
224 |
import cStringIO |
|
225 |
from types import * |
|
226 |
from math import sin, cos, tan, pi, ceil |
|
227 |
||
10 | 228 |
from reportlab.pdfbase import pdfutils |
229 |
from reportlab.pdfbase import pdfdoc |
|
230 |
from reportlab.pdfbase import pdfmetrics |
|
16 | 231 |
from reportlab.pdfgen import pdfgeom, pathobject, textobject |
247 | 232 |
from reportlab.lib.colors import ColorType, toColor |
0 | 233 |
|
176 | 234 |
try: |
235 |
import zlib |
|
236 |
except ImportError: |
|
237 |
zlib = None |
|
238 |
||
418 | 239 |
from reportlab.lib.utils import fp_str |
69 | 240 |
_SeqTypes=(TupleType,ListType) |
241 |
||
0 | 242 |
# Robert Kern |
243 |
# Constants for closing paths. |
|
244 |
# May be useful if one changes 'arc' and 'rect' to take a |
|
245 |
# default argument that tells how to close the path. |
|
246 |
# That way we can draw filled shapes. |
|
247 |
||
248 |
FILL_EVEN_ODD = 0 |
|
249 |
FILL_NON_ZERO = 1 |
|
250 |
#this is used by path-closing routines. |
|
251 |
#map stroke, fill, fillmode -> operator |
|
252 |
# fillmode: 1 = non-Zero (obviously), 0 = evenOdd |
|
253 |
PATH_OPS = {(0, 0, FILL_EVEN_ODD) : 'n', #no op |
|
254 |
(0, 0, FILL_NON_ZERO) : 'n', #no op |
|
255 |
(1, 0, FILL_EVEN_ODD) : 'S', #stroke only |
|
256 |
(1, 0, FILL_NON_ZERO) : 'S', #stroke only |
|
257 |
(0, 1, FILL_EVEN_ODD) : 'f*', #Fill only |
|
258 |
(0, 1, FILL_NON_ZERO) : 'f', #Fill only |
|
259 |
(1, 1, FILL_EVEN_ODD) : 'B*', #Stroke and Fill |
|
260 |
(1, 1, FILL_NON_ZERO) : 'B', #Stroke and Fill |
|
261 |
} |
|
262 |
||
263 |
class Canvas: |
|
262 | 264 |
"""This class is the programmer's interface to the PDF file format. Methods |
265 |
are (or will be) provided here to do just about everything PDF can do. |
|
260 | 266 |
|
267 |
The underlying model to the canvas concept is that of a graphics state machine |
|
268 |
that at any given point in time has a current font, fill color (for figure |
|
269 |
interiors), stroke color (for figure borders), line width and geometric transform, among |
|
270 |
many other characteristics. |
|
271 |
||
272 |
Canvas methods generally either draw something (like canvas.line) using the |
|
273 |
current state of the canvas or change some component of the canvas |
|
274 |
state (like canvas.setFont). The current state can be saved and restored |
|
275 |
using the saveState/restoreState methods. |
|
276 |
||
277 |
Objects are "painted" in the order they are drawn so if, for example |
|
278 |
two rectangles overlap the last draw will appear "on top". PDF form |
|
279 |
objects (supported here) are used to draw complex drawings only once, |
|
280 |
for possible repeated use. |
|
281 |
||
282 |
There are other features of canvas which are not visible when printed, |
|
283 |
such as outlines and bookmarks which are used for navigating a document |
|
284 |
in a viewer. |
|
285 |
||
286 |
Here is a very silly example usage which generates a Hello World pdf document. |
|
287 |
||
288 |
from reportlab.pdfgen import canvas |
|
289 |
c = canvas.Canvas("hello.pdf") |
|
457 | 290 |
from reportlab.lib.units import inch |
260 | 291 |
# move the origin up and to the left |
292 |
c.translate(inch,inch) |
|
293 |
# define a large font |
|
294 |
c.setFont("Helvetica", 80) |
|
295 |
# choose some colors |
|
296 |
c.setStrokeColorRGB(0.2,0.5,0.3) |
|
297 |
c.setFillColorRGB(1,0,1) |
|
298 |
# draw a rectangle |
|
299 |
c.rect(inch,inch,6*inch,9*inch, fill=1) |
|
300 |
# make text go straight up |
|
301 |
c.rotate(90) |
|
302 |
# change color |
|
303 |
c.setFillColorRGB(0,0,0.77) |
|
304 |
# say hello (note after rotate the y coord needs to be negative!) |
|
305 |
c.drawString(3*inch, -3*inch, "Hello World") |
|
306 |
c.showPage() |
|
307 |
c.save() |
|
0 | 308 |
|
309 |
""" |
|
100
b98a1487daad
Color methods in textobject and canvas now synchronised.
andy_robinson
parents:
77
diff
changeset
|
310 |
def __init__(self,filename, |
b98a1487daad
Color methods in textobject and canvas now synchronised.
andy_robinson
parents:
77
diff
changeset
|
311 |
pagesize=(595.27,841.89), |
b98a1487daad
Color methods in textobject and canvas now synchronised.
andy_robinson
parents:
77
diff
changeset
|
312 |
bottomup = 1, |
b98a1487daad
Color methods in textobject and canvas now synchronised.
andy_robinson
parents:
77
diff
changeset
|
313 |
pageCompression=0, |
181
62d7a443cbc4
Added font encoding support and changed default encoding to WinAnsi
andy_robinson
parents:
179
diff
changeset
|
314 |
encoding=pdfdoc.DEFAULT_ENCODING, |
240
022c939a6d55
Preformatted objects now know how to split themselves.
andy_robinson
parents:
232
diff
changeset
|
315 |
verbosity=0): |
260 | 316 |
"""Create a canvas of a given size. etc. |
317 |
Most of the attributes are private - we will use set/get methods |
|
0 | 318 |
as the preferred interface. Default page size is A4.""" |
319 |
self._filename = filename |
|
181
62d7a443cbc4
Added font encoding support and changed default encoding to WinAnsi
andy_robinson
parents:
179
diff
changeset
|
320 |
|
62d7a443cbc4
Added font encoding support and changed default encoding to WinAnsi
andy_robinson
parents:
179
diff
changeset
|
321 |
self._doc = pdfdoc.PDFDocument(encoding) |
100
b98a1487daad
Color methods in textobject and canvas now synchronised.
andy_robinson
parents:
77
diff
changeset
|
322 |
|
b98a1487daad
Color methods in textobject and canvas now synchronised.
andy_robinson
parents:
77
diff
changeset
|
323 |
#this only controls whether it prints 'saved ...' - 0 disables |
b98a1487daad
Color methods in textobject and canvas now synchronised.
andy_robinson
parents:
77
diff
changeset
|
324 |
self._verbosity = verbosity |
181
62d7a443cbc4
Added font encoding support and changed default encoding to WinAnsi
andy_robinson
parents:
179
diff
changeset
|
325 |
|
62d7a443cbc4
Added font encoding support and changed default encoding to WinAnsi
andy_robinson
parents:
179
diff
changeset
|
326 |
|
0 | 327 |
self._pagesize = pagesize |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
328 |
#self._currentPageHasImages = 0 |
0 | 329 |
self._pageTransitionString = '' |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
330 |
self._destinations = {} # dictionary of destinations for cross indexing. |
0 | 331 |
|
176 | 332 |
self.setPageCompression(pageCompression) |
0 | 333 |
self._pageNumber = 1 # keep a count |
260 | 334 |
#self3 = [] #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
|
335 |
self._restartAccumulators() # restart all accumulation state (generalized, arw) |
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
336 |
self._annotationCount = 0 |
77
a5d452cb7a5d
Removed some old comments; tweaks to experimental Outline methods.
andy_robinson
parents:
70
diff
changeset
|
337 |
|
a5d452cb7a5d
Removed some old comments; tweaks to experimental Outline methods.
andy_robinson
parents:
70
diff
changeset
|
338 |
self._outlines = [] # list for a name tree |
0 | 339 |
|
340 |
#PostScript has the origin at bottom left. It is easy to achieve a top- |
|
341 |
#down coord system by translating to the top of the page and setting y |
|
342 |
#scale to -1, but then text is inverted. So self.bottomup is used |
|
343 |
#to also set the text matrix accordingly. You can now choose your |
|
344 |
#drawing coordinates. |
|
345 |
self.bottomup = bottomup |
|
20 | 346 |
self._make_preamble() |
0 | 347 |
|
348 |
#initial graphics state |
|
349 |
self._x = 0 |
|
350 |
self._y = 0 |
|
351 |
self._fontname = 'Times-Roman' |
|
352 |
self._fontsize = 12 |
|
353 |
self._textMode = 0 #track if between BT/ET |
|
354 |
self._leading = 14.4 |
|
355 |
self._currentMatrix = (1., 0., 0., 1., 0., 0.) |
|
356 |
self._fillMode = 0 #even-odd |
|
357 |
||
358 |
#text state |
|
359 |
self._charSpace = 0 |
|
360 |
self._wordSpace = 0 |
|
361 |
self._horizScale = 100 |
|
362 |
self._textRenderMode = 0 |
|
363 |
self._rise = 0 |
|
364 |
self._textLineMatrix = (1., 0., 0., 1., 0., 0.) |
|
365 |
self._textMatrix = (1., 0., 0., 1., 0., 0.) |
|
366 |
||
367 |
# line drawing |
|
368 |
self._lineCap = 0 |
|
369 |
self._lineJoin = 0 |
|
370 |
self._lineDash = None #not done |
|
371 |
self._lineWidth = 0 |
|
372 |
self._mitreLimit = 0 |
|
373 |
||
374 |
self._fillColorRGB = (0,0,0) |
|
375 |
self._strokeColorRGB = (0,0,0) |
|
376 |
||
20 | 377 |
def _make_preamble(self): |
378 |
if self.bottomup: |
|
379 |
#set initial font |
|
380 |
self._preamble = '1 0 0 1 0 0 cm BT /F9 12 Tf 14.4 TL ET' |
|
381 |
else: |
|
382 |
#switch coordinates, flip text and set font |
|
418 | 383 |
self._preamble = '1 0 0 -1 0 %s cm BT /F9 12 Tf 14.4 TL ET' % fp_str(self._pagesize[1]) |
20 | 384 |
|
0 | 385 |
def _escape(self, s): |
386 |
"""PDF escapes are like Python ones, but brackets need slashes before them too. |
|
387 |
Use Python's repr function and chop off the quotes first""" |
|
388 |
s = repr(s)[1:-1] |
|
389 |
s = string.replace(s, '(','\(') |
|
390 |
s = string.replace(s, ')','\)') |
|
391 |
return s |
|
392 |
||
393 |
#info functions - non-standard |
|
394 |
def setAuthor(self, author): |
|
260 | 395 |
"""identify the author for invisible embedding inside the PDF document. |
396 |
the author annotation will appear in the the text of the file but will |
|
397 |
not automatically be seen when the document is viewed.""" |
|
0 | 398 |
self._doc.setAuthor(author) |
77
a5d452cb7a5d
Removed some old comments; tweaks to experimental Outline methods.
andy_robinson
parents:
70
diff
changeset
|
399 |
|
232
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
400 |
def addOutlineEntry(self, title, key, level=0, closed=None): |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
401 |
"""Adds a new entry to the outline at given level. If LEVEL not specified, |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
402 |
entry goes at the top level. If level specified, it must be |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
403 |
no more than 1 greater than the outline level in the last call. |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
404 |
|
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
405 |
The key must be the (unique) name of a bookmark. |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
406 |
the title is the (non-unique) name to be displayed for the entry. |
136 | 407 |
|
166 | 408 |
If closed is set then the entry should show no subsections by default |
232
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
409 |
when displayed. |
166 | 410 |
|
136 | 411 |
Example |
232
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
412 |
c.addOutlineEntry("first section", "section1") |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
413 |
c.addOutlineEntry("introduction", "s1s1", 1, closed=1) |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
414 |
c.addOutlineEntry("body", "s1s2", 1) |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
415 |
c.addOutlineEntry("detail1", "s1s2s1", 2) |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
416 |
c.addOutlineEntry("detail2", "s1s2s2", 2) |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
417 |
c.addOutlineEntry("conclusion", "s1s3", 1) |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
418 |
c.addOutlineEntry("further reading", "s1s3s1", 2) |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
419 |
c.addOutlineEntry("second section", "section1") |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
420 |
c.addOutlineEntry("introduction", "s2s1", 1) |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
421 |
c.addOutlineEntry("body", "s2s2", 1, closed=1) |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
422 |
c.addOutlineEntry("detail1", "s2s2s1", 2) |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
423 |
c.addOutlineEntry("detail2", "s2s2s2", 2) |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
424 |
c.addOutlineEntry("conclusion", "s2s3", 1) |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
425 |
c.addOutlineEntry("further reading", "s2s3s1", 2) |
136 | 426 |
|
260 | 427 |
generated outline looks like |
428 |
- first section |
|
429 |
|- introduction |
|
430 |
|- body |
|
431 |
| |- detail1 |
|
432 |
| |- detail2 |
|
433 |
|- conclusion |
|
434 |
| |- further reading |
|
435 |
- second section |
|
436 |
|- introduction |
|
437 |
|+ body |
|
438 |
|- conclusion |
|
439 |
| |- further reading |
|
440 |
||
441 |
Note that the second "body" is closed. |
|
442 |
||
443 |
Note that you can jump from level 5 to level 3 but not |
|
136 | 444 |
from 3 to 5: instead you need to provide all intervening |
445 |
levels going down (4 in this case). Note that titles can |
|
446 |
collide but keys cannot. |
|
447 |
||
448 |
""" |
|
77
a5d452cb7a5d
Removed some old comments; tweaks to experimental Outline methods.
andy_robinson
parents:
70
diff
changeset
|
449 |
#to be completed |
136 | 450 |
#self._outlines.append(title) |
166 | 451 |
self._doc.outline.addOutlineEntry(key, level, title, closed=closed) |
77
a5d452cb7a5d
Removed some old comments; tweaks to experimental Outline methods.
andy_robinson
parents:
70
diff
changeset
|
452 |
|
0 | 453 |
|
232
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
454 |
def setOutlineNames0(self, *nametree): # keep this for now (?) |
60 | 455 |
"""nametree should can be a recursive tree like so |
456 |
c.setOutlineNames( |
|
457 |
"chapter1dest", |
|
458 |
("chapter2dest", |
|
459 |
["chapter2section1dest", |
|
460 |
"chapter2section2dest", |
|
461 |
"chapter2conclusiondest"] |
|
462 |
), # end of chapter2 description |
|
463 |
"chapter3dest", |
|
464 |
("chapter4dest", ["c4s1", "c4s2"]) |
|
465 |
) |
|
466 |
each of the string names inside must be bound to a bookmark |
|
467 |
before the document is generated. |
|
468 |
""" |
|
77
a5d452cb7a5d
Removed some old comments; tweaks to experimental Outline methods.
andy_robinson
parents:
70
diff
changeset
|
469 |
#print nametree |
60 | 470 |
apply(self._doc.outline.setNames, (self,)+nametree) |
471 |
||
0 | 472 |
def setTitle(self, title): |
260 | 473 |
"""write a title into the PDF file that won't automatically display |
474 |
in the document itself.""" |
|
0 | 475 |
self._doc.setTitle(title) |
476 |
||
477 |
def setSubject(self, subject): |
|
260 | 478 |
"""write a subject into the PDF file that won't automatically display |
479 |
in the document itself.""" |
|
0 | 480 |
self._doc.setSubject(subject) |
481 |
||
482 |
def pageHasData(self): |
|
483 |
"Info function - app can call it after showPage to see if it needs a save" |
|
484 |
return len(self._code) == 0 |
|
60 | 485 |
|
232
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
486 |
def showOutline(self): |
64
568049c4a12f
Using trailing zero convention for new form and link API
andy_robinson
parents:
60
diff
changeset
|
487 |
"Specify that Acrobat Reader should start with the outline tree visible" |
60 | 488 |
self._doc._catalog.showOutline() |
0 | 489 |
|
490 |
def showPage(self): |
|
260 | 491 |
"""Close the current page and possibly start on a new page.""" |
0 | 492 |
page = pdfdoc.PDFPage() |
493 |
page.pagewidth = self._pagesize[0] |
|
494 |
page.pageheight = self._pagesize[1] |
|
495 |
page.hasImages = self._currentPageHasImages |
|
496 |
page.pageTransitionString = self._pageTransitionString |
|
497 |
page.setCompression(self._pageCompression) |
|
498 |
#print stream |
|
499 |
page.setStream([self._preamble] + self._code) |
|
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
500 |
self._setXObjects(page) |
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
501 |
self._setAnnotations(page) |
0 | 502 |
self._doc.addPage(page) |
503 |
||
504 |
#now get ready for the next one |
|
505 |
self._pageNumber = self._pageNumber + 1 |
|
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
506 |
self._restartAccumulators() |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
507 |
|
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
508 |
def _setAnnotations(self,page): |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
509 |
page.Annots = self._annotationrefs |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
510 |
|
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
511 |
def _setXObjects(self, thing): |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
512 |
"""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
|
513 |
forms = self._formsinuse |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
514 |
if forms: |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
515 |
xobjectsdict = self._doc.xobjDict(forms) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
516 |
thing.XObjects = xobjectsdict |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
517 |
else: |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
518 |
thing.XObjects = None |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
519 |
|
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
520 |
def _bookmarkReference(self, name): |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
521 |
"""get a reference to a (possibly undefined, possibly unbound) bookmark""" |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
522 |
d = self._destinations |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
523 |
try: |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
524 |
return d[name] |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
525 |
except: |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
526 |
result = d[name] = pdfdoc.Destination(name) # newly defined, unbound |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
527 |
return result |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
528 |
|
437 | 529 |
def bookmarkPage(self, key): |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
530 |
"""bind a bookmark (destination) to the current page""" |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
531 |
# 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
|
532 |
# XXXX the other ways require tracking of the graphics state.... |
437 | 533 |
dest = self._bookmarkReference(key) |
139
6369f06cf280
eliminated inForm/inPage apis in favor of only beginForm..endForm
aaron_watters
parents:
136
diff
changeset
|
534 |
self._doc.inPage() # try to enable page-only features |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
535 |
pageref = self._doc.thisPageRef() |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
536 |
dest.fit() |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
537 |
dest.setPageRef(pageref) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
538 |
return dest |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
539 |
|
437 | 540 |
def bookmarkHorizontalAbsolute(self, key, yhorizontal): |
260 | 541 |
"""Bind a bookmark (destination) to the current page at a horizontal position. |
542 |
Note that the yhorizontal of the book mark is with respect to the default |
|
543 |
user space (where the origin is at the lower left corner of the page) |
|
544 |
and completely ignores any transform (translation, scale, skew, rotation, |
|
545 |
etcetera) in effect for the current graphics state. The programmer is |
|
546 |
responsible for making sure the bookmark matches an appropriate item on |
|
547 |
the page.""" |
|
437 | 548 |
dest = self._bookmarkReference(key) |
139
6369f06cf280
eliminated inForm/inPage apis in favor of only beginForm..endForm
aaron_watters
parents:
136
diff
changeset
|
549 |
self._doc.inPage() # try to enable page-only features |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
550 |
pageref = self._doc.thisPageRef() |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
551 |
dest.fith(yhorizontal) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
552 |
dest.setPageRef(pageref) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
553 |
return dest |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
554 |
|
139
6369f06cf280
eliminated inForm/inPage apis in favor of only beginForm..endForm
aaron_watters
parents:
136
diff
changeset
|
555 |
#def _inPage0(self): disallowed! |
6369f06cf280
eliminated inForm/inPage apis in favor of only beginForm..endForm
aaron_watters
parents:
136
diff
changeset
|
556 |
# """declare a page, enable page features""" |
6369f06cf280
eliminated inForm/inPage apis in favor of only beginForm..endForm
aaron_watters
parents:
136
diff
changeset
|
557 |
# self._doc.inPage() |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
558 |
|
139
6369f06cf280
eliminated inForm/inPage apis in favor of only beginForm..endForm
aaron_watters
parents:
136
diff
changeset
|
559 |
#def _inForm0(self): |
6369f06cf280
eliminated inForm/inPage apis in favor of only beginForm..endForm
aaron_watters
parents:
136
diff
changeset
|
560 |
# "deprecated in favore of beginForm...endForm" |
6369f06cf280
eliminated inForm/inPage apis in favor of only beginForm..endForm
aaron_watters
parents:
136
diff
changeset
|
561 |
# self._doc.inForm() |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
562 |
|
232
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
563 |
def doForm(self, name): |
260 | 564 |
"""use a form XObj in current operation stream. The form |
565 |
should have been defined previously using beginForm ... endForm. |
|
566 |
The form will be drawn within the context of the current graphics |
|
567 |
state.""" |
|
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
568 |
internalname = self._doc.hasForm(name) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
569 |
if not internalname: |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
570 |
raise ValueError, "form is not defined %s" % name |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
571 |
self._code.append("/%s Do" % internalname) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
572 |
self._formsinuse.append(name) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
573 |
|
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
574 |
def _restartAccumulators(self): |
0 | 575 |
self._code = [] # ready for more... |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
576 |
self._currentPageHasImages = 1 # for safety... |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
577 |
self._formsinuse = [] |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
578 |
self._annotationrefs = [] |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
579 |
self._formData = None |
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
580 |
|
232
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
581 |
def beginForm(self, name, lowerx=0, lowery=0, upperx=None, uppery=None): |
260 | 582 |
"""declare the current graphics stream to be a named form. |
583 |
A graphics stream can either be a page or a form, not both. |
|
584 |
Some operations (like bookmarking) are permitted for pages |
|
585 |
but not forms. The form will not automatically be shown in the |
|
586 |
document but must be explicitly referenced using doForm in pages |
|
587 |
that require the form.""" |
|
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
588 |
self._formData = (name, lowerx, lowery, upperx, uppery) |
139
6369f06cf280
eliminated inForm/inPage apis in favor of only beginForm..endForm
aaron_watters
parents:
136
diff
changeset
|
589 |
self._doc.inForm() |
6369f06cf280
eliminated inForm/inPage apis in favor of only beginForm..endForm
aaron_watters
parents:
136
diff
changeset
|
590 |
#self._inForm0() |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
591 |
|
232
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
592 |
def endForm(self): |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
593 |
"""emit the current collection of graphics operations as a Form |
260 | 594 |
as declared previously in beginForm.""" |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
595 |
(name, lowerx, lowery, upperx, uppery) = self._formData |
139
6369f06cf280
eliminated inForm/inPage apis in favor of only beginForm..endForm
aaron_watters
parents:
136
diff
changeset
|
596 |
#self.makeForm0(name, lowerx, lowery, upperx, uppery) |
6369f06cf280
eliminated inForm/inPage apis in favor of only beginForm..endForm
aaron_watters
parents:
136
diff
changeset
|
597 |
# fall through! makeForm0 disallowed |
6369f06cf280
eliminated inForm/inPage apis in favor of only beginForm..endForm
aaron_watters
parents:
136
diff
changeset
|
598 |
#def makeForm0(self, name, lowerx=0, lowery=0, upperx=None, uppery=None): |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
599 |
"""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
|
600 |
# deprecated in favor or beginForm(...)... endForm() |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
601 |
(w,h) = self._pagesize |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
602 |
if upperx is None: upperx=w |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
603 |
if uppery is None: uppery=h |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
604 |
form = pdfdoc.PDFFormXObject(lowerx=lowerx, lowery=lowery, upperx=upperx, uppery=uppery) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
605 |
form.compression = self._pageCompression |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
606 |
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
|
607 |
self._setXObjects(form) |
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
608 |
self._setAnnotations(form) |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
609 |
self._doc.addForm(name, form) |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
610 |
self._restartAccumulators() |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
611 |
|
232
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
612 |
#def forceCodeInsert0(self, code): |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
613 |
# """I know a whole lot about PDF and I want to add a bunch of code I know will work...""" |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
614 |
# self._code.append(code) |
136 | 615 |
|
64
568049c4a12f
Using trailing zero convention for new form and link API
andy_robinson
parents:
60
diff
changeset
|
616 |
def textAnnotation0(self, contents, Rect=None, addtopage=1, name=None, **kw): |
232
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
617 |
"""Experimental. |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
618 |
""" |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
619 |
if not Rect: |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
620 |
(w,h) = self._pagesize# default to whole page (?) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
621 |
Rect = (0,0,w,h) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
622 |
annotation = apply(pdfdoc.TextAnnotation, (Rect, contents), kw) |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
623 |
self._addAnnotation(annotation, name, addtopage) |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
624 |
|
64
568049c4a12f
Using trailing zero convention for new form and link API
andy_robinson
parents:
60
diff
changeset
|
625 |
def inkAnnotation0(self, contents, InkList=None, Rect=None, addtopage=1, name=None, **kw): |
232
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
626 |
"Experimental" |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
627 |
(w,h) = self._pagesize |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
628 |
if not Rect: |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
629 |
Rect = (0,0,w,h) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
630 |
if not InkList: |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
631 |
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
|
632 |
annotation = apply(pdfdoc.InkAnnotation, (Rect, contents, InkList), kw) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
633 |
self.addAnnotation(annotation, name, addtopage) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
634 |
|
232
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
635 |
def linkAbsolute(self, contents, destinationname, Rect=None, addtopage=1, name=None, **kw): |
260 | 636 |
"""rectangular link annotation positioned wrt the default user space. |
637 |
The identified rectangle on the page becomes a "hot link" which |
|
638 |
when clicked will send the viewer to the page and position identified |
|
639 |
by the destination. |
|
640 |
||
232
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
641 |
Rect identifies (lowerx, lowery, upperx, uppery) for lower left |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
642 |
and upperright points of the rectangle. Translations and other transforms |
260 | 643 |
are IGNORED (the rectangular position is given with respect |
644 |
to the default user space. |
|
232
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
645 |
destinationname should be the name of a bookmark (which may be defined later |
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
646 |
but must be defined before the document is generated). |
260 | 647 |
|
232
150d4caf48c7
removed 0's on stable linkage and outline operations.
aaron_watters
parents:
228
diff
changeset
|
648 |
You may want to use the keyword argument Border='[0 0 0]' to |
260 | 649 |
suppress the visible rectangle around the during viewing link.""" |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
650 |
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
|
651 |
(w,h) = self._pagesize |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
652 |
if not Rect: |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
653 |
Rect = (0,0,w,h) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
654 |
kw["Rect"] = Rect |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
655 |
kw["Contents"] = contents |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
656 |
kw["Destination"] = destination |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
657 |
annotation = apply(pdfdoc.LinkAnnotation, (), kw) |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
658 |
self._addAnnotation(annotation, name, addtopage) |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
659 |
|
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
660 |
def _addAnnotation(self, annotation, name=None, addtopage=1): |
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
661 |
count = self._annotationCount = self._annotationCount+1 |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
662 |
if not name: name="NUMBER"+repr(count) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
663 |
self._doc.addAnnotation(name, annotation) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
664 |
if addtopage: |
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
665 |
self._annotatePage(name) |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
666 |
|
54
9f1cadbf9728
added beginForm..endForm and fixed some naming convention issues.
aaron_watters
parents:
52
diff
changeset
|
667 |
def _annotatePage(self, name): |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
668 |
ref = self._doc.refAnnotation(name) |
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
669 |
self._annotationrefs.append(ref) |
0 | 670 |
|
671 |
def getPageNumber(self): |
|
260 | 672 |
"get the page number for the current page being generated." |
0 | 673 |
return self._pageNumber |
674 |
||
675 |
def save(self): |
|
260 | 676 |
"""Saves and close the PDF document in the file. |
677 |
If there is current data a ShowPage is executed automatically. |
|
678 |
After this operation the canvas must not be used further.""" |
|
0 | 679 |
if len(self._code): |
680 |
self.showPage() |
|
77
a5d452cb7a5d
Removed some old comments; tweaks to experimental Outline methods.
andy_robinson
parents:
70
diff
changeset
|
681 |
|
136 | 682 |
self._doc.SaveToFile(self._filename, self) |
100
b98a1487daad
Color methods in textobject and canvas now synchronised.
andy_robinson
parents:
77
diff
changeset
|
683 |
if self._verbosity > 0: |
177
13d1fe68a5ce
Fix verbose filename print when it's actually a file type object
rgbecker
parents:
176
diff
changeset
|
684 |
if type(self._filename)==StringType: |
13d1fe68a5ce
Fix verbose filename print when it's actually a file type object
rgbecker
parents:
176
diff
changeset
|
685 |
name = self._filename |
13d1fe68a5ce
Fix verbose filename print when it's actually a file type object
rgbecker
parents:
176
diff
changeset
|
686 |
else: |
13d1fe68a5ce
Fix verbose filename print when it's actually a file type object
rgbecker
parents:
176
diff
changeset
|
687 |
if hasattr(self._filename,'name'): |
13d1fe68a5ce
Fix verbose filename print when it's actually a file type object
rgbecker
parents:
176
diff
changeset
|
688 |
name = self._filename.name |
13d1fe68a5ce
Fix verbose filename print when it's actually a file type object
rgbecker
parents:
176
diff
changeset
|
689 |
else: |
179 | 690 |
name = str(filename) |
177
13d1fe68a5ce
Fix verbose filename print when it's actually a file type object
rgbecker
parents:
176
diff
changeset
|
691 |
print 'saved', name |
0 | 692 |
|
693 |
def setPageSize(self, size): |
|
694 |
"""accepts a 2-tuple in points for paper size for this |
|
695 |
and subsequent pages""" |
|
696 |
self._pagesize = size |
|
20 | 697 |
self._make_preamble() |
0 | 698 |
|
699 |
def addLiteral(self, s, escaped=1): |
|
260 | 700 |
"""introduce the literal text of PDF operations s into the current stream. |
701 |
Only use this if you are an expert in the PDF file format.""" |
|
0 | 702 |
if escaped==0: |
703 |
s = self._escape(s) |
|
704 |
self._code.append(s) |
|
705 |
||
706 |
||
707 |
###################################################################### |
|
708 |
# |
|
709 |
# coordinate transformations |
|
710 |
# |
|
711 |
###################################################################### |
|
712 |
||
713 |
||
714 |
def transform(self, a,b,c,d,e,f): |
|
260 | 715 |
"""adjoin a mathematical transform to the current graphics state matrix. |
716 |
Not recommended for beginners.""" |
|
717 |
#"""How can Python track this?""" |
|
434
257af3109bf4
Various brutal changes to paragraph, canvas and textobject for speed/size
rgbecker
parents:
418
diff
changeset
|
718 |
#a0,b0,c0,d0,e0,f0 = self._currentMatrix |
257af3109bf4
Various brutal changes to paragraph, canvas and textobject for speed/size
rgbecker
parents:
418
diff
changeset
|
719 |
#self._currentMatrix = (a0*a+c0*b, b0*a+d0*b, |
257af3109bf4
Various brutal changes to paragraph, canvas and textobject for speed/size
rgbecker
parents:
418
diff
changeset
|
720 |
# a0*c+c0*d, b0*c+d0*d, |
257af3109bf4
Various brutal changes to paragraph, canvas and textobject for speed/size
rgbecker
parents:
418
diff
changeset
|
721 |
# a0*e+c0*f+e0, b0*e+d0*f+f0) |
455 | 722 |
if self._code and self._code[-1][-3:]==' cm': |
434
257af3109bf4
Various brutal changes to paragraph, canvas and textobject for speed/size
rgbecker
parents:
418
diff
changeset
|
723 |
L = string.split(self._code[-1]) |
257af3109bf4
Various brutal changes to paragraph, canvas and textobject for speed/size
rgbecker
parents:
418
diff
changeset
|
724 |
a0, b0, c0, d0, e0, f0 = map(float,L[-7:-1]) |
257af3109bf4
Various brutal changes to paragraph, canvas and textobject for speed/size
rgbecker
parents:
418
diff
changeset
|
725 |
s = len(L)>7 and string.join(L)+ ' %s cm' or '%s cm' |
257af3109bf4
Various brutal changes to paragraph, canvas and textobject for speed/size
rgbecker
parents:
418
diff
changeset
|
726 |
self._code[-1] = s % fp_str(a0*a+c0*b,b0*a+d0*b,a0*c+c0*d,b0*c+d0*d,a0*e+c0*f+e0,b0*e+d0*f+f0) |
257af3109bf4
Various brutal changes to paragraph, canvas and textobject for speed/size
rgbecker
parents:
418
diff
changeset
|
727 |
else: |
257af3109bf4
Various brutal changes to paragraph, canvas and textobject for speed/size
rgbecker
parents:
418
diff
changeset
|
728 |
self._code.append('%s cm' % fp_str(a,b,c,d,e,f)) |
0 | 729 |
|
730 |
def translate(self, dx, dy): |
|
260 | 731 |
"""move the origin from the current (0,0) point to the (dx,dy) point |
732 |
(with respect to the current graphics state).""" |
|
0 | 733 |
self.transform(1,0,0,1,dx,dy) |
734 |
||
735 |
def scale(self, x, y): |
|
260 | 736 |
"""Scale the horizontal dimension by x and the vertical by y |
737 |
(with respect to the current graphics state). |
|
738 |
For example canvas.scale(2.0, 0.5) will make everything short and fat.""" |
|
0 | 739 |
self.transform(x,0,0,y,0,0) |
740 |
||
741 |
def rotate(self, theta): |
|
742 |
"""Canvas.rotate(theta) |
|
743 |
||
260 | 744 |
Rotate the canvas by the angle theta (in degrees).""" |
0 | 745 |
c = cos(theta * pi / 180) |
746 |
s = sin(theta * pi / 180) |
|
747 |
self.transform(c, s, -s, c, 0, 0) |
|
748 |
||
749 |
def skew(self, alpha, beta): |
|
750 |
tanAlpha = tan(alpha * pi / 180) |
|
751 |
tanBeta = tan(beta * pi / 180) |
|
752 |
self.transform(1, tanAlpha, tanBeta, 1, 0, 0) |
|
753 |
||
754 |
###################################################################### |
|
755 |
# |
|
756 |
# graphics state management |
|
757 |
# |
|
758 |
###################################################################### |
|
759 |
||
760 |
||
761 |
||
762 |
def saveState(self): |
|
260 | 763 |
"""Save the current graphics state to be restored later by restoreState. |
764 |
||
765 |
For example: |
|
766 |
canvas.setFont("Helvetica", 20) |
|
767 |
canvas.saveState() |
|
768 |
... |
|
409 | 769 |
canvas.setFont("Courier", 9) |
260 | 770 |
... |
771 |
canvas.restoreState() |
|
772 |
# if the save/restore pairs match then font is Helvetica 20 again. |
|
773 |
""" |
|
774 |
#"""These need expanding to save/restore Python's state tracking too""" |
|
0 | 775 |
self._code.append('q') |
776 |
||
777 |
def restoreState(self): |
|
260 | 778 |
"""restore the graphics state to the matching saved state (see saveState).""" |
779 |
#"""These need expanding to save/restore Python's state tracking too""" |
|
0 | 780 |
self._code.append('Q') |
781 |
||
782 |
############################################################### |
|
783 |
# |
|
784 |
# Drawing methods. These draw things directly without |
|
785 |
# fiddling around with Path objects. We can add any geometry |
|
786 |
# methods we wish as long as their meaning is precise and |
|
787 |
# they are of general use. |
|
788 |
# |
|
789 |
# In general there are two patterns. Closed shapes |
|
790 |
# have the pattern shape(self, args, stroke=1, fill=0); |
|
791 |
# by default they draw an outline only. Line segments come |
|
792 |
# in three flavours: line, bezier, arc (which is a segment |
|
793 |
# of an elliptical arc, approximated by up to four bezier |
|
794 |
# curves, one for each quadrant. |
|
795 |
# |
|
796 |
# In the case of lines, we provide a 'plural' to unroll |
|
797 |
# the inner loop; it is useful for drawing big grids |
|
798 |
################################################################ |
|
799 |
||
800 |
||
801 |
#--------first the line drawing methods----------------------- |
|
802 |
def line(self, x1,y1, x2,y2): |
|
260 | 803 |
"""draw a line segment from (x1,y1) to (x2,y2) (with color, thickness and |
804 |
other attributes determined by the current graphics state).""" |
|
418 | 805 |
self._code.append('n %s m %s l S' % (fp_str(x1, y1), fp_str(x2, y2))) |
0 | 806 |
|
807 |
def lines(self, linelist): |
|
260 | 808 |
"""Like line(), permits many lines to be drawn in one call. |
809 |
for example for the figure |
|
810 |
| |
|
811 |
-- -- |
|
812 |
| |
|
813 |
||
814 |
crosshairs = [(20,0,20,10), (20,30,20,40), (0,20,10,20), (30,20,40,20)] |
|
815 |
canvas.lines(crosshairs) |
|
816 |
""" |
|
0 | 817 |
self._code.append('n') |
818 |
for (x1,y1,x2,y2) in linelist: |
|
418 | 819 |
self._code.append('%s m %s l' % (fp_str(x1, y1), fp_str(x2, y2))) |
0 | 820 |
self._code.append('S') |
821 |
||
822 |
def grid(self, xlist, ylist): |
|
260 | 823 |
"""Lays out a grid in current line style. Supply list of |
0 | 824 |
x an y positions.""" |
825 |
assert len(xlist) > 1, "x coordinate list must have 2+ items" |
|
826 |
assert len(ylist) > 1, "y coordinate list must have 2+ items" |
|
827 |
lines = [] |
|
828 |
y0, y1 = ylist[0], ylist[-1] |
|
829 |
x0, x1 = xlist[0], xlist[-1] |
|
830 |
for x in xlist: |
|
127
44912033ce1b
Removed illegal append statement usage in canvas.grid()
andy_robinson
parents:
117
diff
changeset
|
831 |
lines.append((x,y0,x,y1)) |
0 | 832 |
for y in ylist: |
127
44912033ce1b
Removed illegal append statement usage in canvas.grid()
andy_robinson
parents:
117
diff
changeset
|
833 |
lines.append((x0,y,x1,y)) |
0 | 834 |
self.lines(lines) |
835 |
||
836 |
def bezier(self, x1, y1, x2, y2, x3, y3, x4, y4): |
|
837 |
"Bezier curve with the four given control points" |
|
418 | 838 |
self._code.append('n %s m %s c S' % |
839 |
(fp_str(x1, y1), fp_str(x2, y2, x3, y3, x4, y4)) |
|
0 | 840 |
) |
841 |
def arc(self, x1,y1, x2,y2, startAng=0, extent=90): |
|
260 | 842 |
""" |
0 | 843 |
Draw a partial ellipse inscribed within the rectangle x1,y1,x2,y2, |
844 |
starting at startAng degrees and covering extent degrees. Angles |
|
845 |
start with 0 to the right (+x) and increase counter-clockwise. |
|
846 |
These should have x1<x2 and y1<y2. |
|
260 | 847 |
|
848 |
Contributed to piddlePDF by Robert Kern, 28/7/99. |
|
849 |
Trimmed down by AR to remove color stuff for pdfgen.canvas and |
|
850 |
revert to positive coordinates. |
|
851 |
||
0 | 852 |
The algorithm is an elliptical generalization of the formulae in |
853 |
Jim Fitzsimmon's TeX tutorial <URL: http://www.tinaja.com/bezarc1.pdf>.""" |
|
854 |
||
855 |
pointList = pdfgeom.bezierArc(x1,y1, x2,y2, startAng, extent) |
|
856 |
#move to first point |
|
418 | 857 |
self._code.append('n %s m' % fp_str(pointList[0][:2])) |
0 | 858 |
for curve in pointList: |
418 | 859 |
self._code.append('%s c' % fp_str(curve[2:])) |
0 | 860 |
# stroke |
861 |
self._code.append('S') |
|
862 |
||
863 |
#--------now the shape drawing methods----------------------- |
|
864 |
def rect(self, x, y, width, height, stroke=1, fill=0): |
|
260 | 865 |
"draws a rectangle with lower left corner at (x,y) and width and height as given." |
418 | 866 |
self._code.append('n %s re ' % fp_str(x, y, width, height) |
0 | 867 |
+ PATH_OPS[stroke, fill, self._fillMode]) |
868 |
||
869 |
||
870 |
def ellipse(self, x1, y1, x2, y2, stroke=1, fill=0): |
|
260 | 871 |
""" |
872 |
Draw an ellipse with foci at (x1,y1) (x2,y2). |
|
873 |
||
874 |
Uses bezierArc, which conveniently handles 360 degrees. |
|
875 |
Special thanks to Robert Kern.""" |
|
876 |
### XXXX above documentation is WRONG. Exactly what are (x1,y1), (x2,y2)? |
|
877 |
||
0 | 878 |
pointList = pdfgeom.bezierArc(x1,y1, x2,y2, 0, 360) |
879 |
#move to first point |
|
418 | 880 |
self._code.append('n %s m' % fp_str(pointList[0][:2])) |
0 | 881 |
for curve in pointList: |
418 | 882 |
self._code.append('%s c' % fp_str(curve[2:])) |
0 | 883 |
#finish |
884 |
self._code.append(PATH_OPS[stroke, fill, self._fillMode]) |
|
885 |
||
886 |
||
887 |
def wedge(self, x1,y1, x2,y2, startAng, extent, stroke=1, fill=0): |
|
888 |
"""Like arc, but connects to the centre of the ellipse. |
|
889 |
Most useful for pie charts and PacMan!""" |
|
890 |
||
891 |
x_cen = (x1+x2)/2. |
|
892 |
y_cen = (y1+y2)/2. |
|
893 |
pointList = pdfgeom.bezierArc(x1,y1, x2,y2, startAng, extent) |
|
894 |
||
418 | 895 |
self._code.append('n %s m' % fp_str(x_cen, y_cen)) |
0 | 896 |
# Move the pen to the center of the rectangle |
418 | 897 |
self._code.append('%s l' % fp_str(pointList[0][:2])) |
0 | 898 |
for curve in pointList: |
418 | 899 |
self._code.append('%s c' % fp_str(curve[2:])) |
0 | 900 |
# finish the wedge |
418 | 901 |
self._code.append('%s l ' % fp_str(x_cen, y_cen)) |
0 | 902 |
# final operator |
903 |
self._code.append(PATH_OPS[stroke, fill, self._fillMode]) |
|
904 |
||
905 |
def circle(self, x_cen, y_cen, r, stroke=1, fill=0): |
|
260 | 906 |
"""draw a cirle centered at (x_cen,y_cen) with radius r (special case of ellipse)""" |
0 | 907 |
|
908 |
x1 = x_cen - r |
|
909 |
x2 = x_cen + r |
|
910 |
y1 = y_cen - r |
|
911 |
y2 = y_cen + r |
|
912 |
self.ellipse(x1, y1, x2, y2, stroke, fill) |
|
913 |
||
914 |
def roundRect(self, x, y, width, height, radius, stroke=1, fill=0): |
|
915 |
"""Draws a rectangle with rounded corners. The corners are |
|
916 |
approximately quadrants of a circle, with the given radius.""" |
|
917 |
#use a precomputed set of factors for the bezier approximation |
|
918 |
#to a circle. There are six relevant points on the x axis and y axis. |
|
919 |
#sketch them and it should all make sense! |
|
920 |
t = 0.4472 * radius |
|
921 |
||
922 |
x0 = x |
|
923 |
x1 = x0 + t |
|
924 |
x2 = x0 + radius |
|
925 |
x3 = x0 + width - radius |
|
926 |
x4 = x0 + width - t |
|
927 |
x5 = x0 + width |
|
928 |
||
929 |
y0 = y |
|
930 |
y1 = y0 + t |
|
931 |
y2 = y0 + radius |
|
932 |
y3 = y0 + height - radius |
|
933 |
y4 = y0 + height - t |
|
934 |
y5 = y0 + height |
|
935 |
||
418 | 936 |
self._code.append('n %s m' % fp_str(x2, y0)) |
937 |
self._code.append('%s l' % fp_str(x3, y0)) # bottom row |
|
938 |
self._code.append('%s c' |
|
939 |
% fp_str(x4, y0, x5, y1, x5, y2)) # bottom right |
|
0 | 940 |
|
418 | 941 |
self._code.append('%s l' % fp_str(x5, y3)) # right edge |
942 |
self._code.append('%s c' |
|
943 |
% fp_str(x5, y4, x4, y5, x3, y5)) # top right |
|
0 | 944 |
|
418 | 945 |
self._code.append('%s l' % fp_str(x2, y5)) # top row |
946 |
self._code.append('%s c' |
|
947 |
% fp_str(x1, y5, x0, y4, x0, y3)) # top left |
|
0 | 948 |
|
418 | 949 |
self._code.append('%s l' % fp_str(x0, y2)) # left edge |
950 |
self._code.append('%s c' |
|
951 |
% fp_str(x0, y1, x1, y0, x2, y0)) # bottom left |
|
0 | 952 |
|
953 |
self._code.append('h') #close off, although it should be where it started anyway |
|
954 |
||
955 |
||
956 |
self._code.append(PATH_OPS[stroke, fill, self._fillMode]) |
|
957 |
################################################## |
|
958 |
# |
|
959 |
# Text methods |
|
960 |
# |
|
961 |
# As with graphics, a separate object ensures that |
|
962 |
# everything is bracketed between text operators. |
|
963 |
# The methods below are a high-level convenience. |
|
964 |
# use PDFTextObject for multi-line text. |
|
965 |
################################################## |
|
966 |
||
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
967 |
|
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
968 |
def setFillColorCMYK(self, c, m, y, k): |
260 | 969 |
"""set the fill color useing negative color values |
970 |
(cyan, magenta, yellow and darkness value). |
|
971 |
Takes 4 arguments between 0.0 and 1.0""" |
|
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
972 |
self._fillColorCMYK = (c, m, y, k) |
418 | 973 |
self._code.append('%s k' % fp_str(c, m, y, k)) |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
974 |
|
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
975 |
def setStrokeColorCMYK(self, c, m, y, k): |
260 | 976 |
"""set the stroke color useing negative color values |
977 |
(cyan, magenta, yellow and darkness value). |
|
978 |
Takes 4 arguments between 0.0 and 1.0""" |
|
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
979 |
self._strokeColorCMYK = (c, m, y, k) |
418 | 980 |
self._code.append('%s K' % fp_str(c, m, y, k)) |
52
3bbe0067a2dc
added support for destinations, forms, linkages
aaron_watters
parents:
48
diff
changeset
|
981 |
|
0 | 982 |
def drawString(self, x, y, text): |
983 |
"""Draws a string in the current text styles.""" |
|
984 |
#we could inline this for speed if needed |
|
985 |
t = self.beginText(x, y) |
|
986 |
t.textLine(text) |
|
987 |
self.drawText(t) |
|
988 |
||
989 |
def drawRightString(self, x, y, text): |
|
990 |
"""Draws a string right-aligned with the y coordinate""" |
|
991 |
width = self.stringWidth(text, self._fontname, self._fontsize) |
|
992 |
t = self.beginText(x - width, y) |
|
993 |
t.textLine(text) |
|
994 |
self.drawText(t) |
|
995 |
||
996 |
def drawCentredString(self, x, y, text): |
|
997 |
"""Draws a string right-aligned with the y coordinate. I |
|
998 |
am British so the spelling is correct, OK?""" |
|
999 |
width = self.stringWidth(text, self._fontname, self._fontsize) |
|
1000 |
t = self.beginText(x - 0.5*width, y) |
|
1001 |
t.textLine(text) |
|
1002 |
self.drawText(t) |
|
1003 |
||
1004 |
def getAvailableFonts(self): |
|
1005 |
"""Returns the list of PostScript font names available. |
|
1006 |
Standard set now, but may grow in future with font embedding.""" |
|
1007 |
fontnames = self._doc.getAvailableFonts() |
|
1008 |
fontnames.sort() |
|
1009 |
return fontnames |
|
1010 |
||
1011 |
def setFont(self, psfontname, size, leading = None): |
|
1012 |
"""Sets the font. If leading not specified, defaults to 1.2 x |
|
1013 |
font size. Raises a readable exception if an illegal font |
|
1014 |
is supplied. Font names are case-sensitive! Keeps track |
|
260 | 1015 |
of font name and size for metrics.""" |
0 | 1016 |
self._fontname = psfontname |
1017 |
self._fontsize = size |
|
1018 |
pdffontname = self._doc.getInternalFontName(psfontname) |
|
1019 |
if leading is None: |
|
1020 |
leading = size * 1.2 |
|
1021 |
self._leading = leading |
|
418 | 1022 |
self._code.append('BT %s %s Tf %0.1f TL ET' % (pdffontname, fp_str(size), leading)) |
0 | 1023 |
|
305 | 1024 |
def stringWidth(self, text, fontName, fontSize, encoding=None): |
0 | 1025 |
"gets width of a string in the given font and size" |
305 | 1026 |
if encoding is None: encoding = self._doc.encoding |
117 | 1027 |
return pdfmetrics.stringWidth(text, fontName, fontSize) |
0 | 1028 |
|
1029 |
# basic graphics modes |
|
1030 |
def setLineWidth(self, width): |
|
1031 |
self._lineWidth = width |
|
418 | 1032 |
self._code.append('%s w' % fp_str(width)) |
0 | 1033 |
|
1034 |
def setLineCap(self, mode): |
|
1035 |
"""0=butt,1=round,2=square""" |
|
1036 |
assert mode in (0,1,2), "Line caps allowed: 0=butt,1=round,2=square" |
|
1037 |
self._lineCap = mode |
|
1038 |
self._code.append('%d J' % mode) |
|
1039 |
||
1040 |
def setLineJoin(self, mode): |
|
1041 |
"""0=mitre, 1=round, 2=bevel""" |
|
1042 |
assert mode in (0,1,2), "Line Joins allowed: 0=mitre, 1=round, 2=bevel" |
|
1043 |
self._lineJoin = mode |
|
1044 |
self._code.append('%d j' % mode) |
|
1045 |
||
1046 |
def setMiterLimit(self, limit): |
|
1047 |
self._miterLimit = limit |
|
418 | 1048 |
self._code.append('%s M' % fp_str(limit)) |
0 | 1049 |
|
1050 |
def setDash(self, array=[], phase=0): |
|
1051 |
"""Two notations. pass two numbers, or an array and phase""" |
|
1052 |
if type(array) == IntType or type(array) == FloatType: |
|
1053 |
self._code.append('[%s %s] 0 d' % (array, phase)) |
|
45 | 1054 |
elif type(array) == ListType or type(array) == TupleType: |
409 | 1055 |
assert phase >= 0, "phase is a length in user space" |
0 | 1056 |
textarray = string.join(map(str, array)) |
1057 |
self._code.append('[%s] %s d' % (textarray, phase)) |
|
1058 |
||
1059 |
def setFillColorRGB(self, r, g, b): |
|
260 | 1060 |
"""Set the fill color using positive color description |
1061 |
(Red,Green,Blue). Takes 3 arguments between 0.0 and 1.0""" |
|
0 | 1062 |
self._fillColorRGB = (r, g, b) |
418 | 1063 |
self._code.append('%s rg' % fp_str(r,g,b)) |
0 | 1064 |
|
1065 |
def setStrokeColorRGB(self, r, g, b): |
|
260 | 1066 |
"""Set the stroke color using positive color description |
1067 |
(Red,Green,Blue). Takes 3 arguments between 0.0 and 1.0""" |
|
43
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
1068 |
self._strokeColorRGB = (r, g, b) |
418 | 1069 |
self._code.append('%s RG' % fp_str(r,g,b)) |
43
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
1070 |
|
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
1071 |
def setFillColor(self, aColor): |
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
1072 |
"""Takes a color object, allowing colors to be referred to by name""" |
68 | 1073 |
if type(aColor) == ColorType: |
1074 |
rgb = (aColor.red, aColor.green, aColor.blue) |
|
70 | 1075 |
self._fillColorRGB = rgb |
418 | 1076 |
self._code.append('%s rg' % fp_str(rgb) ) |
69 | 1077 |
elif type(aColor) in _SeqTypes: |
68 | 1078 |
l = len(aColor) |
1079 |
if l==3: |
|
70 | 1080 |
self._fillColorRGB = aColor |
418 | 1081 |
self._code.append('%s rg' % fp_str(aColor) ) |
68 | 1082 |
elif l==4: |
1083 |
self.setFillColorCMYK(self, aColor[0], aColor[1], aColor[2], aColor[3]) |
|
1084 |
else: |
|
1085 |
raise 'Unknown color', str(aColor) |
|
247 | 1086 |
elif type(aColor) is StringType: |
313 | 1087 |
self.setFillColor(colors.toColor(aColor)) |
68 | 1088 |
else: |
1089 |
raise 'Unknown color', str(aColor) |
|
1090 |
||
1091 |
||
43
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
1092 |
def setStrokeColor(self, aColor): |
71baccf1c57f
Canvas has two methods setFillColor(aColor) and setStrokeColor(aColor)
andy_robinson
parents:
36
diff
changeset
|
1093 |
"""Takes a color object, allowing colors to be referred to by name""" |
68 | 1094 |
if type(aColor) == ColorType: |
1095 |
rgb = (aColor.red, aColor.green, aColor.blue) |
|
1096 |
self._strokeColorRGB = rgb |
|
418 | 1097 |
self._code.append('%s RG' % fp_str(rgb) ) |
69 | 1098 |
elif type(aColor) in _SeqTypes: |
68 | 1099 |
l = len(aColor) |
1100 |
if l==3: |
|
1101 |
self._strokeColorRGB = aColor |
|
418 | 1102 |
self._code.append('%s RG' % fp_str(aColor) ) |
68 | 1103 |
elif l==4: |
1104 |
self.setStrokeColorCMYK(self, aColor[0], aColor[1], aColor[2], aColor[3]) |
|
1105 |
else: |
|
1106 |
raise 'Unknown color', str(aColor) |
|
247 | 1107 |
elif type(aColor) is StringType: |
313 | 1108 |
self.setFillColor(toColor(aColor)) |
68 | 1109 |
else: |
1110 |
raise 'Unknown color', str(aColor) |
|
27
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
1111 |
|
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
1112 |
def setFillGray(self, gray): |
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
1113 |
"""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
|
1114 |
self._fillColorRGB = (gray, gray, gray) |
418 | 1115 |
self._code.append('%s g' % fp_str(gray)) |
27
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
1116 |
|
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
1117 |
def setStrokeGray(self, gray): |
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
1118 |
"""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
|
1119 |
self._strokeColorRGB = (gray, gray, gray) |
418 | 1120 |
self._code.append('%s G' % fp_str(gray)) |
27
684657a34422
Added methods setFillGray(g), setStrokeGray(g) where 0 <= g <= 1
andy_robinson
parents:
26
diff
changeset
|
1121 |
|
0 | 1122 |
|
1123 |
# path stuff - the separate path object builds it |
|
1124 |
def beginPath(self): |
|
260 | 1125 |
"""Returns a fresh path object. Paths are used to draw |
1126 |
complex figures. The object returned follows the protocol |
|
1127 |
for a pathobject.PDFPathObject instance""" |
|
0 | 1128 |
return pathobject.PDFPathObject() |
1129 |
||
1130 |
def drawPath(self, aPath, stroke=1, fill=0): |
|
260 | 1131 |
"Draw the path object in the mode indicated" |
409 | 1132 |
self._code.append(aPath.getCode() + ' ' + PATH_OPS[stroke, fill, self._fillMode]) |
0 | 1133 |
|
1134 |
def clipPath(self, aPath, stroke=1, fill=0): |
|
1135 |
"clip as well as drawing" |
|
409 | 1136 |
self._code.append( aPath.getCode() |
1137 |
+ (self._fillMode == FILL_EVEN_ODD and ' W* ' or ' W ') |
|
1138 |
+ PATH_OPS[stroke,fill,self._fillMode]) |
|
0 | 1139 |
|
1140 |
def beginText(self, x=0, y=0): |
|
260 | 1141 |
"""Returns a fresh text object. Text objects are used |
1142 |
to add large amounts of text. See textobject.PDFTextObject""" |
|
0 | 1143 |
return textobject.PDFTextObject(self, x, y) |
1144 |
||
1145 |
def drawText(self, aTextObject): |
|
1146 |
"""Draws a text object""" |
|
1147 |
self._code.append(aTextObject.getCode()) |
|
1148 |
||
1149 |
###################################################### |
|
1150 |
# |
|
1151 |
# Image routines |
|
1152 |
# |
|
1153 |
###################################################### |
|
1154 |
def drawInlineImage(self, image, x,y, width=None,height=None): |
|
33 | 1155 |
"""Draw an Image into the specified rectangle. If width and |
0 | 1156 |
height are omitted, they are calculated from the image size. |
1157 |
Also allow file names as well as images. This allows a |
|
1158 |
caching mechanism""" |
|
411 | 1159 |
|
36 | 1160 |
self._currentPageHasImages = 1 |
0 | 1161 |
|
1162 |
if type(image) == StringType: |
|
228 | 1163 |
if os.path.splitext(image)[1] in ['.jpg', '.JPG', '.jpeg', '.JPEG']: |
33 | 1164 |
#directly process JPEG files |
1165 |
#open file, needs some error handling!! |
|
0 | 1166 |
imageFile = open(image, 'rb') |
228 | 1167 |
info = pdfutils.readJPEGInfo(imageFile) |
0 | 1168 |
imgwidth, imgheight = info[0], info[1] |
1169 |
if info[2] == 1: |
|
1170 |
colorSpace = 'DeviceGray' |
|
1171 |
elif info[2] == 3: |
|
1172 |
colorSpace = 'DeviceRGB' |
|
1173 |
else: #maybe should generate an error, is this right for CMYK? |
|
1174 |
colorSpace = 'DeviceCMYK' |
|
411 | 1175 |
imageFile.seek(0) #reset file pointer |
0 | 1176 |
imagedata = [] |
411 | 1177 |
#imagedata.append('BI /Width %d /Height /BitsPerComponent 8 /ColorSpace /%s /Filter [/Filter [ /ASCII85Decode /DCTDecode] ID' % (info[0], info[1], colorSpace)) |
1178 |
imagedata.append('BI /W %d /H %d /BPC 8 /CS /%s /F [/A85 /DCT] ID' % (info[0], info[1], colorSpace)) |
|
0 | 1179 |
#write in blocks of (??) 60 characters per line to a list |
1180 |
compressed = imageFile.read() |
|
1181 |
encoded = pdfutils._AsciiBase85Encode(compressed) |
|
1182 |
outstream = cStringIO.StringIO(encoded) |
|
1183 |
dataline = outstream.read(60) |
|
1184 |
while dataline <> "": |
|
1185 |
imagedata.append(dataline) |
|
1186 |
dataline = outstream.read(60) |
|
1187 |
imagedata.append('EI') |
|
1188 |
else: |
|
313 | 1189 |
if hasattr(self,'noImageCaching') and self.noImageCaching: |
1190 |
imagedata = pdfutils.cacheImageFile(image,returnInMemory=1) |
|
1191 |
else: |
|
1192 |
if not pdfutils.cachedImageExists(image): |
|
1193 |
if not zlib: |
|
1194 |
print 'zlib not available' |
|
1195 |
return |
|
176 | 1196 |
|
313 | 1197 |
try: |
1198 |
import Image |
|
1199 |
except ImportError: |
|
1200 |
print 'Python Imaging Library not available' |
|
1201 |
return |
|
1202 |
pdfutils.cacheImageFile(image) |
|
33 | 1203 |
|
313 | 1204 |
#now we have one cached, slurp it in |
1205 |
cachedname = os.path.splitext(image)[0] + '.a85' |
|
1206 |
imagedata = open(cachedname,'rb').readlines() |
|
1207 |
#trim off newlines... |
|
1208 |
imagedata = map(string.strip, imagedata) |
|
0 | 1209 |
|
1210 |
#parse line two for width, height |
|
1211 |
words = string.split(imagedata[1]) |
|
1212 |
imgwidth = string.atoi(words[1]) |
|
1213 |
imgheight = string.atoi(words[3]) |
|
1214 |
else: |
|
1215 |
#PIL Image |
|
1216 |
#work out all dimensions |
|
176 | 1217 |
if not zlib: |
33 | 1218 |
print 'zlib not available' |
1219 |
return |
|
0 | 1220 |
myimage = image.convert('RGB') |
1221 |
imgwidth, imgheight = myimage.size |
|
1222 |
imagedata = [] |
|
1223 |
||
1224 |
# this describes what is in the image itself |
|
411 | 1225 |
# *NB* according to the spec you can only use the short form in inline images |
1226 |
#imagedata.append('BI /Width %d /Height /BitsPerComponent 8 /ColorSpace /%s /Filter [/Filter [ /ASCII85Decode /FlateDecode] ID' % (imgwidth, imgheight,'RGB')) |
|
1227 |
imagedata.append('BI /W %d /H %d /BPC 8 /CS /RGB /F [/A85 /Fl] ID' % (imgwidth, imgheight)) |
|
0 | 1228 |
|
1229 |
#use a flate filter and Ascii Base 85 to compress |
|
1230 |
raw = myimage.tostring() |
|
1231 |
assert(len(raw) == imgwidth * imgheight, "Wrong amount of data for image") |
|
1232 |
compressed = zlib.compress(raw) #this bit is very fast... |
|
1233 |
encoded = pdfutils._AsciiBase85Encode(compressed) #...sadly this isn't |
|
1234 |
||
1235 |
#write in blocks of (??) 60 characters per line to a list |
|
1236 |
outstream = cStringIO.StringIO(encoded) |
|
1237 |
dataline = outstream.read(60) |
|
1238 |
while dataline <> "": |
|
1239 |
imagedata.append(dataline) |
|
1240 |
dataline = outstream.read(60) |
|
1241 |
imagedata.append('EI') |
|
1242 |
||
1243 |
#now build the PDF for the image. |
|
1244 |
if not width: |
|
1245 |
width = imgwidth |
|
1246 |
if not height: |
|
1247 |
height = imgheight |
|
1248 |
||
1249 |
# this says where and how big to draw it |
|
434
257af3109bf4
Various brutal changes to paragraph, canvas and textobject for speed/size
rgbecker
parents:
418
diff
changeset
|
1250 |
if not self.bottomup: y = y+height |
257af3109bf4
Various brutal changes to paragraph, canvas and textobject for speed/size
rgbecker
parents:
418
diff
changeset
|
1251 |
self._code.append('q %s 0 0 %s cm' % (fp_str(width), fp_str(height, x, y))) |
28 | 1252 |
|
68 | 1253 |
# self._code.extend(imagedata) if >=python-1.5.2 |
28 | 1254 |
for line in imagedata: |
68 | 1255 |
self._code.append(line) |
1256 |
||
0 | 1257 |
self._code.append('Q') |
1258 |
#self._code.append('BT') |
|
1259 |
||
1260 |
||
1261 |
def setPageCompression(self, onoff=1): |
|
1262 |
"""Possible values 1 or 0 (1 for 'on' is the default). |
|
1263 |
If on, the page data will be compressed, leading to much |
|
1264 |
smaller files, but takes a little longer to create the files. |
|
1265 |
This applies to all subsequent pages, or until setPageCompression() |
|
1266 |
is next called.""" |
|
176 | 1267 |
if onoff and not zlib: |
1268 |
print 'zlib not available' |
|
1269 |
return |
|
0 | 1270 |
self._pageCompression = onoff |
1271 |
||
1272 |
||
1273 |
def setPageTransition(self, effectname=None, duration=1, |
|
1274 |
direction=0,dimension='H',motion='I'): |
|
1275 |
"""PDF allows page transition effects for use when giving |
|
1276 |
presentations. There are six possible effects. You can |
|
1277 |
just guive the effect name, or supply more advanced options |
|
1278 |
to refine the way it works. There are three types of extra |
|
1279 |
argument permitted, and here are the allowed values: |
|
1280 |
direction_arg = [0,90,180,270] |
|
1281 |
dimension_arg = ['H', 'V'] |
|
1282 |
motion_arg = ['I','O'] (start at inside or outside) |
|
1283 |
||
1284 |
This table says which ones take which arguments: |
|
1285 |
||
1286 |
PageTransitionEffects = { |
|
1287 |
'Split': [direction_arg, motion_arg], |
|
1288 |
'Blinds': [dimension_arg], |
|
1289 |
'Box': [motion_arg], |
|
1290 |
'Wipe' : [direction_arg], |
|
1291 |
'Dissolve' : [], |
|
1292 |
'Glitter':[direction_arg] |
|
1293 |
} |
|
1294 |
Have fun! |
|
1295 |
""" |
|
1296 |
if not effectname: |
|
1297 |
self._pageTransitionString = '' |
|
1298 |
return |
|
1299 |
||
1300 |
#first check each optional argument has an allowed value |
|
1301 |
if direction in [0,90,180,270]: |
|
1302 |
direction_arg = '/Di /%d' % direction |
|
1303 |
else: |
|
1304 |
raise 'PDFError', ' directions allowed are 0,90,180,270' |
|
1305 |
||
1306 |
if dimension in ['H', 'V']: |
|
1307 |
dimension_arg = '/Dm /%s' % dimension |
|
1308 |
else: |
|
1309 |
raise'PDFError','dimension values allowed are H and V' |
|