gs.el 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. ;;; gs.el --- interface to Ghostscript
  2. ;; Copyright (C) 1998, 2001-2017 Free Software Foundation, Inc.
  3. ;; Maintainer: emacs-devel@gnu.org
  4. ;; Keywords: internal
  5. ;; Obsolete-since: 26.1
  6. ;; This file is part of GNU Emacs.
  7. ;; GNU Emacs is free software: you can redistribute it and/or modify
  8. ;; it under the terms of the GNU General Public License as published by
  9. ;; the Free Software Foundation, either version 3 of the License, or
  10. ;; (at your option) any later version.
  11. ;; GNU Emacs is distributed in the hope that it will be useful,
  12. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ;; GNU General Public License for more details.
  15. ;; You should have received a copy of the GNU General Public License
  16. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  17. ;;; Commentary:
  18. ;; This code is experimental. Don't use it. Try imagemagick images instead.
  19. ;; When this file is removed from Emacs, associated code in image.c
  20. ;; can be removed too (HAVE_GHOSTSCRIPT).
  21. ;;; Code:
  22. (defvar gs-program "gs"
  23. "The name of the Ghostscript interpreter.")
  24. (defvar gs-device "x11"
  25. "The Ghostscript device to use to produce images.")
  26. (defvar gs-options
  27. '("-q"
  28. ;"-dNOPAUSE"
  29. "-dSAFER"
  30. "-dBATCH"
  31. "-sDEVICE=<device>"
  32. "<file>")
  33. "List of command line arguments to pass to Ghostscript.
  34. Arguments may contain place-holders `<file>' for the name of the
  35. input file, and `<device>' for the device to use.")
  36. (put 'gs-options 'risky-local-variable t)
  37. (defun gs-options (device file)
  38. "Return a list of command line options with place-holders replaced.
  39. DEVICE is the value to substitute for the place-holder `<device>',
  40. FILE is the value to substitute for the place-holder `<file>'."
  41. (mapcar #'(lambda (option)
  42. (setq option (replace-regexp-in-string "<device>" device option)
  43. option (replace-regexp-in-string "<file>" file option)))
  44. gs-options))
  45. ;; The GHOSTVIEW property (taken from gv 3.5.8).
  46. ;;
  47. ;; Type:
  48. ;;
  49. ;; STRING
  50. ;;
  51. ;; Parameters:
  52. ;;
  53. ;; BPIXMAP ORIENT LLX LLY URX URY XDPI YDPI [LEFT BOTTOM TOP RIGHT]
  54. ;;
  55. ;; Scanf format: "%d %d %d %d %d %d %f %f %d %d %d %d"
  56. ;;
  57. ;; Explanation of parameters:
  58. ;;
  59. ;; BPIXMAP: pixmap id of the backing pixmap for the window. If no
  60. ;; pixmap is to be used, this parameter should be zero. This
  61. ;; parameter must be zero when drawing on a pixmap.
  62. ;;
  63. ;; ORIENT: orientation of the page. The number represents clockwise
  64. ;; rotation of the paper in degrees. Permitted values are 0, 90, 180,
  65. ;; 270.
  66. ;;
  67. ;; LLX, LLY, URX, URY: Bounding box of the drawable. The bounding box
  68. ;; is specified in PostScript points in default user coordinates.
  69. ;;
  70. ;; XDPI, YDPI: Resolution of window. (This can be derived from the
  71. ;; other parameters, but not without roundoff error. These values are
  72. ;; included to avoid this error.)
  73. ;;
  74. ;; LEFT, BOTTOM, TOP, RIGHT: (optional) Margins around the window.
  75. ;; The margins extend the imageable area beyond the boundaries of the
  76. ;; window. This is primarily used for popup zoom windows. I have
  77. ;; encountered several instances of PostScript programs that position
  78. ;; themselves with respect to the imageable area. The margins are
  79. ;; specified in PostScript points. If omitted, the margins are
  80. ;; assumed to be 0.
  81. (declare-function x-display-mm-width "xfns.c" (&optional terminal))
  82. (declare-function x-display-pixel-width "xfns.c" (&optional terminal))
  83. (defun gs-width-in-pt (frame pixel-width)
  84. "Return, on FRAME, pixel width PIXEL-WIDTH translated to pt."
  85. (let ((mm (* (float pixel-width)
  86. (/ (float (x-display-mm-width frame))
  87. (float (x-display-pixel-width frame))))))
  88. (/ (* 25.4 mm) 72.0)))
  89. (declare-function x-display-mm-height "xfns.c" (&optional terminal))
  90. (declare-function x-display-pixel-height "xfns.c" (&optional terminal))
  91. (defun gs-height-in-pt (frame pixel-height)
  92. "Return, on FRAME, pixel height PIXEL-HEIGHT translated to pt."
  93. (let ((mm (* (float pixel-height)
  94. (/ (float (x-display-mm-height frame))
  95. (float (x-display-pixel-height frame))))))
  96. (/ (* 25.4 mm) 72.0)))
  97. (declare-function x-change-window-property "xfns.c"
  98. (prop value &optional frame type format outer-p))
  99. (defun gs-set-ghostview-window-prop (frame spec img-width img-height)
  100. "Set the `GHOSTVIEW' window property of FRAME.
  101. SPEC is a GS image specification. IMG-WIDTH is the width of the
  102. requested image, and IMG-HEIGHT is the height of the requested
  103. image in pixels."
  104. (let* ((box (plist-get (cdr spec) :bounding-box))
  105. (llx (elt box 0))
  106. (lly (elt box 1))
  107. (urx (elt box 2))
  108. (ury (elt box 3))
  109. (rotation (or (plist-get (cdr spec) :rotate) 0))
  110. ;; The pixel width IMG-WIDTH of the pixmap gives the
  111. ;; dots, URX - LLX give the inch.
  112. (in-width (/ (- urx llx) 72.0))
  113. (in-height (/ (- ury lly) 72.0))
  114. (xdpi (/ img-width in-width))
  115. (ydpi (/ img-height in-height)))
  116. (x-change-window-property "GHOSTVIEW"
  117. (format "0 %d %d %d %d %d %g %g"
  118. rotation llx lly urx ury xdpi ydpi)
  119. frame)))
  120. (declare-function x-display-grayscale-p "xfns.c" (&optional terminal))
  121. (defun gs-set-ghostview-colors-window-prop (frame pixel-colors)
  122. "Set the `GHOSTVIEW_COLORS' environment variable depending on FRAME."
  123. (let ((mode (cond ((x-display-color-p frame) "Color")
  124. ((x-display-grayscale-p frame) "Grayscale")
  125. (t "Monochrome"))))
  126. (x-change-window-property "GHOSTVIEW_COLORS"
  127. (format "%s %s" mode pixel-colors)
  128. frame)))
  129. (declare-function x-window-property "xfns.c"
  130. (prop &optional frame type source delete-p vector-ret-p))
  131. ;;;###autoload
  132. (defun gs-load-image (frame spec img-width img-height window-and-pixmap-id
  133. pixel-colors)
  134. "Load a PS image for display on FRAME.
  135. SPEC is an image specification, IMG-HEIGHT and IMG-WIDTH are width
  136. and height of the image in pixels. WINDOW-AND-PIXMAP-ID is a string of
  137. the form \"WINDOW-ID PIXMAP-ID\". Value is non-nil if successful."
  138. (unwind-protect
  139. (let ((file (plist-get (cdr spec) :file))
  140. gs
  141. (timeout 40))
  142. ;; Wait while property gets freed from a previous ghostscript process
  143. ;; sit-for returns nil as soon as input starts being
  144. ;; available, so if we want to give GhostScript a reasonable
  145. ;; chance of starting up, we better use sleep-for. We let
  146. ;; sleep-for wait only half the time because if input is
  147. ;; available, it is more likely that we don't care that much
  148. ;; about garbled redisplay and are in a hurry.
  149. (while (and
  150. ;; Wait while the property is not yet available
  151. (not (zerop (length (x-window-property "GHOSTVIEW"
  152. frame))))
  153. ;; The following was an alternative condition: wait
  154. ;; while there is still a process running. The idea
  155. ;; was to avoid contention between processes. Turned
  156. ;; out even more sluggish.
  157. ;; (get-buffer-process "*GS*")
  158. (not (zerop timeout)))
  159. (unless (sit-for 0.1 t)
  160. (sleep-for 0.05))
  161. (setq timeout (1- timeout)))
  162. ;; No use waiting longer. We might want to try killing off
  163. ;; stuck processes, but there is no point in doing so: either
  164. ;; they are stuck for good, in which case the user would
  165. ;; probably be responsible for that, and killing them off will
  166. ;; make debugging harder, or they are not. In that case, they
  167. ;; will cause incomplete displays. But the same will happen
  168. ;; if they are killed, anyway. The whole is rather
  169. ;; disconcerting, and fast scrolling through a dozen images
  170. ;; will make Emacs freeze for a while. The alternatives are a)
  171. ;; proper implementation not waiting at all but creating
  172. ;; appropriate queues, or b) permanently bad display due to
  173. ;; bad cached images. So remember that this
  174. ;; is just a hack and if people don't like the behavior, they
  175. ;; will most likely like the easy alternatives even less.
  176. ;; And at least the image cache will make the delay apparent
  177. ;; just once.
  178. (gs-set-ghostview-window-prop frame spec img-width img-height)
  179. (gs-set-ghostview-colors-window-prop frame pixel-colors)
  180. (setenv "GHOSTVIEW" window-and-pixmap-id)
  181. (setq gs (apply 'start-process "gs" "*GS*" gs-program
  182. (gs-options gs-device file)))
  183. (set-process-query-on-exit-flag gs nil)
  184. gs)
  185. nil))
  186. ;(defun gs-put-tiger ()
  187. ; (let* ((ps-file "/usr/local/share/ghostscript/5.10/examples/tiger.ps")
  188. ; (spec `(image :type postscript
  189. ; :pt-width 200 :pt-height 200
  190. ; :bounding-box (22 171 567 738)
  191. ; :file ,ps-file)))
  192. ; (put-text-property 1 2 'display spec)))
  193. ;
  194. (provide 'gs)
  195. ;;; gs.el ends here