Fix typo in convert-ly.
[lilypond.git] / scm / output-ps.scm
blob9274279a2cf732f61d2db234c88b5d9c586e7bfe
1 ;;;; output-ps.scm -- implement Scheme output interface for PostScript
2 ;;;;
3 ;;;;  source file of the GNU LilyPond music typesetter
4 ;;;; 
5 ;;;; (c) 1998--2007 Jan Nieuwenhuizen <janneke@gnu.org>
6 ;;;;                 Han-Wen Nienhuys <hanwen@xs4all.nl>
8 ;;;; Note: currently misused as testbed for titles with markup, see
9 ;;;;       input/test/title-markup.ly
10 ;;;; 
11 ;;;; TODO:
12 ;;;;   * %% Papersize in (header ...)
13 ;;;;   * text setting, kerning.
14 ;;;;   * document output-interface
16 (define-module (scm output-ps)
17   #:re-export (quote)
19   ;; JUNK this -- see lily.scm: ly:all-output-backend-commands
20   #:export (unknown
21             bezier-sandwich
22             char
23             circle
24             comment
25             dashed-line
26             dashed-slur
27             dot
28             draw-line
29             ellipse
30             embedded-ps
31             named-glyph
32             no-origin
33             oval
34             placebox
35             polygon
36             repeat-slash
37             resetcolor
38             resetrotation
39             round-filled-box
40             setcolor
41             setrotation
42             text
43             ))
46 (use-modules (guile)
47              (ice-9 regex)
48              (srfi srfi-1)
49              (srfi srfi-13)
50              (scm framework-ps)
51              (lily))
53 ;;; helper functions, not part of output interface
54 ;;;
57 ;; ice-9 format uses a lot of memory
58 ;; using simple-format almost halves lilypond cell usage
60 (define (str4 num)
61   (if (or (nan? num) (inf? num))
62       (begin
63         (ly:warning (_ "Found infinity or nan in output. Substituting 0.0"))
64         (if (ly:get-option 'strict-infinity-checking)
65             (exit 1))
66         "0.0")
67       (ly:number->string num)))
69 (define (number-pair->string4 numpair)
70   (ly:format "~4l" numpair)) 
72 ;;;
73 ;;; Lily output interface, PostScript implementation --- cleanup and docme
74 ;;;
76 ;; two beziers
77 (define (bezier-sandwich lst thick)
78   (ly:format "~l ~4f draw_bezier_sandwich" 
79              (map number-pair->string4 lst)
80           thick))
82 (define (char font i)
83   (ly:format "~a (\\~a) show"
84    (ps-font-command font)
85    (ly:inexact->string i 8)))
87 (define (circle radius thick fill)
88   (ly:format
89    "~a ~4f ~4f draw_circle"
90    (if fill
91      "true"
92      "false")
93    radius thick))
95 (define (dashed-line thick on off dx dy phase)
96   (ly:format "~4f ~4f ~4f [ ~4f ~4f ] ~4f draw_dashed_line"
97    dx
98    dy
99    thick
100    on
101    off
102    phase))
104 ;; what the heck is this interface ?
105 (define (dashed-slur thick on off l)
106   (ly:format "~l ~4f [ ~4f ~4f ] 0 draw_dashed_slur"
107           (let ((control-points (append (cddr l) (list (car l) (cadr l)))))
108             (map number-pair->string4 control-points))
109           thick
110           on
111           off))
113 (define (dot x y radius)
114   (ly:format " ~4l draw_dot" (list radius x y)))
116 (define (draw-line thick x1 y1 x2 y2)
117   (ly:format "~4f ~4f ~4f ~4f ~4f draw_line"
118           (- x2 x1) (- y2 y1)
119           x1 y1 thick))
121 (define (ellipse x-radius y-radius thick fill)
122   (ly:format
123    "~a ~4f ~4f ~4f draw_ellipse"
124    (if fill
125      "true"
126      "false")
127    x-radius y-radius thick))
129 (define (embedded-ps string)
130   string)
132 (define (glyph-string postscript-font-name
133                       size
134                       cid?
135                       w-x-y-named-glyphs)
137   (define (glyph-spec w x y g)
138     (let ((prefix (if (string? g) "/" "")))
139       (ly:format "~4f ~4f ~a~a"
140                  (+ w x)  y
141                  prefix g)))
142   
143   (ly:format 
144    (if cid?
145 "/~a /CIDFont findresource ~a output-scale div scalefont setfont
147 ~a print_glyphs"
149 "/~a ~a output-scale div selectfont
151 ~a print_glyphs")
152           postscript-font-name
153           size
154           (string-join (map (lambda (x) (apply glyph-spec x))
155                             (reverse w-x-y-named-glyphs)) "\n")
156           (length w-x-y-named-glyphs)))
159 (define (grob-cause offset grob)
160   (if (ly:get-option 'point-and-click)
161       (let* ((cause (ly:grob-property grob 'cause))
162              (music-origin (if (ly:stream-event? cause)
163                                (ly:event-property cause 'origin))))
164         (if (ly:input-location? music-origin)
165             (let* ((location (ly:input-file-line-char-column music-origin))
166                    (raw-file (car location))
167                    (file (if (is-absolute? raw-file)
168                              raw-file
169                              (string-append (ly-getcwd) "/" raw-file)))
170                    (x-ext (ly:grob-extent grob grob X))
171                    (y-ext (ly:grob-extent grob grob Y)))
173               (if (and (< 0 (interval-length x-ext))
174                        (< 0 (interval-length y-ext)))
175                   (ly:format "~4f ~4f ~4f ~4f (textedit://~a:~a:~a:~a) mark_URI\n"
176                              (+ (car offset) (car x-ext))
177                              (+ (cdr offset) (car y-ext))
178                              (+ (car offset) (cdr x-ext))
179                              (+ (cdr offset) (cdr y-ext))
181                              ;; TODO
182                              ;;full escaping.
184                              ;; backslash is interpreted by GS.
185                              (ly:string-substitute "\\" "/" 
186                                                    (ly:string-substitute " " "%20" file))
187                              (cadr location)
188                              (caddr location)
189                              (cadddr location))
190                   ""))
191             ""))
192       ""))
194 (define (named-glyph font glyph)
195   (ly:format "~a /~a glyphshow " ;;Why is there a space at the end?
196              (ps-font-command font)
197              glyph))
199 (define (no-origin)
200   "")
202 (define (oval x-radius y-radius thick fill)
203   (ly:format
204    "~a ~4f ~4f ~4f draw_oval"
205    (if fill
206      "true"
207      "false")
208    x-radius y-radius thick))
210 (define (placebox x y s) 
211   (ly:format
212 "~4f ~4f moveto
213 ~a\n" x y s))
215 (define (polygon points blot-diameter filled?)
216   (ly:format "~a ~4l ~a ~4f draw_polygon"
217              (if filled? "true" "false")
218              points
219              (- (/ (length points) 2) 1)
220              blot-diameter))
222 (define (repeat-slash width slope beam-thickness)
223   (define (euclidean-length x y)
224     (sqrt (+ (* x x) (* y y))))
226   (let ((x-width (euclidean-length beam-thickness (/ beam-thickness slope)))
227         (height (* width slope)))
228     (ly:format "~4l draw_repeat_slash"
229              (list x-width width height))))
232 (define (round-filled-box left right bottom top blotdiam)
233   (let* ((halfblot (/ blotdiam 2))
234          (x (- halfblot left))
235          (width (- right (+ halfblot x)))
236          (y (- halfblot bottom))
237          (height (- top (+ halfblot y))))
238     (ly:format  "~4l draw_round_box"
239                 (list width height x y blotdiam))))
241 ;; save current color on stack and set new color
242 (define (setcolor r g b)
243   (ly:format "gsave ~4l setrgbcolor\n"
244               (list r g b)))
246 ;; restore color from stack
247 (define (resetcolor) "grestore \n")
249 ;; rotation around given point
250 (define (setrotation ang x y)
251   (ly:format "gsave ~4l translate ~a rotate ~4l translate\n"
252              (list x y)
253              ang
254              (list (* -1 x) (* -1 y))))
256 (define (resetrotation ang x y)
257   "grestore  ")
260 (define (text font s)
261   ;; (ly:warning (_ "TEXT backend-command encountered in Pango backend"))
262   ;; (ly:warning (_ "Arguments: ~a ~a"" font str))
263   
264   (let* ((space-length (cdar (ly:text-dimension font " ")))
265          (space-move (string-append (number->string space-length)
266                                     ;; how much precision do we need here?
267                                     " 0.0 rmoveto "))
268          (out-vec (decode-byte-string s)))
270     (string-append
271      (ps-font-command font) " "
272      (string-join
273       (vector->list
274        (vector-for-each
275         
276         (lambda (sym)
277           (if (eq? sym 'space)
278               space-move
279               (string-append "/" (symbol->string sym) " glyphshow")))
280         out-vec))))))
282 (define (unknown) 
283   "\n unknown\n")
285 (define (url-link url x y)
286   (ly:format "~a ~a currentpoint vector_add  ~a ~a currentpoint vector_add (~a) mark_URI"
287              (car x)
288              (car y)
289              (cdr x)
290              (cdr y)
291              url))
293 (define (utf-8-string pango-font-description string)
294   (ly:warning (_ "utf-8-string encountered in PS backend")))
296 (define (path thickness exps)
297   (define (convert-path-exps exps)
298     (if (pair? exps)
299         (let*
300             ((head (car exps))
301              (rest (cdr exps))
302              (arity 
303               (cond
304                ((memq head '(rmoveto rlineto lineto moveto)) 2)
305                ((memq head '(rcurveto curveto)) 6)
306                (else 1)))
307              (args (take rest arity))
308              )
310           ;; WARNING: this is a vulnerability: a user can output arbitrary PS code here.
311           (cons (ly:format
312                         "~l ~a "
313                         args 
314                         head)
315                 (convert-path-exps (drop rest arity))))
316         '()))
317     
318     
319   (ly:format
320    "1 setlinecap ~a setlinewidth\n~l stroke"
321    thickness
322    (convert-path-exps exps) ))
323