core/vil/file_formats/vil_mit.cxx
Go to the documentation of this file.
00001 // This is core/vil/file_formats/vil_mit.cxx
00002 //
00003 // Author: Joris Schouteden
00004 // Created: 18 Feb 2000
00005 // Converted from vil1 by Peter Vanroose on 17 June 2003.
00006 //
00007 //-----------------------------------------------------------------------------
00008 
00009 #include "vil_mit.h"
00010 
00011 static char const* vil_mit_format_tag = "mit";
00012 
00013 #include <vcl_iostream.h>
00014 #include <vcl_cassert.h>
00015 #include <vcl_cstring.h>
00016 
00017 #include <vil/vil_stream.h>
00018 #include <vil/vil_image_resource.h>
00019 #include <vil/vil_image_view.h>
00020 #include <vil/vil_stream_read.h>
00021 #include <vil/vil_stream_write.h>
00022 #include <vil/vil_exception.h>
00023 
00024 #define MIT_UNSIGNED    0x0001
00025 #define MIT_RGB         0x0002
00026 #define MIT_HSB         0x0003
00027 #define MIT_CAP         0x0004
00028 #define MIT_SIGNED      0x0005
00029 #define MIT_FLOAT       0x0006
00030 #define MIT_EDGE        0x0007
00031 
00032 #define MIT_UCOMPLEX    0x0101
00033 #define MIT_SCOMPLEX    0x0105
00034 #define MIT_FCOMPLEX    0x0106
00035 
00036 #define MIT_UNSIGNED_E  0x0201
00037 #define MIT_SIGNED_E    0x0205
00038 #define MIT_FLOAT_E     0x0206
00039 
00040 #define MIT_UCOMPLEX_E  0x0301
00041 #define MIT_SCOMPLEX_E  0x0305
00042 #define MIT_FCOMPLEX_E  0x0306
00043 
00044 #define EDGE_HOR 0200           /* Edge direction codes */
00045 #define EDGE_VER 0100
00046 
00047 // The mit image format is encoded (in little-endian format) as follows :
00048 //   2 bytes : magic number
00049 //   2 bytes : number of bits per pixel
00050 //   2 bytes : width
00051 //   2 bytes : height
00052 //   raw image data follows.
00053 //
00054 // E.g. :
00055 // 00000000: 01 00 08 00 67 01 5A 01 6D 6D 6D 6D 6D 6D 6D 6D ....g.Z.mmmmmmmm
00056 // 00000010: 6D 6D 6D 6D 6D 6D 6D 6D 6D 6D 6D 6D 6D 6D 6D 6D mmmmmmmmmmmmmmmm
00057 
00058 //----------------------------------------------------------------------
00059 
00060 vil_image_resource_sptr vil_mit_file_format::make_input_image(vil_stream* is)
00061 {
00062   is->seek(0L);
00063   if (is->file_size() < 8L) return 0;
00064   unsigned int type = vil_stream_read_little_endian_uint_16(is);
00065 
00066   if (!(type == MIT_UNSIGNED ||
00067         type == MIT_RGB      ||
00068         type == MIT_SIGNED   ||
00069         type == MIT_FLOAT    ))
00070     return 0;
00071 
00072   unsigned int bpp = vil_stream_read_little_endian_uint_16(is);
00073   if (bpp != 1 && bpp != 8 && bpp != 16 && bpp != 32 && bpp != 64)
00074     return 0;
00075 
00076 #ifdef DEBUG
00077   unsigned int width = vil_stream_read_little_endian_uint_16(is);
00078   unsigned int height= vil_stream_read_little_endian_uint_16(is);
00079   vcl_cerr << __FILE__ " : here we go:\n"
00080            << __FILE__ " : type_ = " << type << vcl_endl
00081            << __FILE__ " : bits_per_pixel_ = " << bpp << vcl_endl
00082            << __FILE__ " : width_ = " << width << vcl_endl
00083            << __FILE__ " : height_ = " << height << vcl_endl;
00084 #endif
00085   return new vil_mit_image(is);
00086 }
00087 
00088 vil_image_resource_sptr vil_mit_file_format::make_output_image(vil_stream* is,
00089                                                                unsigned int ni, unsigned int nj, unsigned int nplanes,
00090                                                                vil_pixel_format format)
00091 {
00092   return new vil_mit_image(is, ni, nj, nplanes, format);
00093 }
00094 
00095 char const* vil_mit_file_format::tag() const
00096 {
00097   return vil_mit_format_tag;
00098 }
00099 
00100 /////////////////////////////////////////////////////////////////////////////
00101 
00102 vil_mit_image::vil_mit_image(vil_stream* is)
00103   : is_(is)
00104 {
00105   is_->ref();
00106   if (!read_header())
00107   {
00108     vcl_cerr << "vil_mit: cannot read file header; creating dummy 0x0 image\n";
00109     ni_ = nj_ = 0; components_ = 1; type_ = 1;
00110     format_ = VIL_PIXEL_FORMAT_BYTE;
00111   }
00112 }
00113 
00114 char const* vil_mit_image::file_format() const
00115 {
00116   return vil_mit_format_tag;
00117 }
00118 
00119 vil_mit_image::vil_mit_image(vil_stream* is,
00120                              unsigned int ni, unsigned int nj, unsigned int nplanes,
00121                              vil_pixel_format format)
00122   : is_(is), ni_(ni), nj_(nj), components_(nplanes), format_(format)
00123 {
00124   is_->ref();
00125   write_header();
00126 }
00127 
00128 vil_mit_image::~vil_mit_image()
00129 {
00130   is_->unref();
00131 }
00132 
00133 bool vil_mit_image::get_property(char const * /*tag*/, void * /*prop*/) const
00134 {
00135   // This is not an in-memory image type, nor is it read-only:
00136   return false;
00137 }
00138 
00139 bool vil_mit_image::read_header()
00140 {
00141   is_->seek(0L);
00142 
00143   type_ = vil_stream_read_little_endian_uint_16(is_);
00144   unsigned int bpp = vil_stream_read_little_endian_uint_16(is_);
00145   ni_ = vil_stream_read_little_endian_uint_16(is_);
00146   nj_ = vil_stream_read_little_endian_uint_16(is_);
00147 
00148   if (type_ == MIT_UNSIGNED) {  // gray
00149     components_ = 1;
00150     format_ = bpp==8  ? VIL_PIXEL_FORMAT_BYTE :
00151               bpp==16 ? VIL_PIXEL_FORMAT_UINT_16 :
00152               bpp==32 ? VIL_PIXEL_FORMAT_UINT_32 :
00153               bpp==1  ? VIL_PIXEL_FORMAT_BOOL :
00154                         VIL_PIXEL_FORMAT_UNKNOWN;
00155   }
00156   else if (type_ == MIT_SIGNED) {
00157     components_ = 1;
00158     format_ = bpp==8  ? VIL_PIXEL_FORMAT_SBYTE :
00159               bpp==16 ? VIL_PIXEL_FORMAT_INT_16 :
00160               bpp==32 ? VIL_PIXEL_FORMAT_INT_32 :
00161                         VIL_PIXEL_FORMAT_UNKNOWN;
00162   }
00163   else if (type_ == MIT_RGB) {
00164     components_ = 3;
00165     format_ = bpp==8  ? VIL_PIXEL_FORMAT_BYTE :
00166               bpp==16 ? VIL_PIXEL_FORMAT_UINT_16 :
00167               bpp==32 ? VIL_PIXEL_FORMAT_UINT_32 :
00168                         VIL_PIXEL_FORMAT_UNKNOWN;
00169   }
00170   else if (type_ == MIT_FLOAT) {
00171     components_ = 1;
00172     format_ = bpp==32 ? VIL_PIXEL_FORMAT_FLOAT :
00173               bpp==64 ? VIL_PIXEL_FORMAT_DOUBLE :
00174                         VIL_PIXEL_FORMAT_UNKNOWN;
00175   }
00176   else
00177     return false;
00178 
00179   return format_ != VIL_PIXEL_FORMAT_UNKNOWN;
00180 }
00181 
00182 bool vil_mit_image::write_header()
00183 {
00184   is_->seek(0L);
00185 
00186   if (format_ == VIL_PIXEL_FORMAT_UINT_32 ||
00187       format_ == VIL_PIXEL_FORMAT_UINT_16 ||
00188       format_ == VIL_PIXEL_FORMAT_BYTE ||
00189       format_ == VIL_PIXEL_FORMAT_BOOL)
00190   {
00191     if (components_ == 3) type_ = MIT_RGB;
00192     else if (components_ == 1) type_ = MIT_UNSIGNED;
00193     else vcl_cerr << __FILE__ " : Can only write RGB or grayscale MIT images\n"
00194                   << " (format="<<format_<<", #components="<<components_<<")\n";
00195   }
00196   else if (format_ == VIL_PIXEL_FORMAT_INT_32 ||
00197            format_ == VIL_PIXEL_FORMAT_INT_16 ||
00198            format_ == VIL_PIXEL_FORMAT_SBYTE)
00199   {
00200     if (components_ == 1) type_ = MIT_SIGNED;
00201     else vcl_cerr << __FILE__ " : Can only write RGB or grayscale MIT images\n"
00202                   << " (format="<<format_<<", #components="<<components_<<")\n";
00203   }
00204   else if (format_ == VIL_PIXEL_FORMAT_RGB_UINT_32 ||
00205            format_ == VIL_PIXEL_FORMAT_RGB_INT_32 ||
00206            format_ == VIL_PIXEL_FORMAT_RGB_UINT_16 ||
00207            format_ == VIL_PIXEL_FORMAT_RGB_INT_16 ||
00208            format_ == VIL_PIXEL_FORMAT_RGB_BYTE ||
00209            format_ == VIL_PIXEL_FORMAT_RGB_SBYTE)
00210   {
00211     if (components_ == 1) type_ = MIT_RGB;
00212     else vcl_cerr << __FILE__ " : Can only write RGB or grayscale MIT images\n"
00213                   << " (format="<<format_<<", #components="<<components_<<")\n";
00214   }
00215   else if (format_ == VIL_PIXEL_FORMAT_RGB_FLOAT ||
00216            format_ == VIL_PIXEL_FORMAT_RGB_DOUBLE)
00217   {
00218     if (components_ == 1) type_ = MIT_FLOAT;
00219     else vcl_cerr << __FILE__ " : Can only write grayscale float-pixel MIT images\n"
00220                   << " (format="<<format_<<", #components="<<components_<<")\n";
00221   }
00222   else
00223     vcl_cerr << __FILE__ " : Can only write RGB or grayscale MIT images\n"
00224              << " (format="<<format_<<", #components="<<components_<<")\n";
00225 
00226   vil_stream_write_little_endian_uint_16(is_, type_);
00227   unsigned int bpp = 8 * bytes_per_pixel();
00228   if (format_ == VIL_PIXEL_FORMAT_BOOL) bpp = 1;
00229   vil_stream_write_little_endian_uint_16(is_, bpp);
00230   vil_stream_write_little_endian_uint_16(is_, ni_);
00231   vil_stream_write_little_endian_uint_16(is_, nj_);
00232   return true;
00233 }
00234 
00235 static inline void swap(void* p,int length)
00236 {
00237   char* t = (char*)p;
00238 #ifdef DEBUG
00239   if (length == sizeof(vxl_uint_32) && *(vxl_uint_32*)p != 0) {
00240     vcl_cerr << "Swapping " << *(vxl_uint_32*)p;
00241     if (length == sizeof(float)) vcl_cerr << " (or " << *(float*)p << ')';
00242   }
00243 #endif
00244   for (int j=0;2*j<length;++j) { char c = t[j]; t[j] = t[length-j-1]; t[length-j-1] = c; }
00245 #ifdef DEBUG
00246   if (length == sizeof(vxl_uint_32) && *(vxl_uint_32*)p != 0) {
00247     vcl_cerr << " to " << *(vxl_uint_32*)p;
00248     if (length == sizeof(float)) vcl_cerr << " (or " << *(float*)p << ')';
00249     vcl_cerr << '\n';
00250   }
00251 #endif
00252 }
00253 
00254 vil_image_view_base_sptr vil_mit_image::get_copy_view(unsigned int x0, unsigned int xs,
00255                                                       unsigned int y0, unsigned int ys) const
00256 {
00257   assert(x0+xs<=ni_);
00258   assert(y0+ys<=nj_);
00259   unsigned int pix_size = 8*bytes_per_pixel();
00260   if (format_==VIL_PIXEL_FORMAT_BOOL) pix_size = 1;
00261   if (format_==VIL_PIXEL_FORMAT_BOOL && x0%8 != 0)
00262     vcl_cerr << "vil_mit_image::get_copy_view(): Warning: x0 should be a multiple of 8 for this type of image\n";
00263   pix_size *= components_;
00264 
00265   vxl_uint_32 rowsize = (pix_size*xs+7)/8;
00266   vil_memory_chunk_sptr buf = new vil_memory_chunk(rowsize*ys,format_);
00267   vxl_byte* ib = reinterpret_cast<vxl_byte*>(buf->data());
00268   for (unsigned int y = y0; y < y0+ys; ++y)
00269   {
00270     is_->seek(8L + y*((ni_*pix_size+7)/8) + x0*pix_size/8);
00271     is_->read(ib, rowsize);
00272     ib += rowsize;
00273   }
00274   if (VXL_BIG_ENDIAN && bytes_per_pixel() > 1) { // MIT image data is little-endian
00275     ib = reinterpret_cast<vxl_byte*>(buf->data());
00276     for (unsigned int i=0;i<xs*ys*components_;++i)
00277       swap(ib+i*bytes_per_pixel(),bytes_per_pixel());
00278   }
00279 
00280 #define ARGS(T) buf, reinterpret_cast<T*>(buf->data()), xs,ys,components_, components_,xs*components_,1
00281   if (format_ == VIL_PIXEL_FORMAT_BOOL)         return new vil_image_view<bool>       (ARGS(bool));
00282   else if (format_ == VIL_PIXEL_FORMAT_BYTE)    return new vil_image_view<vxl_byte>   (ARGS(vxl_byte));
00283   else if (format_ == VIL_PIXEL_FORMAT_SBYTE)   return new vil_image_view<vxl_sbyte>  (ARGS(vxl_sbyte));
00284   else if (format_ == VIL_PIXEL_FORMAT_UINT_16) return new vil_image_view<vxl_uint_16>(ARGS(vxl_uint_16));
00285   else if (format_ == VIL_PIXEL_FORMAT_INT_16)  return new vil_image_view<vxl_int_16> (ARGS(vxl_int_16));
00286   else if (format_ == VIL_PIXEL_FORMAT_UINT_32) return new vil_image_view<vxl_uint_32>(ARGS(vxl_uint_32));
00287   else if (format_ == VIL_PIXEL_FORMAT_INT_32)  return new vil_image_view<vxl_int_32> (ARGS(vxl_int_32));
00288   else if (format_ == VIL_PIXEL_FORMAT_FLOAT)   return new vil_image_view<float>      (ARGS(float));
00289   else if (format_ == VIL_PIXEL_FORMAT_DOUBLE)  return new vil_image_view<double>     (ARGS(double));
00290   else return 0;
00291 #undef ARGS
00292 }
00293 
00294 bool vil_mit_image::put_view(vil_image_view_base const& buf, unsigned int x0, unsigned int y0)
00295 {
00296   assert(buf.pixel_format() == format_); // pixel formats of image and buffer must match
00297   if (!view_fits(buf, x0, y0) || buf.nplanes() != components_)
00298   {
00299     vil_exception_warning(vil_exception_out_of_bounds("vil_mit_image::put_view"));
00300     return false;
00301   }
00302   unsigned int ni = buf.ni();
00303   unsigned int nj = buf.nj();
00304 #ifdef DEBUG
00305   vcl_cerr<<"vil_mit_image::put_view() : buf="
00306           <<ni<<'x'<<nj<<'x'<< buf.nplanes()<<'p'
00307           <<" at ("<<x0<<','<<y0<<")\n";
00308 #endif
00309   vil_image_view<vxl_byte> const& ibuf = reinterpret_cast<vil_image_view<vxl_byte> const&>(buf);
00310   bool buf_is_planar = false;
00311   if (ibuf.istep() == int(components_) && ibuf.jstep() == int(components_*ni) &&
00312       (ibuf.planestep() == 1 || components_ == 1))
00313     buf_is_planar = false;
00314   else if (ibuf.istep() == 1 && ibuf.jstep() == int(ni) &&
00315            (ibuf.planestep() == int(ni*nj) || components_ == 1))
00316     buf_is_planar = true;
00317   else
00318   {
00319     vcl_cerr << "ERROR: " << __FILE__ << ":\n"
00320              << " view does not fit: istep="<<ibuf.istep()
00321              << ", jstep="<<ibuf.jstep()
00322              << ", planestep="<<ibuf.planestep()
00323              << " instead of "<<components_<<','<<components_*ni<<','<<1
00324              << " or 1,"<<ni<<','<<ni*nj<<'\n';
00325     return buf_is_planar; // == false
00326   }
00327   const vxl_byte* ob = ibuf.top_left_ptr();
00328   unsigned int pix_size = 8*bytes_per_pixel();
00329   if (format_==VIL_PIXEL_FORMAT_BOOL) pix_size = 1;
00330   if (format_==VIL_PIXEL_FORMAT_BOOL && x0%8 != 0)
00331     vcl_cerr << "vil_mit_image::put_view(): Warning: x0 should be a multiple of 8 for this type of image\n";
00332   pix_size *= components_;
00333 
00334   vxl_uint_32 rowsize = (pix_size*ni+7)/8;
00335 
00336   if (VXL_LITTLE_ENDIAN || bytes_per_pixel() == 1) // MIT image data is little-endian
00337   {
00338     if (buf_is_planar && components_ > 1) // have to interleave pixels
00339     {
00340       vil_streampos sz = (pix_size/components_+7)/8;
00341       for (unsigned int y = y0; y < y0+nj; ++y)
00342         for (unsigned int x = x0; x < x0+ni; ++x)
00343         {
00344           is_->seek(8L + y*((ni_*pix_size+7)/8) + x*pix_size/8);
00345           for (unsigned int p=0; p<components_; ++p)
00346             if (sz != is_->write(ob+p*ni*nj*sz, sz))
00347               vcl_cerr << "WARNING: " << __FILE__ << ":\n"
00348                        << " could not write "<<sz<<" bytes to stream; y,x="<<y<<','<<x<<'\n';
00349 #ifdef DEBUG
00350             else
00351               vcl_cerr << "written "<<sz<<" bytes to stream; y,x="<<y<<','<<x<<'\n';
00352 #endif
00353             ob += sz;
00354         }
00355     }
00356     else
00357       for (unsigned int y = y0; y < y0+nj; ++y)
00358       {
00359         is_->seek(8L + y*((ni_*pix_size+7)/8) + x0*pix_size/8);
00360         if ((vil_streampos)rowsize != is_->write(ob, rowsize))
00361           vcl_cerr << "WARNING: " << __FILE__ << ":\n"
00362                    << " could not write "<<rowsize<<" bytes to stream; y="<<y<<'\n';
00363 #ifdef DEBUG
00364         else
00365           vcl_cerr << "written "<<rowsize<<" bytes to stream; y="<<y<<'\n';
00366 #endif
00367         ob += rowsize;
00368       }
00369   }
00370   else // VXL_BIG_ENDIAN ==> must swap bytes
00371   {
00372     if (buf_is_planar && components_ > 1) // have to interleave pixels
00373     {
00374       unsigned int sz = bytes_per_pixel();
00375       vxl_byte* tempbuf = new vxl_byte[components_*sz];
00376       for (unsigned int y = y0; y < y0+nj; ++y)
00377         for (unsigned int x = x0; x < x0+ni; ++x)
00378         {
00379           for (unsigned int p=0; p<components_; ++p) {
00380             vcl_memcpy(tempbuf+p*sz, ob+p*ni*nj, sz);
00381             swap(tempbuf+p*sz,sz);
00382           }
00383           is_->seek(8L + pix_size*(y*ni_+x)/8);
00384           if (vil_streampos(components_*sz) != is_->write(tempbuf, components_*sz))
00385              vcl_cerr << "WARNING: " << __FILE__ << ":\n"
00386                       << " could not write "<<components_*sz<<" bytes to stream; y,x="<<y<<','<<x<<'\n';
00387 #ifdef DEBUG
00388           else
00389             vcl_cerr << "written "<<components_*sz<<" bytes to stream; y,x="<<y<<','<<x<<'\n';
00390 #endif
00391           ob += sz;
00392         }
00393       delete[] tempbuf;
00394     }
00395     else
00396     {
00397       vxl_byte* tempbuf = new vxl_byte[rowsize];
00398       for (unsigned int y = y0; y < y0+nj; ++y)
00399       {
00400         vcl_memcpy(tempbuf, ob, rowsize);
00401         for (vxl_uint_32 i=0; i<rowsize; i+=bytes_per_pixel())
00402           swap(tempbuf+i,bytes_per_pixel());
00403         is_->seek(8L + bytes_per_pixel()*(y*ni_+x0));
00404         if ((vil_streampos)rowsize != is_->write(tempbuf, rowsize))
00405           vcl_cerr << "WARNING: " << __FILE__ << ":\n"
00406                    << " could not write "<<rowsize<<" bytes to stream; y="<<y<<'\n';
00407 #ifdef DEBUG
00408         else
00409           vcl_cerr << "written "<<rowsize<<" bytes to stream; y="<<y<<'\n';
00410 #endif
00411         ob += rowsize;
00412       }
00413       delete[] tempbuf;
00414     }
00415   }
00416   return true;
00417 }