00001
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 #include <vil/vil_exception.h>
00017
00018 #define where (vcl_cerr << __FILE__ " : " << __LINE__ << " : ")
00019
00020
00021
00022 vil_image_resource_sptr vil_bmp_file_format::make_input_image(vil_stream* vs)
00023 {
00024
00025 vil_bmp_file_header hdr;
00026 vs->seek(0L);
00027 hdr.read(vs);
00028
00029 if ( hdr.signature_valid() )
00030 return new vil_bmp_image(vs);
00031 else
00032 return 0;
00033 }
00034
00035 vil_image_resource_sptr vil_bmp_file_format::make_output_image(vil_stream* vs,
00036 unsigned nx,
00037 unsigned ny,
00038 unsigned nplanes,
00039 vil_pixel_format format)
00040 {
00041 return new vil_bmp_image(vs, nx, ny, nplanes, format);
00042 }
00043
00044 char const* vil_bmp_format_tag = "bmp";
00045
00046 char const* vil_bmp_file_format::tag() const
00047 {
00048 return vil_bmp_format_tag;
00049 }
00050
00051
00052
00053 char const* vil_bmp_image::file_format() const
00054 {
00055 return vil_bmp_format_tag;
00056 }
00057
00058 vil_bmp_image::vil_bmp_image(vil_stream* is)
00059 : is_(is)
00060 , bit_map_start(-1L)
00061 #if 0
00062 , freds_colormap(0)
00063 , local_color_map_(0)
00064 #endif
00065 {
00066 is_->ref();
00067 if (!read_header())
00068 vil_exception_error(vil_exception_image_io("vil_bmp_image::read_header", "BMP", ""));
00069 }
00070
00071 bool vil_bmp_image::get_property(char const * tag, void * value) const
00072 {
00073 if (vcl_strcmp(vil_property_quantisation_depth, tag)==0)
00074 {
00075 if (value)
00076 *static_cast<unsigned int*>(value) = core_hdr.bitsperpixel / nplanes();
00077 return true;
00078 }
00079
00080 return false;
00081 }
00082
00083 vil_bmp_image::vil_bmp_image(vil_stream* vs, unsigned nx, unsigned ny,
00084 unsigned nplanes, vil_pixel_format format):
00085 is_(vs), bit_map_start(-1L)
00086 {
00087 if (format != VIL_PIXEL_FORMAT_BYTE)
00088 vcl_cerr << "Sorry -- pixel format " << format << " not yet supported\n";
00089
00090 assert(format == VIL_PIXEL_FORMAT_BYTE);
00091 assert(nplanes == 1 || nplanes == 3 || nplanes == 4);
00092
00093 is_->ref();
00094
00095
00096 core_hdr.width = nx;
00097 core_hdr.height = ny;
00098 core_hdr.planes = 1;
00099
00100 core_hdr.bitsperpixel = 8 * nplanes;
00101
00102 write_header();
00103 }
00104
00105 vil_bmp_image::~vil_bmp_image()
00106 {
00107 #if 0
00108
00109 if (local_color_map_)
00110 {
00111 delete [] local_color_map_[0];
00112 delete [] local_color_map_[1];
00113 delete [] local_color_map_[2];
00114 delete local_color_map_;
00115 }
00116
00117 if (freds_colormap)
00118 {
00119 delete [] freds_colormap[0];
00120 delete [] freds_colormap[1];
00121 delete [] freds_colormap[2];
00122 delete [] freds_colormap[3];
00123 delete [] freds_colormap;
00124 freds_colormap = 0;
00125 }
00126 #endif
00127
00128 is_->unref();
00129 }
00130
00131 bool vil_bmp_image::read_header()
00132 {
00133
00134 is_->seek(0L);
00135 file_hdr.read(is_);
00136 if ( ! file_hdr.signature_valid() )
00137 {
00138 where << "File is not a valid BMP file\n";
00139 return false;
00140 }
00141 #ifdef DEBUG
00142 file_hdr.print(vcl_cerr);
00143 #endif
00144
00145
00146 core_hdr.read(is_);
00147 #ifdef DEBUG
00148 core_hdr.print(vcl_cerr);
00149 #endif
00150
00151
00152 if ( core_hdr.bitsperpixel != 8 && core_hdr.bitsperpixel != 24 && core_hdr.bitsperpixel != 32 )
00153 {
00154 where << "BMP file has a non-supported pixel size of " << core_hdr.bitsperpixel << " bits\n";
00155 return false;
00156 }
00157
00158
00159
00160 if (core_hdr.header_size == vil_bmp_core_header::disk_size)
00161 {
00162
00163 }
00164 else if (core_hdr.header_size == vil_bmp_core_header::disk_size + vil_bmp_info_header::disk_size)
00165 {
00166
00167 info_hdr.read(is_);
00168 #ifdef DEBUG
00169 info_hdr.print(vcl_cerr);
00170 #endif
00171 if (info_hdr.compression)
00172 {
00173 where << "cannot cope with compression at the moment\n";
00174 return false;
00175 }
00176 }
00177 else
00178 {
00179
00180 where << "dunno about header_size " << core_hdr.header_size << '\n';
00181 return false;
00182 }
00183
00184
00185 is_->seek(file_hdr.bitmap_offset);
00186 #if 0
00187
00188 if (info_hdr.colormapsize ==0 && info_hdr.colorcount == 0)
00189 {
00190
00191 }
00192 else if (info_hdr.colormapsize == 256 && core_hdr.bitsperpixel == 8)
00193 {
00194
00195
00196
00197 typedef unsigned char uchar;
00198 freds_colormap = new uchar *[4];
00199 freds_colormap[0] = new uchar[256];
00200 freds_colormap[1] = new uchar[256];
00201 freds_colormap[2] = new uchar[256];
00202 freds_colormap[3] = new uchar[256];
00203 uchar bif[4];
00204 for (int i=0; i<256; ++i)
00205 {
00206 is_->read(bif, sizeof(bif));
00207 freds_colormap[0][i] = bif[0];
00208 freds_colormap[1][i] = bif[1];
00209 freds_colormap[2][i] = bif[2];
00210 freds_colormap[3][i] = bif[3];
00211 }
00212 }
00213 else
00214 {
00215
00216 assert(false);
00217 }
00218 #endif
00219
00220
00221 #if 0
00222
00223 int ccount=0;
00224
00225 if (header.biClrUsed != 0)
00226 ccount = header.biClrUsed;
00227 else if (header.biBitCount != 24)
00228 ccount = 1 << header.biBitCount;
00229 else
00230 {
00231 }
00232
00233 if (ccount != 0)
00234 {
00235 unsigned cmap_size;
00236 if (header.biSize == sizeof(xBITMAPCOREHEADER))
00237 cmap_size = ccount*3;
00238 else
00239 cmap_size = ccount*4;
00240
00241 vcl_vector<uchar> cmap(cmap_size, 0);
00242 if (is_->read(&cmap[0], 1024L) != 1024L)
00243 {
00244 vcl_cerr << "Error reading image palette\n";
00245 return false;
00246 }
00247
00248
00249
00250 int ncolors = ccount;
00251 if (ncolors != 0)
00252 {
00253 int **color_map = new int*[3];
00254 for (int i=0; i<3; ++i)
00255 {
00256 color_map[i] = new int[ncolors];
00257 for (int j=0; j<ncolors; j++)
00258 color_map[i][j] = (int) cmap[2-i+4*j];
00259 }
00260
00261
00262 local_color_map_=color_map;
00263 }
00264 }
00265
00266
00267 #endif
00268
00269
00270 bit_map_start = is_->tell();
00271 #ifdef DEBUG
00272 where << "bit_map_start = " << bit_map_start << '\n';
00273 #endif
00274 return bit_map_start == (int)file_hdr.bitmap_offset;
00275 }
00276
00277 bool vil_bmp_image::write_header()
00278 {
00279 #ifdef DEBUG
00280 vcl_cerr << "Writing BMP header\n"
00281 << ni() << 'x' << nj() << '@'
00282 << nplanes() << 'x' <<
00283 vil_pixel_format_sizeof_components(pixel_format()) << '\n';
00284 #endif
00285
00286 int rowlen = ni() * nplanes() *
00287 vil_pixel_format_sizeof_components(pixel_format());
00288 rowlen += (3-(rowlen+3)%4);
00289 int data_size = nj() * rowlen;
00290
00291 if (nplanes() == 1)
00292 info_hdr.colorcount = info_hdr.colormapsize = 1<<
00293 vil_pixel_format_sizeof_components(pixel_format()) * 8;
00294 file_hdr.bitmap_offset = 54L + 4 * info_hdr.colormapsize;
00295 bit_map_start = file_hdr.bitmap_offset;
00296 file_hdr.file_size = file_hdr.bitmap_offset+data_size;
00297 core_hdr.header_size = 40;
00298 core_hdr.width = ni();
00299 core_hdr.height = nj();
00300 core_hdr.bitsperpixel = nplanes()*
00301 vil_pixel_format_sizeof_components(pixel_format()) * 8;
00302 info_hdr.bitmap_size = data_size;
00303
00304 #ifdef DEBUG
00305 file_hdr.print(vcl_cerr);
00306 core_hdr.print(vcl_cerr);
00307 info_hdr.print(vcl_cerr);
00308 #endif
00309 is_->seek(0L);
00310 file_hdr.write(is_);
00311 core_hdr.write(is_);
00312 info_hdr.write(is_);
00313 if (nplanes() == 1)
00314 for (int i=0; i<(1<<vil_pixel_format_sizeof_components(pixel_format())*8); ++i)
00315 for (int j=0; j<4; ++j)
00316 {
00317 unsigned char c = (unsigned char)i;
00318 is_->write(&c,1L);
00319 }
00320
00321 return true;
00322 }
00323
00324
00325 vil_image_view_base_sptr vil_bmp_image::get_copy_view(
00326 unsigned x0, unsigned nx, unsigned y0, unsigned ny) const
00327 {
00328 if (x0+nx > ni() || y0+ny > nj())
00329 {
00330 vil_exception_warning(vil_exception_out_of_bounds("vil_bmp_image::get_copy_view"));
00331 return 0;
00332 }
00333
00334 unsigned const bytes_per_pixel = core_hdr.bitsperpixel / 8;
00335 assert(core_hdr.bitsperpixel == 8 || core_hdr.bitsperpixel == 24 || core_hdr.bitsperpixel == 32 );
00336
00337
00338
00339 unsigned const have_bytes_per_raster = ((bytes_per_pixel * core_hdr.width + 3)/4)*4;
00340
00341
00342 unsigned long want_bytes_per_raster = nx*bytes_per_pixel;
00343
00344 if (nx == ni()) want_bytes_per_raster = have_bytes_per_raster;
00345
00346 vil_memory_chunk_sptr buf = new vil_memory_chunk(want_bytes_per_raster*ny, VIL_PIXEL_FORMAT_BYTE);
00347
00348
00349
00350
00351 y0 = nj() - (y0+ny);
00352
00353
00354
00355
00356
00357 vil_streampos bytes_read = 0;
00358 if (nx == ni())
00359 {
00360 is_->seek(bit_map_start + have_bytes_per_raster*y0);
00361 bytes_read = is_->read(reinterpret_cast<vxl_byte *>(buf->data()), want_bytes_per_raster *ny);
00362 }
00363 else
00364 {
00365 for (unsigned i=0; i<ny; ++i)
00366 {
00367 is_->seek(bit_map_start + have_bytes_per_raster*(i+y0) + x0*bytes_per_pixel);
00368 bytes_read += is_->read(reinterpret_cast<vxl_byte *>(buf->data()) + want_bytes_per_raster*i, want_bytes_per_raster);
00369 }
00370 }
00371 if (bytes_read != vil_streampos(ny * want_bytes_per_raster))
00372 {
00373 vil_exception_warning(
00374 vil_exception_corrupt_image_file("vil_bmp_image::get_copy_view", "BMP", ""));
00375 return 0;
00376 }
00377
00378 vcl_ptrdiff_t plane_step = 1;
00379 if( core_hdr.bitsperpixel == 24 )
00380 {
00381 return new vil_image_view<vxl_byte>(
00382 buf,
00383 reinterpret_cast<vxl_byte *>(buf->data())+(ny-1)*want_bytes_per_raster + nplanes()-1,
00384 nx, ny, nplanes(),
00385 nplanes(), -(long)want_bytes_per_raster, -1);
00386 }
00387 else if( core_hdr.bitsperpixel == 32 )
00388 {
00389
00390
00391 assert( (want_bytes_per_raster & 3) == 0 );
00392 vxl_byte* data = reinterpret_cast<vxl_byte *>(buf->data());
00393 vxl_byte* const data_end = data+(want_bytes_per_raster*ny);
00394 for(; data!=data_end; data+=4)
00395 {
00396
00397
00398
00399 vcl_swap(data[0], data[2]);
00400 }
00401 }
00402
00403 return new vil_image_view<vxl_byte>(
00404 buf,
00405 reinterpret_cast<vxl_byte *>(buf->data())+(ny-1)*want_bytes_per_raster,
00406 nx, ny, nplanes(),
00407 nplanes(), -(long)want_bytes_per_raster, plane_step);
00408 }
00409
00410
00411 bool vil_bmp_image::put_view(const vil_image_view_base& view,
00412 unsigned x0, unsigned y0)
00413 {
00414 if (!view_fits(view, x0, y0))
00415 {
00416 vil_exception_warning(vil_exception_out_of_bounds("vil_bmp_image::put_view"));
00417 return false;
00418 }
00419
00420 assert (view.pixel_format() == VIL_PIXEL_FORMAT_BYTE);
00421 const vil_image_view<vxl_byte> & view2 = static_cast<const vil_image_view<vxl_byte> &>(view);
00422
00423 unsigned const bypp = nplanes();
00424 unsigned const rowlen = ni() * bypp;
00425 unsigned const padlen = (3-(rowlen+3)%4);
00426 vxl_byte padding[3]={0, 0, 0};
00427
00428 if ((view2.planestep() == -1||nplanes()==1)&&
00429 view2.istep()==(int)view2.nplanes())
00430 {
00431 for (unsigned y=0; y<view2.nj(); ++y)
00432 {
00433 is_->seek(bit_map_start+(y+y0)*(rowlen+padlen)+x0*bypp);
00434 is_->write(&view2(0,view2.nj()-y-1,view2.nplanes()-1), rowlen);
00435 if (padlen !=0) is_->write(padding, padlen);
00436 }
00437 }
00438 else if (nplanes()==3)
00439 {
00440 assert(nplanes()==3);
00441 vxl_byte* buf = new vxl_byte[rowlen+padlen];
00442 for (unsigned i=rowlen; i<rowlen+padlen; ++i) buf[i]=0;
00443 for (unsigned j=0; j<view2.nj(); ++j)
00444 {
00445 vxl_byte* b = buf;
00446 unsigned int const negj = view2.nj()-j-1;
00447 for (unsigned i=0; i<view2.ni(); ++i)
00448 {
00449 *(b++) = view2(i, negj, 2);
00450 *(b++) = view2(i, negj, 1);
00451 *(b++) = view2(i, negj, 0);
00452 }
00453 is_->seek(bit_map_start+(j+y0)*(rowlen+padlen)+x0*bypp);
00454 is_->write(buf, rowlen+padlen);
00455 }
00456 delete [] buf;
00457 }
00458 else
00459 {
00460 assert(nplanes()==4);
00461 vxl_byte* buf = new vxl_byte[rowlen+padlen];
00462 for (unsigned i=rowlen; i<rowlen+padlen; ++i) buf[i]=0;
00463 for (unsigned j=0; j<view2.nj(); ++j)
00464 {
00465 vxl_byte* b = buf;
00466 unsigned int const negj = view2.nj()-j-1;
00467 for (unsigned i=0; i<view2.ni(); ++i)
00468 {
00469 *(b++) = view2(i, negj, 2);
00470 *(b++) = view2(i, negj, 1);
00471 *(b++) = view2(i, negj, 0);
00472 *(b++) = view2(i, negj, 3);
00473 }
00474 is_->seek(bit_map_start+(j+y0)*(rowlen+padlen)+x0*bypp);
00475 is_->write(buf, rowlen+padlen);
00476 }
00477 delete [] buf;
00478 }
00479 return true;
00480 }