]> git.donarmstrong.com Git - lilypond.git/blob - scm/output-ps.scm
Fix some bugs in the dynamic engraver and PostScript backend
[lilypond.git] / scm / output-ps.scm
1 ;;;; output-ps.scm -- implement Scheme output interface for PostScript
2 ;;;;
3 ;;;;  source file of the GNU LilyPond music typesetter
4 ;;;; 
5 ;;;; (c) 1998--2006 Jan Nieuwenhuizen <janneke@gnu.org>
6 ;;;;                 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7
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
15
16 (define-module (scm output-ps)
17   #:re-export (quote)
18
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             embedded-ps
30             named-glyph
31             no-origin
32             placebox
33             polygon
34             repeat-slash
35             resetcolor
36             resetrotatino
37             round-filled-box
38             setcolor
39                 setrotation
40             text
41             zigzag-line))
42
43
44 (use-modules (guile)
45              (ice-9 regex)
46              (srfi srfi-1)
47              (srfi srfi-13)
48              (scm framework-ps)
49              (lily))
50
51 ;;; helper functions, not part of output interface
52 ;;;
53
54
55 (define (escape-parentheses s)
56   (regexp-substitute/global #f "(^|[^\\])([\\(\\)])" s 'pre 1 "\\" 2 'post))
57
58 (define (ps-encoding text)
59   (escape-parentheses text))
60
61 (define (round2 num)
62   (/ (round (* 100 num)) 100))
63
64 (define (round4 num)
65   (/ (round (* 10000 num)) 10000))
66
67 (define (str4 num)
68   (format #f "~f" (round4 num)))
69
70 (define (number-pair->string4 numpair)
71   (format #f "~f ~f" (round4 (car numpair)) (round4 (cdr numpair))))
72
73 (define (numbers->string4 numlist)
74   (string-join (map str4 numlist) " "))
75
76 ;; FIXME: lily-def
77 (define-public (ps-string-def prefix key val)
78   (format #f "/ ~a~a (~a) def\n"
79           prefix
80           (symbol->string key)
81           (escape-parentheses val)))
82
83 (define (ps-number-def prefix key val)
84   (let ((s (if (integer? val)
85                (ly:number->string val)
86                (ly:number->string (exact->inexact val)))))
87     (format #f "/~a~a ~a def\n"
88             prefix
89             (symbol->string key) s)))
90
91
92 ;;;
93 ;;; Lily output interface, PostScript implementation --- cleanup and docme
94 ;;;
95
96 ;; two beziers
97 (define (bezier-sandwich lst thick)
98   (format #f "~a ~a draw_bezier_sandwich" 
99           (string-join (map number-pair->string4 lst) " ")
100           (str4 thick)))
101
102 (define (char font i)
103   (format #f "~a (\\~a) show"
104    (ps-font-command font)
105    (ly:inexact->string i 8)))
106
107 (define (circle radius thick fill)
108   (format #f
109    "~a ~f ~f draw_circle"
110    (if fill
111      "true"
112      "false")
113    (round4 radius) (round4 thick)))
114
115 (define (dashed-line thick on off dx dy)
116   (format #f "~a ~a ~a [ ~a ~a ] 0 draw_dashed_line"
117    (str4 dx)
118    (str4 dy)
119    (str4 thick)
120    (str4 on)
121    (str4 off)))
122
123 ;; what the heck is this interface ?
124 (define (dashed-slur thick on off l)
125   (format #f "~a ~a [ ~a ~a ] 0 draw_dashed_slur"
126           (let ((control-points (append (cddr l) (list (car l) (cadr l)))))
127             (string-join (map number-pair->string4 control-points) " "))
128           (str4 thick)
129           (str4 on)
130           (str4 off)))
131
132 (define (dot x y radius)
133   (format #f " ~a draw_dot"
134    (numbers->string4 (list radius x y))))
135
136 (define (draw-line thick x1 y1 x2 y2)
137   (format #f "~a ~a ~a ~a ~a draw_line"
138           (str4 (- x2 x1))
139           (str4 (- y2 y1))
140           (str4 x1)
141           (str4 y1)
142           (str4 thick)))
143
144 (define (embedded-ps string)
145   string)
146
147 (define (glyph-string postscript-font-name
148                       size
149                       cid?
150                       w-x-y-named-glyphs)
151
152   (define (glyph-spec w x y g)
153     (let ((prefix (if (string? g) "/" "")))
154       (format #f "~f ~f ~a~a"
155               (round2 (+ w x))
156               (round2 y)
157               prefix g)))
158   
159   (format #f
160           (if cid?
161 "/~a /CIDFont findresource ~a output-scale div scalefont setfont
162 ~a
163 ~a print_glyphs"
164
165 "/~a ~a output-scale div selectfont
166 ~a
167 ~a print_glyphs")
168           postscript-font-name
169           size
170           (string-join (map (lambda (x) (apply glyph-spec x))
171                             (reverse w-x-y-named-glyphs)) "\n")
172           (length w-x-y-named-glyphs)))
173
174
175 (define (grob-cause offset grob)
176   (let* ((cause (ly:grob-property grob 'cause))
177          (music-origin (if (ly:music? cause)
178                            (ly:music-property cause 'origin))))
179     (if (not (ly:input-location? music-origin))
180         ""
181         (let* ((location (ly:input-file-line-char-column music-origin))
182                (raw-file (car location))
183                (file (if (is-absolute? raw-file)
184                          raw-file
185                          (string-append (ly-getcwd) "/" raw-file)))
186                (x-ext (ly:grob-extent grob grob X))
187                (y-ext (ly:grob-extent grob grob Y)))
188
189           (if (and (< 0 (interval-length x-ext))
190                    (< 0 (interval-length y-ext)))
191               (format #f "~$ ~$ ~$ ~$ (textedit://~a:~a:~a:~a) mark_URI\n"
192                       (+ (car offset) (car x-ext))
193                       (+ (cdr offset) (car y-ext))
194                       (+ (car offset) (cdr x-ext))
195                       (+ (cdr offset) (cdr y-ext))
196
197                       ;; TODO
198                       ;;full escaping.
199
200                       ;; backslash is interpreted by GS.
201                       (string-regexp-substitute "\\\\" "/" 
202                                       (string-regexp-substitute " " "%20" file))
203                       (cadr location)
204                       (caddr location)
205                       (cadddr location))
206               "")))))
207
208 (define (lily-def key val)
209   (let ((prefix "lilypondlayout"))
210     (if (string=?
211           (substring key 0 (min (string-length prefix) (string-length key)))
212           prefix)
213       (format "/~a { ~a } bind def\n" key val)
214       (format "/~a (~a) def\n" key val))))
215
216 (define (named-glyph font glyph)
217   (format #f "~a /~a glyphshow " ;;Why is there a space at the end?
218           (ps-font-command font)
219           glyph))
220
221 (define (no-origin)
222   "")
223
224 (define (placebox x y s) 
225   (format #f
226 "~a ~a moveto
227 ~a\n"
228   (str4 x)
229   (str4 y)
230   s))
231
232 (define (polygon points blot-diameter filled?)
233   (format #f "~a ~a ~a ~a draw_polygon"
234           (if filled? "true" "false")
235           (numbers->string4 points)
236           (number->string (- (/ (length points) 2) 1))
237           (str4 blot-diameter)))
238
239 (define (repeat-slash width slope beam-thickness)
240   (define (euclidean-length x y)
241     (sqrt (+ (* x x) (* y y))))
242
243   (let ((x-width (euclidean-length beam-thickness (/ beam-thickness slope)))
244         (height (* width slope)))
245     (format #f "~a draw_repeat_slash"
246             (numbers->string4 (list x-width width height)))))
247
248 ;; restore color from stack
249 (define (resetcolor) "setrgbcolor\n")
250
251 ;; reset rotation
252 (define (resetrotation ang x y)
253   (format "~a translate ~a rotate ~a translate\n"
254     (numbers->string4 (list x y))
255     (number->string (* -1 ang))
256     (numbers->string4 (list (* -1 x) (* -1 y)))))
257
258 (define (round-filled-box left right bottom top blotdiam)
259   (let* ((halfblot (/ blotdiam 2))
260          (x (- halfblot left))
261          (width (- right (+ halfblot x)))
262          (y (- halfblot bottom))
263          (height (- top (+ halfblot y))))
264     (format #f "~a draw_round_box"
265             (numbers->string4
266               (list width height x y blotdiam)))))
267
268 ;; save current color on stack and set new color
269 (define (setcolor r g b)
270   (format #f "currentrgbcolor ~a setrgbcolor\n"
271           (numbers->string4 (list r g b))))
272
273 ;; rotation around given point
274 (define (setrotation ang x y)
275   (format "~a translate ~a rotate ~a translate\n"
276     (numbers->string4 (list x y))
277     (number->string ang)
278     (numbers->string4 (list (* -1 x) (* -1 y)))))
279
280 (define (text font s)
281   ;; (ly:warning (_ "TEXT backend-command encountered in Pango backend"))
282   ;; (ly:warning (_ "Arguments: ~a ~a"" font str))
283   
284   (let* ((space-length (cdar (ly:text-dimension font " ")))
285          (space-move (string-append (number->string space-length)
286                                     ;; how much precision do we need here?
287                                     " 0.0 rmoveto "))
288          (out-vec (decode-byte-string s)))
289
290     (string-append
291      (ps-font-command font) " "
292      (string-join
293       (vector->list
294        (vector-for-each
295         
296         (lambda (sym)
297           (if (eq? sym 'space)
298               space-move
299               (string-append "/" (symbol->string sym) " glyphshow")))
300         out-vec))))))
301
302 (define (unknown) 
303   "\n unknown\n")
304
305 (define (url-link url x y)
306   (format #f "~$ ~$ ~$ ~$ (~a) mark_URI"
307           (car x)
308           (car y)
309           (cdr x)
310           (cdr y)
311           url))
312
313 (define (utf-8-string pango-font-description string)
314   (ly:warning (_ "utf-8-string encountered in PS backend")))
315
316
317 (define (zigzag-line centre? zzw zzh thick dx dy)
318   (format #f "~a ~a ~a ~a 0 0 ~a ~a draw_zigzag_line"
319    (if centre? "true" "false")
320    (str4 zzw)
321    (str4 zzh)
322    (str4 thick)
323    (str4 dx)
324    (str4 dy)))