1
2 /******************************************************************************
3 * MODULE : printer.cpp
4 * DESCRIPTION: Renderer for printing post-script graphics
5 * COPYRIGHT : (C) 1999 Joris van der Hoeven
6 *******************************************************************************
7 * This software falls under the GNU general public license version 3 or later.
8 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ******************************************************************************/
11
12 #include "printer.hpp"
13 #include "Metafont/tex_files.hpp"
14 #include "Freetype/tt_file.hpp"
15 #include "file.hpp"
16 #include "image_files.hpp"
17 #include "analyze.hpp"
18 #include "iterator.hpp"
19 #include "merge_sort.hpp"
20 #include "scheme.hpp"
21 #include "image_files.hpp"
22 #include "link.hpp"
23 #include "frame.hpp"
24 #include "converter.hpp"
25
26 string PS_CLIP_PUSH ("gsave");
27 string PS_CLIP_POP ("grestore");
28 string PS_CLIP ("cl");
29 string PS_LINE ("ln");
30 string PS_FILL ("fl");
31 string PS_ARC ("ac");
32 string PS_FILL_ARC ("fac");
33 string PS_STROKE ("st");
34 string PS_POL_START ("sp");
35 string PS_POL_NEXT ("np");
36 string PS_POL_END ("ep");
37 string PS1 ("u");
38 string PS2 ("z");
39
40 /******************************************************************************
41 * constructors and destructors
42 ******************************************************************************/
43
printer_rep(url ps_file_name2,int dpi2,int nr_pages2,string page_type2,bool landscape2,double paper_w2,double paper_h2)44 printer_rep::printer_rep (
45 url ps_file_name2, int dpi2, int nr_pages2,
46 string page_type2, bool landscape2, double paper_w2, double paper_h2):
47 renderer_rep (false),
48 ps_file_name (ps_file_name2), dpi (dpi2),
49 nr_pages (nr_pages2), page_type (page_type2),
50 landscape (landscape2), paper_w (paper_w2), paper_h (paper_h2),
51 use_alpha (get_preference ("experimental alpha") == "on"),
52 linelen (0), fg ((color) (-1)), bg ((color) (-1)), opacity (255),
53 ncols (0), lw (-1), nwidths (0), cfn (""), nfonts (0),
54 xpos (0), ypos (0), tex_flag (false), toc (TUPLE),
55 defs ("?"), tex_chars ("?"), tex_width ("?"),
56 tex_fonts ("?"), tex_font_chars (array<int>(0)), metadata ("")
57 {
58 string tex_pro, special_pro, color_pro, texps_pro;
59 load_string ("$TEXMACS_PATH/misc/convert/tex.pro", tex_pro, true);
60 load_string ("$TEXMACS_PATH/misc/convert/special.pro", special_pro, true);
61 load_string ("$TEXMACS_PATH/misc/convert/color.pro", color_pro, true);
62 load_string ("$TEXMACS_PATH/misc/convert/texps.pro", texps_pro, true);
63
64 prologue << "%!PS-Adobe-2.0";
65 if (suffix (ps_file_name) == "eps")
66 prologue << " EPSF-2.0";
67 prologue << "\n"
68 << "%%Creator: TeXmacs-" TEXMACS_VERSION "\n"
69 << "%%Title: " << as_string (tail (ps_file_name)) << "\n"
70 << "%%Pages: " << as_string (nr_pages) << "\n"
71 << "%%PageOrder: Ascend\n";
72 if (page_type != "user")
73 prologue << "%%DocumentPaperSizes: " << page_type << "\n";
74 if (landscape) {
75 psw= (int) (28.36*paper_h+ 0.5);
76 psh= (int) (28.36*paper_w+ 0.5);
77 }
78 else {
79 psw= (int) (28.36*paper_w+ 0.5);
80 psh= (int) (28.36*paper_h+ 0.5);
81 }
82 prologue << "%%BoundingBox: 0 0 "
83 << as_string (psw) << " "
84 << as_string (psh) << "\n";
85 if (landscape)
86 prologue << "%%Orientation: Landscape\n";
87 prologue << "%%EndComments\n\n"
88 << tex_pro << "\n"
89 << special_pro << "\n"
90 << texps_pro << "\n"
91 << "TeXDict begin\n"
92 << as_string ((int) (1864680.0*paper_w+ 0.5)) << " "
93 << as_string ((int) (1864680.0*paper_h+ 0.5)) << " 1000 "
94 << as_string (dpi) << " " << as_string (dpi)
95 << " (TeXmacs) @start\n";
96
97 define (PS_CLIP, string ("/pt4 X /pt3 X /pt2 X /pt1 X\n") *
98 string ("newpath pt1 pt2 moveto pt3 pt2 lineto ") *
99 string ("pt3 pt4 lineto pt1 pt4 lineto pt1 pt2 lineto clip"));
100 define (PS_LINE, string ("/pt4 X /pt3 X /pt2 X /pt1 X\n") *
101 string ("newpath pt1 pt2 moveto pt3 pt4 lineto stroke"));
102 define (PS_FILL, string ("/pt4 X /pt3 X /pt2 X /pt1 X\n") *
103 string ("newpath pt1 pt2 moveto pt3 pt2 lineto ") *
104 string ("pt3 pt4 lineto pt1 pt4 lineto pt1 pt2 eofill stroke"));
105 define (PS_ARC, string ("/a2 X /a1 X /r2 X /r1 X /pt2 X /pt1 X\n") *
106 string ("newpath pt1 pt2 r1 r2 a1 a2 ellipse stroke"));
107 define (PS_FILL_ARC, string ("/a2 X /a1 X /r2 X /r1 X /pt2 X /pt1 X\n") *
108 string ("newpath pt1 pt2 r1 r2 a1 a2 ellipse eofill stroke"));
109 define (PS_STROKE, string ("stroke"));
110 define (PS_POL_START, string ("/pt2 X /pt1 X\n") *
111 string ("newpath pt1 pt2 moveto"));
112 define (PS_POL_NEXT, string ("/pt2 X /pt1 X\n") *
113 string ("pt1 pt2 lineto"));
114 define (PS_POL_END, string ("closepath eofill"));
115 define (PS1, string ("gsave"));
116 define (PS2, string ("1 -1 scale show grestore"));
117
118 cur_page= 0;
119 next_page ();
120 }
121
~printer_rep()122 printer_rep::~printer_rep () {
123 next_page ();
124 generate_toc ();
125 generate_metadata ();
126 body << "\n%%Trailer\n"
127 << "end\n"
128 << "userdict /end-hook known{end-hook} if\n"
129 << "%%EOF\n";
130
131 generate_tex_fonts ();
132 prologue << "end\n"
133
134 << "systemdict /pdfmark known{userdict /?pdfmark systemdict /exec get put}{userdict /?pdfmark systemdict /pop get put userdict /pdfmark systemdict /cleartomark get put}ifelse\n"
135
136 << "%%EndProlog\n\n"
137 << "%%BeginSetup\n"
138 << "%%Feature: *Resolution " << as_string (dpi) << "dpi\n"
139 << "TeXDict begin\n";
140 prologue << "%%BeginPaperSize: " << page_type << "\n";
141 if (page_type != "user")
142 prologue << page_type << "\n";
143 else {
144 prologue << "/setpagedevice where\n";
145 prologue << "{ pop << /PageSize ["
146 << as_string (psw) << " " << as_string (psh)
147 << "] >> setpagedevice }\n";
148 prologue << "if\n";
149 }
150 prologue << "%%EndPaperSize\n";
151 if (landscape)
152 prologue << "@landscape\n";
153 prologue << "%%EndSetup\n";
154
155 string ps_text= prologue * "\n" * body;
156 save_string (ps_file_name, ps_text);
157 }
158
159 bool
is_printer()160 printer_rep::is_printer () {
161 return true;
162 }
163
164 void
next_page()165 printer_rep::next_page () {
166 if (cur_page > 0) print ("eop\n");
167 if (cur_page >= nr_pages) return;
168 cur_page++;
169 body << "\n%%Page: " << as_string (cur_page) << " "
170 << as_string (cur_page) << "\n"
171 << as_string (cur_page) << " "
172 << as_string (cur_page-1) << " bop\n";
173
174 set_clipping (0, (int) (-(dpi*PIXEL*paper_h)/2.54),
175 (int) ((dpi*PIXEL*paper_w)/2.54), 0);
176
177 fg = (color) (-1);
178 bg = (color) (-1);
179 lw = -1;
180 cfn = "";
181 xpos= 0;
182 ypos= 0;
183 }
184
185 /******************************************************************************
186 * subroutines for printing
187 ******************************************************************************/
188
189 void
define(string s,string defn)190 printer_rep::define (string s, string defn) {
191 if (defs->contains (s)) return;
192 defs (defn)= s;
193 prologue << "/" << s << " {" << defn << "} N\n";
194 }
195
196 void
sep()197 printer_rep::sep () {
198 if ((N(body) > 0) &&
199 (body [N(body)-1] != ')') &&
200 (body [N(body)-1] != '\n')) {
201 body << " ";
202 linelen++;
203 tex_flag= false;
204 }
205 }
206
207 void
cr()208 printer_rep::cr () {
209 body << "\n";
210 linelen= 0;
211 tex_flag= false;
212 }
213
214 void
print(string s)215 printer_rep::print (string s) {
216 if (N(s)==0) return;
217 if ((linelen>0) && (linelen+N(s)>79)) {
218 body << "\n";
219 linelen= 0;
220 tex_flag= false;
221 }
222 else if (s[0]!='(') sep ();
223 if (tex_flag && (s[0]=='(')) {
224 body->resize (N(body)-2);
225 linelen -= 2;
226 s= s (1,N(s));
227 }
228 body << s;
229 linelen += N(s);
230 tex_flag= false;
231 }
232
233 void
print(SI x,SI y)234 printer_rep::print (SI x, SI y) {
235 decode (x, y);
236 print (as_string (x-dpi));
237 print (as_string (y-dpi));
238 }
239
240 void
move_to(SI x,SI y)241 printer_rep::move_to (SI x, SI y) {
242 x += ox; y += oy;
243 if (x>=0) x= x/PIXEL; else x= (x-PIXEL+1)/PIXEL;
244 if (y>=0) y= y/PIXEL; else y= (y-PIXEL+1)/PIXEL;
245 if (tex_flag && (xpos==x) && (ypos==y)) return;
246 if (tex_flag && (ypos==y)) {
247 body->resize (N(body)-1);
248 linelen -= 1;
249 tex_flag= false;
250
251 int diff= x-xpos;
252 if ((diff>=-4) && (diff<=4)) print (string ((char) ('p'+diff)));
253 else {
254 print (as_string (diff));
255 print ("b");
256 }
257 xpos= x;
258 return;
259 }
260 xpos= x; ypos= y;
261 print (as_string (x-dpi));
262 print (as_string (-y-dpi));
263 print ("a");
264 }
265
266 string
define_alpha(int a)267 printer_rep::define_alpha (int a) {
268 string aa= as_string (((double) a) / 255.0);
269 string s= "[ /ca " * aa * " /CA " * aa * " /SetTransparency pdfmark";
270 if (!defs->contains (s)) define ("A" * as_string (a), s);
271 return defs[s];
272 }
273
274 void
select_color(color c)275 printer_rep::select_color (color c) {
276 int r, g, b, a;
277 get_rgb_color (c, r, g, b, a);
278 r= 10000+ ((r*1000)/255);
279 g= 10000+ ((g*1000)/255);
280 b= 10000+ ((b*1000)/255);
281 string rr= as_string (r); rr= rr(1,2) * "." * rr(2,5);
282 string gg= as_string (g); gg= gg(1,2) * "." * gg(2,5);
283 string bb= as_string (b); bb= bb(1,2) * "." * bb(2,5);
284 string s = rr * " " * gg * " " * bb * " setrgbcolor";
285 if (use_alpha) s= s * " " * define_alpha (a);
286 if (!defs->contains (s)) {
287 define ("C" * as_string (ncols), s);
288 ncols++;
289 }
290 print (defs[s]);
291 }
292
293 void
select_line_width(SI w)294 printer_rep::select_line_width (SI w) {
295 w= w/PIXEL; if (w<1) w=1;
296 string s = as_string (w) * " setlinewidth";
297 if (!defs->contains (s)) {
298 define ("W" * as_string (nwidths), s);
299 nwidths++;
300 }
301 print (defs[s]);
302 }
303
304 /******************************************************************************
305 * subroutines for fonts
306 ******************************************************************************/
307
308 static string
prepare_text(string s)309 prepare_text (string s) {
310 int i;
311 string r;
312 for (i=0; i<N(s); i++) {
313 int c= ((unsigned char) s[i]);
314 if ((s[i]=='(') || (s[i]==')') || (s[i]=='\\'))
315 r << '\\' << s[i];
316 else if ((c <= 32) || (c >= 128)) {
317 r << '\\';
318 r << ('0' + (c >> 6));
319 r << ('0' + ((c >> 3) & 7));
320 r << ('0' + (c & 7));
321 }
322 else r << s[i];
323 }
324 return r;
325 }
326
327 void
select_tex_font(string name)328 printer_rep::select_tex_font (string name) {
329 if (cfn==name) return;
330 cfn= name;
331 print (tex_fonts [name]);
332 }
333
334 /******************************************************************************
335 * make tex characters and fonts
336 ******************************************************************************/
337
338 static const char* hex_string= "0123456789ABCDEF";
339
340 void
make_tex_char(string name,unsigned char c,glyph gl)341 printer_rep::make_tex_char (string name, unsigned char c, glyph gl) {
342 // cout << "Make char " << (int) c << " of " << name << "\n";
343 string char_name (name * "-" * as_string ((int) c));
344 if (tex_chars->contains (char_name)) return;
345 if (!tex_fonts->contains (name)) {
346 tex_fonts (name)= "F" * as_string (nfonts);
347 tex_font_chars (name)= array<int> (0);
348 nfonts++;
349 }
350 tex_font_chars (name) << ((int) c);
351
352 string hex_code;
353 int i, j, count=0, cur= 0;
354 for (j=0; j < gl->height; j++)
355 for (i=0; i < ((gl->width+7) & (-8)); i++) {
356 cur= cur << 1;
357 if ((i<gl->width) && (gl->get_x(i,j)>0)) cur++;
358 count++;
359 if (count==4) {
360 hex_code << hex_string[cur];
361 cur = 0;
362 count= 0;
363 }
364 }
365
366 int d1= gl->width;
367 int d2= gl->height;
368 int d3= 130+ gl->xoff;
369 int d4= 126+ gl->yoff;
370 int d5= gl->lwidth;
371 if ((d1<256) && (d2<256) && (d3<256) && (d4<256) && (d5<256)) {
372 hex_code << as_hexadecimal (d1, 2) << as_hexadecimal (d2, 2)
373 << as_hexadecimal (d3, 2) << as_hexadecimal (d4, 2)
374 << as_hexadecimal (d5, 2);
375 hex_code= "<" * hex_code * ">";
376 }
377 else {
378 hex_code= "[<" * hex_code * ">";
379 hex_code << as_string (d1) << " " << as_string (d2) << " "
380 << as_string (d3) << " " << as_string (d4) << " "
381 << as_string (d5) << " ";
382 }
383
384 tex_chars (char_name)= hex_code;
385 tex_width (char_name)= as_string (d5);
386 }
387
388 static string
find_ps_font_name(string name,string s)389 find_ps_font_name (string name, string s) {
390 int i, n= N(s);
391 for (i=0; i<n; i++) {
392 if (test (s, i, "/FontName /")) {
393 i += 11;
394 int start= i;
395 while (i<n && s[i] != ' ') i++;
396 return s (start, i);
397 }
398 while (i<n && s[i] != '\12' && s[i] != '\15') i++;
399 }
400 return name;
401 }
402
403
404 #define HEX_PER_LINE 30
405
parse_length(string pfb,int & pos)406 static SI parse_length (string pfb, int& pos) {
407 QN c4= (QN) pfb[pos++];
408 QN c3= (QN) pfb[pos++];
409 QN c2= (QN) pfb[pos++];
410 QI c1= (QI) pfb[pos++];
411 return (((((((SI) c1)<<8)+ ((SI) c2))<<8)+ ((SI) c3))<<8)+ c4;
412 }
413
pfb_to_pfa(url file)414 static string pfb_to_pfa (url file) {
415 //cout << "pfb_to_pfa :" << file << LF;
416 string pfb, pfa;
417 QN magic, type = 0;
418 SI length;
419
420 (void) load_string (file, pfb, true);
421 int pos = 0, size = N(pfb);
422 while ((pos < size) && (type != 3)) {
423 parse (pfb, pos, magic);
424 //cout << "magic:" << as_hexadecimal(magic,2) << LF ;
425 if (magic != 128) {
426 FAILED ("Not a pfb file");
427 }
428 parse (pfb, pos, type);
429 //cout << "type:" << as_hexadecimal(type,2) << LF;
430 switch (type) {
431
432 case 1 :
433 // plain text
434 length = parse_length (pfb, pos);
435 // parse (pfb, pos, length);
436 //cout << "plain text of size " << length << LF;
437 for (int i=0; i <length; i++) {
438 QI ch;
439 parse(pfb, pos, ch);
440 if (ch == '\r') pfa << "\n";
441 else pfa << ch;
442 }
443 break;
444
445 case 2 :
446 // binary data
447 length = parse_length (pfb, pos);
448 // parse (pfb, pos, length);
449 //cout << "binary data of size " << length << LF;
450 for (int i=0; i <length; i++) {
451 QI ch;
452 parse(pfb, pos, ch);
453 pfa << as_hexadecimal (ch, 2);
454 if ((i+1) % HEX_PER_LINE == 0) pfa << "\n";
455 }
456 break;
457
458 case 3 :
459 //cout << "end of file" << LF;
460 // end of file
461 break;
462
463 default :
464 FAILED ("Unknown field type while reading PFB file");
465 break;
466
467 }
468 }
469 return pfa;
470 }
471
472 #undef HEX_PER_LINE
473
474
475
476
477 void
generate_tex_fonts()478 printer_rep::generate_tex_fonts () {
479 hashset<string> done;
480 iterator<string> it= iterate (tex_fonts);
481 while (it->busy ()) {
482 string fn_name= it->next ();
483 array<int> a= tex_font_chars [fn_name];
484 merge_sort (a);
485
486 int i, d, l;
487 string name = tex_fonts [fn_name], ttf;
488 int pos = search_forwards (".", fn_name);
489 string root = (pos==-1? fn_name: fn_name (0, pos));
490 #ifndef OS_WIN32 // we need pfbtopfa
491 if ((pos!=-1) && ends (fn_name, "tt")) {
492 int pos2= search_backwards (":", fn_name);
493 root= fn_name (0, pos2);
494 url u= tt_font_find (root);
495 if (suffix (u) == "pfb") {
496 ttf = pfb_to_pfa (u);
497 }
498 }
499 #endif
500
501 if (ttf != "") {
502 string ttf_name= find_ps_font_name (root, ttf);
503 if (!done->contains (root)) {
504 prologue << "%%BeginFont: " << root << "\n";
505 prologue << ttf;
506 prologue << "\n%%EndFont\n";
507 done->insert (root);
508 }
509
510 array<string> cum;
511 cum << "{}" * as_string (N(a));
512 for (i=0; i<N(a); i++) {
513 string w= tex_width [fn_name * "-" * as_string (a[i])];
514 d= (i==0? a[0]: (a[i]-a[i-1]-1));
515 if (d>0) cum << as_string (d) * "[";
516 cum << w * " ";
517 }
518 d= 255-a[i-1];
519 if (d>0) cum << as_string (d) * "[";
520
521 int szpos = pos-1;
522 while ((szpos>0) && is_numeric (fn_name[szpos-1])) szpos--;
523 double sz = as_double (fn_name (szpos, pos));
524 double dpi= as_double (fn_name (pos+1, N(fn_name)-2));
525 string mag= as_string (83.022 * (sz/10.0) * (dpi/600.0));
526
527 string fdef;
528 for (i=N(cum)-1; i>=0; i--) fdef << cum[i];
529 fdef= "/" * name * " " * fdef * " " * mag * " /" * ttf_name * " rf";
530 for (i=0, l=0; i<N(fdef); i++, l++)
531 if ((l<70) || (fdef[i]!=' ')) prologue << fdef[i];
532 else { prologue << '\n'; l=-1; }
533 prologue << "\n";
534 }
535 else {
536 prologue << "/" << tex_fonts [fn_name]
537 << " " << as_string (N(a))
538 << " " << as_string (a[N(a)-1]+1) << " df\n";
539 for (i=0; i<N(a); i++) {
540 int end;
541 string hex_code= tex_chars [fn_name * "-" * as_string (a[i])];
542 for (end=1; end < N(hex_code); end++)
543 if (hex_code[end-1]=='>') break;
544 string after= hex_code (end, N(hex_code));
545 if ((i>0) && (a[i]==(a[i-1]+1))) after << "I";
546 else after << as_string (a[i]) << " D";
547 if (i==(N(a)-1)) after << " E";
548 hex_code= hex_code (0, end);
549
550 int j, l, n= N(hex_code);
551 for (j=0; j<n; j+=79) {
552 if (n < (j+79)) prologue << hex_code (j, n);
553 else prologue << hex_code (j, j+79) << "\n";
554 }
555 l= 79-(n%79);
556 if (l<N(after)) prologue << "\n";
557 prologue << after << "\n";
558 }
559 }
560 }
561 }
562
563 /******************************************************************************
564 * Transformed rendering
565 ******************************************************************************/
566
567 void
set_transformation(frame fr)568 printer_rep::set_transformation (frame fr) {
569 ASSERT (fr->linear, "only linear transformations have been implemented");
570
571 SI cx1, cy1, cx2, cy2;
572 get_clipping (cx1, cy1, cx2, cy2);
573 rectangle oclip (cx1, cy1, cx2, cy2);
574
575 frame cv= scaling (point (pixel, -pixel),
576 point (-ox+dpi*pixel, -oy-dpi*pixel));
577 frame tr= invert (cv) * fr * cv;
578 point o = tr (point (0.0, 0.0));
579 point ux= tr (point (1.0, 0.0)) - o;
580 point uy= tr (point (0.0, 1.0)) - o;
581 //cout << "Set transformation " << o << ", " << ux << ", " << uy << "\n";
582 double tx= o[0];
583 double ty= o[1];
584 print ("gsave");
585 print ("[");
586 print (as_string (ux[0]));
587 print (as_string (ux[1]));
588 print (as_string (uy[0]));
589 print (as_string (uy[1]));
590 print (as_string (tx));
591 print (as_string (ty));
592 print ("]");
593 print ("concat");
594
595 rectangle nclip= fr [oclip];
596 renderer_rep::clip (nclip->x1, nclip->y1, nclip->x2, nclip->y2);
597 }
598
599 void
reset_transformation()600 printer_rep::reset_transformation () {
601 renderer_rep::unclip ();
602 print ("grestore");
603 }
604
605 /******************************************************************************
606 * Clipping
607 ******************************************************************************/
608
609 void
set_clipping(SI x1,SI y1,SI x2,SI y2,bool restore)610 printer_rep::set_clipping (SI x1, SI y1, SI x2, SI y2, bool restore) {
611 outer_round (x1, y1, x2, y2);
612 renderer_rep::set_clipping (x1, y1, x2, y2);
613 if (restore) {
614 print (PS_CLIP_POP);
615 cfn= "";
616 }
617 else {
618 print (PS_CLIP_PUSH);
619 print (x1, y1);
620 print (x2, y2);
621 print (PS_CLIP);
622 }
623 }
624
625 /******************************************************************************
626 * graphical routines
627 ******************************************************************************/
628
629 pencil
get_pencil()630 printer_rep::get_pencil () {
631 return pen;
632 }
633
634 brush
get_background()635 printer_rep::get_background () {
636 return bgb;
637 }
638
639 void
set_pencil(pencil pen2)640 printer_rep::set_pencil (pencil pen2) {
641 pen= pen2;
642 color c= pen->get_color ();
643 int r, g, b, a;
644 get_rgb_color (c, r, g, b, a);
645 opacity= a;
646 if (a != 255) {
647 int r2, g2, b2, a2;
648 get_rgb_color (bg, r2, g2, b2, a2);
649 r= (r * a + r2 * (255 - a)) / 255;
650 g= (g * a + g2 * (255 - a)) / 255;
651 b= (b * a + b2 * (255 - a)) / 255;
652 c= rgb_color (r, g, b, 255);
653 }
654 if (c != fg) {
655 fg= c;
656 select_color (fg);
657 }
658 //if (pen->w != lw) {
659 // FIXME: apparently, the line width can be overidden by some of
660 // the graphical constructs (example file: newimpl.tm, in which
661 // the second dag was not printed using the right width)
662 lw= pen->get_width ();
663 select_line_width (lw);
664 //}
665 }
666
667 void
set_background(brush b)668 printer_rep::set_background (brush b) {
669 //if (bgb==b) return;
670 bgb= b;
671 bg= b->get_color ();
672 }
673
674 void
draw(int ch,font_glyphs fn,SI x,SI y)675 printer_rep::draw (int ch, font_glyphs fn, SI x, SI y) {
676 if (opacity == 0) return;
677 glyph gl= fn->get(ch);
678 if (is_nil (gl)) return;
679 string name= fn->res_name;
680 unsigned char c= ch;
681 if (ch >= 256) {
682 name= name * "-" * as_string (ch / 256);
683 c= (unsigned char) (ch & 255);
684 }
685 make_tex_char (name, c, gl);
686 select_tex_font (name);
687 move_to (x, y);
688 print ("(" * prepare_text (string ((char) c)) * ")p");
689 tex_flag= true;
690 xpos += gl->lwidth;
691 }
692
693 void
line(SI x1,SI y1,SI x2,SI y2)694 printer_rep::line (SI x1, SI y1, SI x2, SI y2) {
695 if (opacity == 0) return;
696 print (x1, y1);
697 print (x2, y2);
698 print (PS_LINE);
699 }
700
701 void
lines(array<SI> x,array<SI> y)702 printer_rep::lines (array<SI> x, array<SI> y) {
703 if (opacity == 0) return;
704 int i, n= N(x);
705 if ((N(y) != n) || (n<1)) return;
706 print (x[0], y[0]);
707 print (PS_POL_START);
708 for (i=1; i<n; i++) {
709 print (x[i], y[i]);
710 print (PS_POL_NEXT);
711 }
712 print (PS_STROKE);
713 }
714
715 void
clear(SI x1,SI y1,SI x2,SI y2)716 printer_rep::clear (SI x1, SI y1, SI x2, SI y2) {
717 select_color (bg);
718 print (x1, y1);
719 print (x2, y2);
720 print (PS_FILL);
721 select_color (fg);
722 }
723
724 void
fill(SI x1,SI y1,SI x2,SI y2)725 printer_rep::fill (SI x1, SI y1, SI x2, SI y2) {
726 if (opacity == 0) return;
727 if ((x1<x2) && (y1<y2)) {
728 print (x1, y1);
729 print (x2, y2);
730 print (PS_FILL);
731 }
732 }
733
734 void
arc(SI x1,SI y1,SI x2,SI y2,int alpha,int delta)735 printer_rep::arc (SI x1, SI y1, SI x2, SI y2, int alpha, int delta) {
736 if (opacity == 0) return;
737 print ((x1+x2)/2, (y1+y2)/2);
738 print (as_string ((x2-x1)/(2*PIXEL)));
739 print (as_string ((y1-y2)/(2*PIXEL)));
740 print (as_string (((double) alpha)/64));
741 print (as_string (((double) (alpha+delta))/64));
742 print (PS_ARC);
743 }
744
745 void
fill_arc(SI x1,SI y1,SI x2,SI y2,int alpha,int delta)746 printer_rep::fill_arc (SI x1, SI y1, SI x2, SI y2, int alpha, int delta) {
747 if (opacity == 0) return;
748 print ((x1+x2)/2, (y1+y2)/2);
749 print (as_string ((x2-x1)/(2*PIXEL)));
750 print (as_string ((y1-y2)/(2*PIXEL)));
751 print (as_string (((double) alpha)/64));
752 print (as_string (((double) (alpha+delta))/64));
753 print (PS_FILL_ARC);
754 }
755
756 void
polygon(array<SI> x,array<SI> y,bool convex)757 printer_rep::polygon (array<SI> x, array<SI> y, bool convex) {
758 if (opacity == 0) return;
759 (void) convex;
760 int i, n= N(x);
761 if ((N(y) != n) || (n<1)) return;
762 print (x[0], y[0]);
763 print (PS_POL_START);
764 for (i=1; i<n; i++) {
765 print (x[i], y[i]);
766 print (PS_POL_NEXT);
767 }
768 print (PS_POL_END);
769 }
770
771 /*
772 string
773 incorporate_postscript (string s) {
774 int i;
775 string r;
776 for (i=0; i<N(s); )
777 if (s[i] == '%') {
778 for (; (i<N(s)) && (s[i]!='\n'); i++);
779 if (i<N(s)) i++;
780 }
781 else {
782 for (; (i<N(s)) && (s[i]!='\n'); ) r << s[i++];
783 if (i<N(s)) { r << s[i++]; }
784 }
785 return r;
786 }
787 */
788
789 void
image(string name,string eps,SI x1,SI y1,SI x2,SI y2,SI w,SI h,SI x,SI y,int alpha)790 printer_rep::image (
791 string name, string eps, SI x1, SI y1, SI x2, SI y2,
792 SI w, SI h, SI x, SI y, int alpha)
793 {
794 if (opacity == 0 || alpha == 0) return;
795
796 double sc_x= (72.0/dpi) * ((double) (w/PIXEL)) / ((double) (x2-x1));
797 double sc_y= (72.0/dpi) * ((double) (h/PIXEL)) / ((double) (y2-y1));
798 cr ();
799 cr ();
800
801 print (x, y);
802 print ("a");
803 print ("currentpoint");
804 print ("currentpoint");
805 print ("translate");
806 print (as_string (sc_x));
807 print (as_string (sc_y));
808 print ("scale");
809 print ("neg");
810 print ("exch");
811 print ("neg");
812 print ("exch");
813 print ("translate");
814 print (x, y);
815 print ("a");
816 cr ();
817 /* Black Black 248 3155 a currentpoint currentpoint translate
818 0.37114 0.37114 scale neg exch neg exch translate 248 3155 a */
819
820 print ("@beginspecial");
821 print (as_string (x1));
822 print ("@llx");
823 print (as_string (y1));
824 print ("@lly");
825 print (as_string (x2));
826 print ("@urx");
827 print (as_string (y2));
828 print ("@ury");
829 print (as_string (10*(x2-x1)));
830 print ("@rwi");
831 print ("@clip");
832 print ("@setspecial");
833 cr ();
834 /* @beginspecial 0 @llx 0 @lly 613.291260 @urx 613.291260 @ury 6110 @rwi
835 @clip @setspecial */
836
837 body << "%%BeginDocument: " << name << "\n";
838 body << eps; // incorporate_postscript (eps);
839 body << "%%EndDocument";
840 cr ();
841
842 print ("@endspecial");
843 print (x, y);
844 print ("a");
845 print ("currentpoint");
846 print ("currentpoint");
847 print ("translate");
848 print (as_string (1/sc_x));
849 print (as_string (1/sc_y));
850 print ("scale");
851 print ("neg");
852 print ("exch");
853 print ("neg");
854 print ("exch");
855 print ("translate");
856 print (x, y);
857 print ("a");
858 cr ();
859 cr ();
860
861 /* @endspecial 248 3155 a currentpoint currentpoint translate
862 1 0.37114 div 1 0.37114 div scale neg exch neg exch translate
863 248 3155 a 660 3073 a ... */
864
865 (void) w; (void) h;
866 }
867
868 void
fetch(SI x1,SI y1,SI x2,SI y2,renderer ren,SI x,SI y)869 printer_rep::fetch (SI x1, SI y1, SI x2, SI y2, renderer ren, SI x, SI y) {
870 (void) x1; (void) y1; (void) x2; (void) y2;
871 (void) ren; (void) x; (void) y;
872 }
873
874 void
new_shadow(renderer & ren)875 printer_rep::new_shadow (renderer& ren) {
876 (void) ren;
877 }
878
879 void
delete_shadow(renderer & ren)880 printer_rep::delete_shadow (renderer& ren) {
881 (void) ren;
882 }
883
884 void
get_shadow(renderer ren,SI x1,SI y1,SI x2,SI y2)885 printer_rep::get_shadow (renderer ren, SI x1, SI y1, SI x2, SI y2) {
886 (void) ren; (void) x1; (void) y1; (void) x2; (void) y2;
887 }
888
889 void
put_shadow(renderer ren,SI x1,SI y1,SI x2,SI y2)890 printer_rep::put_shadow (renderer ren, SI x1, SI y1, SI x2, SI y2) {
891 (void) ren; (void) x1; (void) y1; (void) x2; (void) y2;
892 }
893
894 void
apply_shadow(SI x1,SI y1,SI x2,SI y2)895 printer_rep::apply_shadow (SI x1, SI y1, SI x2, SI y2) {
896 (void) x1; (void) y1; (void) x2; (void) y2;
897 }
898
899 renderer
shadow(picture & pic,SI x1,SI y1,SI x2,SI y2)900 printer_rep::shadow (picture& pic, SI x1, SI y1, SI x2, SI y2) {
901 renderer ren= renderer_rep::shadow (pic, x1, y1, x2, y2);
902 ren->set_zoom_factor (1.0);
903 return ren;
904 }
905
906 void
draw_picture(picture p,SI x,SI y,int alpha)907 printer_rep::draw_picture (picture p, SI x, SI y, int alpha) {
908 (void) alpha; // FIXME
909 int w= p->get_width (), h= p->get_height ();
910 int ox= p->get_origin_x (), oy= p->get_origin_y ();
911 int pixel= 5*PIXEL;
912 string name= "picture";
913 string eps= picture_as_eps (p, 600);
914 int x1= -ox;
915 int y1= -oy;
916 int x2= w - ox;
917 int y2= h - oy;
918 x -= (int) 2.06 * ox * pixel; // FIXME: where does the magic 2.06 come from?
919 y -= (int) 2.06 * oy * pixel;
920 image (name, eps, x1, y1, x2, y2, w * pixel, h * pixel, x, y, 255);
921 }
922
923 void
draw_scalable(scalable im,SI x,SI y,int alpha)924 printer_rep::draw_scalable (scalable im, SI x, SI y, int alpha) {
925 if (im->get_type () != scalable_image)
926 renderer_rep::draw_scalable (im, x, y, alpha);
927 else {
928 url u= im->get_name ();
929 rectangle r= im->get_logical_extents ();
930 SI w= r->x2, h= r->y2;
931 string ps_image= ps_load (u);
932 string imtext= is_ramdisc (u)? "inline image": as_string (u);
933 int x1, y1, x2, y2;
934 ps_bounding_box (u, x1, y1, x2, y2);
935 image (imtext, ps_image, x1, y1, x2, y2, w, h, x, y, alpha);
936 }
937 }
938
939 void
anchor(string label,SI x1,SI y1,SI x2,SI y2)940 printer_rep::anchor (string label, SI x1, SI y1, SI x2, SI y2) {
941 string s = "(";
942 s = s << prepare_text (label) << ") cvn";
943 if (linelen>0) cr ();
944 print ("[ /Dest");
945 print (s);
946 print ("/View [/XYZ");
947 print (x1, y1);
948 print ("null] /DEST pdfmark");
949 cr ();
950 }
951
952 void
href(string label,SI x1,SI y1,SI x2,SI y2)953 printer_rep::href (string label, SI x1, SI y1, SI x2, SI y2) {
954 bool preserve= (get_locus_rendering ("locus-on-paper") == "preserve");
955 if (linelen>0) cr ();
956 print ("[");
957 if (starts (label, "#")) {
958 print ("/Dest");
959 print ("(" * prepare_text (label) * ") cvn");
960 }
961 else {
962 print ("/A");
963 print ("<< /S /URI /URI (" * prepare_text (label) * ") >>");
964 }
965 print ("/Rect [");
966 print (x1 - 5*PIXEL, y1 - 10*PIXEL);
967 print (x2 + 5*PIXEL, y2 + 10*PIXEL);
968 print ("]");
969 if (preserve)
970 print ("/Border [16 16 1 [3 10]] /Color [0.75 0.5 1.0]");
971 else
972 print ("/Border [16 16 0 [3 10]] /Color [0.75 0.5 1.0]");
973 print ("/Subtype /Link");
974 print ("/ANN pdfmark");
975 cr ();
976 }
977
978 void
toc_entry(string kind,string title,SI x,SI y)979 printer_rep::toc_entry (string kind, string title, SI x, SI y) {
980 decode (x, y);
981 string ls= "1";
982 if (kind == "toc-strong-1") ls= "1";
983 if (kind == "toc-strong-2") ls= "2";
984 if (kind == "toc-1") ls= "3";
985 if (kind == "toc-2") ls= "4";
986 if (kind == "toc-3") ls= "5";
987 if (kind == "toc-4") ls= "6";
988 if (kind == "toc-5") ls= "7";
989 string ps= as_string (cur_page);
990 string xs= as_string (x-dpi);
991 string ys= as_string (y-dpi);
992 toc << tuple (title, ls, ps, xs, ys);
993 }
994
995 void
structure_toc(tree t,int & i,tree & out,string level)996 structure_toc (tree t, int& i, tree& out, string level) {
997 //cout << "Structure " << t[i] << " at " << level << "\n";
998 if (i >= N(t)) return;
999 string nlevel= t[i][1]->label;
1000 if (nlevel <= level) return;
1001 tree next= tuple (t[i]);
1002 i++;
1003 while (i < N(t)) {
1004 string slevel= t[i][1]->label;
1005 if (slevel <= nlevel) break;
1006 structure_toc (t, i, next, nlevel);
1007 }
1008 out << next;
1009 }
1010
1011 static string
to_hex_string(string s)1012 to_hex_string (string s) {
1013 return "<FEFF" * utf8_to_hex_string (cork_to_utf8 (s)) * ">";
1014 }
1015
1016 void
generate_toc_item(tree t)1017 printer_rep::generate_toc_item (tree t) {
1018 string title= t[0][0]->label;
1019 string level= t[0][1]->label;
1020 string page = t[0][2]->label;
1021 string x = t[0][3]->label;
1022 string y = t[0][4]->label;
1023 string htit = to_hex_string (title);
1024 print ("[");
1025 if (N(t) > 1) {
1026 print ("/Count");
1027 print (as_string (1 - N(t)));
1028 }
1029 print ("/Page");
1030 print (page);
1031 print ("/View [ /XYZ");
1032 print (x);
1033 print (y);
1034 print ("0");
1035 print ("]");
1036 print ("/Title " * htit);
1037 print ("/OUT pdfmark");
1038 cr ();
1039 for (int i=1; i<N(t); i++)
1040 generate_toc_item (t[i]);
1041 }
1042
1043 void
generate_toc()1044 printer_rep::generate_toc () {
1045 tree rew (TUPLE);
1046 int i=0;
1047 while (i < N(toc))
1048 structure_toc (toc, i, rew, "0");
1049 for (i=0; i<N(rew); i++)
1050 generate_toc_item (rew[i]);
1051 }
1052
1053 void
set_metadata(string kind,string val)1054 printer_rep::set_metadata (string kind, string val) {
1055 metadata (kind)= val;
1056 }
1057
1058 void
generate_metadata()1059 printer_rep::generate_metadata () {
1060 if (N(metadata) == 0) return;
1061 print ("[");
1062 if (metadata->contains ("title"))
1063 print ("/Title " * to_hex_string (metadata ["title"]));
1064 if (metadata->contains ("author"))
1065 print ("/Author " * to_hex_string (metadata ["author"]));
1066 if (metadata->contains ("subject"))
1067 print ("/Subject " * to_hex_string (metadata ["subject"]));
1068 print ("/DOCINFO pdfmark");
1069 }
1070
1071 /******************************************************************************
1072 * user interface
1073 ******************************************************************************/
1074
1075 renderer
printer(url ps_file_name,int dpi,int nr_pages,string page_type,bool landscape,double paper_w,double paper_h)1076 printer (url ps_file_name, int dpi, int nr_pages,
1077 string page_type, bool landscape, double paper_w, double paper_h)
1078 {
1079 page_type= as_string (call ("standard-paper-size", object (page_type)));
1080 return tm_new<printer_rep> (ps_file_name, dpi, nr_pages,
1081 page_type, landscape, paper_w, paper_h);
1082 }
1083