summaryrefslogtreecommitdiff
path: root/src/drivers
diff options
context:
space:
mode:
authorManolo Gouy <Manolo>2016-02-26 15:24:08 +0000
committerManolo Gouy <Manolo>2016-02-26 15:24:08 +0000
commitcf4825eedf9ee529cd99e8b99b69cdd3ec6ffb69 (patch)
tree147599508534f4db9a34b439ba6c0611e07094a2 /src/drivers
parent53993d4bd1476e6d7700b13a2ca0e1d489a740d4 (diff)
Move PostScript-support files to src/drivers/PostScript/
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3-porting@11222 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/PostScript/Fl_PostScript.cxx1667
-rw-r--r--src/drivers/PostScript/Fl_PostScript_image.cxx674
2 files changed, 2341 insertions, 0 deletions
diff --git a/src/drivers/PostScript/Fl_PostScript.cxx b/src/drivers/PostScript/Fl_PostScript.cxx
new file mode 100644
index 000000000..465ed90f2
--- /dev/null
+++ b/src/drivers/PostScript/Fl_PostScript.cxx
@@ -0,0 +1,1667 @@
+//
+// "$Id$"
+//
+// PostScript device support for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 2010-2016 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
+
+/** \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)
+{
+ 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, ...)
+{
+#ifdef FL_PORTING
+# pragma message "FL_PORTING: must define LC_NUMERIC"
+ va_list args;
+ va_start(args, format);
+ int retval = vfprintf(output, format, args);
+ va_end(args);
+ return retval;
+#else
+ 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;
+#endif
+}
+
+#ifndef FL_DOXYGEN
+
+#if ! (defined(__APPLE__) || defined(WIN32) ) // PORTME: Fl_Surface_Driver - platform PostScript
+# include <src/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__) // PORTME: Fl_Surface_Driver ? - platform PostScript
+#elif defined(WIN32)
+#elif defined(FL_PORTING)
+# pragma message "FL_PORTING: implement postscript printing"
+#else // X11
+/** 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) ) // PORTME: Fl_Surface_Driver - platform PostScript
+
+
+//
+// End of "$Id$".
+//
diff --git a/src/drivers/PostScript/Fl_PostScript_image.cxx b/src/drivers/PostScript/Fl_PostScript_image.cxx
new file mode 100644
index 000000000..f6a118485
--- /dev/null
+++ b/src/drivers/PostScript/Fl_PostScript_image.cxx
@@ -0,0 +1,674 @@
+//
+// "$Id: image.cxx 4324 2005-05-09 21:47:22Z rokan $"
+//
+// Postscript image drawing implementation for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-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 on the following page:
+//
+// http://www.fltk.org/str.php
+//
+
+#ifndef FL_DOXYGEN
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+#include <FL/Fl_PostScript.H>
+#include <FL/Fl.H>
+#include <FL/Fl_Pixmap.H>
+#include <FL/Fl_Bitmap.H>
+
+
+//
+// Implementation of the /ASCII85Encode PostScript filter
+// as described in "PostScript LANGUAGE REFERENCE third edition" p. 131
+//
+struct struct85 {
+ uchar bytes4[4]; // holds up to 4 input bytes
+ int l4; // # of unencoded input bytes
+ int blocks; // counter to insert newlines after 80 output characters
+ uchar chars5[5]; // holds 5 output characters
+};
+
+
+void *Fl_PostScript_Graphics_Driver::prepare85() // prepare to produce ASCII85-encoded output
+{
+ struct85 *big = new struct85;
+ big->l4 = 0;
+ big->blocks = 0;
+ return big;
+}
+
+// ASCII85-encodes 4 input bytes from bytes4 into chars5 array
+// returns # of output chars
+static int convert85(const uchar *bytes4, uchar *chars5)
+{
+ if (bytes4[0] == 0 && bytes4[1] == 0 && bytes4[2] == 0 && bytes4[3] == 0) {
+ chars5[0] = 'z';
+ return 1;
+ }
+ unsigned val = bytes4[0]*(256*256*256) + bytes4[1]*(256*256) + bytes4[2]*256 + bytes4[3];
+ chars5[0] = val / 52200625 + 33; // 52200625 = 85 to the 4th
+ val = val % 52200625;
+ chars5[1] = val / 614125 + 33; // 614125 = 85 cube
+ val = val % 614125;
+ chars5[2] = val / 7225 + 33; // 7225 = 85 squared
+ val = val % 7225;
+ chars5[3] = val / 85 + 33;
+ chars5[4] = val % 85 + 33;
+ return 5;
+}
+
+
+void Fl_PostScript_Graphics_Driver::write85(void *data, const uchar *p, int len) // sends len input bytes for ASCII85 encoding
+{
+ struct85 *big = (struct85 *)data;
+ const uchar *last = p + len;
+ while (p < last) {
+ int c = 4 - big->l4;
+ if (last-p < c) c = last-p;
+ memcpy(big->bytes4 + big->l4, p, c);
+ p += c;
+ big->l4 += c;
+ if (big->l4 == 4) {
+ c = convert85(big->bytes4, big->chars5);
+ fwrite(big->chars5, c, 1, output);
+ big->l4 = 0;
+ if (++big->blocks >= 16) { fputc('\n', output); big->blocks = 0; }
+ }
+ }
+}
+
+
+void Fl_PostScript_Graphics_Driver::close85(void *data) // stops ASCII85-encoding after processing remaining unencoded input bytes, if any
+{
+ struct85 *big = (struct85 *)data;
+ int l;
+ if (big->l4) { // # of remaining unencoded input bytes
+ l = big->l4;
+ while (l < 4) big->bytes4[l++] = 0; // complete them with 0s
+ l = convert85(big->bytes4, big->chars5); // encode them
+ if (l == 1) memset(big->chars5, '!', 5);
+ fwrite(big->chars5, big->l4 + 1, 1, output);
+ }
+ fputs("~>", output); // write EOD mark
+ delete big;
+}
+
+//
+// End of implementation of the /ASCII85Encode PostScript filter
+//
+
+//
+// Implementation of the /RunLengthEncode + /ASCII85Encode PostScript filter
+// as described in "PostScript LANGUAGE REFERENCE third edition" p. 142
+//
+
+struct struct_rle85 {
+ struct85 *data85; // aux data for ASCII85 encoding
+ uchar buffer[128]; // holds non-run data
+ int count; // current buffer length
+ int run_length; // current length of run
+};
+
+void *Fl_PostScript_Graphics_Driver::prepare_rle85() // prepare to produce RLE+ASCII85-encoded output
+{
+ struct_rle85 *rle = new struct_rle85;
+ rle->count = 0;
+ rle->run_length = 0;
+ rle->data85 = (struct85*)prepare85();
+ return rle;
+}
+
+
+void Fl_PostScript_Graphics_Driver::write_rle85(uchar b, void *data) // sends one input byte to RLE+ASCII85 encoding
+{
+ struct_rle85 *rle = (struct_rle85 *)data;
+ uchar c;
+ if (rle->run_length > 0) { // if within a run
+ if (b == rle->buffer[0] && rle->run_length < 128) { // the run can be extended
+ rle->run_length++;
+ return;
+ } else { // output the run
+ c = (uchar)(257 - rle->run_length);
+ write85(rle->data85, &c, 1); // the run-length info
+ write85(rle->data85, rle->buffer, 1); // the byte of the run
+ rle->run_length = 0;
+ }
+ }
+ if (rle->count >= 2 && b == rle->buffer[rle->count-1] && b == rle->buffer[rle->count-2]) {
+ // about to begin a run
+ if (rle->count > 2) { // there is non-run data before the run in the buffer
+ c = (uchar)(rle->count-2 - 1);
+ write85(rle->data85, &c, 1); // length of non-run data
+ write85(rle->data85, rle->buffer, rle->count-2); // non-run data
+ }
+ rle->run_length = 3;
+ rle->buffer[0] = b;
+ rle->count = 0;
+ return;
+ }
+ if (rle->count >= 128) { // the non-run buffer is full, output it
+ c = (uchar)(rle->count - 1);
+ write85(rle->data85, &c, 1); // length of non-run data
+ write85(rle->data85, rle->buffer, rle->count); // non-run data
+ rle->count = 0;
+ }
+ rle->buffer[rle->count++] = b; // add byte to end of non-run buffer
+}
+
+
+void Fl_PostScript_Graphics_Driver::close_rle85(void *data) // stop doing RLE+ASCII85 encoding
+{
+ struct_rle85 *rle = (struct_rle85 *)data;
+ uchar c;
+ if (rle->run_length > 0) { // if within a run, output it
+ c = (uchar)(257 - rle->run_length);
+ write85(rle->data85, &c, 1);
+ write85(rle->data85, rle->buffer, 1);
+ } else if (rle->count) { // output the non-run buffer, if not empty
+ c = (uchar)(rle->count - 1);
+ write85(rle->data85, &c, 1);
+ write85(rle->data85, rle->buffer, rle->count);
+ }
+ c = (uchar)128;
+ write85(rle->data85, &c, 1); // output EOD mark
+ close85(rle->data85); // close ASCII85 encoding process
+ delete rle;
+}
+
+//
+// End of implementation of the /RunLengthEncode + /ASCII85Encode PostScript filter
+//
+
+
+int Fl_PostScript_Graphics_Driver::alpha_mask(const uchar * data, int w, int h, int D, int LD){
+
+ mask = 0;
+ if ((D/2)*2 != D){ //no mask info
+ return 0;
+ }
+ int xx;
+ int i,j, k, l;
+ LD += w*D;
+ int V255=0;
+ int V0 =0;
+ int V_=0;
+ for (j=0;j<h;j++){
+ for (i=0;i<w;i++)
+ switch(data[j*LD+D*i+D-1]){
+ case 255: V255 = 1; break;
+ case 0: V0 = 1; break;
+ default: V_= 1;
+ }
+ if (V_) break;
+ };
+ if (!V_){
+ if (V0)
+ if (V255){// not true alpha, only masking
+ xx = (w+7)/8;
+ mask = new uchar[h * xx];
+ for (i=0;i<h * xx;i++) mask[i]=0;
+ for (j=0;j<h;j++)
+ for (i=0;i<w;i++)
+ if (data[j*LD+D*i+D-1])
+ mask[j*xx+i/8] |= 1 << (i % 8);
+ mx = w;
+ my = h; //mask imensions
+ return 0;
+ } else {
+ mask=0;
+ return 1; //everything masked
+ }
+ else
+ return 0;
+ }
+
+
+
+ ///// Alpha dither, generating (4*w) * 4 mask area /////
+ ///// with Floyd-Steinberg error diffusion /////
+
+ mask = new uchar[((w+1)/2) * h * 4];
+
+ for (i = 0; i<((w+1)/2) * h * 4; i++) mask[i] = 0; //cleaning
+
+
+
+ mx= w*4;
+ my=h*4; // mask dimensions
+
+ xx = (w+1)/2; // mask line width in bytes
+
+ short * errors1 = new short [w*4+2]; // two rows of dither errors
+ short * errors2 = new short [w*4+2]; // two rows of dither errors
+
+ for (i=0; i<w*4+2; i++) errors2[i] = 0; // cleaning,after first swap will become current
+ for (i=0; i<w*4+2; i++) errors1[i] = 0; // cleaning,after first swap will become current
+
+ short * current = errors1;
+ short * next = errors2;
+ short * swap;
+
+ for (j=0; j<h; j++){
+ for (l=0; l<4; ){ // generating 4 rows of mask lines for 1 RGB line
+ int jj = j*4+l;
+
+ /// mask row index
+ swap = next;
+ next = current;
+ current = swap;
+ *(next+1) = 0; // must clean the first cell, next are overriden by *1
+ for (i=0; i<w; i++){
+ for (k=0; k<4; k++){ // generating 4 x-pixels for 1 RGB
+ short error, o1, o2, o3;
+ int ii = i*4+k; // mask cell index
+ short val = data[j*LD+D*i+D-1] + current[1+ii];
+ if (val>127){
+ mask[jj*xx+ii/8] |= 1 << (ii % 8); //set mask bit
+ error = val-255;
+ }else
+ error = val;
+
+ ////// error spreading /////
+ if (error >0){
+ next[ii] += o1 = (error * 3 + 8)/16;
+ current[ii+2] += o2 = (error * 7 + 8)/16;
+ next[ii+2] = o3 =(error + 8)/16; // *1 - ok replacing (cleaning)
+ } else {
+ next[ii] += o1 = (error * 3 - 8)/16;
+ current[ii+2] += o2 = (error * 7 - 8)/16;
+ next[ii+2] = o3 = (error - 8)/16;
+ }
+ next[1+ii] += error - o1 - o2 - o3;
+ }
+ }
+ l++;
+
+ ////// backward
+
+ jj = j*4+l;
+ swap = next;
+ next = current;
+ current = swap;
+ *(next+1) = 0; // must clean the first cell, next are overriden by *1
+
+ for (i = w-1; i >= 0; i--){
+
+ for (k=3; k>=0; k--){ // generating 4 x-pixels for 1 RGB
+ short error, o1, o2, o3;
+
+ int ii = i*4+k; // mask cell index
+ short val = data[j*LD+D*i+D-1] + current[1+ii];
+ if (val>127){
+
+ mask[jj*xx+ii/8] |= 1 << (ii % 8); //set mask bit
+ error = val-255;
+ } else
+ error = val;
+
+ ////// error spreading /////
+ if (error >0){
+ next[ii+2] += o1 = (error * 3 + 8)/16;
+ current[ii] += o2 = (error * 7 + 8)/16;
+ next[ii] = o3 =(error + 8)/16; // *1 - ok replacing (cleaning)
+ } else {
+ next[ii+2] += o1 = (error * 3 - 8)/16;
+
+ current[ii] += o2 = (error * 7 - 8)/16;
+ next[ii] = o3 = (error - 8)/16;
+ }
+ next[1+ii] += error - o1 - o2 - o3;
+ }
+ }
+ l++;
+ }
+ }
+ delete[] errors1;
+ delete[] errors2;
+ return 0;
+}
+
+// bitwise inversion of all 4-bit quantities
+static const unsigned char swapped[16] = {0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15};
+
+// bitwise inversion of a byte
+static inline uchar swap_byte(const uchar b) {
+ return (swapped[b & 0xF] << 4) | swapped[b >> 4];
+}
+
+
+struct callback_data {
+ const uchar *data;
+ int D, LD;
+};
+
+
+static void draw_image_cb(void *data, int x, int y, int w, uchar *buf) {
+ struct callback_data *cb_data;
+ const uchar *curdata;
+
+ cb_data = (struct callback_data*)data;
+ curdata = cb_data->data + x*cb_data->D + y*cb_data->LD;
+
+ memcpy(buf, curdata, w*cb_data->D);
+}
+
+
+void Fl_PostScript_Graphics_Driver::draw_image(const uchar *data, int ix, int iy, int iw, int ih, int D, int LD) {
+ if (D<3){ //mono
+ draw_image_mono(data, ix, iy, iw, ih, D, LD);
+ return;
+ }
+
+ struct callback_data cb_data;
+
+ if (!LD) LD = iw*D;
+
+ cb_data.data = data;
+ cb_data.D = D;
+ cb_data.LD = LD;
+
+ draw_image(draw_image_cb, &cb_data, ix, iy, iw, ih, D);
+}
+
+void Fl_PostScript_Graphics_Driver::draw_image(Fl_Draw_Image_Cb call, void *data, int ix, int iy, int iw, int ih, int D) {
+ double x = ix, y = iy, w = iw, h = ih;
+
+ int level2_mask = 0;
+ fprintf(output,"save\n");
+ int i,j,k;
+ const char * interpol;
+ if (lang_level_ > 1) {
+ if (interpolate_) interpol="true";
+ else interpol="false";
+ if (mask && lang_level_ > 2) {
+ fprintf(output, "%g %g %g %g %i %i %i %i %s CIM\n", x , y+h , w , -h , iw , ih, mx, my, interpol);
+ }
+ else if (mask && lang_level_ == 2) {
+ level2_mask = 1; // use method for drawing masked color image with PostScript level 2
+ fprintf(output, " %g %g %g %g %d %d pixmap_plot\n", x, y, w, h, iw, ih);
+ }
+ else {
+ fprintf(output, "%g %g %g %g %i %i %s CII\n", x , y+h , w , -h , iw , ih, interpol);
+ }
+ } else {
+ fprintf(output , "%g %g %g %g %i %i CI", x , y+h , w , -h , iw , ih);
+ }
+
+ int LD=iw*D;
+ uchar *rgbdata=new uchar[LD];
+ uchar *curmask=mask;
+ void *big = prepare_rle85();
+
+ if (level2_mask) {
+ for (j = ih - 1; j >= 0; j--) { // output full image data
+ call(data, 0, j, iw, rgbdata);
+ uchar *curdata = rgbdata;
+ for (i=0 ; i<iw ; i++) {
+ write_rle85(curdata[0], big); write_rle85(curdata[1], big); write_rle85(curdata[2], big);
+ curdata += D;
+ }
+ }
+ close_rle85(big); fputc('\n', output);
+ big = prepare_rle85();
+ for (j = ih - 1; j >= 0; j--) { // output mask data
+ curmask = mask + j * (my/ih) * ((mx+7)/8);
+ for (k=0; k < my/ih; k++) {
+ for (i=0; i < ((mx+7)/8); i++) {
+ write_rle85(swap_byte(*curmask), big);
+ curmask++;
+ }
+ }
+ }
+ }
+ else {
+ for (j=0; j<ih;j++) {
+ if (mask && lang_level_ > 2) { // InterleaveType 2 mask data
+ for (k=0; k<my/ih;k++) { //for alpha pseudo-masking
+ for (i=0; i<((mx+7)/8);i++) {
+ write_rle85(swap_byte(*curmask), big);
+ curmask++;
+ }
+ }
+ }
+ call(data,0,j,iw,rgbdata);
+ uchar *curdata=rgbdata;
+ for (i=0 ; i<iw ; i++) {
+ uchar r = curdata[0];
+ uchar g = curdata[1];
+ uchar b = curdata[2];
+
+ if (lang_level_<3 && D>3) { //can do mixing using bg_* colors)
+ unsigned int a2 = curdata[3]; //must be int
+ unsigned int a = 255-a2;
+ r = (a2 * r + bg_r * a)/255;
+ g = (a2 * g + bg_g * a)/255;
+ b = (a2 * b + bg_b * a)/255;
+ }
+
+ write_rle85(r, big); write_rle85(g, big); write_rle85(b, big);
+ curdata +=D;
+ }
+
+ }
+ }
+ close_rle85(big);
+ fprintf(output,"\nrestore\n");
+ delete[] rgbdata;
+}
+
+void Fl_PostScript_Graphics_Driver::draw_image_mono(const uchar *data, int ix, int iy, int iw, int ih, int D, int LD) {
+ double x = ix, y = iy, w = iw, h = ih;
+
+ fprintf(output,"save\n");
+
+ int i,j, k;
+
+ const char * interpol;
+ if (lang_level_>1){
+ if (interpolate_)
+ interpol="true";
+ else
+ interpol="false";
+ if (mask && lang_level_>2)
+ fprintf(output, "%g %g %g %g %i %i %i %i %s GIM\n", x , y+h , w , -h , iw , ih, mx, my, interpol);
+ else
+ fprintf(output, "%g %g %g %g %i %i %s GII\n", x , y+h , w , -h , iw , ih, interpol);
+ }else
+ fprintf(output , "%g %g %g %g %i %i GI", x , y+h , w , -h , iw , ih);
+
+
+ if (!LD) LD = iw*D;
+
+
+ int bg = (bg_r + bg_g + bg_b)/3;
+
+ uchar *curmask=mask;
+ void *big = prepare_rle85();
+ for (j=0; j<ih;j++){
+ if (mask){
+ for (k=0;k<my/ih;k++){
+ for (i=0; i<((mx+7)/8);i++){
+ write_rle85(swap_byte(*curmask), big);
+ curmask++;
+ }
+ }
+ }
+ const uchar *curdata=data+j*LD;
+ for (i=0 ; i<iw ; i++) {
+ uchar r = curdata[0];
+ if (lang_level_<3 && D>1) { //can do mixing
+
+ unsigned int a2 = curdata[1]; //must be int
+ unsigned int a = 255-a2;
+ r = (a2 * r + bg * a)/255;
+ }
+ write_rle85(r, big);
+ curdata +=D;
+ }
+
+ }
+ close_rle85(big);
+ fprintf(output,"restore\n");
+}
+
+
+
+void Fl_PostScript_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb call, void *data, int ix, int iy, int iw, int ih, int D) {
+ double x = ix, y = iy, w = iw, h = ih;
+
+ fprintf(output,"save\n");
+ int i,j,k;
+ const char * interpol;
+ if (lang_level_>1){
+ if (interpolate_) interpol="true";
+ else interpol="false";
+ if (mask && lang_level_>2)
+ fprintf(output, "%g %g %g %g %i %i %i %i %s GIM\n", x , y+h , w , -h , iw , ih, mx, my, interpol);
+ else
+ fprintf(output, "%g %g %g %g %i %i %s GII\n", x , y+h , w , -h , iw , ih, interpol);
+ } else
+ fprintf(output , "%g %g %g %g %i %i GI", x , y+h , w , -h , iw , ih);
+
+ int LD=iw*D;
+ uchar *rgbdata=new uchar[LD];
+ uchar *curmask=mask;
+ void *big = prepare_rle85();
+ for (j=0; j<ih;j++){
+
+ if (mask && lang_level_>2){ // InterleaveType 2 mask data
+ for (k=0; k<my/ih;k++){ //for alpha pseudo-masking
+ for (i=0; i<((mx+7)/8);i++){
+ write_rle85(swap_byte(*curmask), big);
+ curmask++;
+ }
+ }
+ }
+ call(data,0,j,iw,rgbdata);
+ uchar *curdata=rgbdata;
+ for (i=0 ; i<iw ; i++) {
+ write_rle85(curdata[0], big);
+ curdata +=D;
+ }
+ }
+ close_rle85(big);
+ fprintf(output,"restore\n");
+ delete[] rgbdata;
+}
+
+
+////////////////////////////// Image classes //////////////////////
+
+
+void Fl_PostScript_Graphics_Driver::draw(Fl_Pixmap * pxm,int XP, int YP, int WP, int HP, int cx, int cy){
+ const char * const * di =pxm->data();
+ int w,h;
+ if (!fl_measure_pixmap(di, w, h)) return;
+ mask=0;
+ mask_bitmap(&mask);
+ mx = WP;
+ my = HP;
+ push_clip(XP, YP, WP, HP);
+ fl_draw_pixmap(di,XP -cx, YP -cy, FL_BLACK );
+ pop_clip();
+ delete[] mask;
+ mask=0;
+ mask_bitmap(0);
+}
+
+void Fl_PostScript_Graphics_Driver::draw(Fl_RGB_Image * rgb,int XP, int YP, int WP, int HP, int cx, int cy){
+ const uchar * di = rgb->array;
+ int w = rgb->w();
+ int h = rgb->h();
+ mask=0;
+ if (lang_level_>2) //when not true, not making alphamask, mixing colors instead...
+ if (alpha_mask(di, w, h, rgb->d(),rgb->ld())) return; //everthing masked, no need for painting!
+ push_clip(XP, YP, WP, HP);
+ draw_image(di, XP + cx, YP + cy, w, h, rgb->d(), rgb->ld());
+ pop_clip();
+ delete[]mask;
+ mask=0;
+}
+
+int Fl_PostScript_Graphics_Driver::draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP){
+ int X, Y, W, H;
+ clip_box(XP,YP,WP,HP,X,Y,W,H); // X,Y,W,H will give the unclipped area of XP,YP,WP,HP
+ if (W == 0 || H == 0) return 1;
+ push_no_clip(); // remove the FLTK clip that can't be rescaled
+ clocale_printf("%d %d %i %i CL\n", X, Y, W, H);
+ clocale_printf("GS %d %d TR %f %f SC GS\n", XP, YP, float(WP)/img->w(), float(HP)/img->h());
+ img->draw(0, 0, img->w(), img->h(), 0, 0);
+ clocale_printf("GR GR\n");
+ pop_clip(); // restore FLTK's clip
+ return 1;
+}
+
+void Fl_PostScript_Graphics_Driver::draw(Fl_Bitmap * bitmap,int XP, int YP, int WP, int HP, int cx, int cy){
+ const uchar * di = bitmap->array;
+ int w,h;
+ int LD=(bitmap->w()+7)/8;
+ int xx;
+
+ if (WP> bitmap->w() - cx){// to assure that it does not go out of bounds;
+ w = bitmap->w() - cx;
+ xx = (bitmap->w()+7)/8 - cx/8; //length of mask in bytes
+ }else{
+ w =WP;
+ xx = (w+7)/8 - cx/8;
+ }
+ if ( HP > bitmap->h()-cy)
+ h = bitmap->h() - cy;
+ else
+ h = HP;
+
+ di += cy*LD + cx/8;
+ int si = cx % 8; // small shift to be clipped, it is simpler than shifting whole mask
+
+ int i,j;
+ push_clip(XP, YP, WP, HP);
+ fprintf(output , "%i %i %i %i %i %i MI\n", XP - si, YP + HP , WP , -HP , w , h);
+
+ void *rle85 = prepare_rle85();
+ for (j=0; j<HP; j++){
+ for (i=0; i<xx; i++){
+ write_rle85(swap_byte(*di), rle85);
+ di++;
+ }
+ }
+ close_rle85(rle85); fputc('\n', output);
+ pop_clip();
+}
+
+#endif // FL_DOXYGEN
+
+//
+// End of "$Id: image.cxx 4324 2005-05-09 21:47:22Z rokan $"
+//
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+