core/vil1/file_formats/vil1_bmp.cxx

Go to the documentation of this file.
00001 // This is core/vil1/file_formats/vil1_bmp.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 
00006 #include "vil1_bmp.h"
00007 
00008 #include <vcl_cassert.h>
00009 #include <vcl_iostream.h>
00010 #include <vcl_vector.h>
00011 #include <vcl_cstring.h>
00012 #include <vil1/vil1_stream.h>
00013 #include <vil1/vil1_property.h>
00014 
00015 #define where (vcl_cerr << __FILE__ ":" << __LINE__ << " : ")
00016 
00017 //--------------------------------------------------------------------------------
00018 
00019 char const* vil1_bmp_format_tag = "bmp";
00020 
00021 vil1_image_impl* vil1_bmp_file_format::make_input_image(vil1_stream* is)
00022 {
00023   // Attempt to read header
00024   vil1_bmp_file_header hdr;
00025   is->seek(0L);
00026   hdr.read(is);
00027 
00028   if ( hdr.signature_valid() )
00029     return new vil1_bmp_generic_image(is);
00030   else
00031     return 0;
00032 }
00033 
00034 vil1_image_impl* vil1_bmp_file_format::make_output_image(vil1_stream* is, int planes,
00035                                                          int width,
00036                                                          int height,
00037                                                          int components,
00038                                                          int bits_per_component,
00039                                                          vil1_component_format format)
00040 {
00041   return new vil1_bmp_generic_image(is, planes, width, height, components, bits_per_component, format);
00042 }
00043 
00044 char const* vil1_bmp_file_format::tag() const
00045 {
00046   return vil1_bmp_format_tag;
00047 }
00048 
00049 /////////////////////////////////////////////////////////////////////////////
00050 
00051 char const* vil1_bmp_generic_image::file_format() const
00052 {
00053   return vil1_bmp_format_tag;
00054 }
00055 
00056 vil1_bmp_generic_image::vil1_bmp_generic_image(vil1_stream* is)
00057   : is_(is)
00058   , bit_map_start(-1L)
00059   //, freds_colormap(0)
00060   //, local_color_map_(0)
00061 {
00062   is_->ref();
00063   read_header();
00064 }
00065 
00066 bool vil1_bmp_generic_image::get_property(char const *tag, void *prop) const
00067 {
00068   if (0==vcl_strcmp(tag, vil1_property_top_row_first))
00069     return prop ? (*(bool*)prop) = false, true : true;
00070 
00071   if (0==vcl_strcmp(tag, vil1_property_left_first))
00072     return prop ? (*(bool*)prop) = true : true;
00073 
00074   if (0==vcl_strcmp(tag, vil1_property_component_order_is_BGR))
00075     return prop ? (*(bool*)prop) = true : true;
00076 
00077   return false;
00078 }
00079 
00080 vil1_bmp_generic_image::vil1_bmp_generic_image(vil1_stream* is,
00081                                                int planes,
00082                                                int width,
00083                                                int height,
00084                                                int components,
00085                                                int bits_per_component,
00086                                                vil1_component_format /*format*/)
00087   : is_(is)
00088   , bit_map_start(-1L)
00089 {
00090   is_->ref();
00091   assert(planes == 1); // FIXME
00092 
00093   // core_hdr.header_size is set up for us.
00094   core_hdr.width = width;
00095   core_hdr.height = height;
00096   core_hdr.planes = planes;
00097   // FIXME - we only support 8 and 24 bpp; add support for 1, 4, 16 and 32 bpp
00098   assert(bits_per_component == 8 && (components == 1 || components == 3));
00099   core_hdr.bitsperpixel = bits_per_component * components;
00100 
00101   write_header();
00102 }
00103 
00104 vil1_bmp_generic_image::~vil1_bmp_generic_image()
00105 {
00106 #if 0
00107   // we must get rid of the local_color_map_;
00108   if (local_color_map_){
00109     delete [] local_color_map_[0];
00110     delete [] local_color_map_[1];
00111     delete [] local_color_map_[2];
00112     delete local_color_map_;
00113   }
00114 
00115   if (freds_colormap) {
00116     delete [] freds_colormap[0];
00117     delete [] freds_colormap[1];
00118     delete [] freds_colormap[2];
00119     delete [] freds_colormap[3];
00120     delete [] freds_colormap;
00121     freds_colormap = 0;
00122   }
00123 #endif
00124 
00125   is_->unref();
00126 }
00127 
00128 bool vil1_bmp_generic_image::read_header()
00129 {
00130   // seek to beginning and read file header.
00131   is_->seek(0L);
00132   file_hdr.read(is_);
00133   if ( ! file_hdr.signature_valid() ) {
00134     where <<  "File is not a valid BMP file\n";
00135     return false;
00136   }
00137 #ifdef DEBUG
00138   file_hdr.print(vcl_cerr); // blather
00139 #endif
00140 
00141   // read core header
00142   core_hdr.read(is_);
00143 #ifdef DEBUG
00144   core_hdr.print(vcl_cerr); // blather
00145 #endif
00146   // allowed values for bitsperpixel are 1 4 8 16 24 32;
00147   // currently we only support 8 and 24 - FIXME
00148   if ( core_hdr.bitsperpixel != 8 && core_hdr.bitsperpixel != 24 ) {
00149     where << "BMP file has a non-supported pixel size of " << core_hdr.bitsperpixel << " bits\n";
00150     return false;
00151   }
00152 
00153   // determine whether or not there is an info header from
00154   // the size field.
00155   if (core_hdr.header_size == vil1_bmp_core_header::disk_size) {
00156     // no info header.
00157   }
00158   else if (core_hdr.header_size == vil1_bmp_core_header::disk_size + vil1_bmp_info_header::disk_size) {
00159     // probably an info header. read it now.
00160     info_hdr.read(is_);
00161 #ifdef DEBUG
00162     info_hdr.print(vcl_cerr); // blather
00163 #endif
00164     if (info_hdr.compression) {
00165       where << "cannot cope with compression at the moment\n";
00166       return false;
00167     }
00168   }
00169   else {
00170     // urgh!
00171     where << "dunno about header_size " << core_hdr.header_size << vcl_endl;
00172     return false;
00173   }
00174 
00175   // skip colormap info
00176   is_->seek(file_hdr.bitmap_offset); // === seek(is_->tell()+info_hdr.colormapsize);
00177 #if 0
00178   // color map nonsense
00179   if (info_hdr.colormapsize ==0 && info_hdr.colorcount == 0) {
00180     // phew! no colour map.
00181   }
00182   else if (info_hdr.colormapsize == 256 && core_hdr.bitsperpixel == 8) {
00183     // In this case I know how to read the colormap because I have hexdumped an example.
00184     // But I ignore the color map in the get_section() routine because I don't care.
00185     // fsm
00186     typedef unsigned char uchar;
00187     freds_colormap = new uchar *[4];
00188     freds_colormap[0] = new uchar[256];
00189     freds_colormap[1] = new uchar[256];
00190     freds_colormap[2] = new uchar[256];
00191     freds_colormap[3] = new uchar[256];
00192     uchar bif[4];
00193     for (int i=0; i<256; ++i) {
00194       is_->read(bif, sizeof(bif));
00195       freds_colormap[0][i] = bif[0];
00196       freds_colormap[1][i] = bif[1];
00197       freds_colormap[2][i] = bif[2];
00198       freds_colormap[3][i] = bif[3];
00199     }
00200   }
00201   else {
00202     // dunno about this.
00203     assert(false); // FIXME
00204   }
00205 #endif
00206 
00207   // old colormap reading code. it's not clear whether or not it worked -- fsm.
00208 #if 0
00209   // Determine the number of colors and set color map if necessary
00210   int ccount=0;
00211 
00212   if (header.biClrUsed != 0)
00213     ccount = header.biClrUsed;
00214   else if (header.biBitCount != 24)
00215     ccount = 1 << header.biBitCount;
00216   else {
00217   }
00218 
00219   if (ccount != 0) {
00220     unsigned cmap_size;
00221     if (header.biSize == sizeof(xBITMAPCOREHEADER))
00222       cmap_size = ccount*3;
00223     else
00224       cmap_size = ccount*4;
00225 
00226     vcl_vector<uchar> cmap(cmap_size, 0); // use vector<> to avoid coreleak
00227     if (is_->read(/* xxx */&cmap[0], 1024L) != 1024L) {
00228       vcl_cerr << "Error reading image palette\n";
00229       return false;
00230     }
00231 
00232     // SetColorNum(ccount);
00233     // int ncolors = get_color_num();
00234     int ncolors = ccount; // good guess
00235     if (ncolors != 0) {
00236       int **color_map = new int*[3];
00237       for (int i=0; i<3; ++i) {
00238         color_map[i] = new int[ncolors];
00239         for (int j=0; j<ncolors; j++)
00240           color_map[i][j] = (int) cmap[2-i+4*j];
00241       }
00242 
00243       // SetColorMap(color_map);  - TODO find out where to save a color map
00244       local_color_map_=color_map;
00245     }
00246   }
00247 
00248   // TODO not obvious where the magic number is read
00249 #endif
00250 
00251   // remember the position of the start of the bitmap data
00252   bit_map_start = is_->tell();
00253 #ifdef DEBUG
00254   where << "bit_map_start = " << bit_map_start << vcl_endl; // blather
00255 #endif
00256   assert(bit_map_start == (int)file_hdr.bitmap_offset); // I think they're supposed to be the same -- fsm.
00257 
00258   return true;
00259 }
00260 
00261 bool vil1_bmp_generic_image::write_header()
00262 {
00263 #ifdef DEBUG
00264   vcl_cerr << "Writing BMP header\n"
00265            << width() << 'x' << height() << '@'
00266            << components() << 'x' << bits_per_component() << '\n';
00267 #endif
00268 
00269   int rowlen = width() * components() * bits_per_component() / 8;
00270   rowlen += (3-(rowlen-1)%4); // round up to multiple of 4
00271   int data_size = height() * rowlen;
00272 
00273   if (components() == 1)
00274     info_hdr.colorcount = info_hdr.colormapsize = 1<<bits_per_component();
00275   file_hdr.bitmap_offset = bit_map_start = 54L + 4 * info_hdr.colormapsize;
00276   file_hdr.file_size = bit_map_start+data_size;
00277   core_hdr.header_size = 40;
00278   core_hdr.width = width();
00279   core_hdr.height = height();
00280   core_hdr.bitsperpixel = components()*bits_per_component();
00281   info_hdr.bitmap_size = data_size;
00282 
00283   is_->seek(0L);
00284   file_hdr.write(is_);
00285   core_hdr.write(is_);
00286   info_hdr.write(is_);
00287   if (components() == 1) // Need to write a colourmap in this case
00288     for (int i=0; i<(1<<bits_per_component()); ++i)
00289       for (int j=0; j<4; ++j)
00290       {
00291         unsigned char c = i;
00292         is_->write(&c,1L);
00293       }
00294 
00295   return true;
00296 }
00297 
00298 //------------------------------------------------------------
00299 
00300 bool vil1_bmp_generic_image::get_section(void* ib, int x0, int y0, int w, int h) const
00301 {
00302   assert(ib != 0);
00303   char *bp = static_cast<char*>(ib);
00304 
00305   //
00306   unsigned bytes_per_pixel = core_hdr.bitsperpixel / 8;
00307   assert(core_hdr.bitsperpixel == 8 || core_hdr.bitsperpixel == 24);
00308   // FIXME - add support for 1, 4, 16 and 32 bpp
00309 
00310   // actual number of bytes per raster in file.
00311   unsigned have_bytes_per_raster = ((bytes_per_pixel * core_hdr.width + 3)>>2)<<2;
00312 
00313   // number of bytes we want per raster.
00314   unsigned long want_bytes_per_raster = w*bytes_per_pixel;
00315 
00316   // read each raster in turn. if the client wants the whole image, it may
00317   // be faster to read() it all in one chunk, so long as the number of bytes
00318   // per image raster is divisible by four (because the file rasters are
00319   // padded at the ends).
00320   for (int i=0; i<h; ++i) {
00321     is_->seek(bit_map_start + have_bytes_per_raster*(i+y0) + x0*bytes_per_pixel);
00322     is_->read(bp + want_bytes_per_raster*i, want_bytes_per_raster);
00323   }
00324 
00325   return true;
00326 }
00327 
00328 
00329 bool vil1_bmp_generic_image::put_section(void const *ib, int x0, int y0, int xs, int ys)
00330 {
00331   assert(ib != 0);
00332   int bypp = (components() * bits_per_component() +7) / 8;
00333   int rowlen = width() * bypp;
00334   rowlen += (3-(rowlen-1)%4); // round up to a multiple of 4
00335 
00336   int skip_rows = height()-y0-ys;
00337 
00338   for (int y=0; y<ys; ++y,++skip_rows)
00339   {
00340     is_->seek(bit_map_start+skip_rows*rowlen+x0*bypp);
00341     is_->write(((char const*)ib)+y*xs*bypp, xs*bypp);
00342   }
00343 
00344   return true;
00345 }

Generated on Sat Nov 22 05:08:28 2008 for core/vil1 by  doxygen 1.5.1