ref: 6e68d605ee9903626b64221607a4577c2c92c6bc
dir: /DoConfig/fltk/src/Fl_PostScript.cxx/
// // "$Id$" // // PostScript device support for the Fast Light Tool Kit (FLTK). // // Copyright 2010-2015 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this // file is missing or damaged, see the license at: // // http://www.fltk.org/COPYING.php // // Please report all bugs and problems to: // // http://www.fltk.org/str.php // #include <FL/Fl_Printer.H> #include <config.h> #include <FL/Fl.H> #include <FL/fl_ask.H> #include <FL/fl_draw.H> #include <stdio.h> #include <FL/Fl_PostScript.H> #include <FL/Fl_Native_File_Chooser.H> #include <stdarg.h> #if defined(USE_X11) #include "Fl_Font.H" #if USE_XFT #include <X11/Xft/Xft.h> #endif #endif const char *Fl_PostScript_Graphics_Driver::class_id = "Fl_PostScript_Graphics_Driver"; const char *Fl_PostScript_File_Device::class_id = "Fl_PostScript_File_Device"; /** \brief Label of the PostScript file chooser window */ const char *Fl_PostScript_File_Device::file_chooser_title = "Select a .ps file"; /** @brief The constructor. */ Fl_PostScript_Graphics_Driver::Fl_PostScript_Graphics_Driver(void) { close_cmd_ = 0; //lang_level_ = 3; lang_level_ = 2; mask = 0; ps_filename_ = NULL; scale_x = scale_y = 1.; bg_r = bg_g = bg_b = 255; } /** \brief The destructor. */ Fl_PostScript_Graphics_Driver::~Fl_PostScript_Graphics_Driver() { if(ps_filename_) free(ps_filename_); } /** @brief The constructor. */ Fl_PostScript_File_Device::Fl_PostScript_File_Device(void) { #ifdef __APPLE__ gc = fl_gc; // the display context is used by fl_text_extents() #endif Fl_Surface_Device::driver( new Fl_PostScript_Graphics_Driver() ); } /** \brief Returns the PostScript driver of this drawing surface. */ Fl_PostScript_Graphics_Driver *Fl_PostScript_File_Device::driver() { return (Fl_PostScript_Graphics_Driver*)Fl_Surface_Device::driver(); } /** @brief Begins the session where all graphics requests will go to a local PostScript file. * Opens a file dialog entitled with Fl_PostScript_File_Device::file_chooser_title to select an output PostScript file. @param pagecount The total number of pages to be created. Use 0 if this number is unknown when this function is called. @param format Desired page format. @param layout Desired page layout. @return 0 if OK, 1 if user cancelled the file dialog, 2 if fopen failed on user-selected output file. */ int Fl_PostScript_File_Device::start_job (int pagecount, enum Fl_Paged_Device::Page_Format format, enum Fl_Paged_Device::Page_Layout layout) { Fl_Native_File_Chooser fnfc; fnfc.title(Fl_PostScript_File_Device::file_chooser_title); fnfc.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); fnfc.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM); fnfc.filter("PostScript\t*.ps\n"); // Show native chooser if ( fnfc.show() ) return 1; Fl_PostScript_Graphics_Driver *ps = driver(); ps->output = fl_fopen(fnfc.filename(), "w"); if(ps->output == NULL) return 2; ps->ps_filename_ = strdup(fnfc.filename()); ps->start_postscript(pagecount, format, layout); this->set_current(); return 0; } extern "C" { static int dont_close(FILE *f) { return 0; } } /** @brief Begins the session where all graphics requests will go to FILE pointer. * @param ps_output A writable FILE pointer that will receive PostScript output and that should not be closed until after end_job() has been called. @param pagecount The total number of pages to be created. Use 0 if this number is unknown when this function is called. @param format Desired page format. @param layout Desired page layout. @return always 0. */ int Fl_PostScript_File_Device::start_job (FILE *ps_output, int pagecount, enum Fl_Paged_Device::Page_Format format, enum Fl_Paged_Device::Page_Layout layout) { Fl_PostScript_Graphics_Driver *ps = driver(); ps->output = ps_output; ps->ps_filename_ = NULL; ps->start_postscript(pagecount, format, layout); ps->close_command(dont_close); // so that end_job() doesn't close the file this->set_current(); return 0; } /** Don't use with this class. */ int Fl_PostScript_File_Device::start_job(int pagecount, int* from, int* to) { return 1; } /** @brief The destructor. */ Fl_PostScript_File_Device::~Fl_PostScript_File_Device() { Fl_PostScript_Graphics_Driver *ps = driver(); if (ps) delete ps; } /** Shields output PostScript data from modifications of the current locale. It typically avoids PostScript errors caused if the current locale uses comma instead of dot as "decimal point". \param format directives controlling output PostScript data \return value returned by vfprintf() call */ int Fl_PostScript_Graphics_Driver::clocale_printf(const char *format, ...) { char *saved_locale = setlocale(LC_NUMERIC, NULL); setlocale(LC_NUMERIC, "C"); va_list args; va_start(args, format); int retval = vfprintf(output, format, args); va_end(args); setlocale(LC_NUMERIC, saved_locale); return retval; } #ifndef FL_DOXYGEN #if ! (defined(__APPLE__) || defined(WIN32) ) # include "print_panel.cxx" #endif // Prolog string static const char * prolog = "%%BeginProlog\n" "/L { /y2 exch def\n" "/x2 exch def\n" "/y1 exch def\n" "/x1 exch def\n" "newpath x1 y1 moveto x2 y2 lineto\n" "stroke}\n" "bind def\n" "/R { /dy exch def\n" "/dx exch def\n" "/y exch def\n" "/x exch def\n" "newpath\n" "x y moveto\n" "dx 0 rlineto\n" "0 dy rlineto\n" "dx neg 0 rlineto\n" "closepath stroke\n" "} bind def\n" "/CL {\n" "/dy exch def\n" "/dx exch def\n" "/y exch def\n" "/x exch def\n" "newpath\n" "x y moveto\n" "dx 0 rlineto\n" "0 dy rlineto\n" "dx neg 0 rlineto\n" "closepath\n" "clip\n" "} bind def\n" "/FR { /dy exch def\n" "/dx exch def\n" "/y exch def\n" "/x exch def\n" "currentlinewidth 0 setlinewidth newpath\n" "x y moveto\n" "dx 0 rlineto\n" "0 dy rlineto\n" "dx neg 0 rlineto\n" "closepath fill setlinewidth\n" "} bind def\n" "/GS { gsave } bind def\n" "/GR { grestore } bind def\n" "/SP { showpage } bind def\n" "/LW { setlinewidth } bind def\n" "/CF /Courier def\n" "/SF { /CF exch def } bind def\n" "/fsize 12 def\n" "/FS { /fsize exch def fsize CF findfont exch scalefont setfont }def \n" "/GL { setgray } bind def\n" "/SRGB { setrgbcolor } bind def\n" "/A85RLE { /ASCII85Decode filter /RunLengthDecode filter } bind def\n" // ASCII85Decode followed by RunLengthDecode filters // color images "/CI { GS /py exch def /px exch def /sy exch def /sx exch def\n" "translate \n" "sx sy scale px py 8 \n" "[ px 0 0 py neg 0 py ]\n" "currentfile A85RLE\n false 3" " colorimage GR\n" "} bind def\n" // gray images "/GI { GS /py exch def /px exch def /sy exch def /sx exch def \n" "translate \n" "sx sy scale px py 8 \n" "[ px 0 0 py neg 0 py ]\n" "currentfile A85RLE\n" "image GR\n" "} bind def\n" // single-color bitmask "/MI { GS /py exch def /px exch def /sy exch def /sx exch def \n" "translate \n" "sx sy scale px py true \n" "[ px 0 0 py neg 0 py ]\n" "currentfile A85RLE\n" "imagemask GR\n" "} bind def\n" // path "/BFP { newpath moveto } def\n" "/BP { newpath } bind def \n" "/PL { lineto } bind def \n" "/PM { moveto } bind def \n" "/MT { moveto } bind def \n" "/LT { lineto } bind def \n" "/EFP { closepath fill } bind def\n" //was:stroke "/ELP { stroke } bind def\n" "/ECP { closepath stroke } bind def\n" // Closed (loop) "/LW { setlinewidth } bind def\n" // ////////////////////////// misc //////////////// "/TR { translate } bind def\n" "/CT { concat } bind def\n" "/RCT { matrix invertmatrix concat} bind def\n" "/SC { scale } bind def\n" //"/GPD { currentpagedevice /PageSize get} def\n" // show at position with desired width // usage: // width (string) x y show_pos_width "/show_pos_width {GS moveto dup dup stringwidth pop exch length 2 div dup 2 le {pop 9999} if " "1 sub exch 3 index exch sub exch " "div 0 2 index 1 -1 scale ashow pop pop GR} bind def\n" // spacing altered to match desired width //"/show_pos_width {GS moveto dup stringwidth pop 3 2 roll exch div -1 matrix scale concat " //"show GR } bind def\n" // horizontally scaled text to match desired width ; static const char * prolog_2 = // prolog relevant only if lang_level >1 // color image dictionaries "/CII {GS /inter exch def /py exch def /px exch def /sy exch def /sx exch def \n" "translate \n" "sx sy scale\n" "/DeviceRGB setcolorspace\n" "/IDD 8 dict def\n" "IDD begin\n" "/ImageType 1 def\n" "/Width px def\n" "/Height py def\n" "/BitsPerComponent 8 def\n" "/Interpolate inter def\n" "/DataSource currentfile A85RLE def\n" "/MultipleDataSources false def\n" "/ImageMatrix [ px 0 0 py neg 0 py ] def\n" "/Decode [ 0 1 0 1 0 1 ] def\n" "end\n" "IDD image GR} bind def\n" // gray image dict "/GII {GS /inter exch def /py exch def /px exch def /sy exch def /sx exch def \n" "translate \n" "sx sy scale\n" "/DeviceGray setcolorspace\n" "/IDD 8 dict def\n" "IDD begin\n" "/ImageType 1 def\n" "/Width px def\n" "/Height py def\n" "/BitsPerComponent 8 def\n" "/Interpolate inter def\n" "/DataSource currentfile A85RLE def\n" "/MultipleDataSources false def\n" "/ImageMatrix [ px 0 0 py neg 0 py ] def\n" "/Decode [ 0 1 ] def\n" "end\n" "IDD image GR} bind def\n" // Create a custom PostScript font derived from PostScript standard text fonts // The encoding of this custom font is as follows: // 0000-00FF coincides with Unicode, that is to ASCII + Latin-1 // 0100-017F coincides with Unicode, that is to Latin Extended-A // 0180-01A6 encodes miscellaneous characters present in PostScript standard text fonts // use ISOLatin1Encoding for all text fonts "/ToISO { dup findfont dup length dict copy begin /Encoding ISOLatin1Encoding def currentdict end definefont pop } def\n" "/Helvetica ToISO /Helvetica-Bold ToISO /Helvetica-Oblique ToISO /Helvetica-BoldOblique ToISO \n" "/Courier ToISO /Courier-Bold ToISO /Courier-Oblique ToISO /Courier-BoldOblique ToISO \n" "/Times-Roman ToISO /Times-Bold ToISO /Times-Italic ToISO /Times-BoldItalic ToISO \n" // define LatinExtA, the encoding of Latin-extended-A + some additional characters // see http://partners.adobe.com/public/developer/en/opentype/glyphlist.txt for their names "/LatinExtA \n" "[ " " /Amacron /amacron /Abreve /abreve /Aogonek /aogonek\n" // begin of Latin Extended-A code page " /Cacute /cacute /Ccircumflex /ccircumflex /Cdotaccent /cdotaccent /Ccaron /ccaron \n" " /Dcaron /dcaron /Dcroat /dcroat\n" " /Emacron /emacron /Ebreve /ebreve /Edotaccent /edotaccent /Eogonek /eogonek /Ecaron /ecaron\n" " /Gcircumflex /gcircumflex /Gbreve /gbreve /Gdotaccent /gdotaccent /Gcommaaccent /gcommaaccent \n" " /Hcircumflex /hcircumflex /Hbar /hbar \n" " /Itilde /itilde /Imacron /imacron /Ibreve /ibreve /Iogonek /iogonek /Idotaccent /dotlessi \n" " /IJ /ij /Jcircumflex /jcircumflex\n" " /Kcommaaccent /kcommaaccent /kgreenlandic \n" " /Lacute /lacute /Lcommaaccent /lcommaaccent /Lcaron /lcaron /Ldotaccent /ldotaccent /Lslash /lslash \n" " /Nacute /nacute /Ncommaaccent /ncommaaccent /Ncaron /ncaron /napostrophe /Eng /eng \n" " /Omacron /omacron /Obreve /obreve /Ohungarumlaut /ohungarumlaut /OE /oe \n" " /Racute /racute /Rcommaaccent /rcommaaccent /Rcaron /rcaron \n" " /Sacute /sacute /Scircumflex /scircumflex /Scedilla /scedilla /Scaron /scaron \n" " /Tcommaaccent /tcommaaccent /Tcaron /tcaron /Tbar /tbar \n" " /Utilde /utilde /Umacron /umacron /Ubreve /ubreve /Uring /uring /Uhungarumlaut /uhungarumlaut /Uogonek /uogonek \n" " /Wcircumflex /wcircumflex /Ycircumflex /ycircumflex /Ydieresis \n" " /Zacute /zacute /Zdotaccent /zdotaccent /Zcaron /zcaron \n" " /longs \n" // end of Latin Extended-A code page " /florin /circumflex /caron /breve /dotaccent /ring \n" // remaining characters from PostScript standard text fonts " /ogonek /tilde /hungarumlaut /endash /emdash \n" " /quoteleft /quoteright /quotesinglbase /quotedblleft /quotedblright \n" " /quotedblbase /dagger /daggerdbl /bullet /ellipsis \n" " /perthousand /guilsinglleft /guilsinglright /fraction /Euro \n" " /trademark /partialdiff /Delta /summation /radical \n" " /infinity /notequal /lessequal /greaterequal /lozenge \n" " /fi /fl /apple \n" " ] def \n" // deal with alternative PostScript names of some characters " /mycharstrings /Helvetica findfont /CharStrings get def\n" " /PSname2 { dup mycharstrings exch known {LatinExtA 3 -1 roll 3 -1 roll put}{pop pop} ifelse } def \n" " 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" // proc that gives LatinExtA encoding to a font "/ToLatinExtA { findfont dup length dict copy begin /Encoding LatinExtA def currentdict end definefont pop } def\n" // create Ext-versions of standard fonts that use LatinExtA encoding \n" "/HelveticaExt /Helvetica ToLatinExtA \n" "/Helvetica-BoldExt /Helvetica-Bold ToLatinExtA /Helvetica-ObliqueExt /Helvetica-Oblique ToLatinExtA \n" "/Helvetica-BoldObliqueExt /Helvetica-BoldOblique ToLatinExtA \n" "/CourierExt /Courier ToLatinExtA /Courier-BoldExt /Courier-Bold ToLatinExtA \n" "/Courier-ObliqueExt /Courier-Oblique ToLatinExtA /Courier-BoldObliqueExt /Courier-BoldOblique ToLatinExtA \n" "/Times-RomanExt /Times-Roman ToLatinExtA /Times-BoldExt /Times-Bold ToLatinExtA \n" "/Times-ItalicExt /Times-Italic ToLatinExtA /Times-BoldItalicExt /Times-BoldItalic ToLatinExtA \n" // proc to create a Type 0 font with 2-byte encoding // that merges a text font with ISO encoding + same font with LatinExtA encoding "/To2byte { 6 dict begin /FontType 0 def \n" "/FDepVector 3 1 roll findfont exch findfont 2 array astore def \n" "/FontMatrix [1 0 0 1 0 0] def /FMapType 6 def /Encoding [ 0 1 0 ] def\n" // 100: Hexa count of ISO array; A7: hexa count of LatinExtA array "/SubsVector < 01 0100 00A7 > def\n" "currentdict end definefont pop } def\n" // create Type 0 versions of standard fonts "/Helvetica2B /HelveticaExt /Helvetica To2byte \n" "/Helvetica-Bold2B /Helvetica-BoldExt /Helvetica-Bold To2byte \n" "/Helvetica-Oblique2B /Helvetica-ObliqueExt /Helvetica-Oblique To2byte \n" "/Helvetica-BoldOblique2B /Helvetica-BoldObliqueExt /Helvetica-BoldOblique To2byte \n" "/Courier2B /CourierExt /Courier To2byte \n" "/Courier-Bold2B /Courier-BoldExt /Courier-Bold To2byte \n" "/Courier-Oblique2B /Courier-ObliqueExt /Courier-Oblique To2byte \n" "/Courier-BoldOblique2B /Courier-BoldObliqueExt /Courier-BoldOblique To2byte \n" "/Times-Roman2B /Times-RomanExt /Times-Roman To2byte \n" "/Times-Bold2B /Times-BoldExt /Times-Bold To2byte \n" "/Times-Italic2B /Times-ItalicExt /Times-Italic To2byte \n" "/Times-BoldItalic2B /Times-BoldItalicExt /Times-BoldItalic To2byte \n" ; static const char * prolog_2_pixmap = // prolog relevant only if lang_level == 2 for pixmaps/masked color images "/pixmap_mat {[ pixmap_sx 0 0 pixmap_sy neg 0 pixmap_sy ]} bind def\n" "/pixmap_dict {" "<< /PatternType 1 " "/PaintType 1 " "/TilingType 2 " "/BBox [0 0 pixmap_sx pixmap_sy] " "/XStep pixmap_sx " "/YStep pixmap_sy\n" "/PaintProc " "{ begin " "pixmap_w pixmap_h scale " "pixmap_sx pixmap_sy 8 " "pixmap_mat " "currentfile A85RLE " "false 3 " "colorimage " "end " "} bind " ">>\n" "} bind def\n" "/pixmap_plot {" "GS " "/pixmap_sy exch def /pixmap_sx exch def\n" "/pixmap_h exch def /pixmap_w exch def\n" "translate\n" "pixmap_dict matrix makepattern setpattern\n" "pixmap_w pixmap_h scale\n" "pixmap_sx pixmap_sy\n" "true\n" "pixmap_mat\n" "currentfile A85RLE\n" "imagemask\n" "GR\n" "} bind def\n" ; static const char * prolog_3 = // prolog relevant only if lang_level >2 // masked color images "/CIM {GS /inter exch def /my exch def /mx exch def /py exch def /px exch def /sy exch def /sx exch def \n" "translate \n" "sx sy scale\n" "/DeviceRGB setcolorspace\n" "/IDD 8 dict def\n" "IDD begin\n" "/ImageType 1 def\n" "/Width px def\n" "/Height py def\n" "/BitsPerComponent 8 def\n" "/Interpolate inter def\n" "/DataSource currentfile A85RLE def\n" "/MultipleDataSources false def\n" "/ImageMatrix [ px 0 0 py neg 0 py ] def\n" "/Decode [ 0 1 0 1 0 1 ] def\n" "end\n" "/IMD 8 dict def\n" "IMD begin\n" "/ImageType 1 def\n" "/Width mx def\n" "/Height my def\n" "/BitsPerComponent 1 def\n" // "/Interpolate inter def\n" "/ImageMatrix [ mx 0 0 my neg 0 my ] def\n" "/Decode [ 1 0 ] def\n" "end\n" "<<\n" "/ImageType 3\n" "/InterleaveType 2\n" "/MaskDict IMD\n" "/DataDict IDD\n" ">> image GR\n" "} bind def\n" // masked gray images "/GIM {GS /inter exch def /my exch def /mx exch def /py exch def /px exch def /sy exch def /sx exch def \n" "translate \n" "sx sy scale\n" "/DeviceGray setcolorspace\n" "/IDD 8 dict def\n" "IDD begin\n" "/ImageType 1 def\n" "/Width px def\n" "/Height py def\n" "/BitsPerComponent 8 def\n" "/Interpolate inter def\n" "/DataSource currentfile A85RLE def\n" "/MultipleDataSources false def\n" "/ImageMatrix [ px 0 0 py neg 0 py ] def\n" "/Decode [ 0 1 ] def\n" "end\n" "/IMD 8 dict def\n" "IMD begin\n" "/ImageType 1 def\n" "/Width mx def\n" "/Height my def\n" "/BitsPerComponent 1 def\n" "/ImageMatrix [ mx 0 0 my neg 0 my ] def\n" "/Decode [ 1 0 ] def\n" "end\n" "<<\n" "/ImageType 3\n" "/InterleaveType 2\n" "/MaskDict IMD\n" "/DataDict IDD\n" ">> image GR\n" "} bind def\n" "\n" ; // end prolog int Fl_PostScript_Graphics_Driver::start_postscript (int pagecount, enum Fl_Paged_Device::Page_Format format, enum Fl_Paged_Device::Page_Layout layout) //returns 0 iff OK { int w, h, x; if (format == Fl_Paged_Device::A4) { left_margin = 18; top_margin = 18; } else { left_margin = 12; top_margin = 12; } page_format_ = (enum Fl_Paged_Device::Page_Format)(format | layout); if (layout & Fl_Paged_Device::LANDSCAPE){ ph_ = Fl_Paged_Device::page_formats[format].width; pw_ = Fl_Paged_Device::page_formats[format].height; } else { pw_ = Fl_Paged_Device::page_formats[format].width; ph_ = Fl_Paged_Device::page_formats[format].height; } fputs("%!PS-Adobe-3.0\n", output); fputs("%%Creator: FLTK\n", output); if (lang_level_>1) fprintf(output, "%%%%LanguageLevel: %i\n" , lang_level_); if ((pages_ = pagecount)) fprintf(output, "%%%%Pages: %i\n", pagecount); else fputs("%%Pages: (atend)\n", output); fprintf(output, "%%%%BeginFeature: *PageSize %s\n", Fl_Paged_Device::page_formats[format].name ); w = Fl_Paged_Device::page_formats[format].width; h = Fl_Paged_Device::page_formats[format].height; if (lang_level_ == 3 && (layout & Fl_Paged_Device::LANDSCAPE) ) { x = w; w = h; h = x; } fprintf(output, "<</PageSize[%d %d]>>setpagedevice\n", w, h ); fputs("%%EndFeature\n", output); fputs("%%EndComments\n", output); fputs(prolog, output); if (lang_level_ > 1) { fputs(prolog_2, output); } if (lang_level_ == 2) { fputs(prolog_2_pixmap, output); } if (lang_level_ > 2) fputs(prolog_3, output); if (lang_level_ >= 3) { fputs("/CS { clipsave } bind def\n", output); fputs("/CR { cliprestore } bind def\n", output); } else { fputs("/CS { GS } bind def\n", output); fputs("/CR { GR } bind def\n", output); } page_policy_ = 1; fputs("%%EndProlog\n",output); if (lang_level_ >= 2) fprintf(output,"<< /Policies << /Pagesize 1 >> >> setpagedevice\n"); reset(); nPages=0; return 0; } void Fl_PostScript_Graphics_Driver::recover(){ color(cr_,cg_,cb_); line_style(linestyle_,linewidth_,linedash_); font(Fl_Graphics_Driver::font(), Fl_Graphics_Driver::size()); } void Fl_PostScript_Graphics_Driver::reset(){ gap_=1; clip_=0; cr_=cg_=cb_=0; Fl_Graphics_Driver::font(FL_HELVETICA, 12); linewidth_=0; linestyle_=FL_SOLID; strcpy(linedash_,""); Clip *c=clip_; ////just not to have memory leaks for badly writen code (forgotten clip popping) while(c){ clip_=clip_->prev; delete c; c=clip_; } } void Fl_PostScript_Graphics_Driver::page_policy(int p){ page_policy_ = p; if(lang_level_>=2) fprintf(output,"<< /Policies << /Pagesize %i >> >> setpagedevice\n", p); } // //////////////////// paging ////////////////////////////////////////// void Fl_PostScript_Graphics_Driver::page(double pw, double ph, int media) { if (nPages){ fprintf(output, "CR\nGR\nGR\nGR\nSP\nrestore\n"); } ++nPages; fprintf(output, "%%%%Page: %i %i\n" , nPages , nPages); fprintf(output, "%%%%PageBoundingBox: 0 0 %d %d\n", pw > ph ? (int)ph : (int)pw , pw > ph ? (int)pw : (int)ph); if (pw>ph){ fprintf(output, "%%%%PageOrientation: Landscape\n"); }else{ fprintf(output, "%%%%PageOrientation: Portrait\n"); } fprintf(output, "%%%%BeginPageSetup\n"); if((media & Fl_Paged_Device::MEDIA) &&(lang_level_>1)){ int r = media & Fl_Paged_Device::REVERSED; if(r) r = 2; fprintf(output, "<< /PageSize [%i %i] /Orientation %i>> setpagedevice\n", (int)(pw+.5), (int)(ph+.5), r); } fprintf(output, "%%%%EndPageSetup\n"); /* pw_ = pw; ph_ = ph;*/ reset(); fprintf(output, "save\n"); fprintf(output, "GS\n"); clocale_printf( "%g %g TR\n", (double)0 /*lm_*/ , ph_ /* - tm_*/); fprintf(output, "1 -1 SC\n"); line_style(0); fprintf(output, "GS\n"); if (!((media & Fl_Paged_Device::MEDIA) &&(lang_level_>1))){ if (pw > ph) { if(media & Fl_Paged_Device::REVERSED) { fprintf(output, "-90 rotate %i 0 translate\n", int(-pw)); } else { fprintf(output, "90 rotate -%i -%i translate\n", (lang_level_ == 2 ? int(pw - ph) : 0), int(ph)); } } else { if(media & Fl_Paged_Device::REVERSED) fprintf(output, "180 rotate %i %i translate\n", int(-pw), int(-ph)); } } fprintf(output, "GS\nCS\n"); } void Fl_PostScript_Graphics_Driver::page(int format){ /* if(format & Fl_Paged_Device::LANDSCAPE){ ph_=Fl_Paged_Device::page_formats[format & 0xFF].width; pw_=Fl_Paged_Device::page_formats[format & 0xFF].height; }else{ pw_=Fl_Paged_Device::page_formats[format & 0xFF].width; ph_=Fl_Paged_Device::page_formats[format & 0xFF].height; }*/ page(pw_,ph_,format & 0xFF00);//,orientation only; } void Fl_PostScript_Graphics_Driver::rect(int x, int y, int w, int h) { // Commented code does not work, i can't find the bug ;-( // fprintf(output, "GS\n"); // fprintf(output, "%i, %i, %i, %i R\n", x , y , w, h); // fprintf(output, "GR\n"); fprintf(output, "GS\n"); fprintf(output,"BP\n"); fprintf(output, "%i %i MT\n", x , y); fprintf(output, "%i %i LT\n", x+w-1 , y); fprintf(output, "%i %i LT\n", x+w-1 , y+h-1); fprintf(output, "%i %i LT\n", x , y+h-1); fprintf(output, "ECP\n"); fprintf(output, "GR\n"); } void Fl_PostScript_Graphics_Driver::rectf(int x, int y, int w, int h) { clocale_printf( "%g %g %i %i FR\n", x-0.5, y-0.5, w, h); } void Fl_PostScript_Graphics_Driver::line(int x1, int y1, int x2, int y2) { fprintf(output, "GS\n"); fprintf(output, "%i %i %i %i L\n", x1 , y1, x2 ,y2); fprintf(output, "GR\n"); } void Fl_PostScript_Graphics_Driver::line(int x0, int y0, int x1, int y1, int x2, int y2) { fprintf(output, "GS\n"); fprintf(output,"BP\n"); fprintf(output, "%i %i MT\n", x0 , y0); fprintf(output, "%i %i LT\n", x1 , y1); fprintf(output, "%i %i LT\n", x2 , y2); fprintf(output, "ELP\n"); fprintf(output, "GR\n"); } void Fl_PostScript_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3){ fprintf(output, "GS\n"); fprintf(output,"BP\n"); fprintf(output, "%i %i MT\n", x , y ); fprintf(output, "%i %i LT\n", x1 , y ); fprintf(output, "%i %i LT\n", x1 , y2); fprintf(output,"%i %i LT\n", x3 , y2); fprintf(output, "ELP\n"); fprintf(output, "GR\n"); } void Fl_PostScript_Graphics_Driver::xyline(int x, int y, int x1, int y2){ fprintf(output, "GS\n"); fprintf(output,"BP\n"); fprintf(output, "%i %i MT\n", x , y); fprintf(output,"%i %i LT\n", x1 , y); fprintf(output, "%i %i LT\n", x1 , y2 ); fprintf(output, "ELP\n"); fprintf(output, "GR\n"); } void Fl_PostScript_Graphics_Driver::xyline(int x, int y, int x1){ fprintf(output, "GS\n"); fprintf(output,"BP\n"); fprintf(output, "%i %i MT\n", x , y); fprintf(output, "%i %i LT\n", x1 , y ); fprintf(output, "ELP\n"); fprintf(output, "GR\n"); } void Fl_PostScript_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3){ fprintf(output, "GS\n"); fprintf(output,"BP\n"); fprintf(output,"%i %i MT\n", x , y); fprintf(output, "%i %i LT\n", x , y1 ); fprintf(output, "%i %i LT\n", x2 , y1 ); fprintf(output , "%i %i LT\n", x2 , y3); fprintf(output, "ELP\n"); fprintf(output, "GR\n"); } void Fl_PostScript_Graphics_Driver::yxline(int x, int y, int y1, int x2){ fprintf(output, "GS\n"); fprintf(output,"BP\n"); fprintf(output, "%i %i MT\n", x , y); fprintf(output, "%i %i LT\n", x , y1); fprintf(output, "%i %i LT\n", x2 , y1); fprintf(output, "ELP\n"); fprintf(output, "GR\n"); } void Fl_PostScript_Graphics_Driver::yxline(int x, int y, int y1){ fprintf(output, "GS\n"); fprintf(output,"BP\n"); fprintf(output, "%i %i MT\n", x , y); fprintf(output, "%i %i LT\n", x , y1); fprintf(output, "ELP\n"); fprintf(output, "GR\n"); } void Fl_PostScript_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2) { fprintf(output, "GS\n"); fprintf(output,"BP\n"); fprintf(output, "%i %i MT\n", x0 , y0); fprintf(output, "%i %i LT\n", x1 , y1); fprintf(output, "%i %i LT\n", x2 , y2); fprintf(output, "ECP\n"); fprintf(output, "GR\n"); } void Fl_PostScript_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) { fprintf(output, "GS\n"); fprintf(output,"BP\n"); fprintf(output, "%i %i MT\n", x0 , y0); fprintf(output, "%i %i LT\n", x1 , y1); fprintf(output, "%i %i LT\n", x2 , y2); fprintf(output, "%i %i LT\n", x3 , y3); fprintf(output, "ECP\n"); fprintf(output, "GR\n"); } void Fl_PostScript_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, int y2) { fprintf(output, "GS\n"); fprintf(output,"BP\n"); fprintf(output, "%i %i MT\n", x0 , y0); fprintf(output,"%i %i LT\n", x1 , y1); fprintf(output, "%i %i LT\n", x2 , y2); fprintf(output, "EFP\n"); fprintf(output, "GR\n"); } void Fl_PostScript_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) { fprintf(output, "GS\n"); fprintf(output,"BP\n"); fprintf(output, "%i %i MT\n", x0 , y0 ); fprintf(output, "%i %i LT\n", x1 , y1 ); fprintf(output, "%i %i LT\n", x2 , y2 ); fprintf(output, "%i %i LT\n", x3 , y3 ); fprintf(output, "EFP\n"); fprintf(output, "GR\n"); } void Fl_PostScript_Graphics_Driver::point(int x, int y){ rectf(x,y,1,1); } static const int dashes_flat[5][7]={ {-1,0,0,0,0,0,0}, {3,1,-1,0,0,0,0}, {1,1,-1,0,0,0,0}, {3,1,1,1,-1,0,0}, {3,1,1,1,1,1,-1} }; //yeah, hack... static const double dashes_cap[5][7]={ {-1,0,0,0,0,0,0}, {2,2,-1,0,0,0,0}, {0.01,1.99,-1,0,0,0,0}, {2,2,0.01,1.99,-1,0,0}, {2,2,0.01,1.99,0.01,1.99,-1} }; void Fl_PostScript_Graphics_Driver::line_style(int style, int width, char* dashes){ //line_styled_=1; linewidth_=width; linestyle_=style; //dashes_= dashes; if(dashes){ if(dashes != linedash_) strcpy(linedash_,dashes); }else linedash_[0]=0; char width0 = 0; if(!width){ width=1; //for screen drawing compatibility width0=1; } fprintf(output, "%i setlinewidth\n", width); if(!style && (!dashes || !(*dashes)) && width0) //system lines style = FL_CAP_SQUARE; int cap = (style &0xf00) >> 8; if(cap) cap--; fprintf(output,"%i setlinecap\n", cap); int join = (style & 0xf000) >> 12; if(join) join--; fprintf(output,"%i setlinejoin\n", join); fprintf(output, "["); if(dashes && *dashes){ while(*dashes){ fprintf(output, "%i ", *dashes); dashes++; } }else{ if(style & 0x200){ // round and square caps, dash length need to be adjusted const double *dt = dashes_cap[style & 0xff]; while (*dt >= 0){ clocale_printf("%g ",width * (*dt)); dt++; } }else{ const int *ds = dashes_flat[style & 0xff]; while (*ds >= 0){ fprintf(output, "%i ",width * (*ds)); ds++; } } } fprintf(output, "] 0 setdash\n"); } static const char *_fontNames[] = { "Helvetica2B", "Helvetica-Bold2B", "Helvetica-Oblique2B", "Helvetica-BoldOblique2B", "Courier2B", "Courier-Bold2B", "Courier-Oblique2B", "Courier-BoldOblique2B", "Times-Roman2B", "Times-Bold2B", "Times-Italic2B", "Times-BoldItalic2B", "Symbol", "Courier2B", "Courier-Bold2B", "ZapfDingbats" }; void Fl_PostScript_Graphics_Driver::font(int f, int s) { Fl_Graphics_Driver *driver = Fl_Display_Device::display_device()->driver(); driver->font(f,s); // Use display fonts for font measurement Fl_Graphics_Driver::font(f, s); Fl_Font_Descriptor *desc = driver->font_descriptor(); this->font_descriptor(desc); if (f < FL_FREE_FONT) { float ps_size = (float) s; fprintf(output, "/%s SF\n" , _fontNames[f]); #if defined(USE_X11) #if USE_XFT // Xft font height is sometimes larger than the required size (see STR 2566). // Increase the PostScript font size by 15% without exceeding the display font height int max = desc->font->height; ps_size = s * 1.15; if (ps_size > max) ps_size = max; #else // Non-Xft fonts can be smaller than required. // Set the PostScript font size to the display font height char *name = desc->font->font_name_list[0]; char *p = strstr(name, "--"); if (p) { sscanf(p + 2, "%f", &ps_size); } #endif // USE_XFT #endif // USE_X11 clocale_printf("%.1f FS\n", ps_size); } } double Fl_PostScript_Graphics_Driver::width(const char *s, int n) { return Fl_Display_Device::display_device()->driver()->width(s, n); } double Fl_PostScript_Graphics_Driver::width(unsigned u) { return Fl_Display_Device::display_device()->driver()->width(u); } int Fl_PostScript_Graphics_Driver::height() { return Fl_Display_Device::display_device()->driver()->height(); } int Fl_PostScript_Graphics_Driver::descent() { return Fl_Display_Device::display_device()->driver()->descent(); } void Fl_PostScript_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &dy, int &w, int &h) { Fl_Display_Device::display_device()->driver()->text_extents(c, n, dx, dy, w, h); } void Fl_PostScript_Graphics_Driver::color(Fl_Color c) { Fl::get_color(c, cr_, cg_, cb_); color(cr_, cg_, cb_); } void Fl_PostScript_Graphics_Driver::color(unsigned char r, unsigned char g, unsigned char b) { Fl_Graphics_Driver::color( fl_rgb_color(r, g, b) ); cr_ = r; cg_ = g; cb_ = b; if (r == g && g == b) { double gray = r/255.0; clocale_printf("%g GL\n", gray); } else { double fr, fg, fb; fr = r/255.0; fg = g/255.0; fb = b/255.0; clocale_printf("%g %g %g SRGB\n", fr , fg , fb); } } void Fl_PostScript_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) { fprintf(output, "GS %d %d translate %d rotate\n", x, y, - angle); this->transformed_draw(str, n, 0, 0); fprintf(output, "GR\n"); } // computes the mask for the RGB image img of all pixels with color != bg static uchar *calc_mask(uchar *img, int w, int h, Fl_Color bg) { uchar red, green, blue, r, g, b; uchar bit, byte, *q; Fl::get_color(bg, red, green, blue); int W = (w+7)/8; // width of mask uchar* mask = new uchar[W * h]; q = mask; while (h-- > 0) { // for each row bit = 0x80; // byte with last bit set byte = 0; // next mask byte to compute for (int j = 0; j < w; j++) { // for each column r = *img++; // the pixel color components g = *img++; b = *img++; // if pixel doesn't have bg color, put it in mask if (r != red || g != green || b != blue) byte |= bit; bit = bit>>1; // shift bit one step to the right if (bit == 0) { // single set bit has fallen out *q++ = byte; // enter byte in mask byte = 0; // reset next mask byte to zero bit = 0x80; // and this byte } } if (bit != 0x80) *q++ = byte; // enter last columns' byte in mask } return mask; } // write to PostScript a bitmap image of a UTF8 string void Fl_PostScript_Graphics_Driver::transformed_draw_extra(const char* str, int n, double x, double y, int w, bool rtl) { // scale for bitmask computation #if defined(USE_X11) && !USE_XFT float scale = 1; // don't scale because we can't expect to have scalable fonts #else float scale = 2; #endif Fl_Fontsize old_size = size(); Fl_Font fontnum = Fl_Graphics_Driver::font(); int w_scaled = (int)(w * (scale + 0.5)); int h = (int)(height() * scale); // create an offscreen image of the string Fl_Color text_color = Fl_Graphics_Driver::color(); Fl_Color bg_color = fl_contrast(FL_WHITE, text_color); Fl_Offscreen off = fl_create_offscreen(w_scaled, (int)(h+3*scale) ); fl_begin_offscreen(off); fl_color(bg_color); // color offscreen background with a shade contrasting with the text color fl_rectf(0, 0, w_scaled, (int)(h+3*scale) ); fl_color(text_color); #if defined(USE_X11) && !USE_XFT // force seeing this font as new so it's applied to the offscreen graphics context fl_graphics_driver->font_descriptor(NULL); fl_font(fontnum, 0); #endif fl_font(fontnum, (Fl_Fontsize)(scale * old_size) ); int w2 = (int)fl_width(str, n); // draw string in offscreen if (rtl) fl_rtl_draw(str, n, w2, (int)(h * 0.8) ); else fl_draw(str, n, 1, (int)(h * 0.8) ); // read (most of) the offscreen image uchar *img = fl_read_image(NULL, 1, 1, w2, h, 0); fl_end_offscreen(); font(fontnum, old_size); fl_delete_offscreen(off); // compute the mask of what is not the background uchar *mask = calc_mask(img, w2, h, bg_color); delete[] img; // write the string image to PostScript as a scaled bitmask scale = w2 / float(w); clocale_printf("%g %g %g %g %d %d MI\n", x, y - h*0.77/scale, w2/scale, h/scale, w2, h); uchar *di; int wmask = (w2+7)/8; void *rle85 = prepare_rle85(); for (int j = h - 1; j >= 0; j--){ di = mask + j * wmask; for (int i = 0; i < wmask; i++){ write_rle85(*di, rle85); di++; } } close_rle85(rle85); fputc('\n', output); delete[] mask; } static int is_in_table(unsigned utf) { unsigned i; static unsigned extra_table_roman[] = { // unicodes/*names*/ of other characters from PostScript standard fonts 0x192/*florin*/, 0x2C6/*circumflex*/, 0x2C7/*caron*/, 0x2D8/*breve*/, 0x2D9/*dotaccent*/, 0x2DA/*ring*/, 0x2DB/*ogonek*/, 0x2DC/*tilde*/, 0x2DD/*hungarumlaut*/, 0x2013/*endash*/, 0x2014/*emdash*/, 0x2018/*quoteleft*/, 0x2019/*quoteright*/, 0x201A/*quotesinglbase*/, 0x201C/*quotedblleft*/, 0x201D/*quotedblright*/, 0x201E/*quotedblbase*/, 0x2020/*dagger*/, 0x2021/*daggerdbl*/, 0x2022/*bullet*/, 0x2026/*ellipsis*/, 0x2030/*perthousand*/, 0x2039/*guilsinglleft*/, 0x203A/*guilsinglright*/, 0x2044/*fraction*/, 0x20AC/*Euro*/, 0x2122/*trademark*/, 0x2202/*partialdiff*/, 0x2206/*Delta*/, 0x2211/*summation*/, 0x221A/*radical*/, 0x221E/*infinity*/, 0x2260/*notequal*/, 0x2264/*lessequal*/, 0x2265/*greaterequal*/, 0x25CA/*lozenge*/, 0xFB01/*fi*/, 0xFB02/*fl*/, 0xF8FF/*apple*/ }; for ( i = 0; i < sizeof(extra_table_roman)/sizeof(int); i++) { if (extra_table_roman[i] == utf) return i + 0x180; } return 0; } // outputs in PostScript a UTF8 string using the same width in points as on display void Fl_PostScript_Graphics_Driver::transformed_draw(const char* str, int n, double x, double y) { int len, code; if (!n || !str || !*str) return; // compute display width of string int w = (int)width(str, n); if (w == 0) return; if (Fl_Graphics_Driver::font() >= FL_FREE_FONT) { transformed_draw_extra(str, n, x, y, w, false); return; } fprintf(output, "%d <~", w); void *data = prepare85(); // transforms UTF8 encoding to our custom PostScript encoding as follows: // extract each unicode character // if unicode <= 0x17F, unicode and PostScript codes are identical // if unicode is one of the values listed in extra_table_roman above // its PostScript code is 0x180 + the character's rank in extra_table_roman // if unicode is something else, draw all string as bitmap image const char *last = str + n; const char *str2 = str; while (str2 < last) { // Extract each unicode character of string. unsigned utf = fl_utf8decode(str2, last, &len); str2 += len; if (utf <= 0x17F) { // until Latin Extended-A ; } else if ( (code = is_in_table(utf)) != 0) { // other handled characters utf = code; } else { // unhandled character: draw all string as bitmap image fprintf(output, "~> pop pop\n"); // close and ignore the opened hex string transformed_draw_extra(str, n, x, y, w, false); return; } // 2 bytes per character, high-order byte first, encode that to ASCII85 uchar c[2]; c[1] = utf & 0xFF; c[0] = (utf & 0xFF00)>>8; write85(data, c, 2); } close85(data); clocale_printf(" %g %g show_pos_width\n", x, y); } void Fl_PostScript_Graphics_Driver::rtl_draw(const char* str, int n, int x, int y) { int w = (int)width(str, n); transformed_draw_extra(str, n, x - w, y, w, true); } void Fl_PostScript_Graphics_Driver::concat(){ clocale_printf("[%g %g %g %g %g %g] CT\n", fl_matrix->a , fl_matrix->b , fl_matrix->c , fl_matrix->d , fl_matrix->x , fl_matrix->y); } void Fl_PostScript_Graphics_Driver::reconcat(){ clocale_printf("[%g %g %g %g %g %g] RCT\n" , fl_matrix->a , fl_matrix->b , fl_matrix->c , fl_matrix->d , fl_matrix->x , fl_matrix->y); } ///////////////// transformed (double) drawings //////////////////////////////// void Fl_PostScript_Graphics_Driver::begin_points(){ fprintf(output, "GS\n"); concat(); fprintf(output, "BP\n"); gap_=1; shape_=POINTS; } void Fl_PostScript_Graphics_Driver::begin_line(){ fprintf(output, "GS\n"); concat(); fprintf(output, "BP\n"); gap_=1; shape_=LINE; } void Fl_PostScript_Graphics_Driver::begin_loop(){ fprintf(output, "GS\n"); concat(); fprintf(output, "BP\n"); gap_=1; shape_=LOOP; } void Fl_PostScript_Graphics_Driver::begin_polygon(){ fprintf(output, "GS\n"); concat(); fprintf(output, "BP\n"); gap_=1; shape_=POLYGON; } void Fl_PostScript_Graphics_Driver::vertex(double x, double y){ if(shape_==POINTS){ clocale_printf("%g %g MT\n", x , y); gap_=1; return; } if(gap_){ clocale_printf("%g %g MT\n", x , y); gap_=0; }else clocale_printf("%g %g LT\n", x , y); } void Fl_PostScript_Graphics_Driver::curve(double x, double y, double x1, double y1, double x2, double y2, double x3, double y3){ if(shape_==NONE) return; if(gap_) clocale_printf("%g %g MT\n", x , y); else clocale_printf("%g %g LT\n", x , y); gap_=0; clocale_printf("%g %g %g %g %g %g curveto \n", x1 , y1 , x2 , y2 , x3 , y3); } void Fl_PostScript_Graphics_Driver::circle(double x, double y, double r){ if(shape_==NONE){ fprintf(output, "GS\n"); concat(); // fprintf(output, "BP\n"); clocale_printf("%g %g %g 0 360 arc\n", x , y , r); reconcat(); // fprintf(output, "ELP\n"); fprintf(output, "GR\n"); }else clocale_printf("%g %g %g 0 360 arc\n", x , y , r); } void Fl_PostScript_Graphics_Driver::arc(double x, double y, double r, double start, double a){ if(shape_==NONE) return; gap_=0; if(start>a) clocale_printf("%g %g %g %g %g arc\n", x , y , r , -start, -a); else clocale_printf("%g %g %g %g %g arcn\n", x , y , r , -start, -a); } void Fl_PostScript_Graphics_Driver::arc(int x, int y, int w, int h, double a1, double a2) { if (w <= 1 || h <= 1) return; fprintf(output, "GS\n"); //fprintf(output, "BP\n"); begin_line(); clocale_printf("%g %g TR\n", x + w/2.0 -0.5 , y + h/2.0 - 0.5); clocale_printf("%g %g SC\n", (w-1)/2.0 , (h-1)/2.0 ); arc(0,0,1,a2,a1); // fprintf(output, "0 0 1 %g %g arc\n" , -a1 , -a2); clocale_printf("%g %g SC\n", 2.0/(w-1) , 2.0/(h-1) ); clocale_printf("%g %g TR\n", -x - w/2.0 +0.5 , -y - h/2.0 +0.5); end_line(); // fprintf(output, "%g setlinewidth\n", 2/sqrt(w*h)); // fprintf(output, "ELP\n"); // fprintf(output, 2.0/w , 2.0/w , " SC\n"; // fprintf(output, (-x - w/2.0) , (-y - h/2) , " TR\n"; fprintf(output, "GR\n"); } void Fl_PostScript_Graphics_Driver::pie(int x, int y, int w, int h, double a1, double a2) { fprintf(output, "GS\n"); begin_polygon(); clocale_printf("%g %g TR\n", x + w/2.0 -0.5 , y + h/2.0 - 0.5); clocale_printf("%g %g SC\n", (w-1)/2.0 , (h-1)/2.0 ); vertex(0,0); arc(0.0,0.0, 1, a2, a1); end_polygon(); fprintf(output, "GR\n"); } void Fl_PostScript_Graphics_Driver::end_points(){ gap_=1; reconcat(); fprintf(output, "ELP\n"); //?? fprintf(output, "GR\n"); shape_=NONE; } void Fl_PostScript_Graphics_Driver::end_line(){ gap_=1; reconcat(); fprintf(output, "ELP\n"); fprintf(output, "GR\n"); shape_=NONE; } void Fl_PostScript_Graphics_Driver::end_loop(){ gap_=1; reconcat(); fprintf(output, "ECP\n"); fprintf(output, "GR\n"); shape_=NONE; } void Fl_PostScript_Graphics_Driver::end_polygon(){ gap_=1; reconcat(); fprintf(output, "EFP\n"); fprintf(output, "GR\n"); shape_=NONE; } void Fl_PostScript_Graphics_Driver::transformed_vertex(double x, double y){ reconcat(); if(gap_){ clocale_printf("%g %g MT\n", x , y); gap_=0; }else clocale_printf("%g %g LT\n", x , y); concat(); } ///////////////////////////// Clipping ///////////////////////////////////////////// void Fl_PostScript_Graphics_Driver::push_clip(int x, int y, int w, int h) { Clip * c=new Clip(); clip_box(x,y,w,h,c->x,c->y,c->w,c->h); c->prev=clip_; clip_=c; fprintf(output, "CR\nCS\n"); if(lang_level_<3) recover(); clocale_printf("%g %g %i %i CL\n", clip_->x-0.5 , clip_->y-0.5 , clip_->w , clip_->h); } void Fl_PostScript_Graphics_Driver::push_no_clip() { Clip * c = new Clip(); c->prev=clip_; clip_=c; clip_->x = clip_->y = clip_->w = clip_->h = -1; fprintf(output, "CR\nCS\n"); if(lang_level_<3) recover(); } void Fl_PostScript_Graphics_Driver::pop_clip() { if(!clip_)return; Clip * c=clip_; clip_=clip_->prev; delete c; fprintf(output, "CR\nCS\n"); if(clip_ && clip_->w >0) clocale_printf("%g %g %i %i CL\n", clip_->x - 0.5, clip_->y - 0.5, clip_->w , clip_->h); // uh, -0.5 is to match screen clipping, for floats there should be something beter if(lang_level_<3) recover(); } int Fl_PostScript_Graphics_Driver::clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H){ if(!clip_){ X=x;Y=y;W=w;H=h; return 1; } if(clip_->w < 0){ X=x;Y=y;W=w;H=h; return 1; } int ret=0; if (x > (X=clip_->x)) {X=x; ret=1;} if (y > (Y=clip_->y)) {Y=y; ret=1;} if ((x+w) < (clip_->x+clip_->w)) { W=x+w-X; ret=1; }else W = clip_->x + clip_->w - X; if(W<0){ W=0; return 1; } if ((y+h) < (clip_->y+clip_->h)) { H=y+h-Y; ret=1; }else H = clip_->y + clip_->h - Y; if(H<0){ W=0; H=0; return 1; } return ret; } int Fl_PostScript_Graphics_Driver::not_clipped(int x, int y, int w, int h){ if(!clip_) return 1; if(clip_->w < 0) return 1; int X, Y, W, H; clip_box(x, y, w, h, X, Y, W, H); if(W) return 1; return 0; } void Fl_PostScript_File_Device::margins(int *left, int *top, int *right, int *bottom) // to implement { Fl_PostScript_Graphics_Driver *ps = driver(); if(left) *left = (int)(ps->left_margin / ps->scale_x + .5); if(right) *right = (int)(ps->left_margin / ps->scale_x + .5); if(top) *top = (int)(ps->top_margin / ps->scale_y + .5); if(bottom) *bottom = (int)(ps->top_margin / ps->scale_y + .5); } int Fl_PostScript_File_Device::printable_rect(int *w, int *h) //returns 0 iff OK { Fl_PostScript_Graphics_Driver *ps = driver(); if(w) *w = (int)((ps->pw_ - 2 * ps->left_margin) / ps->scale_x + .5); if(h) *h = (int)((ps->ph_ - 2 * ps->top_margin) / ps->scale_y + .5); return 0; } void Fl_PostScript_File_Device::origin(int *x, int *y) { Fl_Paged_Device::origin(x, y); } void Fl_PostScript_File_Device::origin(int x, int y) { x_offset = x; y_offset = y; Fl_PostScript_Graphics_Driver *ps = driver(); ps->clocale_printf("GR GR GS %d %d TR %f %f SC %d %d TR %f rotate GS\n", ps->left_margin, ps->top_margin, ps->scale_x, ps->scale_y, x, y, ps->angle); } void Fl_PostScript_File_Device::scale (float s_x, float s_y) { if (s_y == 0.) s_y = s_x; Fl_PostScript_Graphics_Driver *ps = driver(); ps->scale_x = s_x; ps->scale_y = s_y; ps->clocale_printf("GR GR GS %d %d TR %f %f SC %f rotate GS\n", ps->left_margin, ps->top_margin, ps->scale_x, ps->scale_y, ps->angle); } void Fl_PostScript_File_Device::rotate (float rot_angle) { Fl_PostScript_Graphics_Driver *ps = driver(); ps->angle = - rot_angle; ps->clocale_printf("GR GR GS %d %d TR %f %f SC %d %d TR %f rotate GS\n", ps->left_margin, ps->top_margin, ps->scale_x, ps->scale_y, x_offset, y_offset, ps->angle); } void Fl_PostScript_File_Device::translate(int x, int y) { fprintf(driver()->output, "GS %d %d translate GS\n", x, y); } void Fl_PostScript_File_Device::untranslate(void) { fprintf(driver()->output, "GR GR\n"); } int Fl_PostScript_File_Device::start_page (void) { Fl_PostScript_Graphics_Driver *ps = driver(); ps->page(ps->page_format_); x_offset = 0; y_offset = 0; ps->scale_x = ps->scale_y = 1.; ps->angle = 0; fprintf(ps->output, "GR GR GS %d %d translate GS\n", ps->left_margin, ps->top_margin); return 0; } int Fl_PostScript_File_Device::end_page (void) { return 0; } void Fl_PostScript_File_Device::end_job (void) // finishes PostScript & closes file { Fl_PostScript_Graphics_Driver *ps = driver(); if (ps->nPages) { // for eps nPages is 0 so it is fine .... fprintf(ps->output, "CR\nGR\nGR\nGR\nSP\n restore\n"); if (!ps->pages_){ fprintf(ps->output, "%%%%Trailer\n"); fprintf(ps->output, "%%%%Pages: %i\n" , ps->nPages); }; } else fprintf(ps->output, "GR\n restore\n"); fputs("%%EOF",ps->output); ps->reset(); fflush(ps->output); if(ferror(ps->output)) { fl_alert ("Error during PostScript data output."); } if (ps->close_cmd_) { (*ps->close_cmd_)(ps->output); } else { fclose(ps->output); } while (ps->clip_){ Fl_PostScript_Graphics_Driver::Clip * c= ps->clip_; ps->clip_= ps->clip_->prev; delete c; } Fl_Display_Device::display_device()->set_current(); } #endif // FL_DOXYGEN #if ! (defined(__APPLE__) || defined(WIN32) ) /** Starts a print job. */ int Fl_PostScript_Printer::start_job(int pages, int *firstpage, int *lastpage) { enum Fl_Paged_Device::Page_Format format; enum Fl_Paged_Device::Page_Layout layout; // first test version for print dialog if (!print_panel) make_print_panel(); printing_style style = print_load(); print_selection->deactivate(); print_all->setonly(); print_all->do_callback(); print_from->value("1"); { char tmp[10]; snprintf(tmp, sizeof(tmp), "%d", pages); print_to->value(tmp); } print_panel->show(); // this is modal while (print_panel->shown()) Fl::wait(); if (!print_start) // user clicked cancel return 1; // get options switch (print_page_size->value()) { case 0: format = Fl_Paged_Device::LETTER; break; case 2: format = Fl_Paged_Device::LEGAL; break; case 3: format = Fl_Paged_Device::EXECUTIVE; break; case 4: format = Fl_Paged_Device::A3; break; case 5: format = Fl_Paged_Device::A5; break; case 6: format = Fl_Paged_Device::B5; break; case 7: format = Fl_Paged_Device::ENVELOPE; break; case 8: format = Fl_Paged_Device::DLE; break; default: format = Fl_Paged_Device::A4; } { // page range choice int from = 1, to = pages; if (print_pages->value()) { sscanf(print_from->value(), "%d", &from); sscanf(print_to->value(), "%d", &to); } if (from < 1) from = 1; if (to > pages) to = pages; if (to < from) to = from; if (firstpage) *firstpage = from; if (lastpage) *lastpage = to; if (pages > 0) pages = to - from + 1; } if (print_output_mode[0]->value()) layout = Fl_Paged_Device::PORTRAIT; else if (print_output_mode[1]->value()) layout = Fl_Paged_Device::LANDSCAPE; else if (print_output_mode[2]->value()) layout = Fl_Paged_Device::PORTRAIT; else layout = Fl_Paged_Device::LANDSCAPE; int print_pipe = print_choice->value(); // 0 = print to file, >0 = printer (pipe) const char *media = print_page_size->text(print_page_size->value()); const char *printer = (const char *)print_choice->menu()[print_choice->value()].user_data(); if (!print_pipe) printer = "<File>"; if (!print_pipe) // fall back to file printing return Fl_PostScript_File_Device::start_job (pages, format, layout); // Print: pipe the output into the lp command... char command[1024]; if (style == SystemV) snprintf(command, sizeof(command), "lp -s -d %s -n %d -t '%s' -o media=%s", printer, print_collate_button->value() ? 1 : (int)(print_copies->value() + 0.5), "FLTK", media); else snprintf(command, sizeof(command), "lpr -h -P%s -#%d -T FLTK ", printer, print_collate_button->value() ? 1 : (int)(print_copies->value() + 0.5)); Fl_PostScript_Graphics_Driver *ps = driver(); ps->output = popen(command, "w"); if (!ps->output) { fl_alert("could not run command: %s\n",command); return 1; } ps->close_command(pclose); this->set_current(); return ps->start_postscript(pages, format, layout); // start printing } #endif // ! (defined(__APPLE__) || defined(WIN32) ) // // End of "$Id$". //