CoolFace
Apppublic

Aluode/PerceptionLabPortable

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
PSDraw.py238 linesDownload Raw Back to PIL
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 
Aluode/PerceptionLabPortable · CoolFace