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
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
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
00061
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
00086 assert(format == VIL_PIXEL_FORMAT_BYTE);
00087 assert(nplanes == 1 || nplanes == 3);
00088
00089 is_->ref();
00090
00091
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
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
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);
00139 #endif
00140
00141
00142 core_hdr.read(is_);
00143 #ifdef DEBUG
00144 core_hdr.print(vcl_cerr);
00145 #endif
00146
00147
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
00155
00156 if (core_hdr.header_size == vil_bmp_core_header::disk_size)
00157 {
00158
00159 }
00160 else if (core_hdr.header_size == vil_bmp_core_header::disk_size + vil_bmp_info_header::disk_size)
00161 {
00162
00163 info_hdr.read(is_);
00164 #ifdef DEBUG
00165 info_hdr.print(vcl_cerr);
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
00176 where << "dunno about header_size " << core_hdr.header_size << '\n';
00177 return false;
00178 }
00179
00180
00181 is_->seek(file_hdr.bitmap_offset);
00182 #if 0
00183
00184 if (info_hdr.colormapsize ==0 && info_hdr.colorcount == 0)
00185 {
00186
00187 }
00188 else if (info_hdr.colormapsize == 256 && core_hdr.bitsperpixel == 8)
00189 {
00190
00191
00192
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
00212 assert(false);
00213 }
00214 #endif
00215
00216
00217 #if 0
00218
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);
00238 if (is_->read(&cmap[0], 1024L) != 1024L)
00239 {
00240 vcl_cerr << "Error reading image palette\n";
00241 return false;
00242 }
00243
00244
00245
00246 int ncolors = ccount;
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
00258 local_color_map_=color_map;
00259 }
00260 }
00261
00262
00263 #endif
00264
00265
00266 bit_map_start = is_->tell();
00267 #ifdef DEBUG
00268 where << "bit_map_start = " << bit_map_start << '\n';
00269 #endif
00270 assert(bit_map_start == (int)file_hdr.bitmap_offset);
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);
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);
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)
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
00331
00332
00333 unsigned have_bytes_per_raster = ((bytes_per_pixel * core_hdr.width + 3)/4)*4;
00334
00335
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
00343
00344
00345 y0 = nj() - (y0+ny);
00346
00347
00348
00349
00350
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);
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);
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 }