PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/src/psdraw.sc

https://bitbucket.org/bunny351/ezd
Scala | 313 lines | 274 code | 39 blank | 0 comment | 5 complexity | 23bfa0cee0bb3d1fd539263d06b31ad2 MD5 | raw file
  1. ;;; ezd - easy drawing for X11 displays.
  2. ;;;
  3. ;;; The procedures in this module produce a Postscript file representing the
  4. ;;; contents of a window.
  5. ;* Copyright 1990-1993 Digital Equipment Corporation
  6. ;* All Rights Reserved
  7. ;*
  8. ;* Permission to use, copy, and modify this software and its documentation is
  9. ;* hereby granted only under the following terms and conditions. Both the
  10. ;* above copyright notice and this permission notice must appear in all copies
  11. ;* of the software, derivative works or modified versions, and any portions
  12. ;* thereof, and both notices must appear in supporting documentation.
  13. ;*
  14. ;* Users of this software agree to the terms and conditions set forth herein,
  15. ;* and hereby grant back to Digital a non-exclusive, unrestricted, royalty-free
  16. ;* right and license under any changes, enhancements or extensions made to the
  17. ;* core functions of the software, including but not limited to those affording
  18. ;* compatibility with other hardware or software environments, but excluding
  19. ;* applications which incorporate this software. Users further agree to use
  20. ;* their best efforts to return to Digital any such changes, enhancements or
  21. ;* extensions that they make and inform Digital of noteworthy uses of this
  22. ;* software. Correspondence should be provided to Digital at:
  23. ;*
  24. ;* Director of Licensing
  25. ;* Western Research Laboratory
  26. ;* Digital Equipment Corporation
  27. ;* 250 University Avenue
  28. ;* Palo Alto, California 94301
  29. ;*
  30. ;* This software may be distributed (but not offered for sale or transferred
  31. ;* for compensation) to third parties, provided such third parties agree to
  32. ;* abide by the terms and conditions of this notice.
  33. ;*
  34. ;* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
  35. ;* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
  36. ;* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
  37. ;* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  38. ;* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  39. ;* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
  40. ;* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  41. ;* SOFTWARE.
  42. (module psdraw)
  43. (include "struct.sch")
  44. (include "commands.sch")
  45. (include "ezd.sch")
  46. (include "ginfo.sch")
  47. (include "display.sch")
  48. (include "window.sch")
  49. (include "view.sch")
  50. (include "drawing.sch")
  51. (include "graphic.sch")
  52. (include "xternal.sch")
  53. ;;; The views of drawings in a window are output in Postscript to a file by
  54. ;;; the following procedure.
  55. (define (PSFILE window-name file)
  56. (let ((window (name->window window-name))
  57. (save-current-drawing *current-drawing*))
  58. (define (DEFINE-AND-CLIP-WINDOWBORDERPATH x y width height)
  59. (pscommand "/windowborderpath" "{" "newpath"
  60. (+ x width) (+ y height) "moveto" (- width) 0 "rlineto"
  61. 0 (- height) "rlineto" width 0 "rlineto" "closepath"
  62. "}" "def")
  63. (pscommand "windowborderpath" "clip"))
  64. (define (DRAW-VIEW view)
  65. (let ((x (or (view-clip-minx view) 0))
  66. (y (or (view-clip-miny view) 0))
  67. (width (if (view-clip-minx view)
  68. (- (view-clip-maxx view)
  69. (view-clip-minx view))
  70. (window-width window)))
  71. (height (if (view-clip-minx view)
  72. (- (view-clip-maxy view)
  73. (view-clip-miny view))
  74. (window-height window))))
  75. (set! *psfont* #f)
  76. (pscommand "gsave" "xwindowmatrix" "setmatrix")
  77. (define-and-clip-windowborderpath x y width height)
  78. (set-view view '())
  79. (psscale view)
  80. (bbgraphics-intersect (view-bb-head view) x y (+ x width)
  81. (+ y height) psdraw-bbgraphic)
  82. (pscommand "grestore")))
  83. (let loop ()
  84. (unless (or (window-exposed window)
  85. (null? (window-views window)))
  86. (ezd '(pause 1000))
  87. (loop)))
  88. (redraw-all-windows)
  89. (with-output-to-file file
  90. (lambda ()
  91. (psinit (window-width window) (window-height window))
  92. (define-and-clip-windowborderpath 0 0
  93. (window-width window) (window-height window))
  94. (unless (eq? (window-background-name window) 'white)
  95. (pscolor (window-background-name window))
  96. (pscommand "windowborderpath" "fill"))
  97. (for-each draw-view (window-views window))
  98. (psdone)))
  99. (set! *current-drawing* save-current-drawing)))
  100. ;;; The ezd command POSTSCRIPT writes a Postscript representation of the
  101. ;;; contents of a window to a file.
  102. (define-ezd-command
  103. `(postscript ,symbol? ,string?)
  104. "(postscript window-name file-name)"
  105. psfile)
  106. ;;; The header to the Postscript file is written by the following function.
  107. (define *PSCOLOR* #f)
  108. (define *PSFONT* #f)
  109. (define *PSFONTS* '())
  110. ;;; Information about the PostScript imaging area is entered here. The two
  111. ;;; values are the X and Y margin sizes in points.
  112. (define *PSXOFFSET* 27) ;;; 3/8 inch
  113. (define *PSYOFFSET* 99) ;;; 1-3/8 inch
  114. ;;; Widths and heights for available sizes of paper:
  115. (define *PSPAPER* (list "8.5 x 11 inch" "11 x 17 inch"))
  116. (define *PSWIDTH* (list (* 8.5 72) (* 11 72)))
  117. (define *PSHEIGHT* (list (* 11 72) (* 17 72)))
  118. (define (PSINIT width height)
  119. (define ROTATE #f)
  120. (define PSPAPER (car *pspaper*))
  121. (define PSWIDTH (car *pswidth*))
  122. (define PSHEIGHT (car *psheight*))
  123. (define PAPER-SELECTED #f)
  124. (define WIDTH-PTS (/ width *pixels/point*))
  125. (define HEIGHT-PTS (/ height *pixels/point*))
  126. (for-each
  127. (lambda (xpaper xwidth xheight)
  128. (cond (paper-selected)
  129. ((and (<= 0 width-pts (- xwidth (* 2 *psxoffset*)))
  130. (<= 0 height-pts (- xheight (* 2 *psyoffset*))))
  131. (set! paper-selected #t)
  132. (set! pswidth xwidth)
  133. (set! psheight xheight)
  134. (set! pspaper xpaper))
  135. ((and (<= 0 height-pts (- xwidth (* 2 *psxoffset*)))
  136. (<= 0 width-pts (- xheight (* 2 *psyoffset*))))
  137. (set! rotate #t)
  138. (set! paper-selected #t)
  139. (set! pswidth xwidth)
  140. (set! psheight xheight)
  141. (set! pspaper xpaper))))
  142. *pspaper* *pswidth* *psheight*)
  143. (set! *pscolor* #f)
  144. (set! *psfont* #f)
  145. (set! *psfonts* '())
  146. (pscommand "%!PS-Adobe-")
  147. (pscommand "%%Creator: ezd - easy drawing for X11 displays."
  148. "*EZD-VERSION*" *ezd-version*)
  149. (pscommand "%%CreationDate:"
  150. (if (procedure? (top-level-value 'time-of-day))
  151. ((top-level-value 'time-of-day))
  152. (list->string
  153. (let loop ((p ((top-level-value 'open-input-process) "date")))
  154. (let ((c (read-char p)))
  155. (if (eq? c #\newline) '() (cons c (loop p))))))))
  156. (pscommand "%%BoundingBox:"
  157. (inexact->exact
  158. (quotient (- pswidth (if rotate height-pts width-pts)) 2))
  159. (inexact->exact
  160. (quotient (- psheight (if rotate width-pts height-pts)) 2))
  161. (inexact->exact
  162. (- pswidth
  163. (quotient (- pswidth (if rotate height-pts width-pts)) 2)))
  164. (inexact->exact
  165. (- psheight
  166. (quotient (- psheight (if rotate width-pts height-pts)) 2))))
  167. (pscommand "%%DocumentFonts: (atend)")
  168. (pscommand "%%EndComments")
  169. (pscommand "% [Rotate] and center on" pspaper "paper")
  170. (if rotate
  171. (pscommand 90 "rotate" 0 (- pswidth) "translate"
  172. (inexact->exact (quotient (- psheight width-pts) 2))
  173. (inexact->exact (quotient (- pswidth height-pts) 2))
  174. "translate" "% INCLUDE-DELETE")
  175. (pscommand
  176. (inexact->exact (quotient (- pswidth width-pts) 2))
  177. (inexact->exact (quotient (- psheight height-pts) 2))
  178. "translate" "% INCLUDE-DELETE"))
  179. (pscommand
  180. "% Scale to reflect ?? dpi screen vs. 72 points/inch printer and save")
  181. (pscommand (/ *pixels/point*) (/ *pixels/point*) "scale" 1 "setlinewidth"
  182. 0 height "translate" 1 -1 "scale"
  183. "/xwindowmatrix" "matrix" "currentmatrix" "def")
  184. (pscommand "%%EndProlog")
  185. (pscommand "%%Page: 0 1"))
  186. ;;; Scaling for each view is done by the following function.
  187. (define (PSSCALE view)
  188. (pscommand "% Scale to reflect user distance and origin")
  189. (pscommand "xwindowmatrix" "setmatrix"
  190. (view-originx view) (view-originy view) "translate"
  191. (view-scalex view) (view-scaley view) "scale")
  192. (pscommand "/viewmatrix" "matrix" "currentmatrix" "def"))
  193. ;;; Complete the Postscript file.
  194. (define (PSDONE)
  195. (pscommand "showpage" "% INCLUDE-DELETE")
  196. (pscommand "%%Trailer")
  197. (pscommand "%%DocumentFonts:"
  198. (let loop ((fonts *psfonts*))
  199. (if fonts
  200. (let ((rest (loop (cdr fonts)))
  201. (x-ps-pts (assoc (car fonts) *translate-fonts*)))
  202. (if x-ps-pts
  203. (let ((font (cadr x-ps-pts)))
  204. (if (member font rest) rest (cons font rest)))))
  205. '("")))))
  206. ;;; Take a size in screen pixels and convert it to scaled units.
  207. (define (PSXPIXEL x) (* x (/ *width* (user->width *width*))))
  208. (define (PSYPIXEL x) (* x (/ *height* (user->height *height*))))
  209. ;;; Print a list of Postscript commands.
  210. (define (PSCOMMAND . cl)
  211. (let loop ((cl cl))
  212. (cond ((null? cl) #t)
  213. ((or (pair? (car cl)) (null? (car cl)))
  214. (loop (append (car cl) (cdr cl))))
  215. (else (display (car cl))
  216. (cond ((null? (cdr cl)) (newline))
  217. (else (display " ") (loop (cdr cl))))))))
  218. ;;; Set the current Postscript color.
  219. (define (PSCOLOR color)
  220. (let ((color (or color *foreground-name*)))
  221. (when (not (eq? color *pscolor*))
  222. (set! *pscolor* color)
  223. (let* ((rgb (getprop color 'isa-color))
  224. (r (/ (car rgb) 255))
  225. (g (/ (cadr rgb) 255))
  226. (b (/ (caddr rgb) 255)))
  227. (if (= r g b)
  228. (pscommand r "setgray")
  229. (pscommand r g b "setrgbcolor"))))))
  230. ;;; Stroke the currently set path in a given width and optional dash pattern.
  231. (define (PSSTROKE width dash)
  232. (let ((width (max 1 width)))
  233. (pscommand "gsave" "xwindowmatrix" "setmatrix"
  234. (if (not (= width 1))
  235. `(,width "setlinewidth")
  236. '())
  237. (if dash '("[ 3 ]" 0 "setdash") '())
  238. "stroke" "grestore")))
  239. ;;; Turn a string into a Postscript string.
  240. (define (PSSTRING text)
  241. (list->string
  242. (append '(#\()
  243. (let loop ((cl (string->list text)))
  244. (if (null? cl)
  245. '()
  246. (case (car cl)
  247. ((#\( #\) #\\ )
  248. (cons #\\ (cons (car cl) (loop (cdr cl)))))
  249. (else (cons (car cl) (loop (cdr cl)))))))
  250. '(#\)))))
  251. ;;; Set the current PostScript font. Transformation matrix corrects for
  252. ;;; user coordinate system and screen's dpi vs printers 72 pts/inch.
  253. (define (PSFONT font)
  254. (let ((font (or font "fixed")))
  255. (when (not (eq? font *psfont*))
  256. (unless (member font *psfonts*)
  257. (pscommand "xwindowmatrix" "setmatrix"
  258. (string-append "/FONT-" font)
  259. (let ((x (assoc font *translate-fonts*)))
  260. (if x
  261. (list (string-append "/" (cadr x))
  262. "findfont"
  263. "[" (* *pixels/point* (caddr x)) 0 0
  264. (* (- *pixels/point*) (caddr x)) 0 0
  265. "]" "makefont")
  266. (begin (format stderr-port
  267. "Can't translate font: ~a~%"
  268. font)
  269. "FONT-fixed")))
  270. "def"
  271. "viewmatrix" "setmatrix")
  272. (set! *psfonts* (cons font *psfonts*)))
  273. (pscommand (string-append "FONT-" font) "setfont"))
  274. (set! *psfont* font)))