core/vul/vul_psfile.cxx
Go to the documentation of this file.
00001 // This is core/vul/vul_psfile.cxx
00002 #include "vul_psfile.h"
00003 //:
00004 // \file
00005 
00006 #include <vcl_cmath.h>
00007 #include <vcl_iostream.h>
00008 #include <vcl_iomanip.h> // for setw()
00009 #include <vcl_algorithm.h> // for vcl_min()
00010 #include <vcl_cassert.h>
00011 
00012 #define RANGE(a,b,c) { if (a < b) a = b;  if (a > c) a = c; }
00013 #define in_range(a) (a < 0x100)
00014 #define Hex4bit(a) ((char)((a<=9) ? (a+'0') : (a - 10 + 'a')))
00015 
00016 static const float PIX2INCH = 72.0f;
00017 static bool debug = true;
00018 
00019 // sizes of pages in inches
00020 static double paper_size[8][2] = {
00021   { 8.500, 11.000}, // US NORMAL
00022   { 8.268, 11.693}, // A4 210mm x 297mm
00023   { 7.205, 10.118}, // B5 183mm x 257mm
00024   {11.693, 16.535}, // A3 297mm x 420mm
00025   { 8.500, 14.000}, // US LEGAL
00026   {11.000, 17.000}, // B-size
00027   { 3.875,  4.875}, // 4 by 5
00028   { 0.945,  1.417}  // 35mm (24x36)
00029 };
00030 
00031 // size of l+r margin and t+b margin.  image is centered
00032 static double margins[8 ][2] = {
00033   { 1.000, 1.000}, // US NORMAL
00034   { 1.000, 1.000}, // A4
00035   { 1.000, 1.000}, // B5
00036   { 1.000, 1.000}, // A3
00037   { 1.000, 1.000}, // US LEGAL
00038   { 1.000, 1.000}, // B-size
00039   { 0.275, 0.275}, // 4 by 5
00040   { 0.078, 0.078}  // 35mm (24x36)
00041 };
00042 
00043 // min and max value for PostScript paper size
00044 static float ps_minimum = 0.1f;
00045 static float ps_maximum = 8.f;
00046 
00047 static const vcl_streampos HEADER_START(-1);
00048 
00049 //-----------------------------------------------------------------------------
00050 //: Default constructor.
00051 //-----------------------------------------------------------------------------
00052 vul_psfile::vul_psfile(char const* f, bool dbg)
00053   : output_filestream(f),
00054     fg_r(0), fg_g(0), fg_b(0),
00055     bg_r(1), bg_g(1), bg_b(1),
00056     line_width_(1),
00057     scale_x(1.f), scale_y(1.f),
00058     ox(0), oy(0), iw(0), ih(0),
00059     iwf(1.0), ihf(1.0),
00060     psizex(8.5), psizey(11),
00061     pos_inx(4.25), pos_iny(5.5),
00062     width(0), height(0),
00063     filename(f),
00064     printer_paper_type(vul_psfile::US_NORMAL),
00065     printer_paper_orientation(vul_psfile::PORTRAIT),
00066     printer_paper_layout(vul_psfile::CENTER),
00067     reduction_factor(1),
00068     doneps(false),
00069     min_x(1000), min_y(1000),
00070     max_x(-1000), max_y(-1000),
00071     box_width(0), box_height(0),
00072     translate_pos(-1L),
00073     sobj_t_pos(-1L),
00074     header_pos(HEADER_START),
00075     graphics_prolog_exists(false),
00076     exist_image(false),
00077     exist_objs (false)
00078 {
00079   debug = dbg;
00080   if (debug) vcl_cout << "vul_psfile::vul_psfile\n";
00081   postscript_header();
00082 }
00083 
00084 //-----------------------------------------------------------------------------
00085 //: Destructor
00086 //-----------------------------------------------------------------------------
00087 vul_psfile::~vul_psfile()
00088 {
00089   if (debug) vcl_cout << "vul_psfile::~vul_psfile\n";
00090   reset_bounding_box();
00091   if (!doneps)
00092     done();
00093 }
00094 
00095 
00096 //-----------------------------------------------------------------------------
00097 //: Rewrite output bounding box parameters.
00098 //-----------------------------------------------------------------------------
00099 void vul_psfile::reset_bounding_box()
00100 {
00101   vcl_streampos temp_pos;
00102   temp_pos = output_filestream.tellp();
00103 
00104   if (exist_image)
00105   {
00106     // for image part
00107     output_filestream.seekp(translate_pos);
00108     image_translate_and_scale();
00109   }
00110   if (exist_objs)
00111   {
00112     // For Object part.
00113     output_filestream.seekp(sobj_t_pos);
00114     object_translate_and_scale();
00115   }
00116 
00117   // reset Bounding Box parameters (the fourth line).
00118   output_filestream.seekp(header_pos);
00119   reset_postscript_header();
00120   output_filestream.seekp(temp_pos);
00121 }
00122 
00123 //-----------------------------------------------------------------------------
00124 //: Recalculate bounding box and scale x and y (if necessary).
00125 //-----------------------------------------------------------------------------
00126 void vul_psfile::compute_bounding_box()
00127 {
00128   box_width  = max_x - min_x;
00129   box_height = max_y - min_y;
00130 
00131   if (printer_paper_orientation == vul_psfile::LANDSCAPE)
00132   {
00133     psizex = paper_size[printer_paper_type][1];
00134     psizey = paper_size[printer_paper_type][0];
00135   }
00136   else
00137   {
00138     psizex = paper_size[printer_paper_type][0];
00139     psizey = paper_size[printer_paper_type][1];
00140   }
00141 
00142   if (printer_paper_layout == vul_psfile::CENTER)
00143   {
00144     double hsx = box_width  / PIX2INCH * scale_x * .5;
00145     double hsy = box_height / PIX2INCH * scale_y * .5;
00146 
00147     // from xv xvps.c subroutine: centerimage
00148     pos_inx = psizex*.5 - hsx;
00149     pos_iny = psizey*.5 - hsy;
00150 
00151     // make sure 'center' of image is still on page
00152     RANGE(pos_inx, -hsx, psizex-hsx);
00153     RANGE(pos_iny, -hsy, psizey-hsy);
00154 
00155     // round to integer .001ths of an inch
00156     pos_inx = vcl_floor(pos_inx * 1000.0 + 0.5) * .001;
00157     pos_iny = vcl_floor(pos_iny * 1000.0 + 0.5) * .001;
00158   }
00159   else if (printer_paper_layout == vul_psfile::MAX)
00160   {
00161     double hsx = psizex - margins[printer_paper_type][0];
00162     double hsy = psizey - margins[printer_paper_type][1];
00163 
00164     // avoid division by 0:
00165     if (box_width == 0) box_width = 1;
00166     if (box_height == 0) box_height = 1;
00167 
00168     // choose the smaller scaling factor
00169     scale_x = scale_y = (float)vcl_min(hsx/box_width, hsy/box_height) * PIX2INCH;
00170 
00171     RANGE(scale_x,ps_minimum,ps_maximum);
00172     RANGE(scale_y,ps_minimum,ps_maximum);
00173 
00174     pos_inx = psizex*.5 - box_width / PIX2INCH * scale_x *.5;
00175     pos_iny = psizey*.5 - box_height/ PIX2INCH * scale_y *.5;
00176 
00177     // round to integer .001ths of an inch
00178     pos_inx = vcl_floor(pos_inx * 1000.0 + 0.5) * .001;
00179     pos_iny = vcl_floor(pos_iny * 1000.0 + 0.5) * .001;
00180   }
00181 
00182   // printed image will have size iw,ih (in picas)
00183   if (exist_image)
00184   {
00185     iwf = width  * scale_x; iw = int(iwf + 0.5);
00186     ihf = height * scale_y; ih = int(ihf + 0.5);
00187   }
00188   if (exist_objs)
00189   {
00190     iw = int(box_width  * scale_x + 0.5);
00191     ih = int(box_height * scale_y + 0.5);
00192   }
00193 
00194   // compute offset to bottom-left of image (in picas)
00195   ox = int(pos_inx*PIX2INCH+0.5);
00196   oy = int(pos_iny*PIX2INCH+0.5);
00197 
00198   if (debug) vcl_cout << "vul_psfile::compute_bounding_box, box_width = "
00199                       << box_width << ", box_height = " << box_height << '\n';
00200 }
00201 
00202 //-----------------------------------------------------------------------------
00203 //: Set Bounding Box Min and Max x, y.
00204 //-----------------------------------------------------------------------------
00205 void vul_psfile::set_min_max_xy(float xx, float yy)
00206 {
00207   int x = int(xx + 0.5);
00208   int y = int(yy + 0.5);
00209   if (x < min_x)   min_x = x;
00210   if (y < min_y)   min_y = y;
00211   if (x > max_x)   max_x = x;
00212   if (y > max_y)   max_y = y;
00213 }
00214 
00215 //-----------------------------------------------------------------------------
00216 //: Set Bounding Box Min and Max x, y.
00217 //-----------------------------------------------------------------------------
00218 void vul_psfile::set_min_max_xy(int x, int y)
00219 {
00220   if (x < min_x)   min_x = x;
00221   if (y < min_y)   min_y = y;
00222   if (x > max_x)   max_x = x;
00223   if (y > max_y)   max_y = y;
00224 }
00225 
00226 //-----------------------------------------------------------------------------
00227 //: Write 8 bit grey scale image.
00228 //-----------------------------------------------------------------------------
00229 void vul_psfile::print_greyscale_image(unsigned char* buffer, int sizex, int sizey)
00230 {
00231   if (debug)
00232     vcl_cout << "vul_psfile::print_greyscale_image, width = " << sizex
00233              << ", height = " << sizey  << ", reduction_factor = "
00234              << reduction_factor << '\n';
00235 
00236   exist_image = true;
00237   width = sizex;
00238   height = sizey;
00239   set_parameters(sizex,sizey);
00240   compute_bounding_box();
00241 
00242   int new_width = (int)vcl_ceil(sizex/(double)reduction_factor); // round up
00243   int new_height= (int)vcl_ceil(sizey/(double)reduction_factor);
00244 
00245   output_filestream
00246     << "\n%%Page: 1 1\n\n% remember original state\n/origstate save def\n"
00247     << "\n% build a temporary dictionary\n20 dict begin\n\n"
00248     << "% define string to hold a scanline's worth of data\n"
00249     << "/pix " << new_width << " string def\n";
00250 
00251   if (printer_paper_orientation == vul_psfile::LANDSCAPE)
00252     output_filestream
00253       << "% print in landscape mode\n90 rotate 0 " << int(-psizey*PIX2INCH) << " translate\n\n";
00254   output_filestream << "% lower left corner\n";
00255   translate_pos = output_filestream.tellp();
00256   image_translate_and_scale();
00257 
00258   output_filestream
00259     << new_width << ' ' << new_height << " 8             % dimensions of data\n"
00260     << '[' << new_width << " 0 0 -" << new_height << " 0 " << new_height
00261     << "]  % mapping matrix\n{currentfile pix readhexstring pop}\nimage\n\n";
00262   const int linesize = 72;
00263 
00264   // write image data to output PostScript file
00265   for (int j=0; j<new_height; j++)
00266   {
00267     int countrow = 0;
00268     for (int i = 0; i < new_width; i++)
00269     {
00270       int index;
00271 
00272       if (reduction_factor == 1)
00273         index = int(*(buffer + width * j + i));
00274       else // Reduce resolution of image if necessary
00275       {
00276         int pixel_number= (width * j + i) * reduction_factor;
00277         index=0;
00278         int number_of_pixels_sampled=0;
00279         for (int m=0; m < reduction_factor;m++)
00280           for (int n=0; n < reduction_factor;n++)
00281             if (i*reduction_factor+m < width && j*reduction_factor+n < height)
00282             {
00283               index += int(*(buffer + (pixel_number+m+n*width)));
00284               ++number_of_pixels_sampled;
00285             }
00286         index/=number_of_pixels_sampled; // Average the pixel intensity value.
00287       }
00288 
00289       // write hex pixel value
00290       if (in_range(index))
00291       {
00292         char pixel[3];
00293         unsigned char low4 = (unsigned char)  (index & 0x000f);
00294         unsigned char high4 = (unsigned char) ((index & 0x00f0) >> 4);
00295         pixel[0] = Hex4bit(high4);
00296         pixel[1] = Hex4bit(low4);
00297         pixel[2] = '\0';
00298         output_filestream << pixel;
00299       }
00300       else
00301         vcl_cout << " index out of range: " << index << '\n';
00302 
00303       countrow+=2;
00304       if (countrow >= linesize)
00305       {
00306         countrow = 0;
00307         output_filestream << '\n';
00308       }
00309     }
00310     output_filestream << '\n';
00311   }
00312   output_filestream << "% stop using temporary dictionary\nend\n\n"
00313                     << "% restore original state\norigstate restore\n\n";
00314 }
00315 
00316 //-----------------------------------------------------------------------------
00317 //: Write 24 bit colour image.
00318 //-----------------------------------------------------------------------------
00319 void vul_psfile::print_color_image(unsigned char* data, int sizex, int sizey)
00320 {
00321   if (debug)
00322     vcl_cout << "vul_psfile::print_color_image, width = " << sizex
00323              << ", height = " << sizey  << ", reduction_factor = "
00324              << reduction_factor << '\n';
00325 
00326   const int bytes_per_pixel = 3;
00327   exist_image = true;
00328   width = sizex;
00329   height = sizey;
00330   set_parameters(sizex,sizey);
00331   compute_bounding_box();
00332 
00333   int new_width = (int)vcl_ceil(sizex/(double)reduction_factor); // round up
00334   int new_height= (int)vcl_ceil(sizey/(double)reduction_factor);
00335 
00336   // This part uses xv outfile as a reference:
00337   output_filestream
00338     << "\n%%Page: 1 1\n\n"
00339     << "% remember original state\n"
00340     << "/origstate save def\n\n"
00341     << "% build a temporary dictionary\n"
00342     << "20 dict begin\n\n"
00343     << "% define string to hold a scanline's worth of data\n"
00344     << "/pix " << 3 * new_width << " string def\n\n"
00345     << "% define space for color conversions\n"
00346     << "/grays " << new_width << " string def  % space for gray scale line\n"
00347     << "/npixls 0 def\n"
00348     << "/rgbindx 0 def\n\n";
00349 
00350   if (printer_paper_orientation == vul_psfile::LANDSCAPE)
00351     output_filestream
00352       << "% print in landscape mode\n90 rotate 0 " << int(-psizey*PIX2INCH) << " translate\n\n";
00353   output_filestream << "% lower left corner\n";
00354   translate_pos = output_filestream.tellp();
00355   image_translate_and_scale();
00356 
00357   output_filestream
00358     << "\n% define 'colorimage' if it isn't defined\n"
00359     << "% ('colortogray' and 'mergeprocs' come from xwd2ps via xgrab)\n"
00360     << "/colorimage where  % do we know about 'colorimage'?\n"
00361     << "  { pop }          % yes: pop off the 'dict' returned\n"
00362     << "  {                % no:  define one\n"
00363     << "    /colortogray { % define an RGB->I function\n"
00364     << "      /rgbdata exch store  % call input 'rgbdata'\n"
00365     << "      rgbdata length 3 idiv\n"
00366     << "      /npixls exch store\n"
00367     << "      /rgbindx 0 store\n"
00368     << "      0 1 npixls 1 sub {\n"
00369     << "        grays exch\n"
00370     << "        rgbdata rgbindx       get 20 mul % Red\n"
00371     << "        rgbdata rgbindx 1 add get 32 mul % Green\n"
00372     << "        rgbdata rgbindx 2 add get 12 mul % Blue\n"
00373     << "        add add 64 idiv  % I = .3125 R + .5 G + .1875 B\n"
00374     << "        put\n"
00375     << "        /rgbindx rgbindx 3 add store\n"
00376     << "      } for\n"
00377     << "      grays 0 npixls getinterval\n"
00378     << "    } bind def\n\n"
00379     << "    % Utility procedure for colorimage operator.\n"
00380     << "    % This procedure takes two procedures off the stack and merges them into a single procedure.\n\n"
00381     << "    /mergeprocs {\n"
00382     << "      dup length\n"
00383     << "      3 -1 roll\n"
00384     << "      dup\n"
00385     << "      length\n"
00386     << "      dup\n"
00387     << "      5 1 roll\n"
00388     << "      3 -1 roll\n"
00389     << "      add\n"
00390     << "      array cvx\n"
00391     << "      dup\n"
00392     << "      3 -1 roll\n"
00393     << "      0 exch\n"
00394     << "      putinterval\n"
00395     << "      dup\n"
00396     << "      4 2 roll\n"
00397     << "      putinterval\n"
00398     << "    } bind def\n\n"
00399     << "    /colorimage {\n"
00400     << "      pop pop    % remove 'false 3' operands\n"
00401     << "      {colortogray} mergeprocs\n"
00402     << "      image\n"
00403     << "    } bind def\n"
00404     << "  } ifelse    % end of 'false' case\n\n"
00405     << new_width << ' ' << new_height << " 8  % dimensions of data\n"
00406     << '[' << new_width << " 0 0 -" << new_height << " 0 " << new_height << "]  % mapping matrix\n"
00407     << "{currentfile pix readhexstring pop}\n"
00408     << "false 3 colorimage\n\n";
00409 
00410   // write image data into PostScript file.
00411   const int linesize = 72;
00412 
00413   // extract RGB data from pixel value and write it to output file
00414   for (int j = 0; j < new_height;j++)
00415   {
00416     int countrow = 0;
00417     for (int i = 0; i < new_width; i++)
00418     {
00419       for (int c = 0; c < bytes_per_pixel; ++c)
00420       {
00421         // get RGB hex index.
00422         int index;
00423 
00424         if (reduction_factor == 1)
00425           index = int(*(data + (sizex*j+i) * bytes_per_pixel + c));
00426         else // Reduce image if necessary
00427         {
00428           int pixel_number= (sizex*j+i) * bytes_per_pixel * reduction_factor + c;
00429           index=0;
00430           int number_of_pixels_sampled=0;
00431           for (int m=0; m < reduction_factor;m++)
00432             for (int n=0; n < reduction_factor;n++)
00433               if (i*reduction_factor+m < sizex && j*reduction_factor+n < sizey)
00434               {
00435                 index += int(*(data+(pixel_number+(m+n*sizex)*bytes_per_pixel)));
00436                 ++number_of_pixels_sampled;
00437               }
00438           index/=number_of_pixels_sampled;  // average the pixel intensity
00439         }
00440 
00441         // write RGC hex.
00442         if (in_range(index))
00443         {
00444           char pixel[3];
00445           unsigned char low4 = (unsigned char)  (index & 0x000f);
00446           unsigned char high4 = (unsigned char) ((index & 0x00f0) >> 4);
00447           pixel[0] = Hex4bit(high4);
00448           pixel[1] = Hex4bit(low4);
00449           pixel[2] = '\0';
00450           output_filestream << pixel;
00451         }
00452         else
00453           vcl_cout << " index out of range: " << index << '\n';
00454 
00455         countrow+=2;
00456         if (countrow >= linesize)
00457         {
00458           countrow = 0;
00459           output_filestream << '\n';
00460         }
00461       }
00462     }
00463     output_filestream << '\n';
00464   }
00465 
00466   output_filestream << "% stop using temporary dictionary\nend\n\n"
00467                     << "% restore original state\norigstate restore\n\n";
00468 }
00469 
00470 //-----------------------------------------------------------------------------
00471 //: Set graphic coordinate (translate and rotate to local coordinate).
00472 //-----------------------------------------------------------------------------
00473 void vul_psfile::graphic_header()
00474 {
00475   if (printer_paper_orientation == vul_psfile::LANDSCAPE)
00476     output_filestream << "% print in landscape mode\n90 rotate 0 "
00477                       << int(-psizey*PIX2INCH) << " translate\n\n";
00478 
00479   output_filestream.flush();
00480   // save streampos so we can come back and modify it.
00481   sobj_t_pos = output_filestream.tellp();
00482   // move relative coordinate to local origin and set up scale factor.
00483   object_translate_and_scale();
00484 }
00485 
00486 //-----------------------------------------------------------------------------
00487 //: Set Image translate and scale.
00488 //-----------------------------------------------------------------------------
00489 void vul_psfile::image_translate_and_scale()
00490 {
00491   int scale_height = int(height* scale_y);
00492   int scale_min_x  = int(min_x * scale_x);
00493   int scale_max_y  = int(max_y * scale_y);
00494 
00495   if (debug)
00496     vcl_cout << "vul_psfile::image_translate_and_scale, scale_height= "
00497              << scale_height << ", scale_min_x = " << scale_min_x
00498              << ", scale_max_y = " << scale_max_y << '\n';
00499 
00500   output_filestream << vcl_setw(6) << ox - scale_min_x << ' '
00501                     << vcl_setw(6) << oy + scale_max_y - scale_height << " translate\n"
00502                     << "\n% size of image (on paper, in 1/72inch coordinates)\n"
00503                     << vcl_setw(9) << iwf << ' '
00504                     << vcl_setw(9) << ihf << " scale\n\n";
00505 }
00506 
00507 //-----------------------------------------------------------------------------
00508 //: Set object translate and scale.
00509 //-----------------------------------------------------------------------------
00510 void vul_psfile::object_translate_and_scale()
00511 {
00512   int scale_height = int(box_height * scale_y);
00513   int scale_min_x  = int(min_x * scale_x);
00514   int scale_min_y  = int(min_y * scale_y);
00515   // round to integer .01ths
00516   scale_x = vcl_floor(scale_x * 100.0f + 0.5f) * .01f;
00517   scale_y = vcl_floor(scale_y * 100.0f + 0.5f) * .01f;
00518 
00519   // move origin
00520   output_filestream << vcl_setw(6) << ox - scale_min_x << ' '
00521                     << vcl_setw(6) << oy + scale_height + scale_min_y << " translate\n"
00522                     << vcl_setw(9) << scale_x << ' ' << vcl_setw(9) << -scale_y << " scale\n\n"
00523                     << "/originalCTM matrix currentmatrix def\n";
00524 }
00525 
00526 //-----------------------------------------------------------------------------
00527 //: Set ox, oy , iw, ih, iwf, ihf parameters for PostScript file use.
00528 //-----------------------------------------------------------------------------
00529 bool vul_psfile::set_parameters(int sizex,int sizey)
00530 {
00531   width = sizex;
00532   height = sizey;
00533   // avoid division by 0 or other fancy things later on:
00534   assert (width > 0 && height > 0);
00535 
00536   set_min_max_xy(0,0);
00537   set_min_max_xy(width,height);
00538   compute_bounding_box();
00539 
00540   return true;
00541 }
00542 
00543 //-----------------------------------------------------------------------------
00544 //: PostScript file header.
00545 //-----------------------------------------------------------------------------
00546 void vul_psfile::postscript_header()
00547 {
00548   if (header_pos != HEADER_START)
00549   {
00550     vcl_cerr << "vul_psfile: Header already set to " << long(header_pos) << '\n';
00551     return;
00552   }
00553 
00554   output_filestream
00555     << "%!PS-Adobe-2.0 EPSF-2.0\n%%Title: " << filename.c_str()
00556     << "\n%%Creator: vul_psfile\n%%BoundingBox: ";
00557 
00558   header_pos = output_filestream.tellp();
00559   reset_postscript_header();
00560 }
00561 
00562 
00563 //-----------------------------------------------------------------------------
00564 //: Reset PostScript header file
00565 //-----------------------------------------------------------------------------
00566 void vul_psfile::reset_postscript_header()
00567 {
00568   if (printer_paper_orientation == vul_psfile::LANDSCAPE)
00569     output_filestream
00570        << vcl_setw(6) << int(pos_iny*PIX2INCH+0.5) << ' '
00571        << vcl_setw(6) << int(pos_inx*PIX2INCH+0.5) << ' '
00572        << vcl_setw(6) << int(pos_iny*PIX2INCH+0.5)+ih << ' '
00573        << vcl_setw(6) << int(pos_inx*PIX2INCH+0.5)+iw << '\n';
00574   else
00575     output_filestream
00576        << vcl_setw(6) << ox << ' '
00577        << vcl_setw(6) << oy << ' '
00578        << vcl_setw(6) << ox+iw << ' '
00579        << vcl_setw(6) << oy+ih << '\n';
00580   output_filestream << "%%Pages: 1\n%%DocumentFonts:\n%%EndComments\n";
00581 }
00582 
00583 //-----------------------------------------------------------------------------
00584 //: Utility program used in point(), line(), ellipse() and circle()
00585 //-----------------------------------------------------------------------------
00586 void vul_psfile::sobj_rgb_params(char const* obj_str, bool filled)
00587 {
00588   print_graphics_prolog();
00589   output_filestream
00590     << "\nBegin %I " << obj_str << "\n2 0 0 [] 0 SetB\n"
00591     << fg_r << ' ' << fg_g << ' ' << fg_b << " SetCFg\n"
00592     << bg_r << ' ' << bg_g << ' ' << bg_b << " SetCBg\n"
00593     << line_width_ << " setlinewidth\n"
00594     << (filled ? "0": "none") << " SetP %I p n\n";
00595 }
00596 
00597 //-----------------------------------------------------------------------------
00598 //:  Add a line between the given points to the Postscript file.
00599 //-----------------------------------------------------------------------------
00600 void vul_psfile::line(float x1, float y1, float x2, float y2)
00601 {
00602   // set up bounding box.
00603   set_min_max_xy(x1,y1);
00604   set_min_max_xy(x2,y2);
00605   compute_bounding_box();
00606 
00607   print_graphics_prolog();
00608   sobj_rgb_params("Line", false);
00609 
00610   output_filestream << int(x1) << ' ' << int(y1) << ' '
00611                     << int(x2) << ' ' << int(y2) << " Line\nEnd\n";
00612 }
00613 
00614 //-----------------------------------------------------------------------------
00615 //: Add a point at the given coordinates to the Postscript file.
00616 //-----------------------------------------------------------------------------
00617 void vul_psfile::point(float x, float y, float point_size)
00618 {
00619   print_graphics_prolog();
00620   set_min_max_xy(x,y);
00621   compute_bounding_box();
00622 
00623   this->sobj_rgb_params("Point", true);
00624 
00625   point_size /= 2;
00626   output_filestream << x << ' ' << y << ' ' << point_size << ' ' << point_size << " Elli\nEnd\n";
00627 }
00628 
00629 //-----------------------------------------------------------------------------
00630 //: Add an ellipse to the Postscript file.
00631 //-----------------------------------------------------------------------------
00632 void vul_psfile::ellipse(float x, float y, float a_axis, float b_axis, int angle)
00633 {
00634   #ifndef PI // should already be defined in math.h - PVR
00635   #define PI 3.14159265358979323846
00636   #endif
00637   const double radsperdeg = PI/180.0;
00638 
00639   set_min_max_xy(int(x+a_axis*vcl_cos(angle*radsperdeg) + 0.5),
00640                  int(y+a_axis*vcl_sin(angle*radsperdeg) + 0.5) );
00641   set_min_max_xy(int(x-a_axis*vcl_cos(angle*radsperdeg) + 0.5),
00642                  int(y-a_axis*vcl_sin(angle*radsperdeg) + 0.5) );
00643   compute_bounding_box();
00644 
00645   print_graphics_prolog();
00646   sobj_rgb_params("Ellipse", false);
00647   if (angle)
00648     output_filestream << (int)x << ' ' << (int)y << " translate\n"
00649                       << -angle << " rotate\n0 0 " << (int)a_axis << ' '
00650                       << (int)b_axis << " Elli\nEnd\n";
00651   else
00652     output_filestream << (int)x << ' ' << (int)y << ' '
00653                       << (int)a_axis << ' ' << (int)b_axis << " Elli\nEnd\n";
00654 }
00655 
00656 //-----------------------------------------------------------------------------
00657 //: Add a circle with the given centre point and radius to the Postscript file.
00658 //-----------------------------------------------------------------------------
00659 void vul_psfile::circle(float x, float y, float radius)
00660 {
00661   // set up bounding box
00662   set_min_max_xy(x+radius,y);
00663   set_min_max_xy(x-radius,y);
00664   set_min_max_xy(x,y+radius);
00665   set_min_max_xy(x,y-radius);
00666   compute_bounding_box();
00667 
00668   print_graphics_prolog();
00669   sobj_rgb_params("Circle", false);
00670   ellipse(x,y,radius,radius);
00671   output_filestream << "End\n";
00672 }
00673 
00674 //-----------------------------------------------------------------------------
00675 //: the defined procedure for PostScript script use.
00676 //-----------------------------------------------------------------------------
00677 void vul_psfile::print_graphics_prolog()
00678 {
00679   if (graphics_prolog_exists)
00680     return;
00681   exist_objs = true;
00682   output_filestream
00683     << "\n\n%%BeginTargetjrPrologue\n"
00684     << "/arrowhead {\n"
00685     << "  0 begin\n"
00686     << "  transform originalCTM itransform\n"
00687     << "  /taily exch def\n"
00688     << "  /tailx exch def\n"
00689     << "  transform originalCTM itransform\n"
00690     << "  /tipy exch def\n"
00691     << "  /tipx exch def\n"
00692     << "  /dy tipy taily sub def\n"
00693     << "  /dx tipx tailx sub def\n"
00694     << "  /angle dx 0 ne dy 0 ne or { dy dx atan } { 90 } ifelse def\n"
00695     << "  gsave\n"
00696     << "  originalCTM setmatrix\n"
00697     << "  tipx tipy translate\n"
00698     << "  angle rotate\n"
00699     << "  newpath\n"
00700     << "  arrowHeight neg arrowWidth 2 div moveto\n"
00701     << "  0 0 lineto\n"
00702     << "  arrowHeight neg arrowWidth 2 div neg lineto\n"
00703     << "  patternNone not {\n"
00704     << "    originalCTM setmatrix\n"
00705     << "    /padtip arrowHeight 2 exp 0.25 arrowWidth 2 exp mul add sqrt brushWidth mul\n"
00706     << "    arrowWidth div def\n"
00707     << "    /padtail brushWidth 2 div def\n"
00708     << "    tipx tipy translate\n"
00709     << "    angle rotate\n"
00710     << "    padtip 0 translate\n"
00711     << "    arrowHeight padtip add padtail add arrowHeight div dup scale\n"
00712     << "    arrowheadpath\n"
00713     << "    ifill\n"
00714     << "  } if\n"
00715     << "  brushNone not {\n"
00716     << "    originalCTM setmatrix\n"
00717     << "    tipx tipy translate\n"
00718     << "    angle rotate\n"
00719     << "    arrowheadpath\n"
00720     << "    istroke\n"
00721     << "  } if\n"
00722     << "  grestore\n"
00723     << "  end\n"
00724     << "} dup 0 9 dict put def\n\n"
00725     << "/arrowheadpath {\n"
00726     << "  newpath\n"
00727     << "  arrowHeight neg arrowWidth 2 div moveto\n"
00728     << "  0 0 lineto\n"
00729     << "  arrowHeight neg arrowWidth 2 div neg lineto\n"
00730     << "} def\n\n"
00731     << "/leftarrow {\n"
00732     << "  0 begin\n"
00733     << "  y exch get /taily exch def\n"
00734     << "  x exch get /tailx exch def\n"
00735     << "  y exch get /tipy exch def\n"
00736     << "  x exch get /tipx exch def\n"
00737     << "  brushLeftArrow { tipx tipy tailx taily arrowhead } if\n"
00738     << "  end\n"
00739     << "} dup 0 4 dict put def\n\n"
00740     << "/rightarrow {\n"
00741     << "  0 begin\n"
00742     << "  y exch get /tipy exch def\n"
00743     << "  x exch get /tipx exch def\n"
00744     << "  y exch get /taily exch def\n"
00745     << "  x exch get /tailx exch def\n"
00746     << "  brushRightArrow { tipx tipy tailx taily arrowhead } if\n"
00747     << "  end\n"
00748     << "} dup 0 4 dict put def\n\n"
00749     << "%%EndTargetjrPrologue\n\n"
00750     << "/arrowHeight 10 def\n"
00751     << "/arrowWidth 5 def\n\n"
00752     << "/TargetjrDict 50 dict def\n"
00753     << "TargetjrDict begin\n\n"
00754     << "/none null def\n"
00755     << "/numGraphicParameters 17 def\n"
00756     << "/stringLimit 65535 def\n\n"
00757     << "/Begin { save numGraphicParameters dict begin } def\n\n"
00758     << "/End { end restore } def\n\n"
00759     << "/SetB { % width leftarrow rightarrow DashArray DashOffset SetB\n"
00760     << "  dup type /nulltype eq {\n"
00761     << "    pop\n"
00762     << "    false /brushRightArrow idef\n"
00763     << "    false /brushLeftArrow idef\n"
00764     << "    true /brushNone idef\n"
00765     << "  } {\n"
00766     << "    /brushDashOffset idef\n"
00767     << "    /brushDashArray idef\n"
00768     << "    0 ne /brushRightArrow idef\n"
00769     << "    0 ne /brushLeftArrow idef\n"
00770     << "    /brushWidth idef\n"
00771     << "    false /brushNone idef\n"
00772     << "  } ifelse\n"
00773     << "} def\n\n"
00774     << "/SetCFg { /fgblue idef /fggreen idef /fgred idef } def\n\n"
00775     << "/SetCBg { /bgblue idef /bggreen idef /bgred idef } def\n\n"
00776     << "/SetF { /printSize idef /printFont idef } def\n\n"
00777     << "/SetP {  % string -1 SetP  OR gray SetP\n"
00778     << "  dup type /nulltype eq { pop true /patternNone idef }\n"
00779     << "  {\n"
00780     << "    dup -1 eq { /patternGrayLevel idef /patternString idef }\n"
00781     << "    { /patternGrayLevel idef } ifelse\n"
00782     << "    false /patternNone idef\n"
00783     << "  } ifelse\n"
00784     << "} def\n\n"
00785     << "/BSpl {\n"
00786     << "  0 begin\n"
00787     << "  storexyn\n"
00788     << "  newpath\n"
00789     << "  n 1 gt {\n"
00790     << "    0 0 0 0 0 0 1 1 true subspline\n"
00791     << "    n 2 gt {\n"
00792     << "      0 0 0 0 1 1 2 2 false subspline\n"
00793     << "      1 1 n 3 sub { /i exch def i 1 sub dup i dup i 1 add dup i 2 add dup false subspline } for\n"
00794     << "      n 3 sub dup n 2 sub dup n 1 sub dup 2 copy false subspline\n"
00795     << "    } if\n"
00796     << "    n 2 sub dup n 1 sub dup 2 copy 2 copy false subspline\n"
00797     << "    patternNone not brushLeftArrow not brushRightArrow not and and { ifill } if\n"
00798     << "    brushNone not { istroke } if\n"
00799     << "    0 0 1 1 leftarrow\n"
00800     << "    n 2 sub dup n 1 sub dup rightarrow\n"
00801     << "  } if\n"
00802     << "  end\n"
00803     << "} dup 0 4 dict put def\n\n"
00804     << "/Circ { newpath 0 360 arc patternNone not { ifill } if brushNone not { istroke } if } def\n\n"
00805     << "/CBSpl {\n"
00806     << "  0 begin\n"
00807     << "  dup 2 gt {\n"
00808     << "    storexyn\n"
00809     << "    newpath\n"
00810     << "    n 1 sub dup 0 0 1 1 2 2 true subspline\n"
00811     << "    1 1 n 3 sub { /i exch def i 1 sub dup i dup i 1 add dup i 2 add dup false subspline } for\n"
00812     << "    n 3 sub dup n 2 sub dup n 1 sub dup 0 0 false subspline\n"
00813     << "    n 2 sub dup n 1 sub dup 0 0 1 1 false subspline\n"
00814     << "    patternNone not { ifill } if\n"
00815     << "    brushNone not { istroke } if\n"
00816     << "  } { Poly } ifelse\n"
00817     << "  end\n"
00818     << "} dup 0 4 dict put def\n"
00819     << "/Elli {\n"
00820     << "  0 begin\n"
00821     << "  newpath 4 2 roll translate scale\n"
00822     << "  0 0 1 0 360 arc\n"
00823     << "  patternNone not { ifill } if\n"
00824     << "  brushNone not { istroke } if\n"
00825     << "  end\n"
00826     << "} dup 0 1 dict put def\n\n"
00827     << "/Line {\n"
00828     << "  0 begin\n"
00829     << "  2 storexyn\n"
00830     << "  newpath\n"
00831     << "  x 0 get y 0 get moveto\n"
00832     << "  x 1 get y 1 get lineto\n"
00833     << "  brushNone not { istroke } if\n"
00834     << "  0 0 1 1 leftarrow\n"
00835     << "  0 0 1 1 rightarrow\n"
00836     << "  end\n"
00837     << "} dup 0 4 dict put def\n\n"
00838     << "/MLine {\n"
00839     << "  0 begin\n"
00840     << "  storexyn\n"
00841     << "  newpath\n"
00842     << "  n 1 gt {\n"
00843     << "    x 0 get y 0 get moveto\n"
00844     << "    1 1 n 1 sub { /i exch def x i get y i get lineto } for\n"
00845     << "    patternNone not brushLeftArrow not brushRightArrow not and and { ifill } if\n"
00846     << "    brushNone not { istroke } if\n"
00847     << "    0 0 1 1 leftarrow\n"
00848     << "    n 2 sub dup n 1 sub dup rightarrow\n"
00849     << "  } if\n"
00850     << "  end\n"
00851     << "} dup 0 4 dict put def\n\n"
00852     << "/Poly {\n"
00853     << "  3 1 roll\n"
00854     << "  newpath moveto -1 add { lineto } repeat closepath\n"
00855     << "  patternNone not { ifill } if\n"
00856     << "  brushNone not { istroke } if\n"
00857     << "} def\n\n"
00858     << "/Rect {\n"
00859     << "  0 begin\n"
00860     << "  /t exch def\n"
00861     << "  /r exch def\n"
00862     << "  /b exch def\n"
00863     << "  /l exch def\n"
00864     << "  newpath\n"
00865     << "  l b moveto\n"
00866     << "  l t lineto\n"
00867     << "  r t lineto\n"
00868     << "  r b lineto\n"
00869     << "  closepath\n"
00870     << "  patternNone not { ifill } if\n"
00871     << "  brushNone not { istroke } if\n"
00872     << "  end\n"
00873     << "} dup 0 4 dict put def\n\n"
00874     << "/Text { ishow } def\n\n"
00875     << "/idef { dup where { pop pop pop } { exch def } ifelse } def\n\n"
00876     << "/ifill {\n"
00877     << "  0 begin\n"
00878     << "  gsave\n"
00879     << "  patternGrayLevel -1 ne {\n"
00880     << "    fgred bgred fgred sub patternGrayLevel mul add\n"
00881     << "    fggreen bggreen fggreen sub patternGrayLevel mul add\n"
00882     << "    fgblue bgblue fgblue sub patternGrayLevel mul add setrgbcolor\n"
00883     << "    eofill\n"
00884     << "  } {\n"
00885     << "    eoclip\n"
00886     << "    originalCTM setmatrix\n"
00887     << "    pathbbox /t exch def /r exch def /b exch def /l exch def\n"
00888     << "    /w r l sub ceiling cvi def\n"
00889     << "    /h t b sub ceiling cvi def\n"
00890     << "    /imageByteWidth w 8 div ceiling cvi def\n"
00891     << "    /imageHeight h def\n"
00892     << "    bgred bggreen bgblue setrgbcolor\n"
00893     << "    eofill\n"
00894     << "    fgred fggreen fgblue setrgbcolor\n"
00895     << "    w 0 gt h 0 gt and { l w add b translate w neg h scale w h true [w 0 0 h neg 0 h] { patternproc } imagemask } if\n"
00896     << "  } ifelse\n"
00897     << "  grestore\n"
00898     << "  end\n"
00899     << "} dup 0 8 dict put def\n\n"
00900     << "/istroke {\n"
00901     << "  gsave\n"
00902     << "  brushDashOffset -1 eq { [] 0 setdash 1 setgray }\n"
00903     << "  { brushDashArray brushDashOffset setdash fgred fggreen fgblue setrgbcolor } ifelse\n"
00904     << "  originalCTM setmatrix\n"
00905     << "  stroke\n"
00906     << "  grestore\n"
00907     << "} def\n\n"
00908     << "/ishow {\n"
00909     << "  0 begin\n"
00910     << "  gsave\n"
00911     << "  fgred fggreen fgblue setrgbcolor\n"
00912     << "  /fontDict printFont printSize scalefont dup setfont def\n"
00913     << "  /descender fontDict begin 0 [FontBBox] 1 get FontMatrix end\n"
00914     << "  transform exch pop def\n"
00915     << "  /vertoffset 1 printSize sub descender sub def\n"
00916     << "  { 0 vertoffset moveto show /vertoffset vertoffset printSize sub def } forall\n"
00917     << "  grestore\n"
00918     << "  end\n"
00919     << "} dup 0 3 dict put def\n"
00920     << "/patternproc {\n"
00921     << "  0 begin\n"
00922     << "  /patternByteLength patternString length def\n"
00923     << "  /patternHeight patternByteLength 8 mul sqrt cvi def\n"
00924     << "  /patternWidth patternHeight def\n"
00925     << "  /patternByteWidth patternWidth 8 idiv def\n"
00926     << "  /imageByteMaxLength imageByteWidth imageHeight mul\n"
00927     << "  stringLimit patternByteWidth sub min def\n"
00928     << "  /imageMaxHeight imageByteMaxLength imageByteWidth idiv patternHeight idiv\n"
00929     << "  patternHeight mul patternHeight max def\n"
00930     << "  /imageHeight imageHeight imageMaxHeight sub store\n"
00931     << "  /imageString imageByteWidth imageMaxHeight mul patternByteWidth add string def\n"
00932     << "  0 1 imageMaxHeight 1 sub {\n"
00933     << "    /y exch def\n"
00934     << "    /patternRow y patternByteWidth mul patternByteLength mod def\n"
00935     << "    /patternRowString patternString patternRow patternByteWidth getinterval def\n"
00936     << "    /imageRow y imageByteWidth mul def\n"
00937     << "    0 patternByteWidth imageByteWidth 1 sub { /x exch def imageString imageRow x add patternRowString putinterval } for\n"
00938     << "  } for\n"
00939     << "  imageString\n"
00940     << "  end\n"
00941     << "} dup 0 12 dict put def\n\n"
00942     << "/min { dup 3 2 roll dup 4 3 roll lt { exch } if pop } def\n\n"
00943     << "/max { dup 3 2 roll dup 4 3 roll gt { exch } if pop } def\n\n"
00944     << "/midpoint {\n"
00945     << "  0 begin\n"
00946     << "  /y1 exch def\n"
00947     << "  /x1 exch def\n"
00948     << "  /y0 exch def\n"
00949     << "  /x0 exch def\n"
00950     << "  x0 x1 add 2 div\n"
00951     << "  y0 y1 add 2 div\n"
00952     << "  end\n"
00953     << "} dup 0 4 dict put def\n\n"
00954     << "/thirdpoint {\n"
00955     << "  0 begin\n"
00956     << "  /y1 exch def\n"
00957     << "  /x1 exch def\n"
00958     << "  /y0 exch def\n"
00959     << "  /x0 exch def\n"
00960     << "  x0 2 mul x1 add 3 div\n"
00961     << "  y0 2 mul y1 add 3 div\n"
00962     << "  end\n"
00963     << "} dup 0 4 dict put def\n\n"
00964     << "/subspline {\n"
00965     << "  0 begin\n"
00966     << "  /movetoNeeded exch def\n"
00967     << "  y exch get /y3 exch def\n"
00968     << "  x exch get /x3 exch def\n"
00969     << "  y exch get /y2 exch def\n"
00970     << "  x exch get /x2 exch def\n"
00971     << "  y exch get /y1 exch def\n"
00972     << "  x exch get /x1 exch def\n"
00973     << "  y exch get /y0 exch def\n"
00974     << "  x exch get /x0 exch def\n"
00975     << "  x1 y1 x2 y2 thirdpoint\n"
00976     << "  /p1y exch def\n"
00977     << "  /p1x exch def\n"
00978     << "  x2 y2 x1 y1 thirdpoint\n"
00979     << "  /p2y exch def\n"
00980     << "  /p2x exch def\n"
00981     << "  x1 y1 x0 y0 thirdpoint\n"
00982     << "  p1x p1y midpoint\n"
00983     << "  /p0y exch def\n"
00984     << "  /p0x exch def\n"
00985     << "  x2 y2 x3 y3 thirdpoint\n"
00986     << "  p2x p2y midpoint\n"
00987     << "  /p3y exch def\n"
00988     << "  /p3x exch def\n"
00989     << "  movetoNeeded { p0x p0y moveto } if\n"
00990     << "  p1x p1y p2x p2y p3x p3y curveto\n"
00991     << "  end\n"
00992     << "} dup 0 17 dict put def\n\n"
00993     << "/storexyn {\n"
00994     << "  /n exch def\n"
00995     << "  /y n array def\n"
00996     << "  /x n array def\n"
00997     << "  n 1 sub -1 0 { /i exch def y i 3 2 roll put x i 3 2 roll put } for\n"
00998     << "} def\n\n"
00999     << "/SSten { fgred fggreen fgblue setrgbcolor dup true exch 1 0 0 -1 0 6 -1 roll matrix astore } def\n\n"
01000     << "/FSten {\n"
01001     << "  dup 3 -1 roll dup 4 1 roll exch\n"
01002     << "  newpath\n"
01003     << "  0 0 moveto\n"
01004     << "  dup 0 exch lineto\n"
01005     << "  exch dup 3 1 roll exch lineto\n"
01006     << "  0 lineto\n"
01007     << "  closepath\n"
01008     << "  bgred bggreen bgblue setrgbcolor\n"
01009     << "  eofill\n"
01010     << "  SSten\n"
01011     << "} def\n\n"
01012     << "/Rast { exch dup 3 1 roll 1 0 0 -1 0 6 -1 roll matrix astore } def\n\n";
01013 
01014   // For scale and translate ..
01015   graphic_header();
01016 
01017   graphics_prolog_exists = true;
01018 }
01019 
01020 void vul_psfile::done()
01021 {
01022   if (debug) vcl_cout << "vul_psfile::done\n";
01023   doneps = true;
01024   if (graphics_prolog_exists)
01025     output_filestream << "end % TargetjrDict\n";
01026 
01027   output_filestream << "showpage\n%%Trailer\n";
01028 }