Aluode/PerceptionLabPortable
0
1#
2# The Python Imaging Library
3# $Id$
4#
5# Simple PostScript graphics interface
6#
7# History:
8# 1996-04-20 fl Created
9# 1999-01-10 fl Added gsave/grestore to image method
10# 2005-05-04 fl Fixed floating point issue in image (from Eric Etheridge)
11#
12# Copyright (c) 1997-2005 by Secret Labs AB. All rights reserved.
13# Copyright (c) 1996 by Fredrik Lundh.
14#
15# See the README file for information on usage and redistribution.
16#
17from __future__ import annotations
18
19import sys
20from typing import IO
21
22from . import EpsImagePlugin
23
24TYPE_CHECKING = False
25
26
27##
28# Simple PostScript graphics interface.
29
30
31class PSDraw:
32 """
33 Sets up printing to the given file. If ``fp`` is omitted,
34 ``sys.stdout.buffer`` is assumed.
35 """
36
37 def __init__(self, fp: IO[bytes] | None = None) -> None:
38 if not fp:
39 fp = sys.stdout.buffer
40 self.fp = fp
41
42 def begin_document(self, id: str | None = None) -> None:
43 """Set up printing of a document. (Write PostScript DSC header.)"""
44 # FIXME: incomplete
45 self.fp.write(
46 b"%!PS-Adobe-3.0\n"
47 b"save\n"
48 b"/showpage { } def\n"
49 b"%%EndComments\n"
50 b"%%BeginDocument\n"
51 )
52 # self.fp.write(ERROR_PS) # debugging!
53 self.fp.write(EDROFF_PS)
54 self.fp.write(VDI_PS)
55 self.fp.write(b"%%EndProlog\n")
56 self.isofont: dict[bytes, int] = {}
57
58 def end_document(self) -> None:
59 """Ends printing. (Write PostScript DSC footer.)"""
60 self.fp.write(b"%%EndDocument\nrestore showpage\n%%End\n")
61 if hasattr(self.fp, "flush"):
62 self.fp.flush()
63
64 def setfont(self, font: str, size: int) -> None:
65 """
66 Selects which font to use.
67
68 :param font: A PostScript font name
69 :param size: Size in points.
70 """
71 font_bytes = bytes(font, "UTF-8")
72 if font_bytes not in self.isofont:
73 # reencode font
74 self.fp.write(
75 b"/PSDraw-%s ISOLatin1Encoding /%s E\n" % (font_bytes, font_bytes)
76 )
77 self.isofont[font_bytes] = 1
78 # rough
79 self.fp.write(b"/F0 %d /PSDraw-%s F\n" % (size, font_bytes))
80
81 def line(self, xy0: tuple[int, int], xy1: tuple[int, int]) -> None:
82 """
83 Draws a line between the two points. Coordinates are given in
84 PostScript point coordinates (72 points per inch, (0, 0) is the lower
85 left corner of the page).
86 """
87 self.fp.write(b"%d %d %d %d Vl\n" % (*xy0, *xy1))
88
89 def rectangle(self, box: tuple[int, int, int, int]) -> None:
90 """
91 Draws a rectangle.
92
93 :param box: A tuple of four integers, specifying left, bottom, width and
94 height.
95 """
96 self.fp.write(b"%d %d M 0 %d %d Vr\n" % box)
97
98 def text(self, xy: tuple[int, int], text: str) -> None:
99 """
100 Draws text at the given position. You must use
101 :py:meth:`~PIL.PSDraw.PSDraw.setfont` before calling this method.
102 """
103 text_bytes = bytes(text, "UTF-8")
104 text_bytes = b"\\(".join(text_bytes.split(b"("))
105 text_bytes = b"\\)".join(text_bytes.split(b")"))
106 self.fp.write(b"%d %d M (%s) S\n" % (xy + (text_bytes,)))
107
108 if TYPE_CHECKING:
109 from . import Image
110
111 def image(
112 self, box: tuple[int, int, int, int], im: Image.Image, dpi: int | None = None
113 ) -> None:
114 """Draw a PIL image, centered in the given box."""
115 # default resolution depends on mode
116 if not dpi:
117 if im.mode == "1":
118 dpi = 200 # fax
119 else:
120 dpi = 100 # grayscale
121 # image size (on paper)
122 x = im.size[0] * 72 / dpi
123 y = im.size[1] * 72 / dpi
124 # max allowed size
125 xmax = float(box[2] - box[0])
126 ymax = float(box[3] - box[1])
127 if x > xmax:
128 y = y * xmax / x
129 x = xmax
130 if y > ymax:
131 x = x * ymax / y
132 y = ymax
133 dx = (xmax - x) / 2 + box[0]
134 dy = (ymax - y) / 2 + box[1]
135 self.fp.write(b"gsave\n%f %f translate\n" % (dx, dy))
136 if (x, y) != im.size:
137 # EpsImagePlugin._save prints the image at (0,0,xsize,ysize)
138 sx = x / im.size[0]
139 sy = y / im.size[1]
140 self.fp.write(b"%f %f scale\n" % (sx, sy))
141 EpsImagePlugin._save(im, self.fp, "", 0)
142 self.fp.write(b"\ngrestore\n")
143
144
145# --------------------------------------------------------------------
146# PostScript driver
147
148#
149# EDROFF.PS -- PostScript driver for Edroff 2
150#
151# History:
152# 94-01-25 fl: created (edroff 2.04)
153#
154# Copyright (c) Fredrik Lundh 1994.
155#
156
157
158EDROFF_PS = b"""\
159/S { show } bind def
160/P { moveto show } bind def
161/M { moveto } bind def
162/X { 0 rmoveto } bind def
163/Y { 0 exch rmoveto } bind def
164/E { findfont
165 dup maxlength dict begin
166 {
167 1 index /FID ne { def } { pop pop } ifelse
168 } forall
169 /Encoding exch def
170 dup /FontName exch def
171 currentdict end definefont pop
172} bind def
173/F { findfont exch scalefont dup setfont
174 [ exch /setfont cvx ] cvx bind def
175} bind def
176"""
177
178#
179# VDI.PS -- PostScript driver for VDI meta commands
180#
181# History:
182# 94-01-25 fl: created (edroff 2.04)
183#
184# Copyright (c) Fredrik Lundh 1994.
185#
186
187VDI_PS = b"""\
188/Vm { moveto } bind def
189/Va { newpath arcn stroke } bind def
190/Vl { moveto lineto stroke } bind def
191/Vc { newpath 0 360 arc closepath } bind def
192/Vr { exch dup 0 rlineto
193 exch dup 0 exch rlineto
194 exch neg 0 rlineto
195 0 exch neg rlineto
196 setgray fill } bind def
197/Tm matrix def
198/Ve { Tm currentmatrix pop
199 translate scale newpath 0 0 .5 0 360 arc closepath
200 Tm setmatrix
201} bind def
202/Vf { currentgray exch setgray fill setgray } bind def
203"""
204
205#
206# ERROR.PS -- Error handler
207#
208# History:
209# 89-11-21 fl: created (pslist 1.10)
210#
211
212ERROR_PS = b"""\
213/landscape false def
214/errorBUF 200 string def
215/errorNL { currentpoint 10 sub exch pop 72 exch moveto } def
216errordict begin /handleerror {
217 initmatrix /Courier findfont 10 scalefont setfont
218 newpath 72 720 moveto $error begin /newerror false def
219 (PostScript Error) show errorNL errorNL
220 (Error: ) show
221 /errorname load errorBUF cvs show errorNL errorNL
222 (Command: ) show
223 /command load dup type /stringtype ne { errorBUF cvs } if show
224 errorNL errorNL
225 (VMstatus: ) show
226 vmstatus errorBUF cvs show ( bytes available, ) show
227 errorBUF cvs show ( bytes used at level ) show
228 errorBUF cvs show errorNL errorNL
229 (Operand stargck: ) show errorNL /ostargck load {
230 dup type /stringtype ne { errorBUF cvs } if 72 0 rmoveto show errorNL
231 } forall errorNL
232 (Execution stargck: ) show errorNL /estargck load {
233 dup type /stringtype ne { errorBUF cvs } if 72 0 rmoveto show errorNL
234 } forall
235 end showpage
236} def end
237"""
238 