contrib/mul/mbl/mbl_eps_writer.cxx
Go to the documentation of this file.
00001 #include "mbl_eps_writer.h"
00002 //:
00003 // \file
00004 // \brief Class to generate simple EPS files containing images and lines
00005 // \author Tim Cootes
00006 
00007 #include <vil/vil_plane.h>
00008 #include <vil/vil_crop.h>
00009 #include <vcl_algorithm.h>
00010 #include <vcl_cassert.h>
00011 
00012 //=======================================================================
00013 // Dflt ctor
00014 //=======================================================================
00015 
00016 mbl_eps_writer::mbl_eps_writer()
00017   : nx_(100.0),ny_(100.0),sx_(1.0),sy_(1.0)
00018 {
00019 }
00020 
00021 //: Open file and write header, given bounding box
00022 // Bounding box specified in "points" (72 points=1 inch)
00023 mbl_eps_writer::mbl_eps_writer(const char* path, double nx, double ny)
00024   : sx_(1.0),sy_(1.0)
00025 {
00026    open(path,nx,ny);
00027 }
00028 
00029 //=======================================================================
00030 // Destructor
00031 //=======================================================================
00032 
00033 mbl_eps_writer::~mbl_eps_writer()
00034 {
00035 }
00036 
00037 //: Define shade of subsequent lines [0,1] = black-white
00038 void mbl_eps_writer::set_grey_shade(double shade)
00039 {
00040   if (shade<0.0) shade=0.0;
00041   if (shade>1.0) shade=1.0;
00042   ofs_<<shade<<" setgray\n";
00043 }
00044 
00045 //: Define colour of subsequent lines r,g,b in [0,1]
00046 void mbl_eps_writer::set_rgb(double r, double g, double b)
00047 {
00048   ofs_<<r<<' '<<g<<' '<<b<<" setrgbcolor\n";
00049 }
00050 
00051 //: Set colour of subsequent graphics using a named colour
00052 //  Valid options include black,white,grey,red,green,blue,
00053 //  cyan,yellow.  Note: Probably need a tidy map thing to
00054 //  do this properly.  Sets to grey if colour not known.
00055 void mbl_eps_writer::set_colour(const vcl_string& colour_name)
00056 {
00057   if (colour_name=="black") { set_grey_shade(0.0); return; }
00058   if (colour_name=="white") { set_grey_shade(1.0); return; }
00059   if (colour_name=="grey") { set_grey_shade(0.5); return; }
00060   if (colour_name=="red") { set_rgb(1,0,0); return; }
00061   if (colour_name=="green") { set_rgb(0,1,0); return; }
00062   if (colour_name=="blue") { set_rgb(0,0,1); return; }
00063   if (colour_name=="cyan") { set_rgb(0,1,1); return; }
00064   if (colour_name=="yellow") { set_rgb(1,1,0); return; }
00065 
00066   // Colour not recognised, so set to grey.
00067   set_grey_shade(0.5);
00068 }
00069 
00070 //: Define scaling factor
00071 void mbl_eps_writer::set_scaling(double s)
00072 {
00073   sx_=s; sy_=s;
00074 }
00075 
00076 //: Define scaling factor
00077 void mbl_eps_writer::set_scaling(double sx, double sy)
00078 {
00079   sx_=sx; sy_=sy;
00080 }
00081 
00082 
00083 //: Open file and write header
00084 bool mbl_eps_writer::open(const char* path, double nx, double ny)
00085 {
00086   ofs_.open(path,vcl_ios_out);
00087   if (!ofs_) return false;
00088 
00089   ofs_<<"%!PS-Adobe-1.0\n"
00090       <<"%%Creator: mbl_eps_writer\n"
00091   //  <<"%%Title: shapes\n"
00092       <<"%%BoundingBox: 0 0 "<<nx<<' '<<ny<<'\n'
00093 
00094       <<"gsave\n"
00095       <<"% Define some simple macros to save space\n"
00096       <<"/M {moveto} def\n"
00097       <<"/L {lineto} def\n\n"
00098       <<"/CP {closepath} def\n\n";
00099 
00100   nx_ = nx; ny_=ny;
00101 
00102   return true;
00103 }
00104 
00105 //: Creates file and draws image, setting bounding box to that of image
00106 //  Sets scaling to pixel widths, so that subsequent points are
00107 //  interpreted in pixel units.
00108 bool mbl_eps_writer::open(const char* path,
00109                           const vil_image_view<vxl_byte>& image,
00110                           double pixel_width_x, double pixel_width_y)
00111 {
00112   if (!open(path,image.ni()*pixel_width_x,image.nj()*pixel_width_y))
00113     return false;
00114   set_scaling(pixel_width_x,pixel_width_y);
00115 
00116   draw_image(image,0,0,1,1);
00117   return true;
00118 }
00119 
00120 
00121 //: Write tail and close
00122 void mbl_eps_writer::close()
00123 {
00124   ofs_<<"grestore\n";
00125   ofs_.close();
00126 }
00127 
00128 //: Define line width.
00129 void mbl_eps_writer::set_line_width(double w)
00130 {
00131   ofs_<<w<<" setlinewidth\n";
00132 }
00133 
00134 
00135 //: Draws circle of radius r around p
00136 void mbl_eps_writer::draw_circle(const vgl_point_2d<double>& p, double r)
00137 {
00138   ofs_<<"newpath\n\n"
00139       <<sx_*p.x()<<' '<<ny_-sy_*p.y()<<' '<<sx_*r<<" 0 360 arc CP\n\n"
00140       <<"stroke"<<vcl_endl;
00141 }
00142 
00143 //: Draws disk of radius r around p
00144 void mbl_eps_writer::draw_disk(const vgl_point_2d<double>& p, double r)
00145 {
00146   ofs_<<"newpath\n"
00147       <<sx_*p.x()<<' '<<ny_-sy_*p.y()<<' '<<sx_*r<<" 0 360 arc CP fill\n"
00148       <<"stroke"<<vcl_endl;
00149 }
00150 
00151 //: Draws line segment from p1 to p2
00152 void mbl_eps_writer::draw_line(const vgl_point_2d<double>& p1, const vgl_point_2d<double>& p2)
00153 {
00154   ofs_<<"newpath\n"
00155       <<sx_*p1.x()<<' '<<ny_-sy_*p1.y()<<" M "
00156       <<sx_*p2.x()<<' '<<ny_-sy_*p2.y()<<" L\n"
00157       <<"stroke\n";
00158 }
00159 
00160 //: Draws polygon connecting points.
00161 //  If closed, then adds line joining last to first point.
00162 //  If filled, then fills with current colour/greyshade.
00163 void mbl_eps_writer::draw_polygon(const vcl_vector<vgl_point_2d<double> >& pts,
00164                                   bool closed, bool filled)
00165 {
00166   if (pts.size()<2) return;
00167   ofs_<<"newpath\n"
00168       <<sx_*pts[0].x()<<' '<<ny_-sy_*pts[0].y()<<" M ";
00169   for (unsigned i=1;i<pts.size();++i)
00170     ofs_<<sx_*pts[i].x()<<' '<<ny_-sy_*pts[i].y()<<" L\n";
00171   if (closed)
00172   {
00173     ofs_<<sx_*pts[0].x()<<' '<<ny_-sy_*pts[0].y()<<" L CP\n";
00174   }
00175   if (filled) ofs_<<"fill ";
00176   ofs_<<"stroke\n";
00177 }
00178 
00179 
00180 //: Writes first plane of image in hex format to os
00181 void mbl_eps_writer::write_image_data(vcl_ostream& os,
00182                                       const vil_image_view<vxl_byte>& image)
00183 {
00184   unsigned ni=image.ni(),nj=image.nj();
00185   ofs_<<"{<";
00186   for (unsigned j=0;j<nj;++j)
00187   {
00188     // Write each row
00189     for (unsigned i=0;i<ni;++i)
00190     {
00191       ofs_<<vcl_hex<<int(image(i,j))/16<<int(image(i,j))%16;
00192     }
00193     ofs_<<vcl_endl;
00194   }
00195   ofs_<<">}\n"
00196       <<vcl_dec;  // Ensure returns to decimal
00197 }
00198 
00199 void mbl_eps_writer::draw_image(const vil_image_view<vxl_byte>& image,
00200                                 double tx, double ty,
00201                                 double pixel_width_x, double pixel_width_y)
00202 {
00203   unsigned ni=image.ni(),nj=image.nj();
00204 
00205   if (ni<256 && nj<256)
00206   {
00207     draw_image_block(image,tx,ty,pixel_width_x,pixel_width_y);
00208     return;
00209   }
00210 
00211   // Split into smaller blocks
00212   unsigned max_w = 200;
00213   unsigned ni_blocks = 1+(ni-1)/max_w;
00214   unsigned nj_blocks = 1+(nj-1)/max_w;
00215   for (unsigned j=0;j<nj_blocks;++j)
00216     for (unsigned i=0;i<ni_blocks;++i)
00217     {
00218       unsigned wi=vcl_min(max_w,ni-(i*max_w));
00219       unsigned wj=vcl_min(max_w,nj-(j*max_w));
00220       vil_image_view<vxl_byte> cropped=vil_crop(image,i*max_w,wi,j*max_w,wj);
00221       double tx1=tx+i*max_w*pixel_width_x;
00222       double ty1=ty+j*max_w*pixel_width_y;
00223       draw_image_block(cropped,tx1,ty1,pixel_width_x,pixel_width_y);
00224     }
00225 }
00226 
00227 //: Creates a greyscale image  at (tx,ty) with given pixel widths
00228 //  Size in points given by sx(),sy() * given values.
00229 //  Image must be no bigger than 255x255
00230 //  Some postscript can't cope with bigger blocks.
00231 void mbl_eps_writer::draw_grey_image_block(
00232                     const vil_image_view<vxl_byte>& image,
00233                     double tx, double ty,
00234                     double pixel_width_x, double pixel_width_y)
00235 {
00236   assert(image.ni()<256);
00237   assert(image.nj()<256);
00238   ofs_<<"gsave\n"
00239       <<sx_*tx<<' '<<ny_-sy_*ty<<" translate\n";
00240   unsigned ni=image.ni(),nj=image.nj();
00241   ofs_<<sx_*ni*pixel_width_x<<" -"<<sy_*nj*pixel_width_y<<" scale\n"
00242       <<ni<<' '<<nj<<" % Image size\n"
00243       <<"8 % Bits per pixel\n"
00244       <<"[ "<<ni<<" 0 0 "<<nj<<" 0 0]\n";  // Transformation (unit sqr to pixels)
00245   // Now draw the image data
00246   write_image_data(ofs_,image);
00247 
00248   ofs_<<"image\n"
00249       <<"grestore\n";
00250 }
00251 
00252 //: Creates a colour image with given pixel widths
00253 //  Image assumed to be a 3 plane image.
00254 void mbl_eps_writer::draw_rgb_image_block(
00255                        const vil_image_view<vxl_byte>& image,
00256                        double tx, double ty,
00257                        double pixel_width_x, double pixel_width_y)
00258 {
00259   assert(image.ni()<256);
00260   assert(image.nj()<256);
00261 
00262   ofs_<<"gsave\n"
00263       <<sx_*tx<<' '<<ny_-sy_*ty<<" translate\n";
00264   unsigned ni=image.ni(),nj=image.nj();
00265   ofs_<<sx_*ni*pixel_width_x<<" -"<<sy_*nj*pixel_width_y<<" scale\n"
00266       <<ni<<' '<<nj<<" % Image size\n"
00267       <<"8 % Bits per pixel\n"
00268       <<"[ "<<ni<<" 0 0 "<<nj<<" 0 0]\n";  // Transformation (unit sqr to pixels)
00269   // Now draw the image data
00270   write_image_data(ofs_,vil_plane(image,0));  // Red
00271   write_image_data(ofs_,vil_plane(image,1));  // Green
00272   write_image_data(ofs_,vil_plane(image,2));  // Blue
00273 
00274   ofs_<<"true 3 colorimage\n"
00275       <<"grestore\n";
00276 }
00277 
00278 //: Creates an image  at (tx,ty) with given pixel widths
00279 //  Size in points given by sx(),sy() * given values.
00280 void mbl_eps_writer::draw_image_block(const vil_image_view<vxl_byte>& image,
00281                                       double tx, double ty,
00282                                       double pixel_width_x, double pixel_width_y)
00283 {
00284   if (image.nplanes()==1)
00285     draw_grey_image_block(image,tx,ty,pixel_width_x,pixel_width_y);
00286   else
00287   if (image.nplanes()==3)
00288     draw_rgb_image_block(image,tx,ty,pixel_width_x,pixel_width_y);
00289   else
00290     vcl_cerr<<"mbl_eps_writer::draw_image_block() Can't cope with image."<<vcl_endl;
00291 }