core/vil1/file_formats/vil1_ras.cxx

Go to the documentation of this file.
00001 // This is core/vil1/file_formats/vil1_ras.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 
00008 #include "vil1_ras.h"
00009 
00010 #include <vcl_cassert.h>
00011 #include <vcl_iostream.h>
00012 #include <vcl_cstring.h>
00013 
00014 #include <vil1/vil1_stream.h>
00015 #include <vil1/vil1_image_impl.h>
00016 #include <vil1/vil1_image.h>
00017 #include <vil1/vil1_property.h>
00018 
00019 #include <vxl_config.h>
00020 
00021 char const* vil1_ras_format_tag = "ras";
00022 
00023 namespace {
00024 #if VXL_LITTLE_ENDIAN
00025   inline void swap_endian( vxl_uint_32& word )
00026   {
00027     vxl_uint_8* bytes = (vxl_uint_8*)&word;
00028     vxl_uint_8 t = bytes[0];
00029     bytes[0] = bytes[3];
00030     bytes[3] = t;
00031     t = bytes[1];
00032     bytes[1] = bytes[2];
00033     bytes[2] = t;
00034   }
00035 #else // VXL_BIG_ENDIAN: do nothing
00036   inline void swap_endian( vxl_uint_32& ) {}
00037 #endif
00038 
00039   // Equivalent of ntoh
00040   bool read_uint_32( vil1_stream* vs, vxl_uint_32& word )
00041   {
00042     if ( vs->read( &word, 4 ) < 4 )
00043       return false;
00044     swap_endian( word );
00045     return true;
00046   }
00047 
00048   // Equivalent of hton
00049   bool write_uint_32( vil1_stream* vs, vxl_uint_32 word )
00050   {
00051     swap_endian( word );
00052     return vs->write( &word, 4 ) == 4;
00053   }
00054 
00055   // Compute the length of the data from the width, height and depth,
00056   // accounting for any padding that may be necessary to keep the scan
00057   // lines on 16-bit boundaries.
00058   vxl_uint_32 compute_length( vxl_uint_32 w, vxl_uint_32 h, vxl_uint_32 d )
00059   {
00060     w *= (d/8);
00061     w += (w%2);
00062     return h*w;
00063   }
00064 
00065   // From http://gmt.soest.hawaii.edu/gmt/doc/html/GMT_Docs/node111.html
00066   // and other documents on the web.
00067   const vxl_uint_8 RAS_MAGIC[] = { 0x59, 0xA6, 0x6A, 0x95 };
00068   const vxl_uint_32 RT_OLD = 0;          // Raw pixrect image in MSB-first order
00069   const vxl_uint_32 RT_STANDARD = 1;     // Raw pixrect image in MSB-first order
00070   const vxl_uint_32 RT_BYTE_ENCODED = 2; // (Run-length compression of bytes)
00071   const vxl_uint_32 RT_FORMAT_RGB = 3;   // ([X]RGB instead of [X]BGR)
00072   const vxl_uint_32 RMT_NONE = 0;        // No colourmap (ras_maplength is expected to be 0)
00073   const vxl_uint_32 RMT_EQUAL_RGB = 1;   // (red[ras_maplength/3],green[],blue[])
00074 }
00075 
00076 
00077 vil1_image_impl* vil1_ras_file_format::make_input_image(vil1_stream* vs)
00078 {
00079   // Check the magic number
00080   vxl_uint_8 buf[4] = { 0, 0, 0, 0 };
00081   vs->read(buf, 4);
00082   if ( ! ( buf[0] == RAS_MAGIC[0] && buf[1] == RAS_MAGIC[1] &&
00083            buf[2] == RAS_MAGIC[2] && buf[3] == RAS_MAGIC[3]  ) )
00084     return 0;
00085 
00086   return new vil1_ras_generic_image(vs);
00087 }
00088 
00089 vil1_image_impl* vil1_ras_file_format::make_output_image(vil1_stream* vs, int planes,
00090                                                          int width,
00091                                                          int height,
00092                                                          int components,
00093                                                          int bits_per_component,
00094                                                          vil1_component_format format)
00095 {
00096   return new vil1_ras_generic_image(vs, planes, width, height, components, bits_per_component, format);
00097 }
00098 
00099 char const* vil1_ras_file_format::tag() const
00100 {
00101   return vil1_ras_format_tag;
00102 }
00103 
00104 /////////////////////////////////////////////////////////////////////////////
00105 
00106 vil1_ras_generic_image::vil1_ras_generic_image(vil1_stream* vs):
00107   vs_(vs)
00108 {
00109   vs_->ref();
00110   read_header();
00111 }
00112 
00113 bool vil1_ras_generic_image::get_property(char const *tag, void *prop) const
00114 {
00115   if (0==vcl_strcmp(tag, vil1_property_top_row_first))
00116     return prop ? (*(bool*)prop) = true : true;
00117 
00118   if (0==vcl_strcmp(tag, vil1_property_left_first))
00119     return prop ? (*(bool*)prop) = true : true;
00120 
00121   // The default raw colour format is BGR. The default indexed colour
00122   // format is RGB. Go figure.
00123   if (0==vcl_strcmp(tag, vil1_property_component_order_is_BGR)) {
00124     if ( prop )
00125       (*(bool*)prop) = ( map_type_ == RMT_NONE && type_ != RT_FORMAT_RGB );
00126     return true;
00127   }
00128 
00129   return false;
00130 }
00131 
00132 char const* vil1_ras_generic_image::file_format() const
00133 {
00134   return vil1_ras_format_tag;
00135 }
00136 
00137 vil1_ras_generic_image::vil1_ras_generic_image(vil1_stream* vs, int planes,
00138                                                int width,
00139                                                int height,
00140                                                int components,
00141                                                int bits_per_component,
00142                                                vil1_component_format /*format*/)
00143   : vs_(vs)
00144 {
00145   vs_->ref();
00146   width_ = width;
00147   height_ = height;
00148 
00149   if ( planes != 1 ) {
00150     vcl_cerr << __FILE__ << ": can only handle 1 plane\n";
00151     return;
00152   }
00153   if ( components != 3 && components != 1 ) {
00154     vcl_cerr << __FILE__ << ": can't handle " << components << " components\n";
00155     return;
00156   }
00157   if ( bits_per_component != 8 ) {
00158     vcl_cerr << __FILE__ << ": can't handle " << bits_per_component << " bits per component\n";
00159     return;
00160   }
00161 
00162   components_ = components;
00163   bits_per_component_ = bits_per_component;
00164   depth_ = components_ * bits_per_component_;
00165 
00166   if (components_ == 3) {
00167     type_ = RT_FORMAT_RGB;
00168   } else {
00169     type_ = RT_STANDARD;
00170   }
00171   map_type_ = RMT_NONE;
00172   map_length_ = 0;
00173   length_ = compute_length( width_, height_, depth_ );
00174   col_map_ = 0;
00175 
00176   write_header();
00177 }
00178 
00179 vil1_ras_generic_image::~vil1_ras_generic_image()
00180 {
00181   delete[] col_map_;
00182   vs_->unref();
00183 }
00184 
00185 
00186 //: Read the header of a Sun raster file.
00187 bool vil1_ras_generic_image::read_header()
00188 {
00189   // Go to start of file
00190   vs_->seek(0);
00191 
00192   vxl_uint_8 buf[4];
00193   if (vs_->read(buf, 4) < 4) // at end-of-file?
00194     return false;
00195   if (! ( buf[0] == RAS_MAGIC[0] && buf[1] == RAS_MAGIC[1] &&
00196           buf[2] == RAS_MAGIC[2] && buf[3] == RAS_MAGIC[3]  ) )
00197     return false; // magic number isn't correct
00198 
00199   if (!( read_uint_32( vs_, width_ ) &&
00200          read_uint_32( vs_, height_ ) &&
00201          read_uint_32( vs_, depth_ ) &&
00202          read_uint_32( vs_, length_ ) &&
00203          read_uint_32( vs_, type_ ) &&
00204          read_uint_32( vs_, map_type_ ) &&
00205          read_uint_32( vs_, map_length_ ) ) )
00206     return false;
00207 
00208   // Do consistency checks of the header
00209 
00210   if (type_ != RT_OLD && type_ != RT_STANDARD &&
00211       type_ != RT_BYTE_ENCODED && type_ != RT_FORMAT_RGB ) {
00212     vcl_cerr << __FILE__ << ": unknown type " << type_ << vcl_endl;
00213     return false;
00214   }
00215   if ( map_type_ != RMT_NONE && map_type_ != RMT_EQUAL_RGB ) {
00216     vcl_cerr << __FILE__ << ": unknown map type " << map_type_ << vcl_endl;
00217     return false;
00218   }
00219   if ( map_type_ == RMT_NONE && map_length_ != 0 ) {
00220     vcl_cerr << __FILE__ << ": No colour map according to header, but there is a map!\n";
00221     return false;
00222   }
00223 
00224   if ( depth_ != 8 && depth_ != 24 ) {
00225     vcl_cerr << __FILE__ << ": depth " << depth_ << " not implemented\n";
00226     return false;
00227   }
00228 
00229   // The "old" format always has length set to zero, so we should compute it ourselves.
00230   if ( type_ == RT_OLD ) {
00231     length_ = compute_length( width_, height_, depth_ );
00232   }
00233   if ( length_ == 0 ) {
00234     vcl_cerr << __FILE__ << ": header says image has length zero\n";
00235     return false;
00236   }
00237   if ( type_ != RT_BYTE_ENCODED && length_ != compute_length( width_, height_, depth_ ) ) {
00238     vcl_cerr << __FILE__ << ": length " << length_ << " does not match wxhxd = "
00239              << compute_length( width_, height_, depth_ ) << vcl_endl;
00240     return false;
00241   }
00242 
00243   if ( map_length_ ) {
00244     assert( map_length_ % 3 == 0 );
00245     col_map_ = new vxl_uint_8[ map_length_ ];
00246     vs_->read( col_map_, (vil1_streampos)map_length_ );
00247   } else {
00248     col_map_ = 0;
00249   }
00250 
00251   start_of_data_ = vs_->tell();
00252 
00253   assert( depth_ == 8 || depth_ == 24 );
00254 
00255   if ( map_type_ != RMT_NONE || depth_ == 24 ) {
00256     components_ = 3;
00257   } else {
00258     components_ = 1;
00259   }
00260   bits_per_component_ = 8;
00261 
00262   return true;
00263 }
00264 
00265 bool vil1_ras_generic_image::write_header()
00266 {
00267   vs_->seek(0);
00268 
00269   vs_->write( RAS_MAGIC, 4 );
00270 
00271   write_uint_32( vs_, width_ );
00272   write_uint_32( vs_, height_ );
00273   write_uint_32( vs_, depth_ );
00274   write_uint_32( vs_, length_ );
00275   write_uint_32( vs_, type_ );
00276   write_uint_32( vs_, map_type_ );
00277   write_uint_32( vs_, map_length_ );
00278 
00279   assert( map_length_ == 0 );
00280 
00281   start_of_data_ = vs_->tell();
00282 
00283   return true;
00284 }
00285 
00286 bool vil1_ras_generic_image::get_section(void* buf, int x0, int y0, int xs, int ys) const
00287 {
00288   if ( type_ == RT_BYTE_ENCODED )
00289     return false; // not yet implemented
00290 
00291   int file_bytes_per_pixel = (depth_+7)/8;
00292   int buff_bytes_per_pixel = components_ * ( (bits_per_component_+7)/8 );
00293   int file_byte_width = width_ * file_bytes_per_pixel;
00294   file_byte_width += ( file_byte_width % 2 ); // each scan line ends on a 16bit boundary
00295   int file_byte_start = start_of_data_ + y0 * file_byte_width + x0 * file_bytes_per_pixel;
00296   int buff_byte_width = xs * buff_bytes_per_pixel;
00297 
00298   vxl_uint_8* ib = (vxl_uint_8*) buf;
00299 
00300   if ( !col_map_ ) {
00301     // No colourmap, so just read in the bytes. This could be RGB or
00302     // BGR, depending on type_.
00303     for (int y = 0; y < ys; ++y) {
00304       vs_->seek(file_byte_start + y * file_byte_width);
00305       vs_->read(ib + y * buff_byte_width, buff_byte_width);
00306     }
00307 
00308   } else {
00309     assert( file_bytes_per_pixel == 1 && buff_bytes_per_pixel == 3 );
00310     int col_len = map_length_ / 3;
00311     // Read a line, and map every index into an RGB triple
00312     vxl_uint_8* line = new vxl_uint_8[ xs ];
00313     for (int y = 0; y < ys; ++y) {
00314       vs_->seek( file_byte_start + y * file_byte_width );
00315       vs_->read( line, xs );
00316       vxl_uint_8* in_p = line;
00317       vxl_uint_8* out_p = ib + y * buff_byte_width;
00318       for ( int i=0; i < xs; ++i ) {
00319         assert( *in_p < col_len );
00320         *(out_p++) = col_map_[ *in_p ];
00321         *(out_p++) = col_map_[ *in_p + col_len ];
00322         *(out_p++) = col_map_[ *in_p + 2*col_len ];
00323         ++in_p;
00324       }
00325     }
00326     delete[] line;
00327   }
00328 
00329   return true;
00330 }
00331 
00332 bool vil1_ras_generic_image::put_section(void const* buf, int x0, int y0, int xs, int ys)
00333 {
00334   if ( col_map_ ) {
00335     vcl_cerr << __FILE__ << ": writing to file with a colour map is not implemented\n";
00336     return false;
00337   }
00338   if ( type_ == RT_BYTE_ENCODED ) {
00339     vcl_cerr << __FILE__ << ": writing to a run-length encoded file is not implemented\n";
00340     return false;
00341   }
00342   if ( components_ == 3 && type_ != RT_FORMAT_RGB ) {
00343     vcl_cerr << __FILE__ << ": writing BGR format is not implemented\n";
00344     return false;
00345   }
00346 
00347   // With the restrictions above, writing is simple. Just dump the bytes.
00348 
00349   int file_bytes_per_pixel = (depth_+7)/8;
00350   int buff_bytes_per_pixel = components_ * ( (bits_per_component_+7)/8 );
00351   int file_byte_width = width_ * file_bytes_per_pixel;
00352   file_byte_width += ( file_byte_width % 2 ); // each scan line ends on a 16bit boundary
00353   int file_byte_start = start_of_data_ + y0 * file_byte_width + x0 * file_bytes_per_pixel;
00354   int buff_byte_width = xs * buff_bytes_per_pixel;
00355 
00356   assert( file_bytes_per_pixel == buff_bytes_per_pixel );
00357   assert( file_byte_width >= buff_byte_width );
00358 
00359   // only pad if whole lines are written. Otherwise, assume the
00360   // previous contents are valid.
00361   bool need_pad = ( file_byte_width == buff_byte_width+1 );
00362   vxl_uint_8 zero = 0;
00363 
00364   vxl_uint_8 const* ob = (vxl_uint_8 const*) buf;
00365 
00366   for (int y = 0; y < ys; ++y) {
00367     vs_->seek( file_byte_start + y * file_byte_width );
00368     vs_->write( ob + y * buff_byte_width, buff_byte_width );
00369     if ( need_pad )
00370       vs_->write( &zero, 1 );
00371   }
00372 
00373   return true;
00374 }
00375 
00376 vil1_image vil1_ras_generic_image::get_plane(unsigned int plane) const
00377 {
00378   assert(plane == 0);
00379   return const_cast<vil1_ras_generic_image*>(this);
00380 }

Generated on Mon Mar 8 05:09:32 2010 for core/vil1 by  doxygen 1.5.1