fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

Fl_PostScript.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: Fl_PostScript.cxx 8190 2011-01-05 10:21:45Z manolo $"
00003 //
00004 // PostScript device support for the Fast Light Tool Kit (FLTK).
00005 //
00006 // Copyright 2010 by Bill Spitzak and others.
00007 //
00008 // This library is free software; you can redistribute it and/or
00009 // modify it under the terms of the GNU Library General Public
00010 // License as published by the Free Software Foundation; either
00011 // version 2 of the License, or (at your option) any later version.
00012 //
00013 // This library is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 // Library General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU Library General Public
00019 // License along with this library; if not, write to the Free Software
00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00021 // USA.
00022 //
00023 // Please report all bugs and problems to:
00024 //
00025 //     http://www.fltk.org/str.php
00026 //
00027 
00028 #include <FL/Fl.H>
00029 #include <FL/fl_ask.H>
00030 #include <FL/fl_draw.H>
00031 #include <stdio.h>
00032 #include <FL/Fl_PostScript.H>
00033 #include <FL/Fl_Native_File_Chooser.H>
00034 
00035 const char *Fl_PostScript_Graphics_Driver::class_id = "Fl_PostScript_Graphics_Driver";
00036 const char *Fl_PostScript_File_Device::class_id = "Fl_PostScript_File_Device";
00038 const char *Fl_PostScript_File_Device::file_chooser_title = "Select a .ps file";
00039 
00043 Fl_PostScript_Graphics_Driver::Fl_PostScript_Graphics_Driver(void)
00044 {
00045   close_cmd_ = 0;
00046   //lang_level_ = 3;
00047   lang_level_ = 2;
00048   mask = 0;
00049   ps_filename_ = NULL;
00050   class_name(class_id);
00051   scale_x = scale_y = 1.;
00052   bg_r = bg_g = bg_b = 255;
00053 }
00054 
00056 Fl_PostScript_Graphics_Driver::~Fl_PostScript_Graphics_Driver() {
00057   if(ps_filename_) free(ps_filename_);
00058 }
00059 
00063 Fl_PostScript_File_Device::Fl_PostScript_File_Device(void)
00064 {
00065   class_name(class_id);
00066 #ifdef __APPLE__
00067   gc = fl_gc; // the display context is used by fl_text_extents()
00068 #endif
00069   Fl_Surface_Device::driver( new Fl_PostScript_Graphics_Driver() );
00070 }
00071 
00075 Fl_PostScript_Graphics_Driver *Fl_PostScript_File_Device::driver()
00076 {
00077   return (Fl_PostScript_Graphics_Driver*)Fl_Surface_Device::driver();
00078 }
00079 
00080 
00090 int Fl_PostScript_File_Device::start_job (int pagecount, enum Fl_Paged_Device::Page_Format format, 
00091                                           enum Fl_Paged_Device::Page_Layout layout)
00092 {
00093   Fl_Native_File_Chooser fnfc;
00094   fnfc.title(Fl_PostScript_File_Device::file_chooser_title);
00095   fnfc.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
00096   fnfc.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM);
00097   fnfc.filter("PostScript\t*.ps\n");
00098   // Show native chooser
00099   if ( fnfc.show() ) return 1;
00100   Fl_PostScript_Graphics_Driver *ps = driver();
00101   ps->output = fopen(fnfc.filename(), "w");
00102   if(ps->output == NULL) return 2;
00103   ps->ps_filename_ = strdup(fnfc.filename());
00104   ps->start_postscript(pagecount, format, layout);
00105   this->set_current();
00106   return 0;
00107 }
00108 
00109 static int dont_close(FILE *f) 
00110 {
00111   return 0;
00112 }
00113 
00124 int Fl_PostScript_File_Device::start_job (FILE *ps_output, int pagecount, 
00125     enum Fl_Paged_Device::Page_Format format, enum Fl_Paged_Device::Page_Layout layout)
00126 {
00127   Fl_PostScript_Graphics_Driver *ps = driver();
00128   ps->output = ps_output;
00129   ps->ps_filename_ = NULL;
00130   ps->start_postscript(pagecount, format, layout);
00131   ps->close_command(dont_close); // so that end_job() doesn't close the file
00132   this->set_current();
00133   return 0;
00134 }
00135 
00139 Fl_PostScript_File_Device::~Fl_PostScript_File_Device() {
00140   Fl_PostScript_Graphics_Driver *ps = driver();
00141   if (ps) delete ps;
00142 }
00143 
00144 #ifndef FL_DOXYGEN
00145 
00146 #if ! (defined(__APPLE__) || defined(WIN32) )
00147   #include "print_panel.cxx"
00148 #endif
00149 
00150 //  Prolog string 
00151 
00152 static const char * prolog =
00153 "%%BeginProlog\n"
00154 "/L { /y2 exch def\n"
00155 "/x2 exch def\n"
00156 "/y1 exch def\n"
00157 "/x1 exch def\n"
00158 "newpath   x1 y1 moveto x2 y2 lineto\n"
00159 "stroke}\n"
00160 "bind def\n"
00161 
00162 
00163 "/R { /dy exch def\n"
00164 "/dx exch def\n"
00165 "/y exch def\n"
00166 "/x exch def\n"
00167 "newpath\n"
00168 "x y moveto\n"
00169 "dx 0 rlineto\n"
00170 "0 dy rlineto\n"
00171 "dx neg 0 rlineto\n"
00172 "closepath stroke\n"
00173 "} bind def\n"
00174 
00175 "/CL {\n"
00176 "/dy exch def\n"
00177 "/dx exch def\n"
00178 "/y exch def\n"
00179 "/x exch def\n"
00180 "newpath\n"
00181 "x y moveto\n"
00182 "dx 0 rlineto\n"
00183 "0 dy rlineto\n"
00184 "dx neg 0 rlineto\n"
00185 "closepath\n"
00186 "clip\n"
00187 "} bind def\n"
00188 
00189 "/FR { /dy exch def\n"
00190 "/dx exch def\n"
00191 "/y exch def\n"
00192 "/x exch def\n"
00193 "currentlinewidth 0 setlinewidth newpath\n"
00194 "x y moveto\n"
00195 "dx 0 rlineto\n"
00196 "0 dy rlineto\n"
00197 "dx neg 0 rlineto\n"
00198 "closepath fill setlinewidth\n"
00199 "} bind def\n"
00200 
00201 "/GS { gsave } bind  def\n"
00202 "/GR { grestore } bind def\n"
00203 
00204 "/SP { showpage } bind def\n"
00205 "/LW { setlinewidth } bind def\n"
00206 "/CF /Courier def\n"
00207 "/SF { /CF exch def } bind def\n"
00208 "/fsize 12 def\n"
00209 "/FS { /fsize exch def fsize CF findfont exch scalefont setfont }def \n"
00210 
00211 
00212 "/GL { setgray } bind def\n"
00213 "/SRGB { setrgbcolor } bind def\n"
00214 
00215 //  color images 
00216 
00217 "/CI { GS /py exch def /px exch def /sy exch def /sx exch def\n"
00218 "translate \n"
00219 "sx sy scale px py 8 \n"
00220 "[ px 0 0 py neg 0 py ]\n"
00221 "currentfile /ASCIIHexDecode filter\n false 3"
00222 " colorimage GR\n"
00223 "} bind def\n"
00224 
00225 //  gray images 
00226 
00227 "/GI { GS /py exch def /px exch def /sy exch def /sx exch def \n"
00228 "translate \n"
00229 "sx sy scale px py 8 \n"
00230 
00231 
00232 "[ px 0 0 py neg 0 py ]\n"
00233 "currentfile /ASCIIHexDecode filter\n"
00234 "image GR\n"
00235 "} bind def\n"
00236 
00237 // single-color bitmask 
00238 
00239 "/MI { GS /py exch def /px exch def /sy exch def /sx exch def \n"
00240 "translate \n"
00241 "sx sy scale px py true \n"
00242 "[ px 0 0 py neg 0 py ]\n"
00243 "currentfile /ASCIIHexDecode filter\n"
00244 "imagemask GR\n"
00245 "} bind def\n"
00246 
00247 
00248 //  path 
00249 
00250 "/BFP { newpath moveto }  def\n"
00251 "/BP { newpath } bind def \n"
00252 "/PL { lineto } bind def \n"
00253 "/PM { moveto } bind def \n"
00254 "/MT { moveto } bind def \n"
00255 "/LT { lineto } bind def \n"
00256 "/EFP { closepath fill } bind def\n"  //was:stroke
00257 "/ELP { stroke } bind def\n"  
00258 "/ECP { closepath stroke } bind def\n"  // Closed (loop)
00259 "/LW { setlinewidth } bind def\n"
00260 
00261 // ////////////////////////// misc ////////////////
00262 "/TR { translate } bind def\n"
00263 "/CT { concat } bind def\n"
00264 "/RCT { matrix invertmatrix concat} bind def\n"
00265 "/SC { scale } bind def\n"
00266 //"/GPD { currentpagedevice /PageSize get} def\n"
00267 
00268 // show at position with desired width
00269 // usage:
00270 // width (string) x y show_pos_width
00271 "/show_pos_width {GS moveto dup dup stringwidth pop exch length exch 3 index exch sub exch "
00272 "div 0 2 index 1 -1 scale ashow pop pop GR} bind def\n" // spacing altered to match desired width
00273 //"/show_pos_width {GS moveto dup stringwidth pop 3 2 roll exch div -1 matrix scale concat "
00274 //"show GR } bind def\n" // horizontally scaled text to match desired width
00275 
00276 ;
00277 
00278 
00279 static const char * prolog_2 =  // prolog relevant only if lang_level >1
00280 
00281 // color image dictionaries
00282 "/CII {GS /inter exch def /py exch def /px exch def /sy exch def /sx exch def \n"
00283 "translate \n"
00284 "sx sy scale\n"
00285 "/DeviceRGB setcolorspace\n"
00286 "/IDD 8 dict def\n"
00287 "IDD begin\n"
00288 "/ImageType 1 def\n"
00289 "/Width px def\n"
00290 "/Height py def\n"
00291 "/BitsPerComponent 8 def\n"
00292 "/Interpolate inter def\n"
00293 "/DataSource currentfile /ASCIIHexDecode filter def\n"
00294 "/MultipleDataSources false def\n"
00295 "/ImageMatrix [ px 0 0 py neg 0 py ] def\n"
00296 "/Decode [ 0 1 0 1 0 1 ] def\n"
00297 "end\n"
00298 "IDD image GR} bind def\n"
00299 
00300 // gray image dict 
00301 "/GII {GS /inter exch def /py exch def /px exch def /sy exch def /sx exch def \n"
00302 "translate \n"
00303 "sx sy scale\n"
00304 "/DeviceGray setcolorspace\n"
00305 "/IDD 8 dict def\n"
00306 "IDD begin\n"
00307 "/ImageType 1 def\n"
00308 "/Width px def\n"
00309 "/Height py def\n"
00310 "/BitsPerComponent 8 def\n"
00311 
00312 "/Interpolate inter def\n"
00313 "/DataSource currentfile /ASCIIHexDecode filter def\n"
00314 "/MultipleDataSources false def\n"
00315 "/ImageMatrix [ px 0 0 py neg 0 py ] def\n"
00316 "/Decode [ 0 1 ] def\n"
00317 "end\n"
00318 "IDD image GR} bind def\n"
00319 
00320 // Create a custom PostScript font derived from PostScript standard text fonts
00321 // The encoding of this custom font is as follows:
00322 // 0000-00FF  coincides with Unicode, that is to ASCII + Latin-1
00323 // 0100-017F  coincides with Unicode, that is to Latin Extended-A
00324 // 0180-01A6  encodes miscellaneous characters present in PostScript standard text fonts
00325 
00326 // use ISOLatin1Encoding for all text fonts
00327 "/ToISO { dup findfont dup length dict copy begin /Encoding ISOLatin1Encoding def currentdict end definefont pop } def\n"
00328 "/Helvetica ToISO /Helvetica-Bold ToISO /Helvetica-Oblique ToISO /Helvetica-BoldOblique ToISO \n"
00329 "/Courier ToISO /Courier-Bold ToISO /Courier-Oblique ToISO /Courier-BoldOblique ToISO \n"
00330 "/Times-Roman ToISO /Times-Bold ToISO /Times-Italic ToISO /Times-BoldItalic ToISO \n"
00331 
00332 // define LatinExtA, the encoding of Latin-extended-A + some additional characters
00333 // see http://www.adobe.com/devnet/opentype/archives/glyphlist.txt for their names
00334 "/LatinExtA \n"
00335 "[ "
00336 " /Amacron /amacron /Abreve /abreve /Aogonek /aogonek\n" // begin of Latin Extended-A code page
00337 " /Cacute  /cacute  /Ccircumflex  /ccircumflex  /Cdotaccent  /cdotaccent  /Ccaron  /ccaron \n"
00338 " /Dcaron  /dcaron   /Dcroat  /dcroat\n"
00339 " /Emacron  /emacron  /Ebreve  /ebreve  /Edotaccent  /edotaccent  /Eogonek  /eogonek  /Ecaron  /ecaron\n"
00340 " /Gcircumflex  /gcircumflex  /Gbreve  /gbreve  /Gdotaccent  /gdotaccent  /Gcommaaccent  /gcommaaccent \n"
00341 " /Hcircumflex /hcircumflex  /Hbar  /hbar  \n"
00342 " /Itilde  /itilde  /Imacron  /imacron  /Ibreve  /ibreve  /Iogonek  /iogonek /Idotaccent  /dotlessi  \n"
00343 " /IJ  /ij  /Jcircumflex  /jcircumflex\n"
00344 " /Kcommaaccent  /kcommaaccent  /kgreenlandic  \n"
00345 " /Lacute  /lacute  /Lcommaaccent  /lcommaaccent   /Lcaron  /lcaron  /Ldotaccent /ldotaccent   /Lslash  /lslash \n"
00346 " /Nacute  /nacute  /Ncommaaccent  /ncommaaccent  /Ncaron  /ncaron  /napostrophe  /Eng  /eng  \n"
00347 " /Omacron  /omacron /Obreve  /obreve  /Ohungarumlaut  /ohungarumlaut  /OE  /oe \n"
00348 " /Racute  /racute  /Rcommaaccent  /rcommaaccent  /Rcaron  /rcaron \n"
00349 " /Sacute /sacute  /Scircumflex  /scircumflex  /Scedilla /scedilla /Scaron  /scaron \n"
00350 " /Tcommaaccent  /tcommaaccent  /Tcaron  /tcaron  /Tbar  /tbar \n"
00351 " /Utilde  /utilde /Umacron /umacron  /Ubreve  /ubreve  /Uring  /uring  /Uhungarumlaut  /uhungarumlaut  /Uogonek /uogonek \n"
00352 " /Wcircumflex  /wcircumflex  /Ycircumflex  /ycircumflex  /Ydieresis \n"
00353 " /Zacute /zacute /Zdotaccent /zdotaccent /Zcaron /zcaron \n"
00354 " /longs \n" // end of Latin Extended-A code page
00355 " /florin  /circumflex  /caron  /breve  /dotaccent  /ring \n" // remaining characters from PostScript standard text fonts
00356 " /ogonek  /tilde  /hungarumlaut  /endash /emdash \n"
00357 " /quoteleft  /quoteright  /quotesinglbase  /quotedblleft  /quotedblright \n"
00358 " /quotedblbase  /dagger  /daggerdbl  /bullet  /ellipsis \n"
00359 " /perthousand  /guilsinglleft  /guilsinglright  /fraction  /Euro \n"
00360 " /trademark /partialdiff  /Delta /summation  /radical \n"
00361 " /infinity /notequal /lessequal /greaterequal /lozenge \n"
00362 " /fi /fl /apple \n"
00363 " ] def \n"
00364 // deal with alternative PostScript names of some characters
00365 " /mycharstrings /Helvetica findfont /CharStrings get def\n"
00366 " /PSname2 { dup mycharstrings exch known {LatinExtA 3 -1 roll 3 -1 roll put}{pop pop} ifelse } def \n"
00367 " 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"
00368 
00369 // proc that gives LatinExtA encoding to a font
00370 "/ToLatinExtA { findfont dup length dict copy begin /Encoding LatinExtA def currentdict end definefont pop } def\n"
00371 // create Ext-versions of standard fonts that use LatinExtA encoding \n"
00372 "/HelveticaExt /Helvetica ToLatinExtA \n"
00373 "/Helvetica-BoldExt /Helvetica-Bold ToLatinExtA /Helvetica-ObliqueExt /Helvetica-Oblique ToLatinExtA  \n"
00374 "/Helvetica-BoldObliqueExt /Helvetica-BoldOblique ToLatinExtA  \n"
00375 "/CourierExt /Courier ToLatinExtA /Courier-BoldExt /Courier-Bold ToLatinExtA  \n"
00376 "/Courier-ObliqueExt /Courier-Oblique ToLatinExtA /Courier-BoldObliqueExt /Courier-BoldOblique ToLatinExtA \n"
00377 "/Times-RomanExt /Times-Roman ToLatinExtA /Times-BoldExt /Times-Bold ToLatinExtA  \n"
00378 "/Times-ItalicExt /Times-Italic ToLatinExtA /Times-BoldItalicExt /Times-BoldItalic ToLatinExtA \n"
00379 
00380 // proc to create a Type 0 font with 2-byte encoding 
00381 // that merges a text font with ISO encoding + same font with LatinExtA encoding
00382 "/To2byte { 6 dict begin /FontType 0 def \n"
00383 "/FDepVector 3 1 roll findfont exch findfont 2 array astore def \n"
00384 "/FontMatrix [1  0  0  1  0  0] def /FMapType 6 def /Encoding [ 0 1 0 ] def\n"
00385 // 100: Hexa count of ISO array; A7: hexa count of LatinExtA array
00386 "/SubsVector < 01 0100 00A7 > def\n" 
00387 "currentdict end definefont pop } def\n"
00388 // create Type 0 versions of standard fonts
00389 "/Helvetica2B /HelveticaExt /Helvetica To2byte \n"
00390 "/Helvetica-Bold2B /Helvetica-BoldExt /Helvetica-Bold To2byte \n"
00391 "/Helvetica-Oblique2B /Helvetica-ObliqueExt /Helvetica-Oblique To2byte \n"
00392 "/Helvetica-BoldOblique2B /Helvetica-BoldObliqueExt /Helvetica-BoldOblique To2byte \n"
00393 "/Courier2B /CourierExt /Courier To2byte \n"
00394 "/Courier-Bold2B /Courier-BoldExt /Courier-Bold To2byte \n"
00395 "/Courier-Oblique2B /Courier-ObliqueExt /Courier-Oblique To2byte \n"
00396 "/Courier-BoldOblique2B /Courier-BoldObliqueExt /Courier-BoldOblique To2byte \n"
00397 "/Times-Roman2B /Times-RomanExt /Times-Roman To2byte \n"
00398 "/Times-Bold2B /Times-BoldExt /Times-Bold To2byte \n"
00399 "/Times-Italic2B /Times-ItalicExt /Times-Italic To2byte \n"
00400 "/Times-BoldItalic2B /Times-BoldItalicExt /Times-BoldItalic To2byte \n"
00401 ;
00402 
00403 static const char * prolog_2_pixmap =  // prolog relevant only if lang_level == 2 for pixmaps/masked color images
00404 "/pixmap_mat {[ pixmap_sx 0 0 pixmap_sy neg 0 pixmap_sy ]}  bind def\n"
00405 
00406 "/pixmap_dict {"
00407 "<< /PatternType 1 "
00408 "/PaintType 1 "
00409 "/TilingType 2 "
00410 "/BBox [0  0  pixmap_sx  pixmap_sy] "
00411 "/XStep pixmap_sx "
00412 "/YStep pixmap_sy\n"
00413 "/PaintProc "
00414 "{ begin "
00415 "pixmap_w pixmap_h scale "
00416 "pixmap_sx pixmap_sy 8 "
00417 "pixmap_mat "
00418 "currentfile /ASCIIHexDecode filter "
00419 "false 3 "
00420 "colorimage "
00421 "end "
00422 "} bind "
00423 ">>\n"
00424 "} bind def\n"
00425 
00426 "/pixmap_plot {"
00427 "GS "
00428 "/pixmap_sy exch def /pixmap_sx exch def\n"
00429 "/pixmap_h exch def /pixmap_w exch def\n"
00430 "translate\n"
00431 "pixmap_dict matrix makepattern setpattern\n"
00432 "pixmap_w pixmap_h scale\n"
00433 "pixmap_sx pixmap_sy\n"
00434 "true\n"
00435 "pixmap_mat\n"
00436 "currentfile /ASCIIHexDecode filter\n"
00437 "imagemask\n"
00438 "GR\n"
00439 "} bind def\n"
00440 ;
00441 
00442 static const char * prolog_3 = // prolog relevant only if lang_level >2
00443 
00444 // masked color images 
00445 "/CIM {GS /inter exch def /my exch def /mx exch def /py exch def /px exch def /sy exch def /sx exch def \n"
00446 "translate \n"
00447 "sx sy scale\n"
00448 "/DeviceRGB setcolorspace\n"
00449 
00450 "/IDD 8 dict def\n"
00451 
00452 "IDD begin\n"
00453 "/ImageType 1 def\n"
00454 "/Width px def\n"
00455 "/Height py def\n"
00456 "/BitsPerComponent 8 def\n"
00457 "/Interpolate inter def\n"
00458 "/DataSource currentfile /ASCIIHexDecode filter def\n"
00459 "/MultipleDataSources false def\n"
00460 "/ImageMatrix [ px 0 0 py neg 0 py ] def\n"
00461 
00462 "/Decode [ 0 1 0 1 0 1 ] def\n"
00463 "end\n"
00464 
00465 "/IMD 8 dict def\n"
00466 "IMD begin\n"
00467 "/ImageType 1 def\n"
00468 "/Width mx def\n"           
00469 "/Height my def\n"
00470 "/BitsPerComponent 1 def\n"
00471 //  "/Interpolate inter def\n"
00472 "/ImageMatrix [ mx 0 0 my neg 0 my ] def\n"
00473 "/Decode [ 1 0 ] def\n"
00474 "end\n"
00475 
00476 "<<\n"
00477 "/ImageType 3\n"
00478 "/InterleaveType 2\n"
00479 "/MaskDict IMD\n"
00480 "/DataDict IDD\n"
00481 ">> image GR\n"
00482 "} bind def\n"
00483 
00484 
00485 //  masked gray images 
00486 "/GIM {GS /inter exch def /my exch def /mx exch def /py exch def /px exch def /sy exch def /sx exch def \n"
00487 "translate \n"
00488 "sx sy scale\n"
00489 "/DeviceGray setcolorspace\n"
00490 
00491 "/IDD 8 dict def\n"
00492 
00493 "IDD begin\n"
00494 "/ImageType 1 def\n"
00495 "/Width px def\n"
00496 "/Height py def\n"
00497 "/BitsPerComponent 8 def\n"
00498 "/Interpolate inter def\n"
00499 "/DataSource currentfile /ASCIIHexDecode filter def\n"
00500 "/MultipleDataSources false def\n"
00501 "/ImageMatrix [ px 0 0 py neg 0 py ] def\n"
00502 
00503 "/Decode [ 0 1 ] def\n"
00504 "end\n"
00505 
00506 "/IMD 8 dict def\n"
00507 
00508 "IMD begin\n"
00509 "/ImageType 1 def\n"
00510 "/Width mx def\n"           
00511 "/Height my def\n"
00512 "/BitsPerComponent 1 def\n"
00513 "/ImageMatrix [ mx 0 0 my neg 0 my ] def\n"
00514 "/Decode [ 1 0 ] def\n"
00515 "end\n"
00516 
00517 "<<\n"
00518 "/ImageType 3\n"
00519 "/InterleaveType 2\n"
00520 "/MaskDict IMD\n"
00521 "/DataDict IDD\n"
00522 ">> image GR\n"
00523 "} bind def\n"
00524 
00525 
00526 "\n"
00527 ;
00528 
00529 // end prolog 
00530 
00531 int Fl_PostScript_Graphics_Driver::start_postscript (int pagecount, 
00532     enum Fl_Paged_Device::Page_Format format, enum Fl_Paged_Device::Page_Layout layout)
00533 //returns 0 iff OK
00534 {
00535   int w, h, x;
00536   if (format == Fl_Paged_Device::A4) {
00537     left_margin = 18;
00538     top_margin = 18;
00539   }
00540   else {
00541     left_margin = 12;
00542     top_margin = 12;
00543   }
00544   page_format_ = (enum Fl_Paged_Device::Page_Format)(format | layout);
00545   
00546   fputs("%!PS-Adobe-3.0\n", output);
00547   fputs("%%Creator: FLTK\n", output);
00548   if (lang_level_>1)
00549     fprintf(output, "%%%%LanguageLevel: %i\n" , lang_level_);
00550   if ((pages_ = pagecount))
00551     fprintf(output, "%%%%Pages: %i\n", pagecount);
00552   else
00553     fputs("%%Pages: (atend)\n", output);
00554   fprintf(output, "%%%%BeginFeature: *PageSize %s\n", Fl_Paged_Device::page_formats[format].name );
00555   w = Fl_Paged_Device::page_formats[format].width;
00556   h = Fl_Paged_Device::page_formats[format].height;
00557   if (lang_level_ == 3 && (layout & Fl_Paged_Device::LANDSCAPE) ) { x = w; w = h; h = x; }
00558   fprintf(output, "<</PageSize[%d %d]>>setpagedevice\n", w, h );
00559   fputs("%%EndFeature\n", output);
00560   fputs("%%EndComments\n", output);
00561   fputs(prolog, output);
00562   if (lang_level_ > 1) {
00563     fputs(prolog_2, output);
00564     }
00565   if (lang_level_ == 2) {
00566     fputs(prolog_2_pixmap, output);
00567     }
00568   if (lang_level_ > 2)
00569     fputs(prolog_3, output);
00570   if (lang_level_ >= 3) {
00571     fputs("/CS { clipsave } bind def\n", output);
00572     fputs("/CR { cliprestore } bind def\n", output);
00573   } else {
00574     fputs("/CS { GS } bind def\n", output);
00575     fputs("/CR { GR } bind def\n", output);
00576   }
00577   page_policy_ = 1;
00578   
00579   
00580   fputs("%%EndProlog\n",output);
00581   if (lang_level_ >= 2)
00582     fprintf(output,"<< /Policies << /Pagesize 1 >> >> setpagedevice\n");
00583   
00584   reset();
00585   nPages=0;
00586   return 0;
00587 }
00588 
00589 void Fl_PostScript_Graphics_Driver::recover(){
00590   color(cr_,cg_,cb_);
00591   line_style(linestyle_,linewidth_,linedash_);
00592   font(font_,size_);
00593 }
00594 
00595 void Fl_PostScript_Graphics_Driver::reset(){
00596   gap_=1;
00597   clip_=0;
00598   cr_=cg_=cb_=0;
00599   font_=FL_HELVETICA;
00600   size_=12;
00601   linewidth_=0;
00602   linestyle_=FL_SOLID;
00603   strcpy(linedash_,"");
00604   Clip *c=clip_;   
00605   
00606   while(c){
00607     clip_=clip_->prev;
00608     delete c;
00609     c=clip_;
00610   }
00611   
00612 }
00613 
00614 void Fl_PostScript_Graphics_Driver::page_policy(int p){
00615   page_policy_ = p;
00616   if(lang_level_>=2)
00617     fprintf(output,"<< /Policies << /Pagesize %i >> >> setpagedevice\n", p);
00618 }
00619 
00620 // //////////////////// paging //////////////////////////////////////////
00621 
00622 
00623 
00624 void Fl_PostScript_Graphics_Driver::page(double pw, double ph, int media) {
00625   
00626   if (nPages){
00627     fprintf(output, "CR\nGR\nGR\nGR\nSP\nrestore\n");
00628   }
00629   ++nPages;
00630   fprintf(output, "%%%%Page: %i %i\n" , nPages , nPages);
00631   if (pw>ph){
00632     fprintf(output, "%%%%PageOrientation: Landscape\n");
00633   }else{
00634     fprintf(output, "%%%%PageOrientation: Portrait\n");
00635   }
00636   
00637   fprintf(output, "%%%%BeginPageSetup\n");
00638   if((media & Fl_Paged_Device::MEDIA) &&(lang_level_>1)){
00639     int r = media & Fl_Paged_Device::REVERSED;
00640     if(r) r = 2;
00641     fprintf(output, "<< /PageSize [%i %i] /Orientation %i>> setpagedevice\n", (int)(pw+.5), (int)(ph+.5), r);
00642   }
00643   fprintf(output, "%%%%EndPageSetup\n");
00644   
00645   pw_ = pw;
00646   ph_ = ph;
00647   reset();
00648   
00649   fprintf(output, "save\n");
00650   fprintf(output, "GS\n");
00651   fprintf(output, "%g %g TR\n", (double)0 /*lm_*/ , ph_ /* - tm_*/);
00652   fprintf(output, "1 -1 SC\n");
00653   line_style(0);
00654   fprintf(output, "GS\n");
00655   
00656   if (!((media & Fl_Paged_Device::MEDIA) &&(lang_level_>1))){
00657     if (pw > ph) {
00658       if(media & Fl_Paged_Device::REVERSED) {
00659         fprintf(output, "-90 rotate %i 0 translate\n", int(-pw));
00660         }
00661       else {
00662         fprintf(output, "90 rotate -%i -%i translate\n", (lang_level_ == 2 ? int(pw - ph) : 0), int(ph));
00663         }
00664       }
00665       else {
00666         if(media & Fl_Paged_Device::REVERSED)
00667           fprintf(output, "180 rotate %i %i translate\n", int(-pw), int(-ph));
00668         }
00669   }
00670   fprintf(output, "GS\nCS\n");
00671 }
00672 
00673 void Fl_PostScript_Graphics_Driver::page(int format){
00674   
00675   
00676   if(format &  Fl_Paged_Device::LANDSCAPE){
00677     ph_=Fl_Paged_Device::page_formats[format & 0xFF].width;
00678     pw_=Fl_Paged_Device::page_formats[format & 0xFF].height;
00679   }else{
00680     pw_=Fl_Paged_Device::page_formats[format & 0xFF].width;
00681     ph_=Fl_Paged_Device::page_formats[format & 0xFF].height;
00682   }
00683   page(pw_,ph_,format & 0xFF00);//,orientation only;
00684 }
00685 
00686 void Fl_PostScript_Graphics_Driver::rect(int x, int y, int w, int h) {
00687   // Commented code does not work, i can't find the bug ;-(
00688   // fprintf(output, "GS\n");
00689   //  fprintf(output, "%i, %i, %i, %i R\n", x , y , w, h);
00690   //  fprintf(output, "GR\n");
00691   fprintf(output, "GS\n");
00692   fprintf(output,"BP\n");
00693   fprintf(output, "%i %i MT\n", x , y);
00694   fprintf(output, "%i %i LT\n", x+w-1 , y);
00695   fprintf(output, "%i %i LT\n", x+w-1 , y+h-1);
00696   fprintf(output, "%i %i LT\n", x , y+h-1);
00697   fprintf(output, "ECP\n");
00698   fprintf(output, "GR\n");
00699 }
00700 
00701 void Fl_PostScript_Graphics_Driver::rectf(int x, int y, int w, int h) {
00702   fprintf(output, "%g %g %i %i FR\n", x-0.5, y-0.5, w, h);
00703 }
00704 
00705 void Fl_PostScript_Graphics_Driver::line(int x1, int y1, int x2, int y2) {
00706   fprintf(output, "GS\n");
00707   fprintf(output, "%i %i %i %i L\n", x1 , y1, x2 ,y2);
00708   fprintf(output, "GR\n");
00709 }
00710 
00711 void Fl_PostScript_Graphics_Driver::line(int x0, int y0, int x1, int y1, int x2, int y2) {
00712   fprintf(output, "GS\n");
00713   fprintf(output,"BP\n");
00714   fprintf(output, "%i %i MT\n", x0 , y0);
00715   fprintf(output, "%i %i LT\n", x1 , y1);
00716   fprintf(output, "%i %i LT\n", x2 , y2);
00717   fprintf(output, "ELP\n");
00718   fprintf(output, "GR\n");
00719 }
00720 
00721 void Fl_PostScript_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3){
00722   fprintf(output, "GS\n");
00723   fprintf(output,"BP\n");
00724   fprintf(output, "%i %i MT\n", x , y );
00725   fprintf(output, "%i %i LT\n", x1 , y );
00726   fprintf(output, "%i %i LT\n", x1 , y2);
00727   fprintf(output,"%i %i LT\n", x3 , y2);
00728   fprintf(output, "ELP\n");
00729   fprintf(output, "GR\n");
00730 }
00731 
00732 
00733 void Fl_PostScript_Graphics_Driver::xyline(int x, int y, int x1, int y2){
00734   
00735   fprintf(output, "GS\n");
00736   fprintf(output,"BP\n");
00737   fprintf(output, "%i %i MT\n", x , y);
00738   fprintf(output,"%i %i LT\n", x1 , y);
00739   fprintf(output, "%i %i LT\n", x1 , y2 );
00740   fprintf(output, "ELP\n");
00741   fprintf(output, "GR\n");
00742 }
00743 
00744 void Fl_PostScript_Graphics_Driver::xyline(int x, int y, int x1){
00745   fprintf(output, "GS\n");
00746   fprintf(output,"BP\n");
00747   fprintf(output, "%i %i MT\n", x , y);
00748   fprintf(output, "%i %i LT\n", x1 , y );
00749   fprintf(output, "ELP\n");
00750   
00751   fprintf(output, "GR\n");
00752 }
00753 
00754 void Fl_PostScript_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3){
00755   fprintf(output, "GS\n");
00756   
00757   fprintf(output,"BP\n");
00758   fprintf(output,"%i %i MT\n", x , y);
00759   fprintf(output, "%i %i LT\n", x , y1 );
00760   fprintf(output, "%i %i LT\n", x2 , y1 );
00761   fprintf(output , "%i %i LT\n", x2 , y3);
00762   fprintf(output, "ELP\n");
00763   fprintf(output, "GR\n");
00764 }
00765 
00766 void Fl_PostScript_Graphics_Driver::yxline(int x, int y, int y1, int x2){
00767   fprintf(output, "GS\n");
00768   fprintf(output,"BP\n");
00769   fprintf(output, "%i %i MT\n", x , y);
00770   fprintf(output, "%i %i LT\n", x , y1);
00771   fprintf(output, "%i %i LT\n", x2 , y1);
00772   fprintf(output, "ELP\n");
00773   fprintf(output, "GR\n");
00774 }
00775 
00776 void Fl_PostScript_Graphics_Driver::yxline(int x, int y, int y1){
00777   fprintf(output, "GS\n");
00778   fprintf(output,"BP\n");
00779   fprintf(output, "%i %i MT\n", x , y);
00780   fprintf(output, "%i %i LT\n", x , y1);
00781   fprintf(output, "ELP\n");
00782   fprintf(output, "GR\n");
00783 }
00784 
00785 void Fl_PostScript_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2) {
00786   fprintf(output, "GS\n");
00787   fprintf(output,"BP\n");
00788   fprintf(output, "%i %i MT\n", x0 , y0);
00789   fprintf(output, "%i %i LT\n", x1 , y1);
00790   fprintf(output, "%i %i LT\n", x2 , y2);
00791   fprintf(output, "ECP\n");
00792   fprintf(output, "GR\n");
00793 }
00794 
00795 void Fl_PostScript_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) {
00796   fprintf(output, "GS\n");
00797   fprintf(output,"BP\n");
00798   fprintf(output, "%i %i MT\n", x0 , y0);
00799   fprintf(output, "%i %i LT\n", x1 , y1);
00800   fprintf(output, "%i %i LT\n", x2 , y2);
00801   fprintf(output, "%i %i LT\n", x3 , y3);
00802   fprintf(output, "ECP\n");
00803   fprintf(output, "GR\n");
00804 }
00805 
00806 void Fl_PostScript_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, int y2) {
00807   fprintf(output, "GS\n");
00808   fprintf(output,"BP\n");
00809   fprintf(output, "%i %i MT\n", x0 , y0);
00810   fprintf(output,"%i %i LT\n", x1 , y1);
00811   fprintf(output, "%i %i LT\n", x2 , y2);
00812   fprintf(output, "EFP\n");
00813   fprintf(output, "GR\n");
00814 }
00815 
00816 void Fl_PostScript_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) {
00817   fprintf(output, "GS\n");
00818   fprintf(output,"BP\n");
00819   fprintf(output, "%i %i MT\n", x0 , y0 );
00820   fprintf(output, "%i %i LT\n", x1 , y1 );
00821   fprintf(output, "%i %i LT\n", x2 , y2 );
00822   fprintf(output, "%i %i LT\n", x3 , y3 );
00823   
00824   fprintf(output, "EFP\n");
00825   fprintf(output, "GR\n");
00826 }
00827 
00828 void Fl_PostScript_Graphics_Driver::point(int x, int y){
00829   rectf(x,y,1,1);
00830 }
00831 
00832 static int dashes_flat[5][7]={
00833 {-1,0,0,0,0,0,0},
00834 {3,1,-1,0,0,0,0},
00835 {1,1,-1,0,0,0,0},
00836 {3,1,1,1,-1,0,0},
00837 {3,1,1,1,1,1,-1}
00838 };
00839 
00840 
00841 //yeah, hack...
00842 static double dashes_cap[5][7]={
00843 {-1,0,0,0,0,0,0},
00844 {2,2,-1,0,0,0,0},
00845 {0.01,1.99,-1,0,0,0,0},
00846 {2,2,0.01,1.99,-1,0,0},
00847 {2,2,0.01,1.99,0.01,1.99,-1}
00848 };
00849 
00850 
00851 void Fl_PostScript_Graphics_Driver::line_style(int style, int width, char* dashes){
00852   //line_styled_=1;
00853   
00854   linewidth_=width;
00855   linestyle_=style;
00856   //dashes_= dashes;
00857   if(dashes){
00858     if(dashes != linedash_)
00859       strcpy(linedash_,dashes);
00860     
00861   }else
00862     linedash_[0]=0;
00863   char width0 = 0;
00864   if(!width){
00865     width=1; //for screen drawing compatability
00866     width0=1;
00867   }
00868   
00869   fprintf(output, "%i setlinewidth\n", width);
00870   
00871   if(!style && (!dashes || !(*dashes)) && width0) //system lines
00872     style = FL_CAP_SQUARE;
00873   
00874   int cap = (style &0xf00) >> 8;
00875   if(cap) cap--;
00876   fprintf(output,"%i setlinecap\n", cap);
00877   
00878   int join = (style & 0xf000) >> 12;
00879   
00880   if(join) join--;
00881   fprintf(output,"%i setlinejoin\n", join);
00882   
00883   
00884   fprintf(output, "[");
00885   if(dashes && *dashes){
00886     while(*dashes){
00887       fprintf(output, "%i ", *dashes);
00888       dashes++;
00889     }
00890   }else{
00891     int * ds; 
00892     if(style & 0x200){ // round and square caps, dash length need to be adjusted
00893       double *dt = dashes_cap[style & 0xff];
00894       while (*dt >= 0){
00895         fprintf(output, "%g ",width * (*dt));
00896         dt++;
00897       }
00898     }else{
00899       
00900       ds = dashes_flat[style & 0xff];
00901       while (*ds >= 0){
00902         fprintf(output, "%i ",width * (*ds));
00903         ds++;
00904       }
00905     }
00906   }
00907   fprintf(output, "] 0 setdash\n");
00908 }
00909 
00910 static const char *_fontNames[] = {
00911 "Helvetica2B", 
00912 "Helvetica-Bold2B",
00913 "Helvetica-Oblique2B",
00914 "Helvetica-BoldOblique2B",
00915 "Courier2B",
00916 "Courier-Bold2B",
00917 "Courier-Oblique2B",
00918 "Courier-BoldOblique2B",
00919 "Times-Roman2B",
00920 "Times-Bold2B",
00921 "Times-Italic2B",
00922 "Times-BoldItalic2B",
00923 "Symbol",
00924 "Courier2B",
00925 "Courier-Bold2B",
00926 "ZapfDingbats"
00927 };
00928 
00929 void Fl_PostScript_Graphics_Driver::font(int f, int s) {
00930   if (f >= FL_FREE_FONT)
00931     f = FL_COURIER;
00932   fprintf(output, "/%s SF\n" , _fontNames[f]);
00933   fprintf(output,"%i FS\n", s);
00934   Fl_Display_Device::display_device()->driver()->font(f,s); // Use display fonts for font measurement
00935   font_ = f; size_ = s;
00936 }
00937 
00938 void Fl_PostScript_Graphics_Driver::color(Fl_Color c) {
00939   Fl::get_color(c, cr_, cg_, cb_);
00940   color(cr_, cg_, cb_);
00941 }
00942 
00943 void Fl_PostScript_Graphics_Driver::color(unsigned char r, unsigned char g, unsigned char b) {
00944   fl_color_ = fl_rgb_color(r, g, b);
00945   cr_ = r; cg_ = g; cb_ = b;
00946   if (r == g && g == b) {
00947     double gray = r/255.0;
00948     fprintf(output, "%g GL\n", gray);
00949   } else {
00950     double fr, fg, fb;
00951     fr = r/255.0;
00952     fg = g/255.0;
00953     fb = b/255.0;
00954     fprintf(output, "%g %g %g SRGB\n", fr , fg , fb);
00955   }
00956 }
00957 
00958 void Fl_PostScript_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y)
00959 {
00960   fprintf(output, "GS %d %d translate %d rotate\n", x, y, - angle);
00961   this->transformed_draw(str, n, 0, 0);
00962   fprintf(output, "GR\n");
00963 }
00964 
00965 
00966 // computes the mask for the RGB image img of all pixels with color != bg
00967 static uchar *calc_mask(uchar *img, int w, int h, Fl_Color bg)
00968 {
00969   uchar red, green, blue, r, g, b;
00970   uchar bit, byte, *q;
00971   Fl::get_color(bg, red, green, blue);
00972   int W = (w+7)/8; // width of mask
00973   uchar* mask = new uchar[W * h];
00974   q = mask;
00975   while (h-- > 0) { // for each row
00976     bit = 0x80; // byte with last bit set
00977     byte = 0; // next mask byte to compute
00978     for (int j = 0; j < w; j++) { // for each column
00979       r = *img++; // the pixel color components
00980       g = *img++;
00981       b = *img++;
00982       // if pixel doesn't have bg color, put it in mask
00983       if (r != red || g != green || b != blue) byte |= bit;
00984       bit = bit>>1; // shift bit one step to the right
00985       if (bit == 0) { // single set bit has fallen out
00986         *q++ = byte; // enter byte in mask
00987         byte = 0; // reset next mask byte to zero
00988         bit = 0x80; // and this byte
00989         }
00990       }
00991     if (bit != 0x80) *q++ = byte; // enter last columns' byte in mask
00992     }
00993   return mask;
00994 }
00995 
00996 // write to PostScript a bitmap image of a UTF8 string
00997 static void transformed_draw_extra(const char* str, int n, double x, double y, int w, FILE *output) {
00998   const float scale = 3; // scale for bitmask computation
00999   Fl_Fontsize old_size = fl_size();
01000   fl_font(fl_font(), (Fl_Fontsize)(scale * old_size) );
01001   w =  (int)(w *scale + 0.5);
01002   int h = fl_height();
01003   // create an offscreen image of the string
01004   Fl_Color text_color = fl_color();
01005   Fl_Color bg_color = fl_contrast(FL_WHITE, text_color);
01006   Fl_Offscreen off = fl_create_offscreen(w+2, (int)(h+3*scale) );
01007   fl_begin_offscreen(off);
01008   fl_color(bg_color);
01009   // color offscreen background with a shade contrasting with the text color
01010   fl_rectf(0, 0, w+2, (int)(h+3*scale) );
01011   fl_color(text_color);
01012   fl_draw(str, n, 1, (int)(h * 0.8) ); // draw string in offscreen
01013   // read (most of) the offscreen image
01014   uchar *img = fl_read_image(NULL, 1, 1, w, h, 0);
01015   fl_end_offscreen();
01016   fl_font(fl_font(), old_size);
01017   fl_delete_offscreen(off);
01018   // compute the mask of what is not the background
01019   uchar *mask = calc_mask(img, w, h, bg_color);
01020   delete img;
01021   // write the string image to PostScript as a scaled bitmask
01022   fprintf(output, "%g %g %g %g %d %d MI\n", x, y - h*0.77/scale, w/scale, h/scale, w, h);
01023   uchar *di;
01024   int wmask = (w+7)/8;
01025   for (int j = h - 1; j >= 0; j--){
01026     di = mask + j * wmask;
01027     for (int i = 0; i < wmask; i++){
01028       //if (!(i%80)) fprintf(output, "\n"); // don't have lines longer than 255 chars
01029       fprintf(output, "%2.2x", *di );
01030       di++;
01031     }
01032     fprintf(output,"\n");
01033   }
01034   fprintf(output,">\n");
01035   delete mask;
01036 }
01037 
01038 static int is_in_table(unsigned utf) {
01039   unsigned i;
01040   static unsigned extra_table_roman[] = { // unicodes/*names*/ of other characters from PostScript standard fonts
01041     0x192/*florin*/, 0x2C6/*circumflex*/, 0x2C7/*caron*/, 
01042     0x2D8/*breve*/, 0x2D9/*dotaccent*/, 0x2DA/*ring*/, 0x2DB/*ogonek*/, 0x2DC/*tilde*/, 0x2DD/*hungarumlaut*/,
01043     0x2013/*endash*/, 0x2014/*emdash*/, 0x2018/*quoteleft*/, 0x2019/*quoteright*/, 
01044     0x201A/*quotesinglbase*/, 0x201C/*quotedblleft*/, 0x201D/*quotedblright*/, 0x201E/*quotedblbase*/, 
01045     0x2020/*dagger*/, 0x2021/*daggerdbl*/, 0x2022/*bullet*/,
01046     0x2026/*ellipsis*/, 0x2030/*perthousand*/, 0x2039/*guilsinglleft*/, 0x203A/*guilsinglright*/, 
01047     0x2044/*fraction*/, 0x20AC/*Euro*/, 0x2122/*trademark*/, 
01048     0x2202/*partialdiff*/, 0x2206/*Delta*/, 0x2211/*summation*/, 0x221A/*radical*/,
01049     0x221E/*infinity*/, 0x2260/*notequal*/, 0x2264/*lessequal*/, 
01050     0x2265/*greaterequal*/, 
01051     0x25CA/*lozenge*/, 0xFB01/*fi*/, 0xFB02/*fl*/,
01052     0xF8FF/*apple*/
01053   };
01054   for ( i = 0; i < sizeof(extra_table_roman)/sizeof(int); i++) {
01055     if (extra_table_roman[i] == utf) return i + 0x180;
01056   }
01057   return 0;
01058 }
01059 
01060 // outputs in PostScript a UTF8 string using the same width in points as on display
01061 void Fl_PostScript_Graphics_Driver::transformed_draw(const char* str, int n, double x, double y) {
01062   int len, code;
01063   if (!n || !str || !*str) return;
01064   // compute display width of string
01065   int width = (int)fl_width(str, n);
01066   if (width == 0) return;
01067   fprintf(output, "%d <", width);
01068   // transforms UTF8 encoding to our custom PostScript encoding as follows:
01069   // extract each unicode character
01070   // if unicode <= 0x17F, unicode and PostScript codes are identical
01071   // if unicode is one of the values listed in extra_table_roman above
01072   //    its PostScript code is 0x180 + the character's rank in extra_table_roman
01073   // if unicode is something else, draw all string as bitmap image
01074 
01075   const char *last = str + n;
01076   const char *str2 = str;
01077   while (str2 < last) {
01078     // Extract each unicode character of string.
01079     unsigned utf = fl_utf8decode(str2, last, &len);
01080     str2 += len;
01081     if (utf <= 0x17F) { // until Latin Extended-A
01082       ;
01083       }
01084     else if ( (code = is_in_table(utf)) != 0) { // other handled characters
01085       utf = code;
01086       }
01087     else { // unhandled character: draw all string as bitmap image
01088       fprintf(output, "> pop pop\n"); // close and ignore the opened hex string
01089       transformed_draw_extra(str, n, x, y, width, output);
01090       return;
01091     }
01092     fprintf(output, "%4.4X", utf);
01093   }
01094   fprintf(output, "> %g %g show_pos_width\n", x, y);
01095 }
01096 
01097 void Fl_PostScript_Graphics_Driver::rtl_draw(const char* str, int n, int x, int y) {
01098   const char *last = str + n;
01099   const char *str2 = str;
01100   unsigned int *unis = new unsigned int[n + 1];
01101   char *out = new char[n + 1];
01102   int u = 0, len;
01103   char *p = out;
01104   double w = fl_width(str, n);
01105   while (str2 < last) {
01106     unis[u++] = fl_utf8decode(str2, last, &len);
01107     str2 += len;
01108     }
01109   while (u > 0) {
01110     len = fl_utf8encode(unis[--u], p);
01111     p += len;
01112     }
01113   transformed_draw(out, p - out, x - w, y);
01114   delete [] unis;
01115   delete [] out;
01116 }
01117 
01118 struct matrix {double a, b, c, d, x, y;};
01119 extern matrix * fl_matrix;
01120 
01121 void Fl_PostScript_Graphics_Driver::concat(){
01122   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);
01123 }
01124 
01125 void Fl_PostScript_Graphics_Driver::reconcat(){
01126   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);
01127 }
01128 
01130 
01131 
01132 void Fl_PostScript_Graphics_Driver::begin_points(){
01133   fprintf(output, "GS\n");
01134   concat();
01135   
01136   fprintf(output, "BP\n");
01137   gap_=1;
01138   shape_=POINTS;
01139 }
01140 
01141 void Fl_PostScript_Graphics_Driver::begin_line(){
01142   fprintf(output, "GS\n");
01143   concat();
01144   fprintf(output, "BP\n");
01145   gap_=1;
01146   shape_=LINE;
01147 }
01148 
01149 void Fl_PostScript_Graphics_Driver::begin_loop(){
01150   fprintf(output, "GS\n");
01151   concat();
01152   fprintf(output, "BP\n");
01153   gap_=1;
01154   shape_=LOOP;
01155 }
01156 
01157 void Fl_PostScript_Graphics_Driver::begin_polygon(){
01158   fprintf(output, "GS\n");
01159   concat();
01160   fprintf(output, "BP\n");
01161   gap_=1;
01162   shape_=POLYGON;
01163 }
01164 
01165 void Fl_PostScript_Graphics_Driver::vertex(double x, double y){
01166   if(shape_==POINTS){
01167     fprintf(output,"%g %g MT\n", x , y);
01168     gap_=1;
01169     return;
01170   }
01171   if(gap_){
01172     fprintf(output,"%g %g MT\n", x , y);
01173     gap_=0;
01174   }else
01175     fprintf(output, "%g %g LT\n", x , y);
01176 }
01177 
01178 void Fl_PostScript_Graphics_Driver::curve(double x, double y, double x1, double y1, double x2, double y2, double x3, double y3){
01179   if(shape_==NONE) return;
01180   if(gap_)
01181     fprintf(output,"%g %g MT\n", x , y);
01182   else
01183     fprintf(output, "%g %g LT\n", x , y);
01184   gap_=0;
01185   
01186   fprintf(output, "%g %g %g %g %g %g curveto \n", x1 , y1 , x2 , y2 , x3 , y3);
01187 }
01188 
01189 
01190 void Fl_PostScript_Graphics_Driver::circle(double x, double y, double r){
01191   if(shape_==NONE){
01192     fprintf(output, "GS\n");
01193     concat();
01194     //    fprintf(output, "BP\n");
01195     fprintf(output,"%g %g %g 0 360 arc\n", x , y , r);
01196     reconcat();
01197     //    fprintf(output, "ELP\n");
01198     fprintf(output, "GR\n");
01199   }else
01200     
01201     fprintf(output, "%g %g %g 0 360 arc\n", x , y , r);
01202   
01203 }
01204 
01205 void Fl_PostScript_Graphics_Driver::arc(double x, double y, double r, double start, double a){
01206   if(shape_==NONE) return;
01207   gap_=0;
01208   if(start>a)
01209     fprintf(output, "%g %g %g %g %g arc\n", x , y , r , -start, -a);
01210   else
01211     fprintf(output, "%g %g %g %g %g arcn\n", x , y , r , -start, -a);
01212   
01213 }
01214 
01215 void Fl_PostScript_Graphics_Driver::arc(int x, int y, int w, int h, double a1, double a2) {
01216   fprintf(output, "GS\n");
01217   //fprintf(output, "BP\n");
01218   begin_line();
01219   fprintf(output, "%g %g TR\n", x + w/2.0 -0.5 , y + h/2.0 - 0.5);
01220   fprintf(output, "%g %g SC\n", (w-1)/2.0 , (h-1)/2.0 );
01221   arc(0,0,1,a2,a1);
01222   //  fprintf(output, "0 0 1 %g %g arc\n" , -a1 , -a2);
01223   fprintf(output, "%g %g SC\n", 2.0/(w-1) , 2.0/(h-1) );
01224   fprintf(output, "%g %g TR\n", -x - w/2.0 +0.5 , -y - h/2.0 +0.5);
01225   end_line();
01226   
01227   //  fprintf(output, "%g setlinewidth\n",  2/sqrt(w*h));
01228   //  fprintf(output, "ELP\n");
01229   //  fprintf(output, 2.0/w , 2.0/w , " SC\n";
01230   //  fprintf(output, (-x - w/2.0) , (-y - h/2)  , " TR\n";
01231   fprintf(output, "GR\n");
01232 }
01233 
01234 void Fl_PostScript_Graphics_Driver::pie(int x, int y, int w, int h, double a1, double a2) {
01235   
01236   fprintf(output, "GS\n");
01237   fprintf(output, "%g %g TR\n", x + w/2.0 -0.5 , y + h/2.0 - 0.5);
01238   fprintf(output, "%g %g SC\n", (w-1)/2.0 , (h-1)/2.0 );
01239   begin_polygon();
01240   vertex(0,0);
01241   arc(0.0,0.0, 1, a2, a1);
01242   end_polygon();
01243   fprintf(output, "GR\n");
01244 }
01245 
01246 void Fl_PostScript_Graphics_Driver::end_points(){
01247   gap_=1;
01248   reconcat();
01249   fprintf(output, "ELP\n"); //??
01250   fprintf(output, "GR\n");
01251   shape_=NONE;
01252 }
01253 
01254 void Fl_PostScript_Graphics_Driver::end_line(){
01255   gap_=1;
01256   reconcat();
01257   fprintf(output, "ELP\n");
01258   fprintf(output, "GR\n");
01259   shape_=NONE;
01260 }
01261 void Fl_PostScript_Graphics_Driver::end_loop(){
01262   gap_=1;
01263   reconcat();
01264   fprintf(output, "ECP\n");
01265   fprintf(output, "GR\n");
01266   shape_=NONE;
01267 }
01268 
01269 void Fl_PostScript_Graphics_Driver::end_polygon(){
01270   
01271   gap_=1;
01272   reconcat();
01273   fprintf(output, "EFP\n");
01274   fprintf(output, "GR\n");
01275   shape_=NONE;
01276 }
01277 
01278 void Fl_PostScript_Graphics_Driver::transformed_vertex(double x, double y){
01279   reconcat();
01280   if(gap_){
01281     fprintf(output, "%g %g MT\n", x , y);
01282     gap_=0;
01283   }else
01284     fprintf(output, "%g %g LT\n", x , y);
01285   concat();
01286 }
01287 
01289 
01290 void Fl_PostScript_Graphics_Driver::push_clip(int x, int y, int w, int h) {
01291   Clip * c=new Clip();
01292   clip_box(x,y,w,h,c->x,c->y,c->w,c->h);
01293   c->prev=clip_;
01294   clip_=c;
01295   fprintf(output, "CR\nCS\n");
01296   if(lang_level_<3)
01297     recover();
01298   fprintf(output, "%g %g %i %i CL\n", clip_->x-0.5 , clip_->y-0.5 , clip_->w  , clip_->h);
01299   
01300 }
01301 
01302 void Fl_PostScript_Graphics_Driver::push_no_clip() {
01303   Clip * c = new Clip();
01304   c->prev=clip_;
01305   clip_=c;
01306   clip_->x = clip_->y = clip_->w = clip_->h = -1;
01307   fprintf(output, "CR\nCS\n");
01308   if(lang_level_<3)
01309     recover();
01310 }
01311 
01312 void Fl_PostScript_Graphics_Driver::pop_clip() {
01313   if(!clip_)return;
01314   Clip * c=clip_;
01315   clip_=clip_->prev;
01316   delete c;
01317   fprintf(output, "CR\nCS\n");
01318   if(clip_ && clip_->w >0)
01319     fprintf(output, "%g %g %i %i CL\n", clip_->x - 0.5, clip_->y - 0.5, clip_->w  , clip_->h);
01320   // uh, -0.5 is to match screen clipping, for floats there should be something beter
01321   if(lang_level_<3)
01322     recover();
01323 }
01324 
01325 int Fl_PostScript_Graphics_Driver::clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H){
01326   if(!clip_){
01327     X=x;Y=y;W=w;H=h;
01328     return 1;
01329   }
01330   if(clip_->w < 0){
01331     X=x;Y=y;W=w;H=h;
01332     return 1;
01333   }
01334   int ret=0;
01335   if (x > (X=clip_->x)) {X=x; ret=1;}
01336   if (y > (Y=clip_->y)) {Y=y; ret=1;}
01337   if ((x+w) < (clip_->x+clip_->w)) {
01338     W=x+w-X;
01339     
01340     ret=1;
01341     
01342   }else
01343     W = clip_->x + clip_->w - X;
01344   if(W<0){
01345     W=0;
01346     return 1;
01347   }
01348   if ((y+h) < (clip_->y+clip_->h)) {
01349     H=y+h-Y;
01350     ret=1;
01351   }else
01352     H = clip_->y + clip_->h - Y;
01353   if(H<0){
01354     W=0;
01355     H=0;
01356     return 1;
01357   }
01358   return ret;
01359 }
01360 
01361 int Fl_PostScript_Graphics_Driver::not_clipped(int x, int y, int w, int h){
01362   if(!clip_) return 1;
01363   if(clip_->w < 0) return 1;
01364   int X, Y, W, H;
01365   clip_box(x, y, w, h, X, Y, W, H);
01366   if(W) return 1;
01367   return 0;
01368 }
01369 
01370 
01371 void Fl_PostScript_File_Device::margins(int *left, int *top, int *right, int *bottom) // to implement
01372 {
01373   Fl_PostScript_Graphics_Driver *ps = driver();
01374   if(left) *left = (int)(ps->left_margin / ps->scale_x + .5);
01375   if(right) *right = (int)(ps->left_margin / ps->scale_x + .5);
01376   if(top) *top = (int)(ps->top_margin / ps->scale_y + .5);
01377   if(bottom) *bottom = (int)(ps->top_margin / ps->scale_y + .5);
01378 }
01379 
01380 int Fl_PostScript_File_Device::printable_rect(int *w, int *h)
01381 //returns 0 iff OK
01382 {
01383   Fl_PostScript_Graphics_Driver *ps = driver();
01384   if(w) *w = (int)((ps->pw_ - 2 * ps->left_margin) / ps->scale_x + .5);
01385   if(h) *h = (int)((ps->ph_ - 2 * ps->top_margin) / ps->scale_y + .5);
01386   return 0;
01387 }
01388 
01389 void Fl_PostScript_File_Device::origin(int x, int y)
01390 {
01391   x_offset = x;
01392   y_offset = y;
01393   Fl_PostScript_Graphics_Driver *ps = driver();
01394   fprintf(ps->output, "GR GR GS %d %d TR  %f %f SC %d %d TR %f rotate GS\n", 
01395           ps->left_margin, ps->top_margin, ps->scale_x, ps->scale_y, x, y, ps->angle);
01396 }
01397 
01398 void Fl_PostScript_File_Device::scale (float s_x, float s_y)
01399 {
01400   Fl_PostScript_Graphics_Driver *ps = driver();
01401   ps->scale_x = s_x;
01402   ps->scale_y = s_y;
01403   fprintf(ps->output, "GR GR GS %d %d TR  %f %f SC %f rotate GS\n", 
01404           ps->left_margin, ps->top_margin, ps->scale_x, ps->scale_y, ps->angle);
01405 }
01406 
01407 void Fl_PostScript_File_Device::rotate (float rot_angle)
01408 {
01409   Fl_PostScript_Graphics_Driver *ps = driver();
01410   ps->angle = - rot_angle;
01411   fprintf(ps->output, "GR GR GS %d %d TR  %f %f SC %d %d TR %f rotate GS\n", 
01412           ps->left_margin, ps->top_margin, ps->scale_x, ps->scale_y, x_offset, y_offset, ps->angle);
01413 }
01414 
01415 void Fl_PostScript_File_Device::translate(int x, int y)
01416 {
01417   fprintf(driver()->output, "GS %d %d translate GS\n", x, y);
01418 }
01419 
01420 void Fl_PostScript_File_Device::untranslate(void)
01421 {
01422   fprintf(driver()->output, "GR GR\n");
01423 }
01424 
01425 int Fl_PostScript_File_Device::start_page (void)
01426 {
01427   Fl_PostScript_Graphics_Driver *ps = driver();
01428   ps->page(ps->page_format_);
01429   x_offset = 0;
01430   y_offset = 0;
01431   ps->scale_x = ps->scale_y = 1.;
01432   ps->angle = 0;
01433   fprintf(ps->output, "GR GR GS %d %d translate GS\n", ps->left_margin, ps->top_margin);
01434   return 0;
01435 }
01436 
01437 int Fl_PostScript_File_Device::end_page (void)
01438 {
01439   return 0;
01440 }
01441 
01442 void Fl_PostScript_File_Device::end_job (void)
01443 // finishes PostScript & closes file
01444 {
01445   Fl_PostScript_Graphics_Driver *ps = driver();
01446   if (ps->nPages) {  // for eps nPages is 0 so it is fine ....
01447     fprintf(ps->output, "CR\nGR\nGR\nGR\nSP\n restore\n");
01448     if (!ps->pages_){
01449       fprintf(ps->output, "%%%%Trailer\n");
01450       fprintf(ps->output, "%%%%Pages: %i\n" , ps->nPages);
01451     };
01452   } else
01453     fprintf(ps->output, "GR\n restore\n");
01454   fputs("%%EOF",ps->output);
01455   ps->reset();
01456   fflush(ps->output);
01457   if(ferror(ps->output)) {
01458     fl_alert ("Error during PostScript data output.");
01459     }
01460   if (ps->close_cmd_) {
01461     (*ps->close_cmd_)(ps->output);
01462   } else {
01463     fclose(ps->output);
01464     }
01465   while (ps->clip_){
01466     Fl_PostScript_Graphics_Driver::Clip * c= ps->clip_;
01467     ps->clip_= ps->clip_->prev;
01468     delete c;
01469   }
01470   Fl_Display_Device::display_device()->set_current();
01471 }
01472 
01473 #if ! (defined(__APPLE__) || defined(WIN32) )
01474 int Fl_PostScript_Printer::start_job(int pages, int *firstpage, int *lastpage) {
01475   enum Fl_Paged_Device::Page_Format format;
01476   enum Fl_Paged_Device::Page_Layout layout;
01477 
01478   // first test version for print dialog
01479   if (!print_panel) make_print_panel();
01480   print_load();
01481   print_selection->deactivate();
01482   print_all->setonly();
01483   print_all->do_callback();
01484   print_from->value("1");
01485   { char tmp[10]; snprintf(tmp, sizeof(tmp), "%d", pages); print_to->value(tmp); }
01486   print_panel->show(); // this is modal
01487   while (print_panel->shown()) Fl::wait();
01488   
01489   if (!print_start) // user clicked cancel
01490     return 1;
01491 
01492   // get options
01493 
01494   format = print_page_size->value() ? Fl_Paged_Device::A4 : Fl_Paged_Device::LETTER;
01495   { // page range choice
01496     int from = 1, to = pages;
01497     if (print_pages->value()) {
01498       sscanf(print_from->value(), "%d", &from);
01499       sscanf(print_to->value(), "%d", &to);
01500     }
01501     if (from < 1) from = 1;
01502     if (to > pages) to = pages;
01503     if (to < from) to = from;
01504     if (firstpage) *firstpage = from;
01505     if (lastpage) *lastpage = to;
01506     pages = to - from + 1;
01507   }
01508   
01509   if (print_output_mode[0]->value()) layout = Fl_Paged_Device::PORTRAIT;
01510   else if (print_output_mode[1]->value()) layout = Fl_Paged_Device::LANDSCAPE;
01511   else if (print_output_mode[2]->value()) layout = Fl_Paged_Device::PORTRAIT;
01512   else layout = Fl_Paged_Device::LANDSCAPE;
01513 
01514   int print_pipe = print_choice->value();       // 0 = print to file, >0 = printer (pipe)
01515 
01516   const char *media = print_page_size->text(print_page_size->value());
01517   const char *printer = (const char *)print_choice->menu()[print_choice->value()].user_data();
01518   if (!print_pipe) printer = "<File>";
01519 
01520   if (!print_pipe) // fall back to file printing
01521     return Fl_PostScript_File_Device::start_job (pages, format, layout);
01522 
01523   // Print: pipe the output into the lp command...
01524 
01525   char command[1024];
01526   snprintf(command, sizeof(command), "lp -s -d %s -n %d -t '%s' -o media=%s",
01527              printer, print_collate_button->value() ? 1 : (int)(print_copies->value() + 0.5),
01528              "FLTK", media);
01529 
01530   Fl_PostScript_Graphics_Driver *ps = driver();
01531   ps->output = popen(command, "w");
01532   if (!ps->output) {
01533     fl_alert("could not run command: %s\n",command);
01534     return 1;
01535   }
01536   ps->close_command(pclose);
01537   this->set_current();
01538   return ps->start_postscript(pages, format, layout); // start printing
01539 }
01540 
01541 #endif // ! (defined(__APPLE__) || defined(WIN32) )
01542 
01543 #endif // FL_DOXYGEN
01544 
01545 //
01546 // End of "$Id: Fl_PostScript.cxx 8190 2011-01-05 10:21:45Z manolo $".
01547 //