2 // "$Id: Fl_PostScript.cxx 8623 2011-04-24 17:09:41Z AlbrechtS $"
4 // PostScript device support for the Fast Light Tool Kit (FLTK).
6 // Copyright 2010-2011 by Bill Spitzak and others.
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.
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.
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
23 // Please report all bugs and problems to:
25 // http://www.fltk.org/str.php
29 #include <FL/Fl_Cairo.H>
31 #include <FL/fl_ask.H>
32 #include <FL/fl_draw.H>
34 #include <FL/Fl_PostScript.H>
35 #include <FL/Fl_Native_File_Chooser.H>
39 #include <X11/Xft/Xft.h>
43 const char *Fl_PostScript_Graphics_Driver::class_id
= "Fl_PostScript_Graphics_Driver";
44 const char *Fl_PostScript_File_Device::class_id
= "Fl_PostScript_File_Device";
45 /** \brief Label of the PostScript file chooser window */
46 const char *Fl_PostScript_File_Device::file_chooser_title
= "Select a .ps file";
49 @brief The constructor.
51 Fl_PostScript_Graphics_Driver::Fl_PostScript_Graphics_Driver(void)
58 scale_x
= scale_y
= 1.;
59 bg_r
= bg_g
= bg_b
= 255;
62 /** \brief The destructor. */
63 Fl_PostScript_Graphics_Driver::~Fl_PostScript_Graphics_Driver() {
64 if(ps_filename_
) free(ps_filename_
);
68 @brief The constructor.
70 Fl_PostScript_File_Device::Fl_PostScript_File_Device(void)
73 gc
= fl_gc
; // the display context is used by fl_text_extents()
75 Fl_Surface_Device::driver( new Fl_PostScript_Graphics_Driver() );
79 \brief Returns the PostScript driver of this drawing surface.
81 Fl_PostScript_Graphics_Driver
*Fl_PostScript_File_Device::driver()
83 return (Fl_PostScript_Graphics_Driver
*)Fl_Surface_Device::driver();
88 @brief Begins the session where all graphics requests will go to a local PostScript file.
90 Opens a file dialog entitled with Fl_PostScript_File_Device::file_chooser_title to select an output PostScript file.
91 @param pagecount The total number of pages to be created.
92 @param format Desired page format.
93 @param layout Desired page layout.
94 @return 0 if OK, 1 if user cancelled the file dialog, 2 if fopen failed on user-selected output file.
96 int Fl_PostScript_File_Device::start_job (int pagecount
, enum Fl_Paged_Device::Page_Format format
,
97 enum Fl_Paged_Device::Page_Layout layout
)
99 Fl_Native_File_Chooser fnfc
;
100 fnfc
.title(Fl_PostScript_File_Device::file_chooser_title
);
101 fnfc
.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE
);
102 fnfc
.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM
);
103 fnfc
.filter("PostScript\t*.ps\n");
104 // Show native chooser
105 if ( fnfc
.show() ) return 1;
106 Fl_PostScript_Graphics_Driver
*ps
= driver();
107 ps
->output
= fopen(fnfc
.filename(), "w");
108 if(ps
->output
== NULL
) return 2;
109 ps
->ps_filename_
= strdup(fnfc
.filename());
110 ps
->start_postscript(pagecount
, format
, layout
);
115 static int dont_close(FILE *f
)
121 @brief Begins the session where all graphics requests will go to FILE pointer.
123 @param ps_output A writable FILE pointer that will receive PostScript output and that should not be closed
124 until after end_job() has been called.
125 @param pagecount The total number of pages to be created.
126 @param format Desired page format.
127 @param layout Desired page layout.
130 int Fl_PostScript_File_Device::start_job (FILE *ps_output
, int pagecount
,
131 enum Fl_Paged_Device::Page_Format format
, enum Fl_Paged_Device::Page_Layout layout
)
133 Fl_PostScript_Graphics_Driver
*ps
= driver();
134 ps
->output
= ps_output
;
135 ps
->ps_filename_
= NULL
;
136 ps
->start_postscript(pagecount
, format
, layout
);
137 ps
->close_command(dont_close
); // so that end_job() doesn't close the file
143 @brief The destructor.
145 Fl_PostScript_File_Device::~Fl_PostScript_File_Device() {
146 Fl_PostScript_Graphics_Driver
*ps
= driver();
152 #if ! (defined(__APPLE__) || defined(WIN32) )
153 #include "print_panel.cxx"
158 static const char * prolog
=
160 "/L { /y2 exch def\n"
164 "newpath x1 y1 moveto x2 y2 lineto\n"
169 "/R { /dy exch def\n"
195 "/FR { /dy exch def\n"
199 "currentlinewidth 0 setlinewidth newpath\n"
204 "closepath fill setlinewidth\n"
207 "/GS { gsave } bind def\n"
208 "/GR { grestore } bind def\n"
210 "/SP { showpage } bind def\n"
211 "/LW { setlinewidth } bind def\n"
213 "/SF { /CF exch def } bind def\n"
215 "/FS { /fsize exch def fsize CF findfont exch scalefont setfont }def \n"
218 "/GL { setgray } bind def\n"
219 "/SRGB { setrgbcolor } bind def\n"
223 "/CI { GS /py exch def /px exch def /sy exch def /sx exch def\n"
225 "sx sy scale px py 8 \n"
226 "[ px 0 0 py neg 0 py ]\n"
227 "currentfile /ASCIIHexDecode filter\n false 3"
233 "/GI { GS /py exch def /px exch def /sy exch def /sx exch def \n"
235 "sx sy scale px py 8 \n"
238 "[ px 0 0 py neg 0 py ]\n"
239 "currentfile /ASCIIHexDecode filter\n"
243 // single-color bitmask
245 "/MI { GS /py exch def /px exch def /sy exch def /sx exch def \n"
247 "sx sy scale px py true \n"
248 "[ px 0 0 py neg 0 py ]\n"
249 "currentfile /ASCIIHexDecode filter\n"
256 "/BFP { newpath moveto } def\n"
257 "/BP { newpath } bind def \n"
258 "/PL { lineto } bind def \n"
259 "/PM { moveto } bind def \n"
260 "/MT { moveto } bind def \n"
261 "/LT { lineto } bind def \n"
262 "/EFP { closepath fill } bind def\n" //was:stroke
263 "/ELP { stroke } bind def\n"
264 "/ECP { closepath stroke } bind def\n" // Closed (loop)
265 "/LW { setlinewidth } bind def\n"
267 // ////////////////////////// misc ////////////////
268 "/TR { translate } bind def\n"
269 "/CT { concat } bind def\n"
270 "/RCT { matrix invertmatrix concat} bind def\n"
271 "/SC { scale } bind def\n"
272 //"/GPD { currentpagedevice /PageSize get} def\n"
274 // show at position with desired width
276 // width (string) x y show_pos_width
277 "/show_pos_width {GS moveto dup dup stringwidth pop exch length 2 div dup 2 le {pop 9999} if "
278 "1 sub exch 3 index exch sub exch "
279 "div 0 2 index 1 -1 scale ashow pop pop GR} bind def\n" // spacing altered to match desired width
280 //"/show_pos_width {GS moveto dup stringwidth pop 3 2 roll exch div -1 matrix scale concat "
281 //"show GR } bind def\n" // horizontally scaled text to match desired width
286 static const char * prolog_2
= // prolog relevant only if lang_level >1
288 // color image dictionaries
289 "/CII {GS /inter exch def /py exch def /px exch def /sy exch def /sx exch def \n"
292 "/DeviceRGB setcolorspace\n"
298 "/BitsPerComponent 8 def\n"
299 "/Interpolate inter def\n"
300 "/DataSource currentfile /ASCIIHexDecode filter def\n"
301 "/MultipleDataSources false def\n"
302 "/ImageMatrix [ px 0 0 py neg 0 py ] def\n"
303 "/Decode [ 0 1 0 1 0 1 ] def\n"
305 "IDD image GR} bind def\n"
308 "/GII {GS /inter exch def /py exch def /px exch def /sy exch def /sx exch def \n"
311 "/DeviceGray setcolorspace\n"
317 "/BitsPerComponent 8 def\n"
319 "/Interpolate inter def\n"
320 "/DataSource currentfile /ASCIIHexDecode filter def\n"
321 "/MultipleDataSources false def\n"
322 "/ImageMatrix [ px 0 0 py neg 0 py ] def\n"
323 "/Decode [ 0 1 ] def\n"
325 "IDD image GR} bind def\n"
327 // Create a custom PostScript font derived from PostScript standard text fonts
328 // The encoding of this custom font is as follows:
329 // 0000-00FF coincides with Unicode, that is to ASCII + Latin-1
330 // 0100-017F coincides with Unicode, that is to Latin Extended-A
331 // 0180-01A6 encodes miscellaneous characters present in PostScript standard text fonts
333 // use ISOLatin1Encoding for all text fonts
334 "/ToISO { dup findfont dup length dict copy begin /Encoding ISOLatin1Encoding def currentdict end definefont pop } def\n"
335 "/Helvetica ToISO /Helvetica-Bold ToISO /Helvetica-Oblique ToISO /Helvetica-BoldOblique ToISO \n"
336 "/Courier ToISO /Courier-Bold ToISO /Courier-Oblique ToISO /Courier-BoldOblique ToISO \n"
337 "/Times-Roman ToISO /Times-Bold ToISO /Times-Italic ToISO /Times-BoldItalic ToISO \n"
339 // define LatinExtA, the encoding of Latin-extended-A + some additional characters
340 // see http://www.adobe.com/devnet/opentype/archives/glyphlist.txt for their names
343 " /Amacron /amacron /Abreve /abreve /Aogonek /aogonek\n" // begin of Latin Extended-A code page
344 " /Cacute /cacute /Ccircumflex /ccircumflex /Cdotaccent /cdotaccent /Ccaron /ccaron \n"
345 " /Dcaron /dcaron /Dcroat /dcroat\n"
346 " /Emacron /emacron /Ebreve /ebreve /Edotaccent /edotaccent /Eogonek /eogonek /Ecaron /ecaron\n"
347 " /Gcircumflex /gcircumflex /Gbreve /gbreve /Gdotaccent /gdotaccent /Gcommaaccent /gcommaaccent \n"
348 " /Hcircumflex /hcircumflex /Hbar /hbar \n"
349 " /Itilde /itilde /Imacron /imacron /Ibreve /ibreve /Iogonek /iogonek /Idotaccent /dotlessi \n"
350 " /IJ /ij /Jcircumflex /jcircumflex\n"
351 " /Kcommaaccent /kcommaaccent /kgreenlandic \n"
352 " /Lacute /lacute /Lcommaaccent /lcommaaccent /Lcaron /lcaron /Ldotaccent /ldotaccent /Lslash /lslash \n"
353 " /Nacute /nacute /Ncommaaccent /ncommaaccent /Ncaron /ncaron /napostrophe /Eng /eng \n"
354 " /Omacron /omacron /Obreve /obreve /Ohungarumlaut /ohungarumlaut /OE /oe \n"
355 " /Racute /racute /Rcommaaccent /rcommaaccent /Rcaron /rcaron \n"
356 " /Sacute /sacute /Scircumflex /scircumflex /Scedilla /scedilla /Scaron /scaron \n"
357 " /Tcommaaccent /tcommaaccent /Tcaron /tcaron /Tbar /tbar \n"
358 " /Utilde /utilde /Umacron /umacron /Ubreve /ubreve /Uring /uring /Uhungarumlaut /uhungarumlaut /Uogonek /uogonek \n"
359 " /Wcircumflex /wcircumflex /Ycircumflex /ycircumflex /Ydieresis \n"
360 " /Zacute /zacute /Zdotaccent /zdotaccent /Zcaron /zcaron \n"
361 " /longs \n" // end of Latin Extended-A code page
362 " /florin /circumflex /caron /breve /dotaccent /ring \n" // remaining characters from PostScript standard text fonts
363 " /ogonek /tilde /hungarumlaut /endash /emdash \n"
364 " /quoteleft /quoteright /quotesinglbase /quotedblleft /quotedblright \n"
365 " /quotedblbase /dagger /daggerdbl /bullet /ellipsis \n"
366 " /perthousand /guilsinglleft /guilsinglright /fraction /Euro \n"
367 " /trademark /partialdiff /Delta /summation /radical \n"
368 " /infinity /notequal /lessequal /greaterequal /lozenge \n"
371 // deal with alternative PostScript names of some characters
372 " /mycharstrings /Helvetica findfont /CharStrings get def\n"
373 " /PSname2 { dup mycharstrings exch known {LatinExtA 3 -1 roll 3 -1 roll put}{pop pop} ifelse } def \n"
374 " 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"
376 // proc that gives LatinExtA encoding to a font
377 "/ToLatinExtA { findfont dup length dict copy begin /Encoding LatinExtA def currentdict end definefont pop } def\n"
378 // create Ext-versions of standard fonts that use LatinExtA encoding \n"
379 "/HelveticaExt /Helvetica ToLatinExtA \n"
380 "/Helvetica-BoldExt /Helvetica-Bold ToLatinExtA /Helvetica-ObliqueExt /Helvetica-Oblique ToLatinExtA \n"
381 "/Helvetica-BoldObliqueExt /Helvetica-BoldOblique ToLatinExtA \n"
382 "/CourierExt /Courier ToLatinExtA /Courier-BoldExt /Courier-Bold ToLatinExtA \n"
383 "/Courier-ObliqueExt /Courier-Oblique ToLatinExtA /Courier-BoldObliqueExt /Courier-BoldOblique ToLatinExtA \n"
384 "/Times-RomanExt /Times-Roman ToLatinExtA /Times-BoldExt /Times-Bold ToLatinExtA \n"
385 "/Times-ItalicExt /Times-Italic ToLatinExtA /Times-BoldItalicExt /Times-BoldItalic ToLatinExtA \n"
387 // proc to create a Type 0 font with 2-byte encoding
388 // that merges a text font with ISO encoding + same font with LatinExtA encoding
389 "/To2byte { 6 dict begin /FontType 0 def \n"
390 "/FDepVector 3 1 roll findfont exch findfont 2 array astore def \n"
391 "/FontMatrix [1 0 0 1 0 0] def /FMapType 6 def /Encoding [ 0 1 0 ] def\n"
392 // 100: Hexa count of ISO array; A7: hexa count of LatinExtA array
393 "/SubsVector < 01 0100 00A7 > def\n"
394 "currentdict end definefont pop } def\n"
395 // create Type 0 versions of standard fonts
396 "/Helvetica2B /HelveticaExt /Helvetica To2byte \n"
397 "/Helvetica-Bold2B /Helvetica-BoldExt /Helvetica-Bold To2byte \n"
398 "/Helvetica-Oblique2B /Helvetica-ObliqueExt /Helvetica-Oblique To2byte \n"
399 "/Helvetica-BoldOblique2B /Helvetica-BoldObliqueExt /Helvetica-BoldOblique To2byte \n"
400 "/Courier2B /CourierExt /Courier To2byte \n"
401 "/Courier-Bold2B /Courier-BoldExt /Courier-Bold To2byte \n"
402 "/Courier-Oblique2B /Courier-ObliqueExt /Courier-Oblique To2byte \n"
403 "/Courier-BoldOblique2B /Courier-BoldObliqueExt /Courier-BoldOblique To2byte \n"
404 "/Times-Roman2B /Times-RomanExt /Times-Roman To2byte \n"
405 "/Times-Bold2B /Times-BoldExt /Times-Bold To2byte \n"
406 "/Times-Italic2B /Times-ItalicExt /Times-Italic To2byte \n"
407 "/Times-BoldItalic2B /Times-BoldItalicExt /Times-BoldItalic To2byte \n"
410 static const char * prolog_2_pixmap
= // prolog relevant only if lang_level == 2 for pixmaps/masked color images
411 "/pixmap_mat {[ pixmap_sx 0 0 pixmap_sy neg 0 pixmap_sy ]} bind def\n"
417 "/BBox [0 0 pixmap_sx pixmap_sy] "
422 "pixmap_w pixmap_h scale "
423 "pixmap_sx pixmap_sy 8 "
425 "currentfile /ASCIIHexDecode filter "
435 "/pixmap_sy exch def /pixmap_sx exch def\n"
436 "/pixmap_h exch def /pixmap_w exch def\n"
438 "pixmap_dict matrix makepattern setpattern\n"
439 "pixmap_w pixmap_h scale\n"
440 "pixmap_sx pixmap_sy\n"
443 "currentfile /ASCIIHexDecode filter\n"
449 static const char * prolog_3
= // prolog relevant only if lang_level >2
451 // masked color images
452 "/CIM {GS /inter exch def /my exch def /mx exch def /py exch def /px exch def /sy exch def /sx exch def \n"
455 "/DeviceRGB setcolorspace\n"
463 "/BitsPerComponent 8 def\n"
464 "/Interpolate inter def\n"
465 "/DataSource currentfile /ASCIIHexDecode filter def\n"
466 "/MultipleDataSources false def\n"
467 "/ImageMatrix [ px 0 0 py neg 0 py ] def\n"
469 "/Decode [ 0 1 0 1 0 1 ] def\n"
477 "/BitsPerComponent 1 def\n"
478 // "/Interpolate inter def\n"
479 "/ImageMatrix [ mx 0 0 my neg 0 my ] def\n"
480 "/Decode [ 1 0 ] def\n"
485 "/InterleaveType 2\n"
492 // masked gray images
493 "/GIM {GS /inter exch def /my exch def /mx exch def /py exch def /px exch def /sy exch def /sx exch def \n"
496 "/DeviceGray setcolorspace\n"
504 "/BitsPerComponent 8 def\n"
505 "/Interpolate inter def\n"
506 "/DataSource currentfile /ASCIIHexDecode filter def\n"
507 "/MultipleDataSources false def\n"
508 "/ImageMatrix [ px 0 0 py neg 0 py ] def\n"
510 "/Decode [ 0 1 ] def\n"
519 "/BitsPerComponent 1 def\n"
520 "/ImageMatrix [ mx 0 0 my neg 0 my ] def\n"
521 "/Decode [ 1 0 ] def\n"
526 "/InterleaveType 2\n"
538 int Fl_PostScript_Graphics_Driver::start_postscript (int pagecount
,
539 enum Fl_Paged_Device::Page_Format format
, enum Fl_Paged_Device::Page_Layout layout
)
543 if (format
== Fl_Paged_Device::A4
) {
551 page_format_
= (enum Fl_Paged_Device::Page_Format
)(format
| layout
);
553 fputs("%!PS-Adobe-3.0\n", output
);
554 fputs("%%Creator: FLTK\n", output
);
556 fprintf(output
, "%%%%LanguageLevel: %i\n" , lang_level_
);
557 if ((pages_
= pagecount
))
558 fprintf(output
, "%%%%Pages: %i\n", pagecount
);
560 fputs("%%Pages: (atend)\n", output
);
561 fprintf(output
, "%%%%BeginFeature: *PageSize %s\n", Fl_Paged_Device::page_formats
[format
].name
);
562 w
= Fl_Paged_Device::page_formats
[format
].width
;
563 h
= Fl_Paged_Device::page_formats
[format
].height
;
564 if (lang_level_
== 3 && (layout
& Fl_Paged_Device::LANDSCAPE
) ) { x
= w
; w
= h
; h
= x
; }
565 fprintf(output
, "<</PageSize[%d %d]>>setpagedevice\n", w
, h
);
566 fputs("%%EndFeature\n", output
);
567 fputs("%%EndComments\n", output
);
568 fputs(prolog
, output
);
569 if (lang_level_
> 1) {
570 fputs(prolog_2
, output
);
572 if (lang_level_
== 2) {
573 fputs(prolog_2_pixmap
, output
);
576 fputs(prolog_3
, output
);
577 if (lang_level_
>= 3) {
578 fputs("/CS { clipsave } bind def\n", output
);
579 fputs("/CR { cliprestore } bind def\n", output
);
581 fputs("/CS { GS } bind def\n", output
);
582 fputs("/CR { GR } bind def\n", output
);
587 fputs("%%EndProlog\n",output
);
588 if (lang_level_
>= 2)
589 fprintf(output
,"<< /Policies << /Pagesize 1 >> >> setpagedevice\n");
596 void Fl_PostScript_Graphics_Driver::recover(){
598 line_style(linestyle_
,linewidth_
,linedash_
);
599 font(Fl_Graphics_Driver::font(), Fl_Graphics_Driver::size());
602 void Fl_PostScript_Graphics_Driver::reset(){
606 Fl_Graphics_Driver::font(FL_HELVETICA
, 12);
609 strcpy(linedash_
,"");
610 Clip
*c
=clip_
; ////just not to have memory leaks for badly writen code (forgotten clip popping)
620 void Fl_PostScript_Graphics_Driver::page_policy(int p
){
623 fprintf(output
,"<< /Policies << /Pagesize %i >> >> setpagedevice\n", p
);
626 // //////////////////// paging //////////////////////////////////////////
630 void Fl_PostScript_Graphics_Driver::page(double pw
, double ph
, int media
) {
633 fprintf(output
, "CR\nGR\nGR\nGR\nSP\nrestore\n");
636 fprintf(output
, "%%%%Page: %i %i\n" , nPages
, nPages
);
638 fprintf(output
, "%%%%PageOrientation: Landscape\n");
640 fprintf(output
, "%%%%PageOrientation: Portrait\n");
643 fprintf(output
, "%%%%BeginPageSetup\n");
644 if((media
& Fl_Paged_Device::MEDIA
) &&(lang_level_
>1)){
645 int r
= media
& Fl_Paged_Device::REVERSED
;
647 fprintf(output
, "<< /PageSize [%i %i] /Orientation %i>> setpagedevice\n", (int)(pw
+.5), (int)(ph
+.5), r
);
649 fprintf(output
, "%%%%EndPageSetup\n");
655 fprintf(output
, "save\n");
656 fprintf(output
, "GS\n");
657 fprintf(output
, "%g %g TR\n", (double)0 /*lm_*/ , ph_
/* - tm_*/);
658 fprintf(output
, "1 -1 SC\n");
660 fprintf(output
, "GS\n");
662 if (!((media
& Fl_Paged_Device::MEDIA
) &&(lang_level_
>1))){
664 if(media
& Fl_Paged_Device::REVERSED
) {
665 fprintf(output
, "-90 rotate %i 0 translate\n", int(-pw
));
668 fprintf(output
, "90 rotate -%i -%i translate\n", (lang_level_
== 2 ? int(pw
- ph
) : 0), int(ph
));
672 if(media
& Fl_Paged_Device::REVERSED
)
673 fprintf(output
, "180 rotate %i %i translate\n", int(-pw
), int(-ph
));
676 fprintf(output
, "GS\nCS\n");
679 void Fl_PostScript_Graphics_Driver::page(int format
){
682 if(format
& Fl_Paged_Device::LANDSCAPE
){
683 ph_
=Fl_Paged_Device::page_formats
[format
& 0xFF].width
;
684 pw_
=Fl_Paged_Device::page_formats
[format
& 0xFF].height
;
686 pw_
=Fl_Paged_Device::page_formats
[format
& 0xFF].width
;
687 ph_
=Fl_Paged_Device::page_formats
[format
& 0xFF].height
;
689 page(pw_
,ph_
,format
& 0xFF00);//,orientation only;
692 void Fl_PostScript_Graphics_Driver::rect(int x
, int y
, int w
, int h
) {
693 // Commented code does not work, i can't find the bug ;-(
694 // fprintf(output, "GS\n");
695 // fprintf(output, "%i, %i, %i, %i R\n", x , y , w, h);
696 // fprintf(output, "GR\n");
697 fprintf(output
, "GS\n");
698 fprintf(output
,"BP\n");
699 fprintf(output
, "%i %i MT\n", x
, y
);
700 fprintf(output
, "%i %i LT\n", x
+w
-1 , y
);
701 fprintf(output
, "%i %i LT\n", x
+w
-1 , y
+h
-1);
702 fprintf(output
, "%i %i LT\n", x
, y
+h
-1);
703 fprintf(output
, "ECP\n");
704 fprintf(output
, "GR\n");
707 void Fl_PostScript_Graphics_Driver::rectf(int x
, int y
, int w
, int h
) {
708 fprintf(output
, "%g %g %i %i FR\n", x
-0.5, y
-0.5, w
, h
);
711 void Fl_PostScript_Graphics_Driver::line(int x1
, int y1
, int x2
, int y2
) {
712 fprintf(output
, "GS\n");
713 fprintf(output
, "%i %i %i %i L\n", x1
, y1
, x2
,y2
);
714 fprintf(output
, "GR\n");
717 void Fl_PostScript_Graphics_Driver::line(int x0
, int y0
, int x1
, int y1
, int x2
, int y2
) {
718 fprintf(output
, "GS\n");
719 fprintf(output
,"BP\n");
720 fprintf(output
, "%i %i MT\n", x0
, y0
);
721 fprintf(output
, "%i %i LT\n", x1
, y1
);
722 fprintf(output
, "%i %i LT\n", x2
, y2
);
723 fprintf(output
, "ELP\n");
724 fprintf(output
, "GR\n");
727 void Fl_PostScript_Graphics_Driver::xyline(int x
, int y
, int x1
, int y2
, int x3
){
728 fprintf(output
, "GS\n");
729 fprintf(output
,"BP\n");
730 fprintf(output
, "%i %i MT\n", x
, y
);
731 fprintf(output
, "%i %i LT\n", x1
, y
);
732 fprintf(output
, "%i %i LT\n", x1
, y2
);
733 fprintf(output
,"%i %i LT\n", x3
, y2
);
734 fprintf(output
, "ELP\n");
735 fprintf(output
, "GR\n");
739 void Fl_PostScript_Graphics_Driver::xyline(int x
, int y
, int x1
, int y2
){
741 fprintf(output
, "GS\n");
742 fprintf(output
,"BP\n");
743 fprintf(output
, "%i %i MT\n", x
, y
);
744 fprintf(output
,"%i %i LT\n", x1
, y
);
745 fprintf(output
, "%i %i LT\n", x1
, y2
);
746 fprintf(output
, "ELP\n");
747 fprintf(output
, "GR\n");
750 void Fl_PostScript_Graphics_Driver::xyline(int x
, int y
, int x1
){
751 fprintf(output
, "GS\n");
752 fprintf(output
,"BP\n");
753 fprintf(output
, "%i %i MT\n", x
, y
);
754 fprintf(output
, "%i %i LT\n", x1
, y
);
755 fprintf(output
, "ELP\n");
757 fprintf(output
, "GR\n");
760 void Fl_PostScript_Graphics_Driver::yxline(int x
, int y
, int y1
, int x2
, int y3
){
761 fprintf(output
, "GS\n");
763 fprintf(output
,"BP\n");
764 fprintf(output
,"%i %i MT\n", x
, y
);
765 fprintf(output
, "%i %i LT\n", x
, y1
);
766 fprintf(output
, "%i %i LT\n", x2
, y1
);
767 fprintf(output
, "%i %i LT\n", x2
, y3
);
768 fprintf(output
, "ELP\n");
769 fprintf(output
, "GR\n");
772 void Fl_PostScript_Graphics_Driver::yxline(int x
, int y
, int y1
, int x2
){
773 fprintf(output
, "GS\n");
774 fprintf(output
,"BP\n");
775 fprintf(output
, "%i %i MT\n", x
, y
);
776 fprintf(output
, "%i %i LT\n", x
, y1
);
777 fprintf(output
, "%i %i LT\n", x2
, y1
);
778 fprintf(output
, "ELP\n");
779 fprintf(output
, "GR\n");
782 void Fl_PostScript_Graphics_Driver::yxline(int x
, int y
, int y1
){
783 fprintf(output
, "GS\n");
784 fprintf(output
,"BP\n");
785 fprintf(output
, "%i %i MT\n", x
, y
);
786 fprintf(output
, "%i %i LT\n", x
, y1
);
787 fprintf(output
, "ELP\n");
788 fprintf(output
, "GR\n");
791 void Fl_PostScript_Graphics_Driver::loop(int x0
, int y0
, int x1
, int y1
, int x2
, int y2
) {
792 fprintf(output
, "GS\n");
793 fprintf(output
,"BP\n");
794 fprintf(output
, "%i %i MT\n", x0
, y0
);
795 fprintf(output
, "%i %i LT\n", x1
, y1
);
796 fprintf(output
, "%i %i LT\n", x2
, y2
);
797 fprintf(output
, "ECP\n");
798 fprintf(output
, "GR\n");
801 void Fl_PostScript_Graphics_Driver::loop(int x0
, int y0
, int x1
, int y1
, int x2
, int y2
, int x3
, int y3
) {
802 fprintf(output
, "GS\n");
803 fprintf(output
,"BP\n");
804 fprintf(output
, "%i %i MT\n", x0
, y0
);
805 fprintf(output
, "%i %i LT\n", x1
, y1
);
806 fprintf(output
, "%i %i LT\n", x2
, y2
);
807 fprintf(output
, "%i %i LT\n", x3
, y3
);
808 fprintf(output
, "ECP\n");
809 fprintf(output
, "GR\n");
812 void Fl_PostScript_Graphics_Driver::polygon(int x0
, int y0
, int x1
, int y1
, int x2
, int y2
) {
813 fprintf(output
, "GS\n");
814 fprintf(output
,"BP\n");
815 fprintf(output
, "%i %i MT\n", x0
, y0
);
816 fprintf(output
,"%i %i LT\n", x1
, y1
);
817 fprintf(output
, "%i %i LT\n", x2
, y2
);
818 fprintf(output
, "EFP\n");
819 fprintf(output
, "GR\n");
822 void Fl_PostScript_Graphics_Driver::polygon(int x0
, int y0
, int x1
, int y1
, int x2
, int y2
, int x3
, int y3
) {
823 fprintf(output
, "GS\n");
824 fprintf(output
,"BP\n");
825 fprintf(output
, "%i %i MT\n", x0
, y0
);
826 fprintf(output
, "%i %i LT\n", x1
, y1
);
827 fprintf(output
, "%i %i LT\n", x2
, y2
);
828 fprintf(output
, "%i %i LT\n", x3
, y3
);
830 fprintf(output
, "EFP\n");
831 fprintf(output
, "GR\n");
834 void Fl_PostScript_Graphics_Driver::point(int x
, int y
){
838 static int dashes_flat
[5][7]={
848 static double dashes_cap
[5][7]={
851 {0.01,1.99,-1,0,0,0,0},
852 {2,2,0.01,1.99,-1,0,0},
853 {2,2,0.01,1.99,0.01,1.99,-1}
857 void Fl_PostScript_Graphics_Driver::line_style(int style
, int width
, char* dashes
){
864 if(dashes
!= linedash_
)
865 strcpy(linedash_
,dashes
);
871 width
=1; //for screen drawing compatibility
875 fprintf(output
, "%i setlinewidth\n", width
);
877 if(!style
&& (!dashes
|| !(*dashes
)) && width0
) //system lines
878 style
= FL_CAP_SQUARE
;
880 int cap
= (style
&0xf00) >> 8;
882 fprintf(output
,"%i setlinecap\n", cap
);
884 int join
= (style
& 0xf000) >> 12;
887 fprintf(output
,"%i setlinejoin\n", join
);
890 fprintf(output
, "[");
891 if(dashes
&& *dashes
){
893 fprintf(output
, "%i ", *dashes
);
898 if(style
& 0x200){ // round and square caps, dash length need to be adjusted
899 double *dt
= dashes_cap
[style
& 0xff];
901 fprintf(output
, "%g ",width
* (*dt
));
906 ds
= dashes_flat
[style
& 0xff];
908 fprintf(output
, "%i ",width
* (*ds
));
913 fprintf(output
, "] 0 setdash\n");
916 static const char *_fontNames
[] = {
919 "Helvetica-Oblique2B",
920 "Helvetica-BoldOblique2B",
924 "Courier-BoldOblique2B",
928 "Times-BoldItalic2B",
935 void Fl_PostScript_Graphics_Driver::font(int f
, int s
) {
936 Fl_Graphics_Driver
*driver
= Fl_Display_Device::display_device()->driver();
937 driver
->font(f
,s
); // Use display fonts for font measurement
938 Fl_Graphics_Driver::font(f
, s
);
939 Fl_Font_Descriptor
*desc
= driver
->font_descriptor();
940 this->font_descriptor(desc
);
941 if (f
< FL_FREE_FONT
) {
943 fprintf(output
, "/%s SF\n" , _fontNames
[f
]);
946 // Xft font height is sometimes larger than the required size (see STR 2566).
947 // Increase the PostScript font size by 15% without exceeding the display font height
948 int max
= desc
->font
->height
;
950 if (ps_size
> max
) ps_size
= max
;
952 // Non-Xft fonts can be smaller than required.
953 // Set the PostScript font size to the display font height
954 char *name
= desc
->font
->font_name_list
[0];
955 char *p
= strstr(name
, "--");
957 sscanf(p
+ 2, "%f", &ps_size
);
961 fprintf(output
,"%.1f FS\n", ps_size
);
965 double Fl_PostScript_Graphics_Driver::width(const char *s
, int n
) {
966 return Fl_Display_Device::display_device()->driver()->width(s
, n
);
969 int Fl_PostScript_Graphics_Driver::height() {
970 return Fl_Display_Device::display_device()->driver()->height();
973 int Fl_PostScript_Graphics_Driver::descent() {
974 return Fl_Display_Device::display_device()->driver()->descent();
977 void Fl_PostScript_Graphics_Driver::text_extents(const char *c
, int n
, int &dx
, int &dy
, int &w
, int &h
) {
978 Fl_Display_Device::display_device()->driver()->text_extents(c
, n
, dx
, dy
, w
, h
);
982 void Fl_PostScript_Graphics_Driver::color(Fl_Color c
) {
983 Fl::get_color(c
, cr_
, cg_
, cb_
);
984 color(cr_
, cg_
, cb_
);
987 void Fl_PostScript_Graphics_Driver::color(unsigned char r
, unsigned char g
, unsigned char b
) {
988 Fl_Graphics_Driver::color( fl_rgb_color(r
, g
, b
) );
989 cr_
= r
; cg_
= g
; cb_
= b
;
990 if (r
== g
&& g
== b
) {
991 double gray
= r
/255.0;
992 fprintf(output
, "%g GL\n", gray
);
998 fprintf(output
, "%g %g %g SRGB\n", fr
, fg
, fb
);
1002 void Fl_PostScript_Graphics_Driver::draw(int angle
, const char *str
, int n
, int x
, int y
)
1004 fprintf(output
, "GS %d %d translate %d rotate\n", x
, y
, - angle
);
1005 this->transformed_draw(str
, n
, 0, 0);
1006 fprintf(output
, "GR\n");
1010 // computes the mask for the RGB image img of all pixels with color != bg
1011 static uchar
*calc_mask(uchar
*img
, int w
, int h
, Fl_Color bg
)
1013 uchar red
, green
, blue
, r
, g
, b
;
1014 uchar bit
, byte
, *q
;
1015 Fl::get_color(bg
, red
, green
, blue
);
1016 int W
= (w
+7)/8; // width of mask
1017 uchar
* mask
= new uchar
[W
* h
];
1019 while (h
-- > 0) { // for each row
1020 bit
= 0x80; // byte with last bit set
1021 byte
= 0; // next mask byte to compute
1022 for (int j
= 0; j
< w
; j
++) { // for each column
1023 r
= *img
++; // the pixel color components
1026 // if pixel doesn't have bg color, put it in mask
1027 if (r
!= red
|| g
!= green
|| b
!= blue
) byte
|= bit
;
1028 bit
= bit
>>1; // shift bit one step to the right
1029 if (bit
== 0) { // single set bit has fallen out
1030 *q
++ = byte
; // enter byte in mask
1031 byte
= 0; // reset next mask byte to zero
1032 bit
= 0x80; // and this byte
1035 if (bit
!= 0x80) *q
++ = byte
; // enter last columns' byte in mask
1040 // write to PostScript a bitmap image of a UTF8 string
1041 static void transformed_draw_extra(const char* str
, int n
, double x
, double y
, int w
,
1042 FILE *output
, Fl_Graphics_Driver
*driver
, bool rtl
) {
1043 // scale for bitmask computation
1044 #if defined(USE_X11) && !USE_XFT
1045 float scale
= 1; // don't scale because we can't expect to have scalable fonts
1049 Fl_Fontsize old_size
= driver
->size();
1050 Fl_Font fontnum
= driver
->font();
1051 int w_scaled
= (int)(w
* (scale
+ 0.5));
1052 int h
= (int)(driver
->height() * scale
);
1053 // create an offscreen image of the string
1054 Fl_Color text_color
= driver
->color();
1055 Fl_Color bg_color
= fl_contrast(FL_WHITE
, text_color
);
1056 Fl_Offscreen off
= fl_create_offscreen(w_scaled
, (int)(h
+3*scale
) );
1057 fl_begin_offscreen(off
);
1059 // color offscreen background with a shade contrasting with the text color
1060 fl_rectf(0, 0, w_scaled
, (int)(h
+3*scale
) );
1061 fl_color(text_color
);
1062 #if defined(USE_X11) && !USE_XFT
1063 // force seeing this font as new so it's applied to the offscreen graphics context
1064 fl_graphics_driver
->font_descriptor(NULL
);
1065 fl_font(fontnum
, 0);
1067 fl_font(fontnum
, (Fl_Fontsize
)(scale
* old_size
) );
1068 int w2
= (int)fl_width(str
, n
);
1069 // draw string in offscreen
1070 if (rtl
) fl_rtl_draw(str
, n
, w2
, (int)(h
* 0.8) );
1071 else fl_draw(str
, n
, 1, (int)(h
* 0.8) );
1072 // read (most of) the offscreen image
1073 uchar
*img
= fl_read_image(NULL
, 1, 1, w2
, h
, 0);
1075 driver
->font(fontnum
, old_size
);
1076 fl_delete_offscreen(off
);
1077 // compute the mask of what is not the background
1078 uchar
*mask
= calc_mask(img
, w2
, h
, bg_color
);
1080 // write the string image to PostScript as a scaled bitmask
1081 scale
= w2
/ float(w
);
1082 fprintf(output
, "%g %g %g %g %d %d MI\n", x
, y
- h
*0.77/scale
, w2
/scale
, h
/scale
, w2
, h
);
1084 int wmask
= (w2
+7)/8;
1085 for (int j
= h
- 1; j
>= 0; j
--){
1086 di
= mask
+ j
* wmask
;
1087 for (int i
= 0; i
< wmask
; i
++){
1088 //if (!(i%80)) fprintf(output, "\n"); // don't have lines longer than 255 chars
1089 fprintf(output
, "%2.2x", *di
);
1092 fprintf(output
,"\n");
1094 fprintf(output
,">\n");
1098 static int is_in_table(unsigned utf
) {
1100 static unsigned extra_table_roman
[] = { // unicodes/*names*/ of other characters from PostScript standard fonts
1101 0x192/*florin*/, 0x2C6/*circumflex*/, 0x2C7/*caron*/,
1102 0x2D8/*breve*/, 0x2D9/*dotaccent*/, 0x2DA/*ring*/, 0x2DB/*ogonek*/, 0x2DC/*tilde*/, 0x2DD/*hungarumlaut*/,
1103 0x2013/*endash*/, 0x2014/*emdash*/, 0x2018/*quoteleft*/, 0x2019/*quoteright*/,
1104 0x201A/*quotesinglbase*/, 0x201C/*quotedblleft*/, 0x201D/*quotedblright*/, 0x201E/*quotedblbase*/,
1105 0x2020/*dagger*/, 0x2021/*daggerdbl*/, 0x2022/*bullet*/,
1106 0x2026/*ellipsis*/, 0x2030/*perthousand*/, 0x2039/*guilsinglleft*/, 0x203A/*guilsinglright*/,
1107 0x2044/*fraction*/, 0x20AC/*Euro*/, 0x2122/*trademark*/,
1108 0x2202/*partialdiff*/, 0x2206/*Delta*/, 0x2211/*summation*/, 0x221A/*radical*/,
1109 0x221E/*infinity*/, 0x2260/*notequal*/, 0x2264/*lessequal*/,
1110 0x2265/*greaterequal*/,
1111 0x25CA/*lozenge*/, 0xFB01/*fi*/, 0xFB02/*fl*/,
1114 for ( i
= 0; i
< sizeof(extra_table_roman
)/sizeof(int); i
++) {
1115 if (extra_table_roman
[i
] == utf
) return i
+ 0x180;
1120 // outputs in PostScript a UTF8 string using the same width in points as on display
1121 void Fl_PostScript_Graphics_Driver::transformed_draw(const char* str
, int n
, double x
, double y
) {
1123 if (!n
|| !str
|| !*str
) return;
1124 // compute display width of string
1125 int w
= (int)width(str
, n
);
1127 if (Fl_Graphics_Driver::font() >= FL_FREE_FONT
) {
1128 transformed_draw_extra(str
, n
, x
, y
, w
, output
, this, false);
1131 fprintf(output
, "%d <", w
);
1132 // transforms UTF8 encoding to our custom PostScript encoding as follows:
1133 // extract each unicode character
1134 // if unicode <= 0x17F, unicode and PostScript codes are identical
1135 // if unicode is one of the values listed in extra_table_roman above
1136 // its PostScript code is 0x180 + the character's rank in extra_table_roman
1137 // if unicode is something else, draw all string as bitmap image
1139 const char *last
= str
+ n
;
1140 const char *str2
= str
;
1141 while (str2
< last
) {
1142 // Extract each unicode character of string.
1143 unsigned utf
= fl_utf8decode(str2
, last
, &len
);
1145 if (utf
<= 0x17F) { // until Latin Extended-A
1148 else if ( (code
= is_in_table(utf
)) != 0) { // other handled characters
1151 else { // unhandled character: draw all string as bitmap image
1152 fprintf(output
, "> pop pop\n"); // close and ignore the opened hex string
1153 transformed_draw_extra(str
, n
, x
, y
, w
, output
, this, false);
1156 fprintf(output
, "%4.4X", utf
);
1158 fprintf(output
, "> %g %g show_pos_width\n", x
, y
);
1161 void Fl_PostScript_Graphics_Driver::rtl_draw(const char* str
, int n
, int x
, int y
) {
1162 int w
= (int)width(str
, n
);
1163 transformed_draw_extra(str
, n
, x
- w
, y
, w
, output
, this, true);
1166 void Fl_PostScript_Graphics_Driver::concat(){
1167 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
);
1170 void Fl_PostScript_Graphics_Driver::reconcat(){
1171 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
);
1174 ///////////////// transformed (double) drawings ////////////////////////////////
1177 void Fl_PostScript_Graphics_Driver::begin_points(){
1178 fprintf(output
, "GS\n");
1181 fprintf(output
, "BP\n");
1186 void Fl_PostScript_Graphics_Driver::begin_line(){
1187 fprintf(output
, "GS\n");
1189 fprintf(output
, "BP\n");
1194 void Fl_PostScript_Graphics_Driver::begin_loop(){
1195 fprintf(output
, "GS\n");
1197 fprintf(output
, "BP\n");
1202 void Fl_PostScript_Graphics_Driver::begin_polygon(){
1203 fprintf(output
, "GS\n");
1205 fprintf(output
, "BP\n");
1210 void Fl_PostScript_Graphics_Driver::vertex(double x
, double y
){
1212 fprintf(output
,"%g %g MT\n", x
, y
);
1217 fprintf(output
,"%g %g MT\n", x
, y
);
1220 fprintf(output
, "%g %g LT\n", x
, y
);
1223 void Fl_PostScript_Graphics_Driver::curve(double x
, double y
, double x1
, double y1
, double x2
, double y2
, double x3
, double y3
){
1224 if(shape_
==NONE
) return;
1226 fprintf(output
,"%g %g MT\n", x
, y
);
1228 fprintf(output
, "%g %g LT\n", x
, y
);
1231 fprintf(output
, "%g %g %g %g %g %g curveto \n", x1
, y1
, x2
, y2
, x3
, y3
);
1235 void Fl_PostScript_Graphics_Driver::circle(double x
, double y
, double r
){
1237 fprintf(output
, "GS\n");
1239 // fprintf(output, "BP\n");
1240 fprintf(output
,"%g %g %g 0 360 arc\n", x
, y
, r
);
1242 // fprintf(output, "ELP\n");
1243 fprintf(output
, "GR\n");
1246 fprintf(output
, "%g %g %g 0 360 arc\n", x
, y
, r
);
1250 void Fl_PostScript_Graphics_Driver::arc(double x
, double y
, double r
, double start
, double a
){
1251 if(shape_
==NONE
) return;
1254 fprintf(output
, "%g %g %g %g %g arc\n", x
, y
, r
, -start
, -a
);
1256 fprintf(output
, "%g %g %g %g %g arcn\n", x
, y
, r
, -start
, -a
);
1260 void Fl_PostScript_Graphics_Driver::arc(int x
, int y
, int w
, int h
, double a1
, double a2
) {
1261 fprintf(output
, "GS\n");
1262 //fprintf(output, "BP\n");
1264 fprintf(output
, "%g %g TR\n", x
+ w
/2.0 -0.5 , y
+ h
/2.0 - 0.5);
1265 fprintf(output
, "%g %g SC\n", (w
-1)/2.0 , (h
-1)/2.0 );
1267 // fprintf(output, "0 0 1 %g %g arc\n" , -a1 , -a2);
1268 fprintf(output
, "%g %g SC\n", 2.0/(w
-1) , 2.0/(h
-1) );
1269 fprintf(output
, "%g %g TR\n", -x
- w
/2.0 +0.5 , -y
- h
/2.0 +0.5);
1272 // fprintf(output, "%g setlinewidth\n", 2/sqrt(w*h));
1273 // fprintf(output, "ELP\n");
1274 // fprintf(output, 2.0/w , 2.0/w , " SC\n";
1275 // fprintf(output, (-x - w/2.0) , (-y - h/2) , " TR\n";
1276 fprintf(output
, "GR\n");
1279 void Fl_PostScript_Graphics_Driver::pie(int x
, int y
, int w
, int h
, double a1
, double a2
) {
1281 fprintf(output
, "GS\n");
1282 fprintf(output
, "%g %g TR\n", x
+ w
/2.0 -0.5 , y
+ h
/2.0 - 0.5);
1283 fprintf(output
, "%g %g SC\n", (w
-1)/2.0 , (h
-1)/2.0 );
1286 arc(0.0,0.0, 1, a2
, a1
);
1288 fprintf(output
, "GR\n");
1291 void Fl_PostScript_Graphics_Driver::end_points(){
1294 fprintf(output
, "ELP\n"); //??
1295 fprintf(output
, "GR\n");
1299 void Fl_PostScript_Graphics_Driver::end_line(){
1302 fprintf(output
, "ELP\n");
1303 fprintf(output
, "GR\n");
1306 void Fl_PostScript_Graphics_Driver::end_loop(){
1309 fprintf(output
, "ECP\n");
1310 fprintf(output
, "GR\n");
1314 void Fl_PostScript_Graphics_Driver::end_polygon(){
1318 fprintf(output
, "EFP\n");
1319 fprintf(output
, "GR\n");
1323 void Fl_PostScript_Graphics_Driver::transformed_vertex(double x
, double y
){
1326 fprintf(output
, "%g %g MT\n", x
, y
);
1329 fprintf(output
, "%g %g LT\n", x
, y
);
1333 ///////////////////////////// Clipping /////////////////////////////////////////////
1335 void Fl_PostScript_Graphics_Driver::push_clip(int x
, int y
, int w
, int h
) {
1336 Clip
* c
=new Clip();
1337 clip_box(x
,y
,w
,h
,c
->x
,c
->y
,c
->w
,c
->h
);
1340 fprintf(output
, "CR\nCS\n");
1343 fprintf(output
, "%g %g %i %i CL\n", clip_
->x
-0.5 , clip_
->y
-0.5 , clip_
->w
, clip_
->h
);
1347 void Fl_PostScript_Graphics_Driver::push_no_clip() {
1348 Clip
* c
= new Clip();
1351 clip_
->x
= clip_
->y
= clip_
->w
= clip_
->h
= -1;
1352 fprintf(output
, "CR\nCS\n");
1357 void Fl_PostScript_Graphics_Driver::pop_clip() {
1362 fprintf(output
, "CR\nCS\n");
1363 if(clip_
&& clip_
->w
>0)
1364 fprintf(output
, "%g %g %i %i CL\n", clip_
->x
- 0.5, clip_
->y
- 0.5, clip_
->w
, clip_
->h
);
1365 // uh, -0.5 is to match screen clipping, for floats there should be something beter
1370 int Fl_PostScript_Graphics_Driver::clip_box(int x
, int y
, int w
, int h
, int &X
, int &Y
, int &W
, int &H
){
1380 if (x
> (X
=clip_
->x
)) {X
=x
; ret
=1;}
1381 if (y
> (Y
=clip_
->y
)) {Y
=y
; ret
=1;}
1382 if ((x
+w
) < (clip_
->x
+clip_
->w
)) {
1388 W
= clip_
->x
+ clip_
->w
- X
;
1393 if ((y
+h
) < (clip_
->y
+clip_
->h
)) {
1397 H
= clip_
->y
+ clip_
->h
- Y
;
1406 int Fl_PostScript_Graphics_Driver::not_clipped(int x
, int y
, int w
, int h
){
1407 if(!clip_
) return 1;
1408 if(clip_
->w
< 0) return 1;
1410 clip_box(x
, y
, w
, h
, X
, Y
, W
, H
);
1416 void Fl_PostScript_File_Device::margins(int *left
, int *top
, int *right
, int *bottom
) // to implement
1418 Fl_PostScript_Graphics_Driver
*ps
= driver();
1419 if(left
) *left
= (int)(ps
->left_margin
/ ps
->scale_x
+ .5);
1420 if(right
) *right
= (int)(ps
->left_margin
/ ps
->scale_x
+ .5);
1421 if(top
) *top
= (int)(ps
->top_margin
/ ps
->scale_y
+ .5);
1422 if(bottom
) *bottom
= (int)(ps
->top_margin
/ ps
->scale_y
+ .5);
1425 int Fl_PostScript_File_Device::printable_rect(int *w
, int *h
)
1428 Fl_PostScript_Graphics_Driver
*ps
= driver();
1429 if(w
) *w
= (int)((ps
->pw_
- 2 * ps
->left_margin
) / ps
->scale_x
+ .5);
1430 if(h
) *h
= (int)((ps
->ph_
- 2 * ps
->top_margin
) / ps
->scale_y
+ .5);
1434 void Fl_PostScript_File_Device::origin(int *x
, int *y
)
1436 Fl_Paged_Device::origin(x
, y
);
1439 void Fl_PostScript_File_Device::origin(int x
, int y
)
1443 Fl_PostScript_Graphics_Driver
*ps
= driver();
1444 fprintf(ps
->output
, "GR GR GS %d %d TR %f %f SC %d %d TR %f rotate GS\n",
1445 ps
->left_margin
, ps
->top_margin
, ps
->scale_x
, ps
->scale_y
, x
, y
, ps
->angle
);
1448 void Fl_PostScript_File_Device::scale (float s_x
, float s_y
)
1450 if (s_y
== 0.) s_y
= s_x
;
1451 Fl_PostScript_Graphics_Driver
*ps
= driver();
1454 fprintf(ps
->output
, "GR GR GS %d %d TR %f %f SC %f rotate GS\n",
1455 ps
->left_margin
, ps
->top_margin
, ps
->scale_x
, ps
->scale_y
, ps
->angle
);
1458 void Fl_PostScript_File_Device::rotate (float rot_angle
)
1460 Fl_PostScript_Graphics_Driver
*ps
= driver();
1461 ps
->angle
= - rot_angle
;
1462 fprintf(ps
->output
, "GR GR GS %d %d TR %f %f SC %d %d TR %f rotate GS\n",
1463 ps
->left_margin
, ps
->top_margin
, ps
->scale_x
, ps
->scale_y
, x_offset
, y_offset
, ps
->angle
);
1466 void Fl_PostScript_File_Device::translate(int x
, int y
)
1468 fprintf(driver()->output
, "GS %d %d translate GS\n", x
, y
);
1471 void Fl_PostScript_File_Device::untranslate(void)
1473 fprintf(driver()->output
, "GR GR\n");
1476 int Fl_PostScript_File_Device::start_page (void)
1478 Fl_PostScript_Graphics_Driver
*ps
= driver();
1479 ps
->page(ps
->page_format_
);
1482 ps
->scale_x
= ps
->scale_y
= 1.;
1484 fprintf(ps
->output
, "GR GR GS %d %d translate GS\n", ps
->left_margin
, ps
->top_margin
);
1488 int Fl_PostScript_File_Device::end_page (void)
1493 void Fl_PostScript_File_Device::end_job (void)
1494 // finishes PostScript & closes file
1496 Fl_PostScript_Graphics_Driver
*ps
= driver();
1497 if (ps
->nPages
) { // for eps nPages is 0 so it is fine ....
1498 fprintf(ps
->output
, "CR\nGR\nGR\nGR\nSP\n restore\n");
1500 fprintf(ps
->output
, "%%%%Trailer\n");
1501 fprintf(ps
->output
, "%%%%Pages: %i\n" , ps
->nPages
);
1504 fprintf(ps
->output
, "GR\n restore\n");
1505 fputs("%%EOF",ps
->output
);
1508 if(ferror(ps
->output
)) {
1509 fl_alert ("Error during PostScript data output.");
1511 if (ps
->close_cmd_
) {
1512 (*ps
->close_cmd_
)(ps
->output
);
1517 Fl_PostScript_Graphics_Driver::Clip
* c
= ps
->clip_
;
1518 ps
->clip_
= ps
->clip_
->prev
;
1521 Fl_Display_Device::display_device()->set_current();
1524 #if ! (defined(__APPLE__) || defined(WIN32) )
1525 int Fl_PostScript_Printer::start_job(int pages
, int *firstpage
, int *lastpage
) {
1526 enum Fl_Paged_Device::Page_Format format
;
1527 enum Fl_Paged_Device::Page_Layout layout
;
1529 // first test version for print dialog
1530 if (!print_panel
) make_print_panel();
1532 print_selection
->deactivate();
1533 print_all
->setonly();
1534 print_all
->do_callback();
1535 print_from
->value("1");
1536 { char tmp
[10]; snprintf(tmp
, sizeof(tmp
), "%d", pages
); print_to
->value(tmp
); }
1537 print_panel
->show(); // this is modal
1538 while (print_panel
->shown()) Fl::wait();
1540 if (!print_start
) // user clicked cancel
1545 format
= print_page_size
->value() ? Fl_Paged_Device::A4
: Fl_Paged_Device::LETTER
;
1546 { // page range choice
1547 int from
= 1, to
= pages
;
1548 if (print_pages
->value()) {
1549 sscanf(print_from
->value(), "%d", &from
);
1550 sscanf(print_to
->value(), "%d", &to
);
1552 if (from
< 1) from
= 1;
1553 if (to
> pages
) to
= pages
;
1554 if (to
< from
) to
= from
;
1555 if (firstpage
) *firstpage
= from
;
1556 if (lastpage
) *lastpage
= to
;
1557 pages
= to
- from
+ 1;
1560 if (print_output_mode
[0]->value()) layout
= Fl_Paged_Device::PORTRAIT
;
1561 else if (print_output_mode
[1]->value()) layout
= Fl_Paged_Device::LANDSCAPE
;
1562 else if (print_output_mode
[2]->value()) layout
= Fl_Paged_Device::PORTRAIT
;
1563 else layout
= Fl_Paged_Device::LANDSCAPE
;
1565 int print_pipe
= print_choice
->value(); // 0 = print to file, >0 = printer (pipe)
1567 const char *media
= print_page_size
->text(print_page_size
->value());
1568 const char *printer
= (const char *)print_choice
->menu()[print_choice
->value()].user_data();
1569 if (!print_pipe
) printer
= "<File>";
1571 if (!print_pipe
) // fall back to file printing
1572 return Fl_PostScript_File_Device::start_job (pages
, format
, layout
);
1574 // Print: pipe the output into the lp command...
1577 snprintf(command
, sizeof(command
), "lp -s -d %s -n %d -t '%s' -o media=%s",
1578 printer
, print_collate_button
->value() ? 1 : (int)(print_copies
->value() + 0.5),
1581 Fl_PostScript_Graphics_Driver
*ps
= driver();
1582 ps
->output
= popen(command
, "w");
1584 fl_alert("could not run command: %s\n",command
);
1587 ps
->close_command(pclose
);
1588 this->set_current();
1589 return ps
->start_postscript(pages
, format
, layout
); // start printing
1592 #endif // ! (defined(__APPLE__) || defined(WIN32) )
1594 #endif // FL_DOXYGEN
1597 // End of "$Id: Fl_PostScript.cxx 8623 2011-04-24 17:09:41Z AlbrechtS $".