core/vil/file_formats/vil_bmp.cxx

Go to the documentation of this file.
00001 // This is core/vil/file_formats/vil_bmp.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 
00006 #include "vil_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 <vil/vil_stream.h>
00013 #include <vil/vil_property.h>
00014 #include <vil/vil_memory_chunk.h>
00015 #include <vil/vil_image_view.h>
00016 
00017 #define where (vcl_cerr << __FILE__ " : " << __LINE__ << " : ")
00018 
00019 //--------------------------------------------------------------------------------
00020 
00021 vil_image_resource_sptr vil_bmp_file_format::make_input_image(vil_stream* vs)
00022 {
00023   // Attempt to read header
00024   vil_bmp_file_header hdr;
00025   vs->seek(0L);
00026   hdr.read(vs);
00027 
00028   if ( hdr.signature_valid() )
00029     return new vil_bmp_image(vs);
00030   else
00031     return 0;
00032 }
00033 
00034 vil_image_resource_sptr vil_bmp_file_format::make_output_image(vil_stream* vs,
00035                                                                unsigned nx,
00036                                                                unsigned ny,
00037                                                                unsigned nplanes,
00038                                                                vil_pixel_format format)
00039 {
00040   return new vil_bmp_image(vs, nx, ny, nplanes, format);
00041 }
00042 
00043 char const* vil_bmp_format_tag = "bmp";
00044 
00045 char const* vil_bmp_file_format::tag() const
00046 {
00047   return vil_bmp_format_tag;
00048 }
00049 
00050 /////////////////////////////////////////////////////////////////////////////
00051 
00052 char const* vil_bmp_image::file_format() const
00053 {
00054   return vil_bmp_format_tag;
00055 }
00056 
00057 vil_bmp_image::vil_bmp_image(vil_stream* is)
00058   : is_(is)
00059   , bit_map_start(-1L)
00060   //, freds_colormap(0)
00061   //, local_color_map_(0)
00062 {
00063   is_->ref();
00064   read_header();
00065 }
00066 
00067 bool vil_bmp_image::get_property(char const * tag, void * value) const
00068 {
00069   if (vcl_strcmp(vil_property_quantisation_depth, tag)==0)
00070   {
00071     if (value)
00072       *static_cast<unsigned int*>(value) = core_hdr.bitsperpixel / nplanes();
00073     return true;
00074   }
00075 
00076   return false;
00077 }
00078 
00079 vil_bmp_image::vil_bmp_image(vil_stream* vs, unsigned nx, unsigned ny,
00080                              unsigned nplanes, vil_pixel_format format):
00081   is_(vs), bit_map_start(-1L)
00082 {
00083   if (format != VIL_PIXEL_FORMAT_BYTE)
00084     vcl_cerr << "Sorry -- pixel format " << format << " not yet supported\n";
00085   // FIXME - we only support 8 and 24 bpp; add support for 1, 4, 16 and 32 bpp
00086   assert(format == VIL_PIXEL_FORMAT_BYTE);
00087   assert(nplanes == 1 || nplanes == 3);
00088 
00089   is_->ref();
00090 
00091   // core_hdr.header_size is set up for us.
00092   core_hdr.width = nx;
00093   core_hdr.height = ny;
00094   core_hdr.planes = 1;
00095 
00096   core_hdr.bitsperpixel = 8 * nplanes;
00097 
00098   write_header();
00099 }
00100 
00101 vil_bmp_image::~vil_bmp_image()
00102 {
00103 #if 0
00104   // we must get rid of the local_color_map_;
00105   if (local_color_map_)
00106   {
00107     delete [] local_color_map_[0];
00108     delete [] local_color_map_[1];
00109     delete [] local_color_map_[2];
00110     delete local_color_map_;
00111   }
00112 
00113   if (freds_colormap)
00114   {
00115     delete [] freds_colormap[0];
00116     delete [] freds_colormap[1];
00117     delete [] freds_colormap[2];
00118     delete [] freds_colormap[3];
00119     delete [] freds_colormap;
00120     freds_colormap = 0;
00121   }
00122 #endif
00123 
00124   is_->unref();
00125 }
00126 
00127 bool vil_bmp_image::read_header()
00128 {
00129   // seek to beginning and read file header.
00130   is_->seek(0L);
00131   file_hdr.read(is_);
00132   if ( ! file_hdr.signature_valid() )
00133   {
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   {
00150     where << "BMP file has a non-supported pixel size of " << core_hdr.bitsperpixel << " bits\n";
00151     return false;
00152   }
00153 
00154   // determine whether or not there is an info header from
00155   // the size field.
00156   if (core_hdr.header_size == vil_bmp_core_header::disk_size)
00157   {
00158     // no info header.
00159   }
00160   else if (core_hdr.header_size == vil_bmp_core_header::disk_size + vil_bmp_info_header::disk_size)
00161   {
00162     // probably an info header. read it now.
00163     info_hdr.read(is_);
00164 #ifdef DEBUG
00165     info_hdr.print(vcl_cerr); // blather
00166 #endif
00167     if (info_hdr.compression)
00168     {
00169       where << "cannot cope with compression at the moment\n";
00170       return false;
00171     }
00172   }
00173   else
00174   {
00175     // urgh!
00176     where << "dunno about header_size " << core_hdr.header_size << '\n';
00177     return false;
00178   }
00179 
00180   // skip colormap info
00181   is_->seek(file_hdr.bitmap_offset); // === seek(is_->tell()+info_hdr.colormapsize);
00182 #if 0
00183   // color map nonsense
00184   if (info_hdr.colormapsize ==0 && info_hdr.colorcount == 0)
00185   {
00186     // phew! no colour map.
00187   }
00188   else if (info_hdr.colormapsize == 256 && core_hdr.bitsperpixel == 8)
00189   {
00190     // In this case I know how to read the colormap because I have hexdumped an example.
00191     // But I ignore the color map in the get_view( Fix params) routine because I don't care.
00192     // fsm
00193     typedef unsigned char uchar;
00194     freds_colormap = new uchar *[4];
00195     freds_colormap[0] = new uchar[256];
00196     freds_colormap[1] = new uchar[256];
00197     freds_colormap[2] = new uchar[256];
00198     freds_colormap[3] = new uchar[256];
00199     uchar bif[4];
00200     for (int i=0; i<256; ++i)
00201     {
00202       is_->read(bif, sizeof(bif));
00203       freds_colormap[0][i] = bif[0];
00204       freds_colormap[1][i] = bif[1];
00205       freds_colormap[2][i] = bif[2];
00206       freds_colormap[3][i] = bif[3];
00207     }
00208   }
00209   else
00210   {
00211     // dunno about this.
00212     assert(false); // FIXME
00213   }
00214 #endif
00215 
00216   // old colormap reading code. it's not clear whether or not it worked -- fsm.
00217 #if 0
00218   // Determine the number of colors and set color map if necessary
00219   int ccount=0;
00220 
00221   if (header.biClrUsed != 0)
00222     ccount = header.biClrUsed;
00223   else if (header.biBitCount != 24)
00224     ccount = 1 << header.biBitCount;
00225   else
00226   {
00227   }
00228 
00229   if (ccount != 0)
00230   {
00231     unsigned cmap_size;
00232     if (header.biSize == sizeof(xBITMAPCOREHEADER))
00233       cmap_size = ccount*3;
00234     else
00235       cmap_size = ccount*4;
00236 
00237     vcl_vector<uchar> cmap(cmap_size, 0); // use vector<> to avoid coreleak
00238     if (is_->read(/* xxx */&cmap[0], 1024L) != 1024L)
00239     {
00240       vcl_cerr << "Error reading image palette\n";
00241       return false;
00242     }
00243 
00244     // SetColorNum(ccount);
00245     // int ncolors = get_color_num();
00246     int ncolors = ccount; // good guess
00247     if (ncolors != 0)
00248     {
00249       int **color_map = new int*[3];
00250       for (int i=0; i<3; ++i)
00251       {
00252         color_map[i] = new int[ncolors];
00253         for (int j=0; j<ncolors; j++)
00254           color_map[i][j] = (int) cmap[2-i+4*j];
00255       }
00256 
00257       // SetColorMap(color_map);  - TODO find out where to save a color map
00258       local_color_map_=color_map;
00259     }
00260   }
00261 
00262   // TODO not obvious where the magic number is read
00263 #endif
00264 
00265   // remember the position of the start of the bitmap data
00266   bit_map_start = is_->tell();
00267 #ifdef DEBUG
00268   where << "bit_map_start = " << bit_map_start << '\n'; // blather
00269 #endif
00270   assert(bit_map_start == (int)file_hdr.bitmap_offset); // I think they're supposed to be the same -- fsm.
00271 
00272   return true;
00273 }
00274 
00275 bool vil_bmp_image::write_header()
00276 {
00277 #ifdef DEBUG
00278   vcl_cerr << "Writing BMP header\n"
00279            << ni() << 'x' << nj() << '@'
00280            << nplanes() << 'x' <<
00281            vil_pixel_format_sizeof_components(pixel_format()) << '\n';
00282 #endif
00283 
00284   int rowlen = ni() * nplanes() *
00285     vil_pixel_format_sizeof_components(pixel_format());
00286   rowlen += (3-(rowlen+3)%4); // round up to a multiple of 4
00287   int data_size = nj() * rowlen;
00288 
00289   if (nplanes() == 1)
00290     info_hdr.colorcount = info_hdr.colormapsize = 1<<
00291       vil_pixel_format_sizeof_components(pixel_format()) * 8;
00292   file_hdr.bitmap_offset = 54L + 4 * info_hdr.colormapsize;
00293   bit_map_start = file_hdr.bitmap_offset;
00294   file_hdr.file_size = file_hdr.bitmap_offset+data_size;
00295   core_hdr.header_size = 40;
00296   core_hdr.width = ni();
00297   core_hdr.height = nj();
00298   core_hdr.bitsperpixel = nplanes()*
00299     vil_pixel_format_sizeof_components(pixel_format()) * 8;
00300   info_hdr.bitmap_size = data_size;
00301 
00302 #ifdef DEBUG
00303   file_hdr.print(vcl_cerr);
00304   core_hdr.print(vcl_cerr); // blather
00305   info_hdr.print(vcl_cerr);
00306 #endif
00307   is_->seek(0L);
00308   file_hdr.write(is_);
00309   core_hdr.write(is_);
00310   info_hdr.write(is_);
00311   if (nplanes() == 1) // Need to write a colourmap in this case
00312     for (int i=0; i<(1<<vil_pixel_format_sizeof_components(pixel_format())*8); ++i)
00313       for (int j=0; j<4; ++j)
00314       {
00315         unsigned char c = i;
00316         is_->write(&c,1L);
00317       }
00318 
00319   return true;
00320 }
00321 
00322 //------------------------------------------------------------
00323 vil_image_view_base_sptr vil_bmp_image::get_copy_view(
00324   unsigned x0, unsigned nx, unsigned y0, unsigned ny) const
00325 {
00326   if (x0+nx > ni() || y0+ny > nj()) return 0;
00327   //
00328   unsigned bytes_per_pixel = core_hdr.bitsperpixel / 8;
00329   assert(core_hdr.bitsperpixel == 8 || core_hdr.bitsperpixel == 24);
00330   // FIXME - add support for 1, 4, 16 and 32 bpp
00331 
00332   // actual number of bytes per raster in file.
00333   unsigned have_bytes_per_raster = ((bytes_per_pixel * core_hdr.width + 3)/4)*4;
00334 
00335   // number of bytes we want per raster.
00336   unsigned long want_bytes_per_raster = nx*bytes_per_pixel;
00337 
00338   if (nx == ni()) want_bytes_per_raster =  have_bytes_per_raster;
00339 
00340   vil_memory_chunk_sptr buf = new vil_memory_chunk(want_bytes_per_raster*ny, VIL_PIXEL_FORMAT_BYTE);
00341 
00342   // BMP images are stored with a flipped y-axis w.r.t. conventional
00343   // pixel axes.
00344   //
00345   y0 = nj() - (y0+ny);
00346 
00347   // read each raster in turn. if the client wants the whole image, it may
00348   // be faster to read() it all in one chunk, so long as the number of bytes
00349   // per image raster is divisible by four (because the file rasters are
00350   // padded at the ends).
00351   if (nx == ni())
00352   {
00353     is_->seek(bit_map_start + have_bytes_per_raster*y0);
00354     is_->read(reinterpret_cast<vxl_byte *>(buf->data()), want_bytes_per_raster *ny);
00355   }
00356   else
00357   {
00358     for (unsigned i=0; i<ny; ++i)
00359     {
00360       is_->seek(bit_map_start + have_bytes_per_raster*(i+y0) + x0*bytes_per_pixel);
00361       is_->read(reinterpret_cast<vxl_byte *>(buf->data()) + want_bytes_per_raster*i, want_bytes_per_raster);
00362     }
00363   }
00364 
00365   return new vil_image_view<vxl_byte>(
00366     buf,
00367     reinterpret_cast<vxl_byte *>(buf->data())+(ny-1)*want_bytes_per_raster + nplanes()-1,
00368     nx, ny, nplanes(),
00369     nplanes(), -(long)want_bytes_per_raster, -1);
00370 }
00371 
00372 
00373 bool vil_bmp_image::put_view(const vil_image_view_base& view,
00374                              unsigned x0, unsigned y0)
00375 {
00376   if (!view_fits(view, x0, y0))
00377   {
00378     vcl_cerr << "ERROR: " << __FILE__ << ":\n view does not fit\n";
00379     return false;
00380   }
00381 
00382   assert (view.pixel_format() == VIL_PIXEL_FORMAT_BYTE); // FIXME
00383   const vil_image_view<vxl_byte> & view2 = static_cast<const vil_image_view<vxl_byte> &>(view);
00384 
00385   unsigned bypp = nplanes();
00386   unsigned rowlen = ni() * bypp;
00387   unsigned padlen = (3-(rowlen+3)%4); // round row length up to a multiple of 4
00388   vxl_byte padding[3]={0, 0, 0};
00389 
00390   if ((view2.planestep() == -1||nplanes()==1)&&
00391       view2.istep()==(int)view2.nplanes())
00392   {
00393     for (unsigned y=0; y<view2.nj(); ++y)
00394     {
00395       is_->seek(bit_map_start+(y+y0)*(rowlen+padlen)+x0*bypp);
00396       is_->write(&view2(0,view2.nj()-y-1,view2.nplanes()-1), rowlen);
00397       if (padlen !=0) is_->write(padding, padlen);
00398     }
00399   }
00400   else
00401   {
00402     assert(nplanes()==3);
00403     vxl_byte* buf = new vxl_byte[rowlen+padlen];
00404     for (unsigned i=rowlen; i<rowlen+padlen; ++i) buf[i]=0;
00405     for (unsigned j=0; j<view2.nj(); ++j)
00406     {
00407       vxl_byte* b = buf;
00408       for (unsigned i=0; i<view2.ni(); ++i)
00409       {
00410         *(b++) = view2(i, view2.nj()-j-1, 2);
00411         *(b++) = view2(i, view2.nj()-j-1, 1);
00412         *(b++) = view2(i, view2.nj()-j-1, 0);
00413       }
00414       is_->seek(bit_map_start+(j+y0)*(rowlen+padlen)+x0*bypp);
00415       is_->write(buf, rowlen+padlen);
00416     }
00417     delete [] buf;
00418   }
00419   return true;
00420 }

Generated on Sat Nov 22 05:07:51 2008 for core/vil by  doxygen 1.5.1