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