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