1 //
2 // "$Id$"
3 //
4 // PostScript device support for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 2010-2015 by Bill Spitzak and others.
7 //
8 // This library is free software. Distribution and use rights are outlined in
9 // the file "COPYING" which should have been included with this file. If this
10 // file is missing or damaged, see the license at:
11 //
12 // http://www.fltk.org/COPYING.php
13 //
14 // Please report all bugs and problems to:
15 //
16 // http://www.fltk.org/str.php
17 //
18
19 #include <FL/Fl_Printer.H>
20 #include <config.h>
21 #include <FL/Fl.H>
22 #include <FL/fl_ask.H>
23 #include <FL/fl_draw.H>
24 #include <stdio.h>
25 #include <FL/Fl_PostScript.H>
26 #include <FL/Fl_Native_File_Chooser.H>
27 #include <stdarg.h>
28 #if defined(USE_X11)
29 #include "Fl_Font.H"
30 #if USE_XFT
31 #include <X11/Xft/Xft.h>
32 #endif
33 #endif
34
35 const char *Fl_PostScript_Graphics_Driver::class_id = "Fl_PostScript_Graphics_Driver";
36 const char *Fl_PostScript_File_Device::class_id = "Fl_PostScript_File_Device";
37 /** \brief Label of the PostScript file chooser window */
38 const char *Fl_PostScript_File_Device::file_chooser_title = "Select a .ps file";
39
40 /**
41 @brief The constructor.
42 */
Fl_PostScript_Graphics_Driver(void)43 Fl_PostScript_Graphics_Driver::Fl_PostScript_Graphics_Driver(void)
44 {
45 close_cmd_ = 0;
46 //lang_level_ = 3;
47 lang_level_ = 2;
48 mask = 0;
49 ps_filename_ = NULL;
50 scale_x = scale_y = 1.;
51 bg_r = bg_g = bg_b = 255;
52 }
53
54 /** \brief The destructor. */
~Fl_PostScript_Graphics_Driver()55 Fl_PostScript_Graphics_Driver::~Fl_PostScript_Graphics_Driver() {
56 if(ps_filename_) free(ps_filename_);
57 }
58
59 /**
60 @brief The constructor.
61 */
Fl_PostScript_File_Device(void)62 Fl_PostScript_File_Device::Fl_PostScript_File_Device(void)
63 {
64 #ifdef __APPLE__
65 gc = fl_gc; // the display context is used by fl_text_extents()
66 #endif
67 Fl_Surface_Device::driver( new Fl_PostScript_Graphics_Driver() );
68 }
69
70 /**
71 \brief Returns the PostScript driver of this drawing surface.
72 */
driver()73 Fl_PostScript_Graphics_Driver *Fl_PostScript_File_Device::driver()
74 {
75 return (Fl_PostScript_Graphics_Driver*)Fl_Surface_Device::driver();
76 }
77
78
79 /**
80 @brief Begins the session where all graphics requests will go to a local PostScript file.
81 *
82 Opens a file dialog entitled with Fl_PostScript_File_Device::file_chooser_title to select an output PostScript file.
83 @param pagecount The total number of pages to be created. Use 0 if this number is unknown when this function is called.
84 @param format Desired page format.
85 @param layout Desired page layout.
86 @return 0 if OK, 1 if user cancelled the file dialog, 2 if fopen failed on user-selected output file.
87 */
start_job(int pagecount,enum Fl_Paged_Device::Page_Format format,enum Fl_Paged_Device::Page_Layout layout)88 int Fl_PostScript_File_Device::start_job (int pagecount, enum Fl_Paged_Device::Page_Format format,
89 enum Fl_Paged_Device::Page_Layout layout)
90 {
91 Fl_Native_File_Chooser fnfc;
92 fnfc.title(Fl_PostScript_File_Device::file_chooser_title);
93 fnfc.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
94 fnfc.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM | Fl_Native_File_Chooser::USE_FILTER_EXT);
95 fnfc.filter("PostScript\t*.ps\n");
96 // Show native chooser
97 if ( fnfc.show() ) return 1;
98 Fl_PostScript_Graphics_Driver *ps = driver();
99 ps->output = fl_fopen(fnfc.filename(), "w");
100 if(ps->output == NULL) return 2;
101 ps->ps_filename_ = strdup(fnfc.filename());
102 ps->start_postscript(pagecount, format, layout);
103 this->set_current();
104 return 0;
105 }
106
107 extern "C" {
dont_close(FILE * f)108 static int dont_close(FILE *f)
109 {
110 return 0;
111 }
112 }
113
114 /**
115 @brief Begins the session where all graphics requests will go to FILE pointer.
116 *
117 @param ps_output A writable FILE pointer that will receive PostScript output and that should not be closed
118 until after end_job() has been called.
119 @param pagecount The total number of pages to be created. Use 0 if this number is unknown when this function is called.
120 @param format Desired page format.
121 @param layout Desired page layout.
122 @return always 0.
123 */
start_job(FILE * ps_output,int pagecount,enum Fl_Paged_Device::Page_Format format,enum Fl_Paged_Device::Page_Layout layout)124 int Fl_PostScript_File_Device::start_job (FILE *ps_output, int pagecount,
125 enum Fl_Paged_Device::Page_Format format, enum Fl_Paged_Device::Page_Layout layout)
126 {
127 Fl_PostScript_Graphics_Driver *ps = driver();
128 ps->output = ps_output;
129 ps->ps_filename_ = NULL;
130 ps->start_postscript(pagecount, format, layout);
131 ps->close_command(dont_close); // so that end_job() doesn't close the file
132 this->set_current();
133 return 0;
134 }
135
136 /** Don't use with this class. */
start_job(int pagecount,int * from,int * to)137 int Fl_PostScript_File_Device::start_job(int pagecount, int* from, int* to)
138 {
139 return 1;
140 }
141
142 /**
143 @brief The destructor.
144 */
~Fl_PostScript_File_Device()145 Fl_PostScript_File_Device::~Fl_PostScript_File_Device() {
146 Fl_PostScript_Graphics_Driver *ps = driver();
147 if (ps) delete ps;
148 }
149
150 /** Shields output PostScript data from modifications of the current locale.
151 It typically avoids PostScript errors caused if the current locale uses comma instead of dot
152 as "decimal point".
153 \param format directives controlling output PostScript data
154 \return value returned by vfprintf() call
155 */
clocale_printf(const char * format,...)156 int Fl_PostScript_Graphics_Driver::clocale_printf(const char *format, ...)
157 {
158 char *saved_locale = setlocale(LC_NUMERIC, NULL);
159 setlocale(LC_NUMERIC, "C");
160 va_list args;
161 va_start(args, format);
162 int retval = vfprintf(output, format, args);
163 va_end(args);
164 setlocale(LC_NUMERIC, saved_locale);
165 return retval;
166 }
167
168 #ifndef FL_DOXYGEN
169
170 #if ! (defined(__APPLE__) || defined(WIN32) )
171 # include "print_panel.cxx"
172 #endif
173
174 // Prolog string
175
176 static const char * prolog =
177 "%%BeginProlog\n"
178 "/L { /y2 exch def\n"
179 "/x2 exch def\n"
180 "/y1 exch def\n"
181 "/x1 exch def\n"
182 "newpath x1 y1 moveto x2 y2 lineto\n"
183 "stroke}\n"
184 "bind def\n"
185
186
187 "/R { /dy exch def\n"
188 "/dx exch def\n"
189 "/y exch def\n"
190 "/x exch def\n"
191 "newpath\n"
192 "x y moveto\n"
193 "dx 0 rlineto\n"
194 "0 dy rlineto\n"
195 "dx neg 0 rlineto\n"
196 "closepath stroke\n"
197 "} bind def\n"
198
199 "/CL {\n"
200 "/dy exch def\n"
201 "/dx exch def\n"
202 "/y exch def\n"
203 "/x exch def\n"
204 "newpath\n"
205 "x y moveto\n"
206 "dx 0 rlineto\n"
207 "0 dy rlineto\n"
208 "dx neg 0 rlineto\n"
209 "closepath\n"
210 "clip\n"
211 "} bind def\n"
212
213 "/FR { /dy exch def\n"
214 "/dx exch def\n"
215 "/y exch def\n"
216 "/x exch def\n"
217 "currentlinewidth 0 setlinewidth newpath\n"
218 "x y moveto\n"
219 "dx 0 rlineto\n"
220 "0 dy rlineto\n"
221 "dx neg 0 rlineto\n"
222 "closepath fill setlinewidth\n"
223 "} bind def\n"
224
225 "/GS { gsave } bind def\n"
226 "/GR { grestore } bind def\n"
227
228 "/SP { showpage } bind def\n"
229 "/LW { setlinewidth } bind def\n"
230 "/CF /Courier def\n"
231 "/SF { /CF exch def } bind def\n"
232 "/fsize 12 def\n"
233 "/FS { /fsize exch def fsize CF findfont exch scalefont setfont }def \n"
234
235
236 "/GL { setgray } bind def\n"
237 "/SRGB { setrgbcolor } bind def\n"
238
239 "/A85RLE { /ASCII85Decode filter /RunLengthDecode filter } bind def\n" // ASCII85Decode followed by RunLengthDecode filters
240
241 // color images
242
243 "/CI { GS /py exch def /px exch def /sy exch def /sx exch def\n"
244 "translate \n"
245 "sx sy scale px py 8 \n"
246 "[ px 0 0 py neg 0 py ]\n"
247 "currentfile A85RLE\n false 3"
248 " colorimage GR\n"
249 "} bind def\n"
250
251 // gray images
252
253 "/GI { GS /py exch def /px exch def /sy exch def /sx exch def \n"
254 "translate \n"
255 "sx sy scale px py 8 \n"
256
257
258 "[ px 0 0 py neg 0 py ]\n"
259 "currentfile A85RLE\n"
260 "image GR\n"
261 "} bind def\n"
262
263 // single-color bitmask
264
265 "/MI { GS /py exch def /px exch def /sy exch def /sx exch def \n"
266 "translate \n"
267 "sx sy scale px py true \n"
268 "[ px 0 0 py neg 0 py ]\n"
269 "currentfile A85RLE\n"
270 "imagemask GR\n"
271 "} bind def\n"
272
273
274 // path
275
276 "/BFP { newpath moveto } def\n"
277 "/BP { newpath } bind def \n"
278 "/PL { lineto } bind def \n"
279 "/PM { moveto } bind def \n"
280 "/MT { moveto } bind def \n"
281 "/LT { lineto } bind def \n"
282 "/EFP { closepath fill } bind def\n" //was:stroke
283 "/ELP { stroke } bind def\n"
284 "/ECP { closepath stroke } bind def\n" // Closed (loop)
285 "/LW { setlinewidth } bind def\n"
286
287 // ////////////////////////// misc ////////////////
288 "/TR { translate } bind def\n"
289 "/CT { concat } bind def\n"
290 "/RCT { matrix invertmatrix concat} bind def\n"
291 "/SC { scale } bind def\n"
292 //"/GPD { currentpagedevice /PageSize get} def\n"
293
294 // show at position with desired width
295 // usage:
296 // width (string) x y show_pos_width
297 "/show_pos_width {GS moveto dup dup stringwidth pop exch length 2 div dup 2 le {pop 9999} if "
298 "1 sub exch 3 index exch sub exch "
299 "div 0 2 index 1 -1 scale ashow pop pop GR} bind def\n" // spacing altered to match desired width
300 //"/show_pos_width {GS moveto dup stringwidth pop 3 2 roll exch div -1 matrix scale concat "
301 //"show GR } bind def\n" // horizontally scaled text to match desired width
302
303 ;
304
305
306 static const char * prolog_2 = // prolog relevant only if lang_level >1
307
308 // color image dictionaries
309 "/CII {GS /inter exch def /py exch def /px exch def /sy exch def /sx exch def \n"
310 "translate \n"
311 "sx sy scale\n"
312 "/DeviceRGB setcolorspace\n"
313 "/IDD 8 dict def\n"
314 "IDD begin\n"
315 "/ImageType 1 def\n"
316 "/Width px def\n"
317 "/Height py def\n"
318 "/BitsPerComponent 8 def\n"
319 "/Interpolate inter def\n"
320 "/DataSource currentfile A85RLE def\n"
321 "/MultipleDataSources false def\n"
322 "/ImageMatrix [ px 0 0 py neg 0 py ] def\n"
323 "/Decode [ 0 1 0 1 0 1 ] def\n"
324 "end\n"
325 "IDD image GR} bind def\n"
326
327 // gray image dict
328 "/GII {GS /inter exch def /py exch def /px exch def /sy exch def /sx exch def \n"
329 "translate \n"
330 "sx sy scale\n"
331 "/DeviceGray setcolorspace\n"
332 "/IDD 8 dict def\n"
333 "IDD begin\n"
334 "/ImageType 1 def\n"
335 "/Width px def\n"
336 "/Height py def\n"
337 "/BitsPerComponent 8 def\n"
338
339 "/Interpolate inter def\n"
340 "/DataSource currentfile A85RLE def\n"
341 "/MultipleDataSources false def\n"
342 "/ImageMatrix [ px 0 0 py neg 0 py ] def\n"
343 "/Decode [ 0 1 ] def\n"
344 "end\n"
345 "IDD image GR} bind def\n"
346
347 // Create a custom PostScript font derived from PostScript standard text fonts
348 // The encoding of this custom font is as follows:
349 // 0000-00FF coincides with Unicode, that is to ASCII + Latin-1
350 // 0100-017F coincides with Unicode, that is to Latin Extended-A
351 // 0180-01A6 encodes miscellaneous characters present in PostScript standard text fonts
352
353 // use ISOLatin1Encoding for all text fonts
354 "/ToISO { dup findfont dup length dict copy begin /Encoding ISOLatin1Encoding def currentdict end definefont pop } def\n"
355 "/Helvetica ToISO /Helvetica-Bold ToISO /Helvetica-Oblique ToISO /Helvetica-BoldOblique ToISO \n"
356 "/Courier ToISO /Courier-Bold ToISO /Courier-Oblique ToISO /Courier-BoldOblique ToISO \n"
357 "/Times-Roman ToISO /Times-Bold ToISO /Times-Italic ToISO /Times-BoldItalic ToISO \n"
358
359 // define LatinExtA, the encoding of Latin-extended-A + some additional characters
360 // see http://partners.adobe.com/public/developer/en/opentype/glyphlist.txt for their names
361 "/LatinExtA \n"
362 "[ "
363 " /Amacron /amacron /Abreve /abreve /Aogonek /aogonek\n" // begin of Latin Extended-A code page
364 " /Cacute /cacute /Ccircumflex /ccircumflex /Cdotaccent /cdotaccent /Ccaron /ccaron \n"
365 " /Dcaron /dcaron /Dcroat /dcroat\n"
366 " /Emacron /emacron /Ebreve /ebreve /Edotaccent /edotaccent /Eogonek /eogonek /Ecaron /ecaron\n"
367 " /Gcircumflex /gcircumflex /Gbreve /gbreve /Gdotaccent /gdotaccent /Gcommaaccent /gcommaaccent \n"
368 " /Hcircumflex /hcircumflex /Hbar /hbar \n"
369 " /Itilde /itilde /Imacron /imacron /Ibreve /ibreve /Iogonek /iogonek /Idotaccent /dotlessi \n"
370 " /IJ /ij /Jcircumflex /jcircumflex\n"
371 " /Kcommaaccent /kcommaaccent /kgreenlandic \n"
372 " /Lacute /lacute /Lcommaaccent /lcommaaccent /Lcaron /lcaron /Ldotaccent /ldotaccent /Lslash /lslash \n"
373 " /Nacute /nacute /Ncommaaccent /ncommaaccent /Ncaron /ncaron /napostrophe /Eng /eng \n"
374 " /Omacron /omacron /Obreve /obreve /Ohungarumlaut /ohungarumlaut /OE /oe \n"
375 " /Racute /racute /Rcommaaccent /rcommaaccent /Rcaron /rcaron \n"
376 " /Sacute /sacute /Scircumflex /scircumflex /Scedilla /scedilla /Scaron /scaron \n"
377 " /Tcommaaccent /tcommaaccent /Tcaron /tcaron /Tbar /tbar \n"
378 " /Utilde /utilde /Umacron /umacron /Ubreve /ubreve /Uring /uring /Uhungarumlaut /uhungarumlaut /Uogonek /uogonek \n"
379 " /Wcircumflex /wcircumflex /Ycircumflex /ycircumflex /Ydieresis \n"
380 " /Zacute /zacute /Zdotaccent /zdotaccent /Zcaron /zcaron \n"
381 " /longs \n" // end of Latin Extended-A code page
382 " /florin /circumflex /caron /breve /dotaccent /ring \n" // remaining characters from PostScript standard text fonts
383 " /ogonek /tilde /hungarumlaut /endash /emdash \n"
384 " /quoteleft /quoteright /quotesinglbase /quotedblleft /quotedblright \n"
385 " /quotedblbase /dagger /daggerdbl /bullet /ellipsis \n"
386 " /perthousand /guilsinglleft /guilsinglright /fraction /Euro \n"
387 " /trademark /partialdiff /Delta /summation /radical \n"
388 " /infinity /notequal /lessequal /greaterequal /lozenge \n"
389 " /fi /fl /apple \n"
390 " ] def \n"
391 // deal with alternative PostScript names of some characters
392 " /mycharstrings /Helvetica findfont /CharStrings get def\n"
393 " /PSname2 { dup mycharstrings exch known {LatinExtA 3 -1 roll 3 -1 roll put}{pop pop} ifelse } def \n"
394 " 16#20 /Gdot PSname2 16#21 /gdot PSname2 16#30 /Idot PSname2 16#3F /Ldot PSname2 16#40 /ldot PSname2 16#7F /slong PSname2 \n"
395
396 // proc that gives LatinExtA encoding to a font
397 "/ToLatinExtA { findfont dup length dict copy begin /Encoding LatinExtA def currentdict end definefont pop } def\n"
398 // create Ext-versions of standard fonts that use LatinExtA encoding \n"
399 "/HelveticaExt /Helvetica ToLatinExtA \n"
400 "/Helvetica-BoldExt /Helvetica-Bold ToLatinExtA /Helvetica-ObliqueExt /Helvetica-Oblique ToLatinExtA \n"
401 "/Helvetica-BoldObliqueExt /Helvetica-BoldOblique ToLatinExtA \n"
402 "/CourierExt /Courier ToLatinExtA /Courier-BoldExt /Courier-Bold ToLatinExtA \n"
403 "/Courier-ObliqueExt /Courier-Oblique ToLatinExtA /Courier-BoldObliqueExt /Courier-BoldOblique ToLatinExtA \n"
404 "/Times-RomanExt /Times-Roman ToLatinExtA /Times-BoldExt /Times-Bold ToLatinExtA \n"
405 "/Times-ItalicExt /Times-Italic ToLatinExtA /Times-BoldItalicExt /Times-BoldItalic ToLatinExtA \n"
406
407 // proc to create a Type 0 font with 2-byte encoding
408 // that merges a text font with ISO encoding + same font with LatinExtA encoding
409 "/To2byte { 6 dict begin /FontType 0 def \n"
410 "/FDepVector 3 1 roll findfont exch findfont 2 array astore def \n"
411 "/FontMatrix [1 0 0 1 0 0] def /FMapType 6 def /Encoding [ 0 1 0 ] def\n"
412 // 100: Hexa count of ISO array; A7: hexa count of LatinExtA array
413 "/SubsVector < 01 0100 00A7 > def\n"
414 "currentdict end definefont pop } def\n"
415 // create Type 0 versions of standard fonts
416 "/Helvetica2B /HelveticaExt /Helvetica To2byte \n"
417 "/Helvetica-Bold2B /Helvetica-BoldExt /Helvetica-Bold To2byte \n"
418 "/Helvetica-Oblique2B /Helvetica-ObliqueExt /Helvetica-Oblique To2byte \n"
419 "/Helvetica-BoldOblique2B /Helvetica-BoldObliqueExt /Helvetica-BoldOblique To2byte \n"
420 "/Courier2B /CourierExt /Courier To2byte \n"
421 "/Courier-Bold2B /Courier-BoldExt /Courier-Bold To2byte \n"
422 "/Courier-Oblique2B /Courier-ObliqueExt /Courier-Oblique To2byte \n"
423 "/Courier-BoldOblique2B /Courier-BoldObliqueExt /Courier-BoldOblique To2byte \n"
424 "/Times-Roman2B /Times-RomanExt /Times-Roman To2byte \n"
425 "/Times-Bold2B /Times-BoldExt /Times-Bold To2byte \n"
426 "/Times-Italic2B /Times-ItalicExt /Times-Italic To2byte \n"
427 "/Times-BoldItalic2B /Times-BoldItalicExt /Times-BoldItalic To2byte \n"
428 ;
429
430 static const char * prolog_2_pixmap = // prolog relevant only if lang_level == 2 for pixmaps/masked color images
431 "/pixmap_mat {[ pixmap_sx 0 0 pixmap_sy neg 0 pixmap_sy ]} bind def\n"
432
433 "/pixmap_dict {"
434 "<< /PatternType 1 "
435 "/PaintType 1 "
436 "/TilingType 2 "
437 "/BBox [0 0 pixmap_sx pixmap_sy] "
438 "/XStep pixmap_sx "
439 "/YStep pixmap_sy\n"
440 "/PaintProc "
441 "{ begin "
442 "pixmap_w pixmap_h scale "
443 "pixmap_sx pixmap_sy 8 "
444 "pixmap_mat "
445 "currentfile A85RLE "
446 "false 3 "
447 "colorimage "
448 "end "
449 "} bind "
450 ">>\n"
451 "} bind def\n"
452
453 "/pixmap_plot {"
454 "GS "
455 "/pixmap_sy exch def /pixmap_sx exch def\n"
456 "/pixmap_h exch def /pixmap_w exch def\n"
457 "translate\n"
458 "pixmap_dict matrix makepattern setpattern\n"
459 "pixmap_w pixmap_h scale\n"
460 "pixmap_sx pixmap_sy\n"
461 "true\n"
462 "pixmap_mat\n"
463 "currentfile A85RLE\n"
464 "imagemask\n"
465 "GR\n"
466 "} bind def\n"
467 ;
468
469 static const char * prolog_3 = // prolog relevant only if lang_level >2
470
471 // masked color images
472 "/CIM {GS /inter exch def /my exch def /mx exch def /py exch def /px exch def /sy exch def /sx exch def \n"
473 "translate \n"
474 "sx sy scale\n"
475 "/DeviceRGB setcolorspace\n"
476
477 "/IDD 8 dict def\n"
478
479 "IDD begin\n"
480 "/ImageType 1 def\n"
481 "/Width px def\n"
482 "/Height py def\n"
483 "/BitsPerComponent 8 def\n"
484 "/Interpolate inter def\n"
485 "/DataSource currentfile A85RLE def\n"
486 "/MultipleDataSources false def\n"
487 "/ImageMatrix [ px 0 0 py neg 0 py ] def\n"
488
489 "/Decode [ 0 1 0 1 0 1 ] def\n"
490 "end\n"
491
492 "/IMD 8 dict def\n"
493 "IMD begin\n"
494 "/ImageType 1 def\n"
495 "/Width mx def\n"
496 "/Height my def\n"
497 "/BitsPerComponent 1 def\n"
498 // "/Interpolate inter def\n"
499 "/ImageMatrix [ mx 0 0 my neg 0 my ] def\n"
500 "/Decode [ 1 0 ] def\n"
501 "end\n"
502
503 "<<\n"
504 "/ImageType 3\n"
505 "/InterleaveType 2\n"
506 "/MaskDict IMD\n"
507 "/DataDict IDD\n"
508 ">> image GR\n"
509 "} bind def\n"
510
511
512 // masked gray images
513 "/GIM {GS /inter exch def /my exch def /mx exch def /py exch def /px exch def /sy exch def /sx exch def \n"
514 "translate \n"
515 "sx sy scale\n"
516 "/DeviceGray setcolorspace\n"
517
518 "/IDD 8 dict def\n"
519
520 "IDD begin\n"
521 "/ImageType 1 def\n"
522 "/Width px def\n"
523 "/Height py def\n"
524 "/BitsPerComponent 8 def\n"
525 "/Interpolate inter def\n"
526 "/DataSource currentfile A85RLE def\n"
527 "/MultipleDataSources false def\n"
528 "/ImageMatrix [ px 0 0 py neg 0 py ] def\n"
529
530 "/Decode [ 0 1 ] def\n"
531 "end\n"
532
533 "/IMD 8 dict def\n"
534
535 "IMD begin\n"
536 "/ImageType 1 def\n"
537 "/Width mx def\n"
538 "/Height my def\n"
539 "/BitsPerComponent 1 def\n"
540 "/ImageMatrix [ mx 0 0 my neg 0 my ] def\n"
541 "/Decode [ 1 0 ] def\n"
542 "end\n"
543
544 "<<\n"
545 "/ImageType 3\n"
546 "/InterleaveType 2\n"
547 "/MaskDict IMD\n"
548 "/DataDict IDD\n"
549 ">> image GR\n"
550 "} bind def\n"
551
552
553 "\n"
554 ;
555
556 // end prolog
557
start_postscript(int pagecount,enum Fl_Paged_Device::Page_Format format,enum Fl_Paged_Device::Page_Layout layout)558 int Fl_PostScript_Graphics_Driver::start_postscript (int pagecount,
559 enum Fl_Paged_Device::Page_Format format, enum Fl_Paged_Device::Page_Layout layout)
560 //returns 0 iff OK
561 {
562 int w, h, x;
563 if (format == Fl_Paged_Device::A4) {
564 left_margin = 18;
565 top_margin = 18;
566 }
567 else {
568 left_margin = 12;
569 top_margin = 12;
570 }
571 page_format_ = (enum Fl_Paged_Device::Page_Format)(format | layout);
572 if (layout & Fl_Paged_Device::LANDSCAPE){
573 ph_ = Fl_Paged_Device::page_formats[format].width;
574 pw_ = Fl_Paged_Device::page_formats[format].height;
575 } else {
576 pw_ = Fl_Paged_Device::page_formats[format].width;
577 ph_ = Fl_Paged_Device::page_formats[format].height;
578 }
579
580 fputs("%!PS-Adobe-3.0\n", output);
581 fputs("%%Creator: FLTK\n", output);
582 if (lang_level_>1)
583 fprintf(output, "%%%%LanguageLevel: %i\n" , lang_level_);
584 if ((pages_ = pagecount))
585 fprintf(output, "%%%%Pages: %i\n", pagecount);
586 else
587 fputs("%%Pages: (atend)\n", output);
588 fprintf(output, "%%%%BeginFeature: *PageSize %s\n", Fl_Paged_Device::page_formats[format].name );
589 w = Fl_Paged_Device::page_formats[format].width;
590 h = Fl_Paged_Device::page_formats[format].height;
591 if (lang_level_ == 3 && (layout & Fl_Paged_Device::LANDSCAPE) ) { x = w; w = h; h = x; }
592 fprintf(output, "<</PageSize[%d %d]>>setpagedevice\n", w, h );
593 fputs("%%EndFeature\n", output);
594 fputs("%%EndComments\n", output);
595 fputs(prolog, output);
596 if (lang_level_ > 1) {
597 fputs(prolog_2, output);
598 }
599 if (lang_level_ == 2) {
600 fputs(prolog_2_pixmap, output);
601 }
602 if (lang_level_ > 2)
603 fputs(prolog_3, output);
604 if (lang_level_ >= 3) {
605 fputs("/CS { clipsave } bind def\n", output);
606 fputs("/CR { cliprestore } bind def\n", output);
607 } else {
608 fputs("/CS { GS } bind def\n", output);
609 fputs("/CR { GR } bind def\n", output);
610 }
611 page_policy_ = 1;
612
613
614 fputs("%%EndProlog\n",output);
615 if (lang_level_ >= 2)
616 fprintf(output,"<< /Policies << /Pagesize 1 >> >> setpagedevice\n");
617
618 reset();
619 nPages=0;
620 return 0;
621 }
622
recover()623 void Fl_PostScript_Graphics_Driver::recover(){
624 color(cr_,cg_,cb_);
625 line_style(linestyle_,linewidth_,linedash_);
626 font(Fl_Graphics_Driver::font(), Fl_Graphics_Driver::size());
627 }
628
reset()629 void Fl_PostScript_Graphics_Driver::reset(){
630 gap_=1;
631 clip_=0;
632 cr_=cg_=cb_=0;
633 Fl_Graphics_Driver::font(FL_HELVETICA, 12);
634 linewidth_=0;
635 linestyle_=FL_SOLID;
636 strcpy(linedash_,"");
637 Clip *c=clip_; ////just not to have memory leaks for badly writen code (forgotten clip popping)
638
639 while(c){
640 clip_=clip_->prev;
641 delete c;
642 c=clip_;
643 }
644
645 }
646
page_policy(int p)647 void Fl_PostScript_Graphics_Driver::page_policy(int p){
648 page_policy_ = p;
649 if(lang_level_>=2)
650 fprintf(output,"<< /Policies << /Pagesize %i >> >> setpagedevice\n", p);
651 }
652
653 // //////////////////// paging //////////////////////////////////////////
654
655
656
page(double pw,double ph,int media)657 void Fl_PostScript_Graphics_Driver::page(double pw, double ph, int media) {
658
659 if (nPages){
660 fprintf(output, "CR\nGR\nGR\nGR\nSP\nrestore\n");
661 }
662 ++nPages;
663 fprintf(output, "%%%%Page: %i %i\n" , nPages , nPages);
664 fprintf(output, "%%%%PageBoundingBox: 0 0 %d %d\n", pw > ph ? (int)ph : (int)pw , pw > ph ? (int)pw : (int)ph);
665 if (pw>ph){
666 fprintf(output, "%%%%PageOrientation: Landscape\n");
667 }else{
668 fprintf(output, "%%%%PageOrientation: Portrait\n");
669 }
670
671 fprintf(output, "%%%%BeginPageSetup\n");
672 if((media & Fl_Paged_Device::MEDIA) &&(lang_level_>1)){
673 int r = media & Fl_Paged_Device::REVERSED;
674 if(r) r = 2;
675 fprintf(output, "<< /PageSize [%i %i] /Orientation %i>> setpagedevice\n", (int)(pw+.5), (int)(ph+.5), r);
676 }
677 fprintf(output, "%%%%EndPageSetup\n");
678
679 /* pw_ = pw;
680 ph_ = ph;*/
681 reset();
682
683 fprintf(output, "save\n");
684 fprintf(output, "GS\n");
685 clocale_printf( "%g %g TR\n", (double)0 /*lm_*/ , ph_ /* - tm_*/);
686 fprintf(output, "1 -1 SC\n");
687 line_style(0);
688 fprintf(output, "GS\n");
689
690 if (!((media & Fl_Paged_Device::MEDIA) &&(lang_level_>1))){
691 if (pw > ph) {
692 if(media & Fl_Paged_Device::REVERSED) {
693 fprintf(output, "-90 rotate %i 0 translate\n", int(-pw));
694 }
695 else {
696 fprintf(output, "90 rotate -%i -%i translate\n", (lang_level_ == 2 ? int(pw - ph) : 0), int(ph));
697 }
698 }
699 else {
700 if(media & Fl_Paged_Device::REVERSED)
701 fprintf(output, "180 rotate %i %i translate\n", int(-pw), int(-ph));
702 }
703 }
704 fprintf(output, "GS\nCS\n");
705 }
706
page(int format)707 void Fl_PostScript_Graphics_Driver::page(int format){
708 /* if(format & Fl_Paged_Device::LANDSCAPE){
709 ph_=Fl_Paged_Device::page_formats[format & 0xFF].width;
710 pw_=Fl_Paged_Device::page_formats[format & 0xFF].height;
711 }else{
712 pw_=Fl_Paged_Device::page_formats[format & 0xFF].width;
713 ph_=Fl_Paged_Device::page_formats[format & 0xFF].height;
714 }*/
715 page(pw_,ph_,format & 0xFF00);//,orientation only;
716 }
717
rect(int x,int y,int w,int h)718 void Fl_PostScript_Graphics_Driver::rect(int x, int y, int w, int h) {
719 // Commented code does not work, i can't find the bug ;-(
720 // fprintf(output, "GS\n");
721 // fprintf(output, "%i, %i, %i, %i R\n", x , y , w, h);
722 // fprintf(output, "GR\n");
723 fprintf(output, "GS\n");
724 fprintf(output,"BP\n");
725 fprintf(output, "%i %i MT\n", x , y);
726 fprintf(output, "%i %i LT\n", x+w-1 , y);
727 fprintf(output, "%i %i LT\n", x+w-1 , y+h-1);
728 fprintf(output, "%i %i LT\n", x , y+h-1);
729 fprintf(output, "ECP\n");
730 fprintf(output, "GR\n");
731 }
732
rectf(int x,int y,int w,int h)733 void Fl_PostScript_Graphics_Driver::rectf(int x, int y, int w, int h) {
734 clocale_printf( "%g %g %i %i FR\n", x-0.5, y-0.5, w, h);
735 }
736
line(int x1,int y1,int x2,int y2)737 void Fl_PostScript_Graphics_Driver::line(int x1, int y1, int x2, int y2) {
738 fprintf(output, "GS\n");
739 fprintf(output, "%i %i %i %i L\n", x1 , y1, x2 ,y2);
740 fprintf(output, "GR\n");
741 }
742
line(int x0,int y0,int x1,int y1,int x2,int y2)743 void Fl_PostScript_Graphics_Driver::line(int x0, int y0, int x1, int y1, int x2, int y2) {
744 fprintf(output, "GS\n");
745 fprintf(output,"BP\n");
746 fprintf(output, "%i %i MT\n", x0 , y0);
747 fprintf(output, "%i %i LT\n", x1 , y1);
748 fprintf(output, "%i %i LT\n", x2 , y2);
749 fprintf(output, "ELP\n");
750 fprintf(output, "GR\n");
751 }
752
xyline(int x,int y,int x1,int y2,int x3)753 void Fl_PostScript_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3){
754 fprintf(output, "GS\n");
755 fprintf(output,"BP\n");
756 fprintf(output, "%i %i MT\n", x , y );
757 fprintf(output, "%i %i LT\n", x1 , y );
758 fprintf(output, "%i %i LT\n", x1 , y2);
759 fprintf(output,"%i %i LT\n", x3 , y2);
760 fprintf(output, "ELP\n");
761 fprintf(output, "GR\n");
762 }
763
764
xyline(int x,int y,int x1,int y2)765 void Fl_PostScript_Graphics_Driver::xyline(int x, int y, int x1, int y2){
766
767 fprintf(output, "GS\n");
768 fprintf(output,"BP\n");
769 fprintf(output, "%i %i MT\n", x , y);
770 fprintf(output,"%i %i LT\n", x1 , y);
771 fprintf(output, "%i %i LT\n", x1 , y2 );
772 fprintf(output, "ELP\n");
773 fprintf(output, "GR\n");
774 }
775
xyline(int x,int y,int x1)776 void Fl_PostScript_Graphics_Driver::xyline(int x, int y, int x1){
777 fprintf(output, "GS\n");
778 fprintf(output,"BP\n");
779 fprintf(output, "%i %i MT\n", x , y);
780 fprintf(output, "%i %i LT\n", x1 , y );
781 fprintf(output, "ELP\n");
782
783 fprintf(output, "GR\n");
784 }
785
yxline(int x,int y,int y1,int x2,int y3)786 void Fl_PostScript_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3){
787 fprintf(output, "GS\n");
788
789 fprintf(output,"BP\n");
790 fprintf(output,"%i %i MT\n", x , y);
791 fprintf(output, "%i %i LT\n", x , y1 );
792 fprintf(output, "%i %i LT\n", x2 , y1 );
793 fprintf(output , "%i %i LT\n", x2 , y3);
794 fprintf(output, "ELP\n");
795 fprintf(output, "GR\n");
796 }
797
yxline(int x,int y,int y1,int x2)798 void Fl_PostScript_Graphics_Driver::yxline(int x, int y, int y1, int x2){
799 fprintf(output, "GS\n");
800 fprintf(output,"BP\n");
801 fprintf(output, "%i %i MT\n", x , y);
802 fprintf(output, "%i %i LT\n", x , y1);
803 fprintf(output, "%i %i LT\n", x2 , y1);
804 fprintf(output, "ELP\n");
805 fprintf(output, "GR\n");
806 }
807
yxline(int x,int y,int y1)808 void Fl_PostScript_Graphics_Driver::yxline(int x, int y, int y1){
809 fprintf(output, "GS\n");
810 fprintf(output,"BP\n");
811 fprintf(output, "%i %i MT\n", x , y);
812 fprintf(output, "%i %i LT\n", x , y1);
813 fprintf(output, "ELP\n");
814 fprintf(output, "GR\n");
815 }
816
loop(int x0,int y0,int x1,int y1,int x2,int y2)817 void Fl_PostScript_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2) {
818 fprintf(output, "GS\n");
819 fprintf(output,"BP\n");
820 fprintf(output, "%i %i MT\n", x0 , y0);
821 fprintf(output, "%i %i LT\n", x1 , y1);
822 fprintf(output, "%i %i LT\n", x2 , y2);
823 fprintf(output, "ECP\n");
824 fprintf(output, "GR\n");
825 }
826
loop(int x0,int y0,int x1,int y1,int x2,int y2,int x3,int y3)827 void Fl_PostScript_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) {
828 fprintf(output, "GS\n");
829 fprintf(output,"BP\n");
830 fprintf(output, "%i %i MT\n", x0 , y0);
831 fprintf(output, "%i %i LT\n", x1 , y1);
832 fprintf(output, "%i %i LT\n", x2 , y2);
833 fprintf(output, "%i %i LT\n", x3 , y3);
834 fprintf(output, "ECP\n");
835 fprintf(output, "GR\n");
836 }
837
polygon(int x0,int y0,int x1,int y1,int x2,int y2)838 void Fl_PostScript_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, int y2) {
839 fprintf(output, "GS\n");
840 fprintf(output,"BP\n");
841 fprintf(output, "%i %i MT\n", x0 , y0);
842 fprintf(output,"%i %i LT\n", x1 , y1);
843 fprintf(output, "%i %i LT\n", x2 , y2);
844 fprintf(output, "EFP\n");
845 fprintf(output, "GR\n");
846 }
847
polygon(int x0,int y0,int x1,int y1,int x2,int y2,int x3,int y3)848 void Fl_PostScript_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) {
849 fprintf(output, "GS\n");
850 fprintf(output,"BP\n");
851 fprintf(output, "%i %i MT\n", x0 , y0 );
852 fprintf(output, "%i %i LT\n", x1 , y1 );
853 fprintf(output, "%i %i LT\n", x2 , y2 );
854 fprintf(output, "%i %i LT\n", x3 , y3 );
855
856 fprintf(output, "EFP\n");
857 fprintf(output, "GR\n");
858 }
859
point(int x,int y)860 void Fl_PostScript_Graphics_Driver::point(int x, int y){
861 rectf(x,y,1,1);
862 }
863
864 static const int dashes_flat[5][7]={
865 {-1,0,0,0,0,0,0},
866 {3,1,-1,0,0,0,0},
867 {1,1,-1,0,0,0,0},
868 {3,1,1,1,-1,0,0},
869 {3,1,1,1,1,1,-1}
870 };
871
872
873 //yeah, hack...
874 static const double dashes_cap[5][7]={
875 {-1,0,0,0,0,0,0},
876 {2,2,-1,0,0,0,0},
877 {0.01,1.99,-1,0,0,0,0},
878 {2,2,0.01,1.99,-1,0,0},
879 {2,2,0.01,1.99,0.01,1.99,-1}
880 };
881
882
line_style(int style,int width,char * dashes)883 void Fl_PostScript_Graphics_Driver::line_style(int style, int width, char* dashes){
884 //line_styled_=1;
885
886 linewidth_=width;
887 linestyle_=style;
888 //dashes_= dashes;
889 if(dashes){
890 if(dashes != linedash_)
891 strcpy(linedash_,dashes);
892
893 }else
894 linedash_[0]=0;
895 char width0 = 0;
896 if(!width){
897 width=1; //for screen drawing compatibility
898 width0=1;
899 }
900
901 fprintf(output, "%i setlinewidth\n", width);
902
903 if(!style && (!dashes || !(*dashes)) && width0) //system lines
904 style = FL_CAP_SQUARE;
905
906 int cap = (style &0xf00) >> 8;
907 if(cap) cap--;
908 fprintf(output,"%i setlinecap\n", cap);
909
910 int join = (style & 0xf000) >> 12;
911
912 if(join) join--;
913 fprintf(output,"%i setlinejoin\n", join);
914
915
916 fprintf(output, "[");
917 if(dashes && *dashes){
918 while(*dashes){
919 fprintf(output, "%i ", *dashes);
920 dashes++;
921 }
922 }else{
923 if(style & 0x200){ // round and square caps, dash length need to be adjusted
924 const double *dt = dashes_cap[style & 0xff];
925 while (*dt >= 0){
926 clocale_printf("%g ",width * (*dt));
927 dt++;
928 }
929 }else{
930
931 const int *ds = dashes_flat[style & 0xff];
932 while (*ds >= 0){
933 fprintf(output, "%i ",width * (*ds));
934 ds++;
935 }
936 }
937 }
938 fprintf(output, "] 0 setdash\n");
939 }
940
941 static const char *_fontNames[] = {
942 "Helvetica2B",
943 "Helvetica-Bold2B",
944 "Helvetica-Oblique2B",
945 "Helvetica-BoldOblique2B",
946 "Courier2B",
947 "Courier-Bold2B",
948 "Courier-Oblique2B",
949 "Courier-BoldOblique2B",
950 "Times-Roman2B",
951 "Times-Bold2B",
952 "Times-Italic2B",
953 "Times-BoldItalic2B",
954 "Symbol",
955 "Courier2B",
956 "Courier-Bold2B",
957 "ZapfDingbats"
958 };
959
font(int f,int s)960 void Fl_PostScript_Graphics_Driver::font(int f, int s) {
961 Fl_Graphics_Driver *driver = Fl_Display_Device::display_device()->driver();
962 driver->font(f,s); // Use display fonts for font measurement
963 Fl_Graphics_Driver::font(f, s);
964 Fl_Font_Descriptor *desc = driver->font_descriptor();
965 this->font_descriptor(desc);
966 if (f < FL_FREE_FONT) {
967 float ps_size = (float) s;
968 fprintf(output, "/%s SF\n" , _fontNames[f]);
969 #if defined(USE_X11)
970 #if USE_XFT
971 // Xft font height is sometimes larger than the required size (see STR 2566).
972 // Increase the PostScript font size by 15% without exceeding the display font height
973 int max = desc->font->height;
974 ps_size = s * 1.15;
975 if (ps_size > max) ps_size = max;
976 #else
977 // Non-Xft fonts can be smaller than required.
978 // Set the PostScript font size to the display font height
979 char *name = desc->font->font_name_list[0];
980 char *p = strstr(name, "--");
981 if (p) {
982 sscanf(p + 2, "%f", &ps_size);
983 }
984 #endif // USE_XFT
985 #endif // USE_X11
986 clocale_printf("%.1f FS\n", ps_size);
987 }
988 }
989
width(const char * s,int n)990 double Fl_PostScript_Graphics_Driver::width(const char *s, int n) {
991 return Fl_Display_Device::display_device()->driver()->width(s, n);
992 }
993
width(unsigned u)994 double Fl_PostScript_Graphics_Driver::width(unsigned u) {
995 return Fl_Display_Device::display_device()->driver()->width(u);
996 }
997
height()998 int Fl_PostScript_Graphics_Driver::height() {
999 return Fl_Display_Device::display_device()->driver()->height();
1000 }
1001
descent()1002 int Fl_PostScript_Graphics_Driver::descent() {
1003 return Fl_Display_Device::display_device()->driver()->descent();
1004 }
1005
text_extents(const char * c,int n,int & dx,int & dy,int & w,int & h)1006 void Fl_PostScript_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &dy, int &w, int &h) {
1007 Fl_Display_Device::display_device()->driver()->text_extents(c, n, dx, dy, w, h);
1008 }
1009
1010
color(Fl_Color c)1011 void Fl_PostScript_Graphics_Driver::color(Fl_Color c) {
1012 Fl::get_color(c, cr_, cg_, cb_);
1013 color(cr_, cg_, cb_);
1014 }
1015
color(unsigned char r,unsigned char g,unsigned char b)1016 void Fl_PostScript_Graphics_Driver::color(unsigned char r, unsigned char g, unsigned char b) {
1017 Fl_Graphics_Driver::color( fl_rgb_color(r, g, b) );
1018 cr_ = r; cg_ = g; cb_ = b;
1019 if (r == g && g == b) {
1020 double gray = r/255.0;
1021 clocale_printf("%g GL\n", gray);
1022 } else {
1023 double fr, fg, fb;
1024 fr = r/255.0;
1025 fg = g/255.0;
1026 fb = b/255.0;
1027 clocale_printf("%g %g %g SRGB\n", fr , fg , fb);
1028 }
1029 }
1030
draw(int angle,const char * str,int n,int x,int y)1031 void Fl_PostScript_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y)
1032 {
1033 fprintf(output, "GS %d %d translate %d rotate\n", x, y, - angle);
1034 this->transformed_draw(str, n, 0, 0);
1035 fprintf(output, "GR\n");
1036 }
1037
1038
1039 // computes the mask for the RGB image img of all pixels with color != bg
calc_mask(uchar * img,int w,int h,Fl_Color bg)1040 static uchar *calc_mask(uchar *img, int w, int h, Fl_Color bg)
1041 {
1042 uchar red, green, blue, r, g, b;
1043 uchar bit, byte, *q;
1044 Fl::get_color(bg, red, green, blue);
1045 int W = (w+7)/8; // width of mask
1046 uchar* mask = new uchar[W * h];
1047 q = mask;
1048 while (h-- > 0) { // for each row
1049 bit = 0x80; // byte with last bit set
1050 byte = 0; // next mask byte to compute
1051 for (int j = 0; j < w; j++) { // for each column
1052 r = *img++; // the pixel color components
1053 g = *img++;
1054 b = *img++;
1055 // if pixel doesn't have bg color, put it in mask
1056 if (r != red || g != green || b != blue) byte |= bit;
1057 bit = bit>>1; // shift bit one step to the right
1058 if (bit == 0) { // single set bit has fallen out
1059 *q++ = byte; // enter byte in mask
1060 byte = 0; // reset next mask byte to zero
1061 bit = 0x80; // and this byte
1062 }
1063 }
1064 if (bit != 0x80) *q++ = byte; // enter last columns' byte in mask
1065 }
1066 return mask;
1067 }
1068
1069 // write to PostScript a bitmap image of a UTF8 string
transformed_draw_extra(const char * str,int n,double x,double y,int w,bool rtl)1070 void Fl_PostScript_Graphics_Driver::transformed_draw_extra(const char* str, int n, double x, double y, int w, bool rtl)
1071 {
1072 // scale for bitmask computation
1073 #if defined(USE_X11) && !USE_XFT
1074 float scale = 1; // don't scale because we can't expect to have scalable fonts
1075 #else
1076 float scale = 2;
1077 #endif
1078 Fl_Fontsize old_size = size();
1079 Fl_Font fontnum = Fl_Graphics_Driver::font();
1080 int w_scaled = (int)(w * (scale + 0.5));
1081 int h = (int)(height() * scale);
1082 // create an offscreen image of the string
1083 Fl_Color text_color = Fl_Graphics_Driver::color();
1084 Fl_Color bg_color = fl_contrast(FL_WHITE, text_color);
1085 Fl_Offscreen off = fl_create_offscreen(w_scaled, (int)(h+3*scale) );
1086 fl_begin_offscreen(off);
1087 fl_color(bg_color);
1088 // color offscreen background with a shade contrasting with the text color
1089 fl_rectf(0, 0, w_scaled, (int)(h+3*scale) );
1090 fl_color(text_color);
1091 #if defined(USE_X11) && !USE_XFT
1092 // force seeing this font as new so it's applied to the offscreen graphics context
1093 fl_graphics_driver->font_descriptor(NULL);
1094 fl_font(fontnum, 0);
1095 #endif
1096 fl_font(fontnum, (Fl_Fontsize)(scale * old_size) );
1097 int w2 = (int)fl_width(str, n);
1098 // draw string in offscreen
1099 if (rtl) fl_rtl_draw(str, n, w2, (int)(h * 0.8) );
1100 else fl_draw(str, n, 1, (int)(h * 0.8) );
1101 // read (most of) the offscreen image
1102 uchar *img = fl_read_image(NULL, 1, 1, w2, h, 0);
1103 fl_end_offscreen();
1104 font(fontnum, old_size);
1105 fl_delete_offscreen(off);
1106 // compute the mask of what is not the background
1107 uchar *mask = calc_mask(img, w2, h, bg_color);
1108 delete[] img;
1109 // write the string image to PostScript as a scaled bitmask
1110 scale = w2 / float(w);
1111 clocale_printf("%g %g %g %g %d %d MI\n", x, y - h*0.77/scale, w2/scale, h/scale, w2, h);
1112 uchar *di;
1113 int wmask = (w2+7)/8;
1114 void *rle85 = prepare_rle85();
1115 for (int j = h - 1; j >= 0; j--){
1116 di = mask + j * wmask;
1117 for (int i = 0; i < wmask; i++){
1118 write_rle85(*di, rle85);
1119 di++;
1120 }
1121 }
1122 close_rle85(rle85); fputc('\n', output);
1123 delete[] mask;
1124 }
1125
is_in_table(unsigned utf)1126 static int is_in_table(unsigned utf) {
1127 unsigned i;
1128 static unsigned extra_table_roman[] = { // unicodes/*names*/ of other characters from PostScript standard fonts
1129 0x192/*florin*/, 0x2C6/*circumflex*/, 0x2C7/*caron*/,
1130 0x2D8/*breve*/, 0x2D9/*dotaccent*/, 0x2DA/*ring*/, 0x2DB/*ogonek*/, 0x2DC/*tilde*/, 0x2DD/*hungarumlaut*/,
1131 0x2013/*endash*/, 0x2014/*emdash*/, 0x2018/*quoteleft*/, 0x2019/*quoteright*/,
1132 0x201A/*quotesinglbase*/, 0x201C/*quotedblleft*/, 0x201D/*quotedblright*/, 0x201E/*quotedblbase*/,
1133 0x2020/*dagger*/, 0x2021/*daggerdbl*/, 0x2022/*bullet*/,
1134 0x2026/*ellipsis*/, 0x2030/*perthousand*/, 0x2039/*guilsinglleft*/, 0x203A/*guilsinglright*/,
1135 0x2044/*fraction*/, 0x20AC/*Euro*/, 0x2122/*trademark*/,
1136 0x2202/*partialdiff*/, 0x2206/*Delta*/, 0x2211/*summation*/, 0x221A/*radical*/,
1137 0x221E/*infinity*/, 0x2260/*notequal*/, 0x2264/*lessequal*/,
1138 0x2265/*greaterequal*/,
1139 0x25CA/*lozenge*/, 0xFB01/*fi*/, 0xFB02/*fl*/,
1140 0xF8FF/*apple*/
1141 };
1142 for ( i = 0; i < sizeof(extra_table_roman)/sizeof(int); i++) {
1143 if (extra_table_roman[i] == utf) return i + 0x180;
1144 }
1145 return 0;
1146 }
1147
1148 // outputs in PostScript a UTF8 string using the same width in points as on display
transformed_draw(const char * str,int n,double x,double y)1149 void Fl_PostScript_Graphics_Driver::transformed_draw(const char* str, int n, double x, double y) {
1150 int len, code;
1151 if (!n || !str || !*str) return;
1152 // compute display width of string
1153 int w = (int)width(str, n);
1154 if (w == 0) return;
1155 if (Fl_Graphics_Driver::font() >= FL_FREE_FONT) {
1156 transformed_draw_extra(str, n, x, y, w, false);
1157 return;
1158 }
1159 fprintf(output, "%d <~", w);
1160 void *data = prepare85();
1161 // transforms UTF8 encoding to our custom PostScript encoding as follows:
1162 // extract each unicode character
1163 // if unicode <= 0x17F, unicode and PostScript codes are identical
1164 // if unicode is one of the values listed in extra_table_roman above
1165 // its PostScript code is 0x180 + the character's rank in extra_table_roman
1166 // if unicode is something else, draw all string as bitmap image
1167
1168 const char *last = str + n;
1169 const char *str2 = str;
1170 while (str2 < last) {
1171 // Extract each unicode character of string.
1172 unsigned utf = fl_utf8decode(str2, last, &len);
1173 str2 += len;
1174 if (utf <= 0x17F) { // until Latin Extended-A
1175 ;
1176 }
1177 else if ( (code = is_in_table(utf)) != 0) { // other handled characters
1178 utf = code;
1179 }
1180 else { // unhandled character: draw all string as bitmap image
1181 fprintf(output, "~> pop pop\n"); // close and ignore the opened hex string
1182 transformed_draw_extra(str, n, x, y, w, false);
1183 return;
1184 }
1185 // 2 bytes per character, high-order byte first, encode that to ASCII85
1186 uchar c[2]; c[1] = utf & 0xFF; c[0] = (utf & 0xFF00)>>8; write85(data, c, 2);
1187 }
1188 close85(data);
1189 clocale_printf(" %g %g show_pos_width\n", x, y);
1190 }
1191
rtl_draw(const char * str,int n,int x,int y)1192 void Fl_PostScript_Graphics_Driver::rtl_draw(const char* str, int n, int x, int y) {
1193 int w = (int)width(str, n);
1194 transformed_draw_extra(str, n, x - w, y, w, true);
1195 }
1196
concat()1197 void Fl_PostScript_Graphics_Driver::concat(){
1198 clocale_printf("[%g %g %g %g %g %g] CT\n", fl_matrix->a , fl_matrix->b , fl_matrix->c , fl_matrix->d , fl_matrix->x , fl_matrix->y);
1199 }
1200
reconcat()1201 void Fl_PostScript_Graphics_Driver::reconcat(){
1202 clocale_printf("[%g %g %g %g %g %g] RCT\n" , fl_matrix->a , fl_matrix->b , fl_matrix->c , fl_matrix->d , fl_matrix->x , fl_matrix->y);
1203 }
1204
1205 ///////////////// transformed (double) drawings ////////////////////////////////
1206
1207
begin_points()1208 void Fl_PostScript_Graphics_Driver::begin_points(){
1209 fprintf(output, "GS\n");
1210 concat();
1211
1212 fprintf(output, "BP\n");
1213 gap_=1;
1214 shape_=POINTS;
1215 }
1216
begin_line()1217 void Fl_PostScript_Graphics_Driver::begin_line(){
1218 fprintf(output, "GS\n");
1219 concat();
1220 fprintf(output, "BP\n");
1221 gap_=1;
1222 shape_=LINE;
1223 }
1224
begin_loop()1225 void Fl_PostScript_Graphics_Driver::begin_loop(){
1226 fprintf(output, "GS\n");
1227 concat();
1228 fprintf(output, "BP\n");
1229 gap_=1;
1230 shape_=LOOP;
1231 }
1232
begin_polygon()1233 void Fl_PostScript_Graphics_Driver::begin_polygon(){
1234 fprintf(output, "GS\n");
1235 concat();
1236 fprintf(output, "BP\n");
1237 gap_=1;
1238 shape_=POLYGON;
1239 }
1240
vertex(double x,double y)1241 void Fl_PostScript_Graphics_Driver::vertex(double x, double y){
1242 if(shape_==POINTS){
1243 clocale_printf("%g %g MT\n", x , y);
1244 gap_=1;
1245 return;
1246 }
1247 if(gap_){
1248 clocale_printf("%g %g MT\n", x , y);
1249 gap_=0;
1250 }else
1251 clocale_printf("%g %g LT\n", x , y);
1252 }
1253
curve(double x,double y,double x1,double y1,double x2,double y2,double x3,double y3)1254 void Fl_PostScript_Graphics_Driver::curve(double x, double y, double x1, double y1, double x2, double y2, double x3, double y3){
1255 if(shape_==NONE) return;
1256 if(gap_)
1257 clocale_printf("%g %g MT\n", x , y);
1258 else
1259 clocale_printf("%g %g LT\n", x , y);
1260 gap_=0;
1261
1262 clocale_printf("%g %g %g %g %g %g curveto \n", x1 , y1 , x2 , y2 , x3 , y3);
1263 }
1264
1265
circle(double x,double y,double r)1266 void Fl_PostScript_Graphics_Driver::circle(double x, double y, double r){
1267 if(shape_==NONE){
1268 fprintf(output, "GS\n");
1269 concat();
1270 // fprintf(output, "BP\n");
1271 clocale_printf("%g %g %g 0 360 arc\n", x , y , r);
1272 reconcat();
1273 // fprintf(output, "ELP\n");
1274 fprintf(output, "GR\n");
1275 }else
1276
1277 clocale_printf("%g %g %g 0 360 arc\n", x , y , r);
1278
1279 }
1280
arc(double x,double y,double r,double start,double a)1281 void Fl_PostScript_Graphics_Driver::arc(double x, double y, double r, double start, double a){
1282 if(shape_==NONE) return;
1283 gap_=0;
1284 if(start>a)
1285 clocale_printf("%g %g %g %g %g arc\n", x , y , r , -start, -a);
1286 else
1287 clocale_printf("%g %g %g %g %g arcn\n", x , y , r , -start, -a);
1288
1289 }
1290
arc(int x,int y,int w,int h,double a1,double a2)1291 void Fl_PostScript_Graphics_Driver::arc(int x, int y, int w, int h, double a1, double a2) {
1292 if (w <= 1 || h <= 1) return;
1293 fprintf(output, "GS\n");
1294 //fprintf(output, "BP\n");
1295 begin_line();
1296 clocale_printf("%g %g TR\n", x + w/2.0 -0.5 , y + h/2.0 - 0.5);
1297 clocale_printf("%g %g SC\n", (w-1)/2.0 , (h-1)/2.0 );
1298 arc(0,0,1,a2,a1);
1299 // fprintf(output, "0 0 1 %g %g arc\n" , -a1 , -a2);
1300 clocale_printf("%g %g SC\n", 2.0/(w-1) , 2.0/(h-1) );
1301 clocale_printf("%g %g TR\n", -x - w/2.0 +0.5 , -y - h/2.0 +0.5);
1302 end_line();
1303
1304 // fprintf(output, "%g setlinewidth\n", 2/sqrt(w*h));
1305 // fprintf(output, "ELP\n");
1306 // fprintf(output, 2.0/w , 2.0/w , " SC\n";
1307 // fprintf(output, (-x - w/2.0) , (-y - h/2) , " TR\n";
1308 fprintf(output, "GR\n");
1309 }
1310
pie(int x,int y,int w,int h,double a1,double a2)1311 void Fl_PostScript_Graphics_Driver::pie(int x, int y, int w, int h, double a1, double a2) {
1312 fprintf(output, "GS\n");
1313 begin_polygon();
1314 clocale_printf("%g %g TR\n", x + w/2.0 -0.5 , y + h/2.0 - 0.5);
1315 clocale_printf("%g %g SC\n", (w-1)/2.0 , (h-1)/2.0 );
1316 vertex(0,0);
1317 arc(0.0,0.0, 1, a2, a1);
1318 end_polygon();
1319 fprintf(output, "GR\n");
1320 }
1321
end_points()1322 void Fl_PostScript_Graphics_Driver::end_points(){
1323 gap_=1;
1324 reconcat();
1325 fprintf(output, "ELP\n"); //??
1326 fprintf(output, "GR\n");
1327 shape_=NONE;
1328 }
1329
end_line()1330 void Fl_PostScript_Graphics_Driver::end_line(){
1331 gap_=1;
1332 reconcat();
1333 fprintf(output, "ELP\n");
1334 fprintf(output, "GR\n");
1335 shape_=NONE;
1336 }
end_loop()1337 void Fl_PostScript_Graphics_Driver::end_loop(){
1338 gap_=1;
1339 reconcat();
1340 fprintf(output, "ECP\n");
1341 fprintf(output, "GR\n");
1342 shape_=NONE;
1343 }
1344
end_polygon()1345 void Fl_PostScript_Graphics_Driver::end_polygon(){
1346
1347 gap_=1;
1348 reconcat();
1349 fprintf(output, "EFP\n");
1350 fprintf(output, "GR\n");
1351 shape_=NONE;
1352 }
1353
transformed_vertex(double x,double y)1354 void Fl_PostScript_Graphics_Driver::transformed_vertex(double x, double y){
1355 reconcat();
1356 if(gap_){
1357 clocale_printf("%g %g MT\n", x , y);
1358 gap_=0;
1359 }else
1360 clocale_printf("%g %g LT\n", x , y);
1361 concat();
1362 }
1363
1364 ///////////////////////////// Clipping /////////////////////////////////////////////
1365
push_clip(int x,int y,int w,int h)1366 void Fl_PostScript_Graphics_Driver::push_clip(int x, int y, int w, int h) {
1367 Clip * c=new Clip();
1368 clip_box(x,y,w,h,c->x,c->y,c->w,c->h);
1369 c->prev=clip_;
1370 clip_=c;
1371 fprintf(output, "CR\nCS\n");
1372 if(lang_level_<3)
1373 recover();
1374 clocale_printf("%g %g %i %i CL\n", clip_->x-0.5 , clip_->y-0.5 , clip_->w , clip_->h);
1375
1376 }
1377
push_no_clip()1378 void Fl_PostScript_Graphics_Driver::push_no_clip() {
1379 Clip * c = new Clip();
1380 c->prev=clip_;
1381 clip_=c;
1382 clip_->x = clip_->y = clip_->w = clip_->h = -1;
1383 fprintf(output, "CR\nCS\n");
1384 if(lang_level_<3)
1385 recover();
1386 }
1387
pop_clip()1388 void Fl_PostScript_Graphics_Driver::pop_clip() {
1389 if(!clip_)return;
1390 Clip * c=clip_;
1391 clip_=clip_->prev;
1392 delete c;
1393 fprintf(output, "CR\nCS\n");
1394 if(clip_ && clip_->w >0)
1395 clocale_printf("%g %g %i %i CL\n", clip_->x - 0.5, clip_->y - 0.5, clip_->w , clip_->h);
1396 // uh, -0.5 is to match screen clipping, for floats there should be something beter
1397 if(lang_level_<3)
1398 recover();
1399 }
1400
clip_box(int x,int y,int w,int h,int & X,int & Y,int & W,int & H)1401 int Fl_PostScript_Graphics_Driver::clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H){
1402 if(!clip_){
1403 X=x;Y=y;W=w;H=h;
1404 return 1;
1405 }
1406 if(clip_->w < 0){
1407 X=x;Y=y;W=w;H=h;
1408 return 1;
1409 }
1410 int ret=0;
1411 if (x > (X=clip_->x)) {X=x; ret=1;}
1412 if (y > (Y=clip_->y)) {Y=y; ret=1;}
1413 if ((x+w) < (clip_->x+clip_->w)) {
1414 W=x+w-X;
1415
1416 ret=1;
1417
1418 }else
1419 W = clip_->x + clip_->w - X;
1420 if(W<0){
1421 W=0;
1422 return 1;
1423 }
1424 if ((y+h) < (clip_->y+clip_->h)) {
1425 H=y+h-Y;
1426 ret=1;
1427 }else
1428 H = clip_->y + clip_->h - Y;
1429 if(H<0){
1430 W=0;
1431 H=0;
1432 return 1;
1433 }
1434 return ret;
1435 }
1436
not_clipped(int x,int y,int w,int h)1437 int Fl_PostScript_Graphics_Driver::not_clipped(int x, int y, int w, int h){
1438 if(!clip_) return 1;
1439 if(clip_->w < 0) return 1;
1440 int X, Y, W, H;
1441 clip_box(x, y, w, h, X, Y, W, H);
1442 if(W) return 1;
1443 return 0;
1444 }
1445
margins(int * left,int * top,int * right,int * bottom)1446 void Fl_PostScript_File_Device::margins(int *left, int *top, int *right, int *bottom) // to implement
1447 {
1448 Fl_PostScript_Graphics_Driver *ps = driver();
1449 if(left) *left = (int)(ps->left_margin / ps->scale_x + .5);
1450 if(right) *right = (int)(ps->left_margin / ps->scale_x + .5);
1451 if(top) *top = (int)(ps->top_margin / ps->scale_y + .5);
1452 if(bottom) *bottom = (int)(ps->top_margin / ps->scale_y + .5);
1453 }
1454
printable_rect(int * w,int * h)1455 int Fl_PostScript_File_Device::printable_rect(int *w, int *h)
1456 //returns 0 iff OK
1457 {
1458 Fl_PostScript_Graphics_Driver *ps = driver();
1459 if(w) *w = (int)((ps->pw_ - 2 * ps->left_margin) / ps->scale_x + .5);
1460 if(h) *h = (int)((ps->ph_ - 2 * ps->top_margin) / ps->scale_y + .5);
1461 return 0;
1462 }
1463
origin(int * x,int * y)1464 void Fl_PostScript_File_Device::origin(int *x, int *y)
1465 {
1466 Fl_Paged_Device::origin(x, y);
1467 }
1468
origin(int x,int y)1469 void Fl_PostScript_File_Device::origin(int x, int y)
1470 {
1471 x_offset = x;
1472 y_offset = y;
1473 Fl_PostScript_Graphics_Driver *ps = driver();
1474 ps->clocale_printf("GR GR GS %d %d TR %f %f SC %d %d TR %f rotate GS\n",
1475 ps->left_margin, ps->top_margin, ps->scale_x, ps->scale_y, x, y, ps->angle);
1476 }
1477
scale(float s_x,float s_y)1478 void Fl_PostScript_File_Device::scale (float s_x, float s_y)
1479 {
1480 if (s_y == 0.) s_y = s_x;
1481 Fl_PostScript_Graphics_Driver *ps = driver();
1482 ps->scale_x = s_x;
1483 ps->scale_y = s_y;
1484 ps->clocale_printf("GR GR GS %d %d TR %f %f SC %f rotate GS\n",
1485 ps->left_margin, ps->top_margin, ps->scale_x, ps->scale_y, ps->angle);
1486 }
1487
rotate(float rot_angle)1488 void Fl_PostScript_File_Device::rotate (float rot_angle)
1489 {
1490 Fl_PostScript_Graphics_Driver *ps = driver();
1491 ps->angle = - rot_angle;
1492 ps->clocale_printf("GR GR GS %d %d TR %f %f SC %d %d TR %f rotate GS\n",
1493 ps->left_margin, ps->top_margin, ps->scale_x, ps->scale_y, x_offset, y_offset, ps->angle);
1494 }
1495
translate(int x,int y)1496 void Fl_PostScript_File_Device::translate(int x, int y)
1497 {
1498 fprintf(driver()->output, "GS %d %d translate GS\n", x, y);
1499 }
1500
untranslate(void)1501 void Fl_PostScript_File_Device::untranslate(void)
1502 {
1503 fprintf(driver()->output, "GR GR\n");
1504 }
1505
start_page(void)1506 int Fl_PostScript_File_Device::start_page (void)
1507 {
1508 Fl_PostScript_Graphics_Driver *ps = driver();
1509 ps->page(ps->page_format_);
1510 x_offset = 0;
1511 y_offset = 0;
1512 ps->scale_x = ps->scale_y = 1.;
1513 ps->angle = 0;
1514 fprintf(ps->output, "GR GR GS %d %d translate GS\n", ps->left_margin, ps->top_margin);
1515 return 0;
1516 }
1517
end_page(void)1518 int Fl_PostScript_File_Device::end_page (void)
1519 {
1520 return 0;
1521 }
1522
end_job(void)1523 void Fl_PostScript_File_Device::end_job (void)
1524 // finishes PostScript & closes file
1525 {
1526 Fl_PostScript_Graphics_Driver *ps = driver();
1527 if (ps->nPages) { // for eps nPages is 0 so it is fine ....
1528 fprintf(ps->output, "CR\nGR\nGR\nGR\nSP\n restore\n");
1529 if (!ps->pages_){
1530 fprintf(ps->output, "%%%%Trailer\n");
1531 fprintf(ps->output, "%%%%Pages: %i\n" , ps->nPages);
1532 };
1533 } else
1534 fprintf(ps->output, "GR\n restore\n");
1535 fputs("%%EOF",ps->output);
1536 ps->reset();
1537 fflush(ps->output);
1538 if(ferror(ps->output)) {
1539 fl_alert ("Error during PostScript data output.");
1540 }
1541 if (ps->close_cmd_) {
1542 (*ps->close_cmd_)(ps->output);
1543 } else {
1544 fclose(ps->output);
1545 }
1546 while (ps->clip_){
1547 Fl_PostScript_Graphics_Driver::Clip * c= ps->clip_;
1548 ps->clip_= ps->clip_->prev;
1549 delete c;
1550 }
1551 Fl_Display_Device::display_device()->set_current();
1552 }
1553
1554 #endif // FL_DOXYGEN
1555
1556 #if ! (defined(__APPLE__) || defined(WIN32) )
1557 /** Starts a print job. */
start_job(int pages,int * firstpage,int * lastpage)1558 int Fl_PostScript_Printer::start_job(int pages, int *firstpage, int *lastpage) {
1559 enum Fl_Paged_Device::Page_Format format;
1560 enum Fl_Paged_Device::Page_Layout layout;
1561
1562 // first test version for print dialog
1563 if (!print_panel) make_print_panel();
1564 printing_style style = print_load();
1565 print_selection->deactivate();
1566 print_all->setonly();
1567 print_all->do_callback();
1568 print_from->value("1");
1569 { char tmp[10]; snprintf(tmp, sizeof(tmp), "%d", pages); print_to->value(tmp); }
1570 print_panel->show(); // this is modal
1571 while (print_panel->shown()) Fl::wait();
1572
1573 if (!print_start) // user clicked cancel
1574 return 1;
1575
1576 // get options
1577
1578 switch (print_page_size->value()) {
1579 case 0:
1580 format = Fl_Paged_Device::LETTER;
1581 break;
1582 case 2:
1583 format = Fl_Paged_Device::LEGAL;
1584 break;
1585 case 3:
1586 format = Fl_Paged_Device::EXECUTIVE;
1587 break;
1588 case 4:
1589 format = Fl_Paged_Device::A3;
1590 break;
1591 case 5:
1592 format = Fl_Paged_Device::A5;
1593 break;
1594 case 6:
1595 format = Fl_Paged_Device::B5;
1596 break;
1597 case 7:
1598 format = Fl_Paged_Device::ENVELOPE;
1599 break;
1600 case 8:
1601 format = Fl_Paged_Device::DLE;
1602 break;
1603 default:
1604 format = Fl_Paged_Device::A4;
1605 }
1606
1607 { // page range choice
1608 int from = 1, to = pages;
1609 if (print_pages->value()) {
1610 sscanf(print_from->value(), "%d", &from);
1611 sscanf(print_to->value(), "%d", &to);
1612 }
1613 if (from < 1) from = 1;
1614 if (to > pages) to = pages;
1615 if (to < from) to = from;
1616 if (firstpage) *firstpage = from;
1617 if (lastpage) *lastpage = to;
1618 if (pages > 0) pages = to - from + 1;
1619 }
1620
1621 if (print_output_mode[0]->value()) layout = Fl_Paged_Device::PORTRAIT;
1622 else if (print_output_mode[1]->value()) layout = Fl_Paged_Device::LANDSCAPE;
1623 else if (print_output_mode[2]->value()) layout = Fl_Paged_Device::PORTRAIT;
1624 else layout = Fl_Paged_Device::LANDSCAPE;
1625
1626 int print_pipe = print_choice->value(); // 0 = print to file, >0 = printer (pipe)
1627
1628 const char *media = print_page_size->text(print_page_size->value());
1629 const char *printer = (const char *)print_choice->menu()[print_choice->value()].user_data();
1630 if (!print_pipe) printer = "<File>";
1631
1632 if (!print_pipe) // fall back to file printing
1633 return Fl_PostScript_File_Device::start_job (pages, format, layout);
1634
1635 // Print: pipe the output into the lp command...
1636
1637 char command[1024];
1638 if (style == SystemV) snprintf(command, sizeof(command), "lp -s -d %s -n %d -t '%s' -o media=%s",
1639 printer, print_collate_button->value() ? 1 : (int)(print_copies->value() + 0.5), "FLTK", media);
1640 else snprintf(command, sizeof(command), "lpr -h -P%s -#%d -T FLTK ",
1641 printer, print_collate_button->value() ? 1 : (int)(print_copies->value() + 0.5));
1642
1643 Fl_PostScript_Graphics_Driver *ps = driver();
1644 ps->output = popen(command, "w");
1645 if (!ps->output) {
1646 fl_alert("could not run command: %s\n",command);
1647 return 1;
1648 }
1649 ps->close_command(pclose);
1650 this->set_current();
1651 return ps->start_postscript(pages, format, layout); // start printing
1652 }
1653
1654 #endif // ! (defined(__APPLE__) || defined(WIN32) )
1655
1656
1657 //
1658 // End of "$Id$".
1659 //
1660