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