Pillow/src/PIL/PSDraw.py

236 lines
6.5 KiB
Python
Raw Normal View History

2010-07-31 06:52:47 +04:00
#
# The Python Imaging Library
# $Id$
#
2020-07-10 11:48:02 +03:00
# Simple PostScript graphics interface
2010-07-31 06:52:47 +04:00
#
# History:
# 1996-04-20 fl Created
# 1999-01-10 fl Added gsave/grestore to image method
# 2005-05-04 fl Fixed floating point issue in image (from Eric Etheridge)
#
# Copyright (c) 1997-2005 by Secret Labs AB. All rights reserved.
# Copyright (c) 1996 by Fredrik Lundh.
#
# See the README file for information on usage and redistribution.
#
import sys
from . import EpsImagePlugin
2014-08-26 17:47:10 +04:00
2010-07-31 06:52:47 +04:00
##
2020-07-10 11:48:02 +03:00
# Simple PostScript graphics interface.
2010-07-31 06:52:47 +04:00
class PSDraw:
2013-10-14 09:30:00 +04:00
"""
2020-09-01 20:16:46 +03:00
Sets up printing to the given file. If ``fp`` is omitted,
2020-07-10 00:46:28 +03:00
:py:data:`sys.stdout` is assumed.
2013-10-14 09:30:00 +04:00
"""
2010-07-31 06:52:47 +04:00
def __init__(self, fp=None):
if not fp:
fp = sys.stdout
self.fp = fp
2014-12-27 23:26:54 +03:00
def _fp_write(self, to_write):
2019-09-26 15:12:28 +03:00
if self.fp == sys.stdout:
2014-12-27 23:26:54 +03:00
self.fp.write(to_write)
else:
2019-03-21 16:28:20 +03:00
self.fp.write(bytes(to_write, "UTF-8"))
2014-12-27 23:26:54 +03:00
2014-08-26 17:47:10 +04:00
def begin_document(self, id=None):
2020-07-10 11:48:02 +03:00
"""Set up printing of a document. (Write PostScript DSC header.)"""
2010-07-31 06:52:47 +04:00
# FIXME: incomplete
2019-03-21 16:28:20 +03:00
self._fp_write(
"%!PS-Adobe-3.0\n"
"save\n"
"/showpage { } def\n"
"%%EndComments\n"
"%%BeginDocument\n"
)
# self._fp_write(ERROR_PS) # debugging!
2014-12-27 23:26:54 +03:00
self._fp_write(EDROFF_PS)
self._fp_write(VDI_PS)
self._fp_write("%%EndProlog\n")
2010-07-31 06:52:47 +04:00
self.isofont = {}
def end_document(self):
2020-07-10 11:48:02 +03:00
"""Ends printing. (Write PostScript DSC footer.)"""
2019-03-21 16:28:20 +03:00
self._fp_write("%%EndDocument\nrestore showpage\n%%End\n")
2010-07-31 06:52:47 +04:00
if hasattr(self.fp, "flush"):
self.fp.flush()
def setfont(self, font, size):
2013-10-14 09:30:00 +04:00
"""
Selects which font to use.
2020-07-10 11:48:02 +03:00
:param font: A PostScript font name
2013-10-14 09:30:00 +04:00
:param size: Size in points.
"""
if font not in self.isofont:
2010-07-31 06:52:47 +04:00
# reencode font
self._fp_write(f"/PSDraw-{font} ISOLatin1Encoding /{font} E\n")
2010-07-31 06:52:47 +04:00
self.isofont[font] = 1
# rough
self._fp_write(f"/F0 {size} /PSDraw-{font} F\n")
2010-07-31 06:52:47 +04:00
def line(self, xy0, xy1):
2013-10-14 09:30:00 +04:00
"""
Draws a line between the two points. Coordinates are given in
2020-07-10 11:48:02 +03:00
PostScript point coordinates (72 points per inch, (0, 0) is the lower
2013-10-14 09:30:00 +04:00
left corner of the page).
"""
self._fp_write("%d %d %d %d Vl\n" % (*xy0, *xy1))
2010-07-31 06:52:47 +04:00
def rectangle(self, box):
2013-10-14 09:30:00 +04:00
"""
Draws a rectangle.
:param box: A 4-tuple of integers whose order and function is currently
undocumented.
Hint: the tuple is passed into this format string:
.. code-block:: python
%d %d M %d %d 0 Vr\n
"""
2014-12-27 23:26:54 +03:00
self._fp_write("%d %d M %d %d 0 Vr\n" % box)
2010-07-31 06:52:47 +04:00
def text(self, xy, text):
2013-10-14 09:30:00 +04:00
"""
Draws text at the given position. You must use
:py:meth:`~PIL.PSDraw.PSDraw.setfont` before calling this method.
"""
text = "\\(".join(text.split("("))
text = "\\)".join(text.split(")"))
self._fp_write(f"{xy[0]} {xy[1]} M ({text}) S\n")
2010-07-31 06:52:47 +04:00
2014-08-26 17:47:10 +04:00
def image(self, box, im, dpi=None):
2013-10-14 09:30:00 +04:00
"""Draw a PIL image, centered in the given box."""
2010-07-31 06:52:47 +04:00
# default resolution depends on mode
if not dpi:
if im.mode == "1":
2014-08-26 17:47:10 +04:00
dpi = 200 # fax
2010-07-31 06:52:47 +04:00
else:
2014-08-26 17:47:10 +04:00
dpi = 100 # greyscale
2010-07-31 06:52:47 +04:00
# image size (on paper)
x = im.size[0] * 72 / dpi
y = im.size[1] * 72 / dpi
2010-07-31 06:52:47 +04:00
# max allowed size
xmax = float(box[2] - box[0])
ymax = float(box[3] - box[1])
if x > xmax:
2014-08-26 17:47:10 +04:00
y = y * xmax / x
x = xmax
2010-07-31 06:52:47 +04:00
if y > ymax:
2014-08-26 17:47:10 +04:00
x = x * ymax / y
y = ymax
2010-07-31 06:52:47 +04:00
dx = (xmax - x) / 2 + box[0]
dy = (ymax - y) / 2 + box[1]
self._fp_write(f"gsave\n{dx:f} {dy:f} translate\n")
2010-07-31 06:52:47 +04:00
if (x, y) != im.size:
# EpsImagePlugin._save prints the image at (0,0,xsize,ysize)
sx = x / im.size[0]
sy = y / im.size[1]
self._fp_write(f"{sx:f} {sy:f} scale\n")
2010-07-31 06:52:47 +04:00
EpsImagePlugin._save(im, self.fp, None, 0)
2014-12-27 23:26:54 +03:00
self._fp_write("\ngrestore\n")
2010-07-31 06:52:47 +04:00
2019-03-21 16:28:20 +03:00
2010-07-31 06:52:47 +04:00
# --------------------------------------------------------------------
2020-07-10 11:48:02 +03:00
# PostScript driver
2010-07-31 06:52:47 +04:00
#
2020-07-10 11:48:02 +03:00
# EDROFF.PS -- PostScript driver for Edroff 2
2010-07-31 06:52:47 +04:00
#
# History:
# 94-01-25 fl: created (edroff 2.04)
#
# Copyright (c) Fredrik Lundh 1994.
#
2018-03-03 12:54:00 +03:00
2010-07-31 06:52:47 +04:00
EDROFF_PS = """\
/S { show } bind def
/P { moveto show } bind def
/M { moveto } bind def
/X { 0 rmoveto } bind def
/Y { 0 exch rmoveto } bind def
/E { findfont
dup maxlength dict begin
{
1 index /FID ne { def } { pop pop } ifelse
} forall
/Encoding exch def
dup /FontName exch def
currentdict end definefont pop
} bind def
/F { findfont exch scalefont dup setfont
[ exch /setfont cvx ] cvx bind def
} bind def
"""
#
2020-07-10 11:48:02 +03:00
# VDI.PS -- PostScript driver for VDI meta commands
2010-07-31 06:52:47 +04:00
#
# History:
# 94-01-25 fl: created (edroff 2.04)
#
# Copyright (c) Fredrik Lundh 1994.
#
VDI_PS = """\
/Vm { moveto } bind def
/Va { newpath arcn stroke } bind def
/Vl { moveto lineto stroke } bind def
/Vc { newpath 0 360 arc closepath } bind def
/Vr { exch dup 0 rlineto
exch dup neg 0 exch rlineto
exch neg 0 rlineto
0 exch rlineto
100 div setgray fill 0 setgray } bind def
/Tm matrix def
/Ve { Tm currentmatrix pop
translate scale newpath 0 0 .5 0 360 arc closepath
Tm setmatrix
} bind def
/Vf { currentgray exch setgray fill setgray } bind def
"""
#
# ERROR.PS -- Error handler
#
# History:
# 89-11-21 fl: created (pslist 1.10)
#
ERROR_PS = """\
/landscape false def
/errorBUF 200 string def
/errorNL { currentpoint 10 sub exch pop 72 exch moveto } def
errordict begin /handleerror {
initmatrix /Courier findfont 10 scalefont setfont
newpath 72 720 moveto $error begin /newerror false def
(PostScript Error) show errorNL errorNL
(Error: ) show
/errorname load errorBUF cvs show errorNL errorNL
(Command: ) show
/command load dup type /stringtype ne { errorBUF cvs } if show
errorNL errorNL
(VMstatus: ) show
vmstatus errorBUF cvs show ( bytes available, ) show
errorBUF cvs show ( bytes used at level ) show
errorBUF cvs show errorNL errorNL
(Operand stargck: ) show errorNL /ostargck load {
dup type /stringtype ne { errorBUF cvs } if 72 0 rmoveto show errorNL
} forall errorNL
(Execution stargck: ) show errorNL /estargck load {
dup type /stringtype ne { errorBUF cvs } if 72 0 rmoveto show errorNL
} forall
end showpage
} def end
"""