00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007
00008 #include "vil_ras.h"
00009
00010 #include <vcl_cassert.h>
00011 #include <vcl_iostream.h>
00012 #include <vcl_vector.h>
00013
00014 #include <vil/vil_stream.h>
00015 #include <vil/vil_image_resource.h>
00016 #include <vil/vil_image_view.h>
00017 #include <vil/vil_memory_chunk.h>
00018 #include <vil/vil_exception.h>
00019
00020 #include <vxl_config.h>
00021
00022 char const* vil_ras_format_tag = "ras";
00023
00024
00025
00026
00027
00028
00029 namespace
00030 {
00031 #if VXL_LITTLE_ENDIAN
00032
00033
00034 inline
00035 void swap_endian( vxl_uint_32& word )
00036 {
00037 vxl_uint_8* bytes = reinterpret_cast<vxl_uint_8*>( &word );
00038 vxl_uint_8 t = bytes[0];
00039 bytes[0] = bytes[3];
00040 bytes[3] = t;
00041 t = bytes[1];
00042 bytes[1] = bytes[2];
00043 bytes[2] = t;
00044 }
00045 #endif
00046
00047
00048
00049
00050 bool read_uint_32( vil_stream* vs, vxl_uint_32& word )
00051 {
00052 if ( vs->read( &word, 4 ) < 4 )
00053 return false;
00054 #if VXL_LITTLE_ENDIAN
00055 swap_endian( word );
00056 #endif
00057 return true;
00058 }
00059
00060
00061
00062 bool write_uint_32( vil_stream* vs, vxl_uint_32 word )
00063 {
00064 #if VXL_LITTLE_ENDIAN
00065 swap_endian( word );
00066 #endif
00067 return vs->write( &word, 4 ) == 4;
00068 }
00069
00070
00071
00072
00073
00074 vxl_uint_32 compute_length( vxl_uint_32 w, vxl_uint_32 h, vxl_uint_32 d )
00075 {
00076 w *= (d/8);
00077 w += (w%2);
00078 return h*w;
00079 }
00080
00081
00082
00083 const vxl_uint_8 RAS_MAGIC[] = { 0x59, 0xA6, 0x6A, 0x95 };
00084 const vxl_uint_32 RT_OLD = 0;
00085 const vxl_uint_32 RT_STANDARD = 1;
00086 const vxl_uint_32 RT_BYTE_ENCODED = 2;
00087 const vxl_uint_32 RT_FORMAT_RGB = 3;
00088 const vxl_uint_32 RMT_NONE = 0;
00089 const vxl_uint_32 RMT_EQUAL_RGB = 1;
00090 }
00091
00092
00093
00094
00095
00096
00097 vil_image_resource_sptr
00098 vil_ras_file_format::
00099 make_input_image( vil_stream* vs )
00100 {
00101
00102 vxl_uint_8 buf[4] = { 0, 0, 0, 0 };
00103 vs->read( buf, 4 );
00104 if ( ! ( buf[0] == RAS_MAGIC[0] && buf[1] == RAS_MAGIC[1] &&
00105 buf[2] == RAS_MAGIC[2] && buf[3] == RAS_MAGIC[3] ) )
00106 return 0;
00107
00108 return new vil_ras_image( vs );
00109 }
00110
00111
00112 vil_image_resource_sptr
00113 vil_ras_file_format::make_output_image( vil_stream* vs,
00114 unsigned ni,
00115 unsigned nj,
00116 unsigned nplanes,
00117 vil_pixel_format format)
00118 {
00119 return new vil_ras_image(vs, ni, nj, nplanes, format );
00120 }
00121
00122
00123 char const*
00124 vil_ras_file_format::
00125 tag() const
00126 {
00127 return vil_ras_format_tag;
00128 }
00129
00130
00131
00132
00133
00134
00135 vil_ras_image::
00136 vil_ras_image( vil_stream* vs ):
00137 vs_(vs)
00138 {
00139 vs_->ref();
00140 read_header();
00141 }
00142
00143
00144 bool
00145 vil_ras_image::
00146 get_property( char const* , void* ) const
00147 {
00148
00149 return false;
00150 }
00151
00152
00153 char const*
00154 vil_ras_image::
00155 file_format() const
00156 {
00157 return vil_ras_format_tag;
00158 }
00159
00160
00161 vil_ras_image::
00162 vil_ras_image(vil_stream* vs,
00163 unsigned ni,
00164 unsigned nj,
00165 unsigned nplanes,
00166 vil_pixel_format format )
00167 {
00168 vs_ = vs; vs_->ref();
00169 width_ = ni;
00170 height_ = nj;
00171
00172 components_ = nplanes * vil_pixel_format_num_components( format );
00173 if ( components_ != 1 && components_ != 3 )
00174 {
00175 vcl_cerr << __FILE__ << ": can't handle "
00176 << nplanes << " x "
00177 << vil_pixel_format_num_components( format ) << " components\n";
00178 return;
00179 }
00180
00181 bits_per_component_ = 8 * vil_pixel_format_sizeof_components( format );
00182
00183 if ( bits_per_component_ != 8 ) {
00184 vcl_cerr << __FILE__ << ": can't handle " << bits_per_component_ << " bits per component\n";
00185 return;
00186 }
00187
00188 depth_ = components_ * bits_per_component_;
00189
00190 if (components_ == 3)
00191 type_ = RT_FORMAT_RGB;
00192 else
00193 type_ = RT_STANDARD;
00194 map_type_ = RMT_NONE;
00195 map_length_ = 0;
00196 length_ = compute_length( width_, height_, depth_ );
00197 col_map_ = 0;
00198
00199 write_header();
00200 }
00201
00202
00203 vil_ras_image::
00204 ~vil_ras_image()
00205 {
00206 delete[] col_map_;
00207 vs_->unref();
00208 }
00209
00210
00211
00212 bool
00213 vil_ras_image::
00214 read_header()
00215 {
00216
00217 vs_->seek(0);
00218
00219 vxl_uint_8 buf[4];
00220 if ( vs_->read(buf, 4) < 4 )
00221 return false;
00222 if (! ( buf[0] == RAS_MAGIC[0] && buf[1] == RAS_MAGIC[1] &&
00223 buf[2] == RAS_MAGIC[2] && buf[3] == RAS_MAGIC[3] ) )
00224 return false;
00225
00226 if ( !( read_uint_32( vs_, width_ ) &&
00227 read_uint_32( vs_, height_ ) &&
00228 read_uint_32( vs_, depth_ ) &&
00229 read_uint_32( vs_, length_ ) &&
00230 read_uint_32( vs_, type_ ) &&
00231 read_uint_32( vs_, map_type_ ) &&
00232 read_uint_32( vs_, map_length_ ) ) )
00233 return false;
00234
00235
00236 if ( map_type_ != RMT_NONE || depth_ == 24 ) {
00237 components_ = 3;
00238 } else {
00239 components_ = 1;
00240 }
00241
00242 if (type_ != RT_OLD && type_ != RT_STANDARD &&
00243 type_ != RT_BYTE_ENCODED && type_ != RT_FORMAT_RGB ) {
00244 vcl_cerr << __FILE__ << ": unknown type " << type_ << vcl_endl;
00245 return false;
00246 }
00247 if ( map_type_ != RMT_NONE && map_type_ != RMT_EQUAL_RGB ) {
00248 vcl_cerr << __FILE__ << ": unknown map type " << map_type_ << vcl_endl;
00249 return false;
00250 }
00251 if ( map_type_ == RMT_NONE && map_length_ != 0 ) {
00252 vcl_cerr << __FILE__ << ": No colour map according to header, but there is a map!\n";
00253 return false;
00254 }
00255
00256 if ( depth_ != 8 && !(depth_== 16&&components_==1) && depth_ != 24 ) {
00257 vcl_cerr << __FILE__ << ": depth " << depth_ << " not implemented\n";
00258 return false;
00259 }
00260
00261
00262 if ( type_ == RT_OLD ) {
00263 length_ = compute_length( width_, height_, depth_ );
00264 }
00265 if ( length_ == 0 ) {
00266 vcl_cerr << __FILE__ << ": header says image has length zero\n";
00267 return false;
00268 }
00269 if ( type_ != RT_BYTE_ENCODED && length_ != compute_length( width_, height_, depth_ ) ) {
00270 vcl_cerr << __FILE__ << ": length " << length_ << " does not match wxhxd = "
00271 << compute_length( width_, height_, depth_ ) << vcl_endl;
00272 return false;
00273 }
00274 if ( map_length_ % 3 != 0 ) {
00275 vcl_cerr << __FILE__ << ": color map length is not a multiple of 3\n";
00276 return false;
00277 }
00278
00279 if ( map_length_ ) {
00280 col_map_ = new vxl_uint_8[ map_length_ ];
00281 vs_->read( col_map_, (vil_streampos)map_length_ );
00282 } else {
00283 col_map_ = 0;
00284 }
00285
00286 start_of_data_ = vs_->tell();
00287
00288 bits_per_component_ = 8;
00289 if (components_==1)
00290 bits_per_component_ = depth_;
00291 return true;
00292 }
00293
00294
00295 bool
00296 vil_ras_image::
00297 write_header()
00298 {
00299 vs_->seek(0);
00300
00301 vs_->write( RAS_MAGIC, 4 );
00302
00303
00304 assert( map_length_ == 0 );
00305
00306 write_uint_32( vs_, width_ );
00307 write_uint_32( vs_, height_ );
00308 write_uint_32( vs_, depth_ );
00309 write_uint_32( vs_, length_ );
00310 write_uint_32( vs_, type_ );
00311 write_uint_32( vs_, map_type_ );
00312 write_uint_32( vs_, map_length_ );
00313
00314 start_of_data_ = vs_->tell();
00315
00316 return true;
00317 }
00318
00319
00320 unsigned
00321 vil_ras_image::
00322 nplanes() const
00323 {
00324 return components_;
00325 }
00326
00327
00328 unsigned
00329 vil_ras_image::
00330 ni() const
00331 {
00332 return width_;
00333 }
00334
00335
00336 unsigned
00337 vil_ras_image::
00338 nj() const
00339 {
00340 return height_;
00341 }
00342
00343 vil_pixel_format
00344 vil_ras_image::
00345 pixel_format() const
00346 {
00347 if (bits_per_component_ == 8)
00348 return VIL_PIXEL_FORMAT_BYTE;
00349 if (bits_per_component_ == 16)
00350 return VIL_PIXEL_FORMAT_UINT_16;
00351 return VIL_PIXEL_FORMAT_UNKNOWN;
00352 }
00353
00354 vil_image_view_base_sptr
00355 vil_ras_image::
00356 get_copy_view( unsigned i0, unsigned ni,
00357 unsigned j0, unsigned nj ) const
00358 {
00359 if ( type_ == RT_BYTE_ENCODED )
00360 return 0;
00361
00362 unsigned file_bytes_per_pixel = (depth_+7)/8;
00363 unsigned buff_bytes_per_pixel = components_ * ( (bits_per_component_+7)/8 );
00364 unsigned file_byte_width = width_ * file_bytes_per_pixel;
00365 file_byte_width += ( file_byte_width % 2 );
00366 vil_streampos file_byte_start = start_of_data_ + j0 * file_byte_width + i0 * file_bytes_per_pixel;
00367 unsigned buff_byte_width = ni * buff_bytes_per_pixel;
00368 vil_pixel_format fmt = pixel_format();
00369 vil_memory_chunk_sptr buf = new vil_memory_chunk(ni * nj * buff_bytes_per_pixel, fmt );
00370
00371 vxl_uint_8* ib = reinterpret_cast<vxl_uint_8*>( buf->data() );
00372
00373 if ( !col_map_ )
00374 {
00375
00376
00377 for ( unsigned j = 0; j < nj; ++j ) {
00378 vs_->seek( file_byte_start + j * file_byte_width );
00379 vs_->read( ib + j * buff_byte_width, buff_byte_width );
00380
00381 if ( type_ != RT_FORMAT_RGB && components_ == 3 ) {
00382 vxl_uint_8* pixel = ib + j * buff_byte_width;
00383 for ( unsigned i = 0; i < ni; ++i ) {
00384 vxl_uint_8* rp = pixel+2;
00385 vxl_uint_8 t = *pixel;
00386 *pixel = *rp;
00387 *rp = t;
00388 pixel += 3;
00389 }
00390 }
00391 }
00392 }
00393 else
00394 {
00395 assert( file_bytes_per_pixel == 1 && buff_bytes_per_pixel == 3 );
00396 unsigned col_len = map_length_ / 3;
00397
00398 vcl_vector<vxl_uint_8> line( ni );
00399 for ( unsigned j = 0; j < nj; ++j ) {
00400 vs_->seek( file_byte_start + j * file_byte_width );
00401 vs_->read( &line[0], line.size() );
00402 vxl_uint_8* in_p = &line[0];
00403 vxl_uint_8* out_p = ib + j * buff_byte_width;
00404 for ( unsigned i=0; i < ni; ++i ) {
00405 assert( *in_p < col_len );
00406 *(out_p++) = col_map_[ *in_p ];
00407 *(out_p++) = col_map_[ *in_p + col_len ];
00408 *(out_p++) = col_map_[ *in_p + 2*col_len ];
00409 ++in_p;
00410 }
00411 }
00412 }
00413 if (fmt==VIL_PIXEL_FORMAT_BYTE)
00414 return new vil_image_view<vxl_byte>( buf, ib,
00415 ni, nj, components_,
00416 components_, components_*ni, 1 );
00417 if (fmt==VIL_PIXEL_FORMAT_UINT_16&&components_==1)
00418 {
00419
00420 #if (VXL_LITTLE_ENDIAN)
00421 vxl_byte s[2];
00422 for (unsigned long is = 0; is<ni*nj*2; is+=2)
00423 {
00424 s[0]= *(ib+is);
00425 s[1]= *(ib+is+1);
00426 *(ib+is)=s[1];
00427 *(ib+is+1)=s[0];
00428 }
00429 #endif
00430 vxl_uint_16* sib = reinterpret_cast<vxl_uint_16*>(ib);
00431 return new vil_image_view<vxl_uint_16>( buf, sib,
00432 ni, nj, components_,
00433 components_, components_*ni, 1 );
00434 }
00435 return 0;
00436 }
00437
00438
00439 bool
00440 vil_ras_image::
00441 put_view( const vil_image_view_base& view, unsigned i0, unsigned j0 )
00442 {
00443
00444 vil_image_view<vxl_uint_8> section( view );
00445
00446 if ( ! this->view_fits( section, i0, j0 ) ) {
00447 vil_exception_warning(vil_exception_out_of_bounds("vil_ras_image::put_view"));
00448 return false;
00449 }
00450
00451 if ( section.nplanes() != components_ ) {
00452 vcl_cerr << "ERROR: " << __FILE__ << ": data parameters of view don't match\n";
00453 return false;
00454 }
00455
00456 if ( col_map_ ) {
00457 vcl_cerr << __FILE__ << ": writing to file with a colour map is not implemented\n";
00458 return false;
00459 }
00460 if ( type_ == RT_BYTE_ENCODED ) {
00461 vcl_cerr << __FILE__ << ": writing to a run-length encoded file is not implemented\n";
00462 return false;
00463 }
00464 if ( components_ == 3 && type_ != RT_FORMAT_RGB ) {
00465 vcl_cerr << __FILE__ << ": writing BGR format is not implemented\n";
00466 return false;
00467 }
00468
00469
00470
00471 unsigned file_bytes_per_pixel = (depth_+7)/8;
00472 unsigned buff_bytes_per_pixel = components_ * ( (bits_per_component_+7)/8 );
00473 unsigned file_byte_width = width_ * file_bytes_per_pixel;
00474 file_byte_width += ( file_byte_width % 2 );
00475 vil_streampos file_byte_start = start_of_data_ + j0 * file_byte_width + i0 * file_bytes_per_pixel;
00476 unsigned buff_byte_width = view.ni() * buff_bytes_per_pixel;
00477
00478 assert( file_bytes_per_pixel == buff_bytes_per_pixel );
00479 assert( file_byte_width >= buff_byte_width );
00480
00481
00482
00483
00484
00485 vcl_vector<vxl_uint_8> data_buffer;
00486 if ( file_byte_width == buff_byte_width+1 ) {
00487 data_buffer.resize( file_byte_width );
00488 data_buffer[ file_byte_width-1 ] = 0;
00489 } else {
00490 data_buffer.resize( buff_byte_width );
00491 }
00492
00493 for ( unsigned j = 0; j < section.nj(); ++j )
00494 {
00495
00496
00497
00498
00499
00500 vxl_uint_8* ptr = &data_buffer[0];
00501 for ( unsigned i = i0; i < section.ni(); ++i ) {
00502 for ( unsigned p = 0; p < section.nplanes(); ++p ) {
00503 *ptr = section(i,j,p);
00504 ++ptr;
00505 }
00506 }
00507
00508
00509 vs_->seek( file_byte_start + j * file_byte_width );
00510 vs_->write( &data_buffer[0], data_buffer.size() );
00511 }
00512
00513 return true;
00514 }