PSDraw.py 6.6 KB

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