core/vil1/file_formats/vil1_pnm.cxx

Go to the documentation of this file.
00001 // This is core/vil1/file_formats/vil1_pnm.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 
00008 #include "vil1_pnm.h"
00009 
00010 #include <vcl_cassert.h>
00011 #include <vcl_vector.h>
00012 #include <vcl_iostream.h>
00013 #include <vcl_cstring.h>
00014 
00015 #include <vil1/vil1_stream.h>
00016 #include <vil1/vil1_image_impl.h>
00017 #include <vil1/vil1_image.h>
00018 #include <vil1/vil1_property.h>
00019 
00020 #include <vxl_config.h>
00021 #undef sprintf // This works around a bug in libintl.h
00022 #include <vcl_cstdio.h> // for sprintf
00023 
00024 char const* vil1_pnm_format_tag = "pnm";
00025 
00026 static inline bool iseol(int c)
00027 {
00028   return c == 10 || c == 13;
00029 }
00030 
00031 static inline bool isws(int c)
00032 {
00033   return c == ' ' || c == '\t' || c == 10 || c == 13;
00034 }
00035 
00036 vil1_image_impl* vil1_pnm_file_format::make_input_image(vil1_stream* vs)
00037 {
00038   // Attempt to read header
00039   unsigned char buf[3];
00040   vs->read(buf, 3L);
00041   bool ok = ((buf[0] == 'P') &&
00042              iseol(buf[2]) &&
00043              (buf[1] >= '1' && buf[2] <= '6'));
00044   if (!ok)
00045     return 0;
00046 
00047   return new vil1_pnm_generic_image(vs);
00048 }
00049 
00050 vil1_image_impl* vil1_pnm_file_format::make_output_image(vil1_stream* vs, int planes,
00051                                                          int width,
00052                                                          int height,
00053                                                          int components,
00054                                                          int bits_per_component,
00055                                                          vil1_component_format format)
00056 {
00057   return new vil1_pnm_generic_image(vs, planes, width, height, components, bits_per_component, format);
00058 }
00059 
00060 char const* vil1_pnm_file_format::tag() const
00061 {
00062   return vil1_pnm_format_tag;
00063 }
00064 
00065 /////////////////////////////////////////////////////////////////////////////
00066 
00067 vil1_pnm_generic_image::vil1_pnm_generic_image(vil1_stream* vs):
00068   vs_(vs)
00069 {
00070   vs_->ref();
00071   read_header();
00072 }
00073 
00074 bool vil1_pnm_generic_image::get_property(char const *tag, void *prop) const
00075 {
00076   if (0==vcl_strcmp(tag, vil1_property_top_row_first))
00077     return prop ? (*(bool*)prop) = true : true;
00078 
00079   if (0==vcl_strcmp(tag, vil1_property_left_first))
00080     return prop ? (*(bool*)prop) = true : true;
00081 
00082   return false;
00083 }
00084 
00085 char const* vil1_pnm_generic_image::file_format() const
00086 {
00087   return vil1_pnm_format_tag;
00088 }
00089 
00090 vil1_pnm_generic_image::vil1_pnm_generic_image(vil1_stream* vs, int planes,
00091                                                int width,
00092                                                int height,
00093                                                int components,
00094                                                int bits_per_component,
00095                                                vil1_component_format ):
00096   vs_(vs)
00097 {
00098   vs_->ref();
00099   width_ = width;
00100   height_ = height;
00101 
00102   components_ = components * planes;
00103   bits_per_component_ = bits_per_component;
00104 
00105   if (components_ == 3) {
00106     magic_ = 6;
00107   } else if (components_ == 1) {
00108     if (bits_per_component_ == 1)
00109       magic_ = 4;
00110     else
00111       magic_ = 5;
00112   }
00113   // from August 2000, pnm allows 16 bit samples in rawbits format, stored MSB.
00114   if (bits_per_component_ > 16) magic_ -= 3;
00115 
00116   if (bits_per_component_ < 31)
00117     maxval_ = (1L<<bits_per_component_)-1;
00118   else
00119     maxval_ = 0x7FFFFFFF; // not 0xFFFFFFFF as the pnm format does not allow values > MAX_INT
00120 
00121   write_header();
00122 }
00123 
00124 vil1_pnm_generic_image::~vil1_pnm_generic_image()
00125 {
00126   //delete vs_;
00127   vs_->unref();
00128 }
00129 
00130 // Skip over spaces and comments; temp is the current vs character
00131 static void SkipSpaces(vil1_stream* vs, char& temp)
00132 {
00133   while (isws(temp) || temp == '#')
00134   {
00135     if (temp == '#') // skip this line:
00136       while (!iseol(temp))
00137         if (1L > vs->read(&temp,1L)) return; // at end-of-file?
00138     // skip this `whitespace' byte by reading the next byte:
00139     if (1L > vs->read(&temp,1L)) return;
00140   }
00141 }
00142 
00143 // Get a nonnegative integer from the vs stream; temp is the current vs byte
00144 static int ReadInteger(vil1_stream* vs, char& temp)
00145 {
00146   int n = 0;
00147   while ((temp >= '0') && (temp <= '9'))
00148   {
00149     n *= 10; n += (temp - '0');
00150     if (1L > vs->read(&temp,1L)) return n; // at end-of-file?
00151   }
00152   return n;
00153 }
00154 
00155 #if VXL_LITTLE_ENDIAN
00156 // Convert the buffer of 16 bit words from MSB to host order
00157 static void ConvertMSBToHost( void* buf, int num_words )
00158 {
00159   unsigned char* ptr = (unsigned char*)buf;
00160   for ( int i=0; i < num_words; ++i ) {
00161     unsigned char t = *ptr;
00162     *ptr = *(ptr+1);
00163     *(ptr+1) = t;
00164     ptr += 2;
00165   }
00166 }
00167 
00168 // Convert the buffer of 16 bit words from host order to MSB
00169 static void ConvertHostToMSB( void* buf, int num_words )
00170 {
00171   unsigned char* ptr = (unsigned char*)buf;
00172   for ( int i=0; i < num_words; ++i ) {
00173     unsigned char t = *ptr;
00174     *ptr = *(ptr+1);
00175     *(ptr+1) = t;
00176     ptr += 2;
00177   }
00178 }
00179 
00180 #else // VXL_BIG_ENDIAN: do nothing
00181 inline static void ConvertMSBToHost( void*, int ) {}
00182 inline static void ConvertHostToMSB( void*, int ) {}
00183 #endif
00184 
00185 //: This method accepts any valid PNM file (first 3 bytes "P1\n" to "P6\n")
00186 bool vil1_pnm_generic_image::read_header()
00187 {
00188   char temp;
00189 
00190   // Go to start of file
00191   vs_->seek(0L);
00192 
00193   char buf[3];
00194   if (3L > vs_->read(buf, 3L)) return false; // at end-of-file?
00195   if (buf[0] != 'P') return false;
00196   if (!iseol(buf[2])) return false;
00197   magic_ = buf[1] - '0';
00198   if (magic_ < 1 || magic_ > 6) return false;
00199 
00200   // read 1 byte
00201   vs_->read(&temp, 1L);
00202 
00203   //Skip over spaces and comments
00204   SkipSpaces(vs_,temp);
00205 
00206   //Read in Width
00207   width_ = ReadInteger(vs_,temp);
00208 
00209   //Skip over spaces and comments
00210   SkipSpaces(vs_,temp);
00211 
00212   //Read in Height
00213   height_ = ReadInteger(vs_,temp);
00214 
00215   // a pbm (bitmap) image does not have a maxval field
00216   if (magic_ == 1 || magic_ == 4)
00217     maxval_ = 1;
00218   else
00219   {
00220     //Skip over spaces and comments
00221     SkipSpaces(vs_,temp);
00222 
00223     //Read in Maxval
00224     maxval_ = ReadInteger(vs_,temp);
00225   }
00226 
00227   start_of_data_ = vs_->tell() - 1L;
00228 
00229   //Final end-of-line or other white space (1 byte) before the data section begins
00230   if (isws(temp))
00231     ++start_of_data_;
00232 
00233   components_ = ((magic_ == 3 || magic_ == 6) ? 3 : 1);
00234 
00235   if (magic_ == 1 || magic_ == 4)
00236     bits_per_component_ = 1;
00237   else {
00238     if (maxval_ == 0) assert(!"indentation is everything");
00239     else if (maxval_ <= 0xFF) bits_per_component_ = 8;
00240     else if (maxval_ <= 0xFFFF) bits_per_component_ = 16;
00241     else if (maxval_ <= 0xFFFFFF) bits_per_component_ = 24;
00242     else if (maxval_ <= 0x7FFFFFFF) bits_per_component_ = 32;
00243     else assert(!"vil1_pnm_generic_image: maxval is too big");
00244   }
00245 
00246   return true;
00247 }
00248 
00249 bool vil1_pnm_generic_image::write_header()
00250 {
00251   vs_->seek(0L);
00252 
00253   char buf[1024];
00254   vcl_sprintf(buf, "P%d\n#vil1 pnm image, #c=%u, bpc=%u\n%u %u\n",
00255               magic_, components_, bits_per_component_, width_, height_);
00256   vs_->write(buf, vcl_strlen(buf));
00257   if (magic_ != 1 && magic_ != 4)
00258   {
00259     vcl_sprintf(buf, "%lu\n", maxval_);
00260     vs_->write(buf, vcl_strlen(buf));
00261   }
00262   start_of_data_ = vs_->tell();
00263   return true;
00264 }
00265 
00266 bool operator>>(vil1_stream& vs, int& a)
00267 {
00268   char c; vs.read(&c,1L);
00269   SkipSpaces(&vs,c);
00270   if (c < '0' || c > '9') return false; // non-digit found
00271   a = ReadInteger(&vs,c);
00272   return true;
00273 }
00274 
00275 bool operator>>(vil1_stream& vs, unsigned char& a)
00276 {
00277   int b; vs >> b;
00278   a = static_cast<unsigned char>(b);
00279   return b >= 0 && b <= 0xff;
00280 }
00281 
00282 bool operator>>(vil1_stream& vs, unsigned short& a)
00283 {
00284   int b; vs >> b;
00285   a = static_cast<unsigned short>(b);
00286   return b >= 0 && b <= 0xffff;
00287 }
00288 
00289 bool operator>>(vil1_stream& vs, unsigned int& a)
00290 {
00291   int b; vs >> b;
00292   a = static_cast<unsigned int>(b);
00293   return b >= 0;
00294 }
00295 
00296 bool vil1_pnm_generic_image::get_section(void* buf, int x0, int y0, int xs, int ys) const
00297 {
00298   unsigned char* ib = (unsigned char*) buf;
00299   unsigned short* jb = (unsigned short*) buf;
00300   unsigned int* kb = (unsigned int*) buf;
00301   //
00302   if (magic_ > 4) // pgm or ppm raw image
00303   {
00304     int bytes_per_sample = (bits_per_component_+7)/8;
00305     int bytes_per_pixel = components_ * bytes_per_sample;
00306     int byte_start = start_of_data_ + (y0 * width_ + x0) * bytes_per_pixel;
00307     int byte_width = width_ * bytes_per_pixel;
00308     int byte_out_width = xs * bytes_per_pixel;
00309 
00310     for (int y = 0; y < ys; ++y) {
00311       vs_->seek(byte_start + y * byte_width);
00312       vs_->read(ib + y * byte_out_width, byte_out_width);
00313     }
00314     if ( bytes_per_sample==2 && VXL_LITTLE_ENDIAN ) {
00315       ConvertMSBToHost( buf, xs*ys*components_ );
00316     } else if ( bytes_per_sample > 2 ) {
00317       vcl_cerr << "ERROR: pnm: reading rawbits format with > 16bit samples\n";
00318       return false;
00319     }
00320   }
00321   else if (magic_ == 4) // pbm (bitmap) raw image
00322   {
00323     int byte_width = (width_+7)/8;
00324     int byte_out_width = (xs+7)/8;
00325 
00326     for (int y = 0; y < ys; ++y) {
00327       vil1_streampos byte_start = start_of_data_ + (y0+y) * byte_width + x0/8;
00328       vs_->seek(byte_start);
00329       unsigned char a; vs_->read(&a, 1L);
00330       int s = x0&7; // = x0%8;
00331       unsigned char b = 0; // output
00332       int t = 0;
00333       for (int x = 0; x < xs; ++x) {
00334         b |= static_cast<unsigned char>(((a>>(7-s))&1)<<(7-t)); // single bit; high bit = first
00335         if (s >= 7) { vs_->read(&a, 1L); s = 0; }
00336         else ++s;
00337         if (t >= 7) { ib[y * byte_out_width + x/8] = b; b = 0; t = 0; }
00338         else ++t;
00339       }
00340       if (t) ib[y * byte_out_width + (xs-1)/8] = b;
00341     }
00342   }
00343   else // ascii (non-raw) image data
00344   {
00345     vs_->seek(start_of_data_);
00346     //0. Skip to the starting line
00347     //
00348     for (int t = 0; t < y0*width_*components_; ++t) { int a; (*vs_) >> a; }
00349     for (int y = 0; y < ys; ++y) {
00350       // 1. Skip to column x0
00351       //
00352       for (int t = 0; t < x0*components_; ++t) { int a; (*vs_) >> a; }
00353       // 2. Read the data
00354       //
00355       if (bits_per_component_ <= 1) {
00356         --ib; // to compensate for first ++ib
00357         for (int x=0,t=0; x<xs*components_; ++x,++t) {
00358           if ((t&=7)==0) *++ib=0; int a; (*vs_) >> a; if (a) *ib|=static_cast<unsigned char>(1<<(7-t)); }
00359         ++ib;
00360       }
00361       else if (bits_per_component_ <= 8)
00362         for (int x = 0; x < xs*components_; ++x) { unsigned char a; (*vs_) >> a; *(ib++)=a; }
00363       else if (bits_per_component_ <= 16)
00364         for (int x = 0; x < xs*components_; ++x) { unsigned short a; (*vs_) >> a; *(jb++)=a; }
00365       else
00366         for (int x = 0; x < xs*components_; ++x) { unsigned int a; (*vs_) >> a; *(kb++)=a; }
00367       // 3. Skip to the next line
00368       //
00369       for (int t = 0; t < (width_-x0-xs)*components_; ++t) { int a; (*vs_) >> a; }
00370     }
00371   }
00372 
00373   return true;
00374 }
00375 
00376 void operator<<(vil1_stream& vs, int a)
00377 {
00378   char buf[128]; vcl_sprintf(buf, " %d\n", a); vs.write(buf,vcl_strlen(buf));
00379 }
00380 
00381 bool vil1_pnm_generic_image::put_section(void const* buf, int x0, int y0, int xs, int ys)
00382 {
00383   unsigned char const* ob = (unsigned char const*) buf;
00384   unsigned short const* pb = (unsigned short const*) buf;
00385   unsigned int const* qb = (unsigned int const*) buf;
00386 
00387   if (magic_ > 4) // pgm or ppm raw image
00388   {
00389     int bytes_per_sample = (bits_per_component_+7)/8;
00390     int bytes_per_pixel = components_ * bytes_per_sample;
00391     vil1_streampos byte_start = start_of_data_ + (y0 * width_ + x0) * bytes_per_pixel;
00392     int byte_width = width_ * bytes_per_pixel;
00393     int byte_out_width = xs * bytes_per_pixel;
00394 
00395     if ( bytes_per_sample==1 || ( bytes_per_sample==2 && VXL_BIG_ENDIAN ) ) {
00396       for (int y = 0; y < ys; ++y) {
00397         vs_->seek(byte_start + y * byte_width);
00398         vs_->write(ob + y * byte_out_width, byte_out_width);
00399       }
00400     }
00401     else if ( bytes_per_sample==2 ) {
00402       // Little endian host; must convert words to have MSB first.
00403       // Can't convert the input buffer, because it's not ours.
00404       // Convert line by line to avoid duplicating a potentially large image.
00405       vcl_vector<unsigned char> tempbuf( byte_out_width );
00406       for (int y = 0; y < ys; ++y) {
00407         vs_->seek(byte_start + y * byte_width);
00408         vcl_memcpy( &tempbuf[0], ob + y * byte_out_width, byte_out_width );
00409         ConvertHostToMSB( &tempbuf[0], xs*components_ );
00410         vs_->write(&tempbuf[0], byte_out_width);
00411       }
00412     }
00413     else {
00414       vcl_cerr << "ERROR: pnm: writing rawbits format with > 16bit samples\n";
00415       return false;
00416     }
00417   }
00418   else if (magic_ == 4) // pbm (bitmap) raw image
00419   {
00420     int byte_width = (width_+7)/8;
00421     int byte_out_width = (xs+7)/8;
00422 
00423     for (int y = 0; y < ys; ++y)
00424     {
00425       vil1_streampos byte_start = start_of_data_ + (y0+y) * byte_width + x0/8;
00426       vs_->seek(byte_start);
00427       int s = x0&7; // = x0%8;
00428       int t = 0;
00429       unsigned char a = 0, b = ob[y * byte_out_width];
00430       if (s) {
00431         vs_->read(&a, 1L);
00432         vs_->seek(byte_start);
00433         a &= static_cast<unsigned char>(((1<<s)-1)<<(8-s)); // clear the last 8-s bits of a
00434       }
00435       for (int x = 0; x < xs; ++x) {
00436         if (b&(1<<(7-t))) a |= static_cast<unsigned char>(1<<(7-s)); // single bit; high bit = first
00437         if (t >= 7) { b = ob[y * byte_out_width + (x+1)/8]; t = 0; }
00438         else ++t;
00439         if (s >= 7) { vs_->write(&a, 1L); ++byte_start; s = 0; a = 0; }
00440         else ++s;
00441       }
00442       if (s) {
00443         if (x0+xs < width_) {
00444           vs_->seek(byte_start);
00445           unsigned char c; vs_->read(&c, 1L);
00446           vs_->seek(byte_start);
00447           c &= static_cast<unsigned char>((1<<(8-s))-1); // clear the first s bits of c
00448           a |= c;
00449         }
00450         vs_->write(&a, 1L);
00451       }
00452     }
00453   }
00454   else // ascii (non-raw) image data
00455   {
00456     if (x0 > 0 || y0 > 0 || xs < width_)
00457       return false; // can only write the full image in this mode
00458     vs_->seek(start_of_data_);
00459     for (int y = 0; y < ys; ++y) {
00460       if (bits_per_component_ <= 1)
00461         for (int x = 0; x < xs*components_; ++x) { (*vs_) << ((ob[x/8]>>(7-(x&7)))&1); }
00462       else if (bits_per_component_ <= 8)
00463         for (int x = 0; x < xs*components_; ++x) { (*vs_) << ob[x]; }
00464       else if (bits_per_component_ <= 16)
00465         for (int x = 0; x < xs*components_; ++x) { (*vs_) << pb[x]; }
00466       else
00467         for (int x = 0; x < xs*components_; ++x) { (*vs_) << qb[x]; }
00468       ob += xs; pb += xs; qb += xs;
00469     }
00470   }
00471 
00472   return true;
00473 }
00474 
00475 vil1_image vil1_pnm_generic_image::get_plane(unsigned int plane) const
00476 {
00477   assert(plane == 0);
00478   return const_cast<vil1_pnm_generic_image*>(this);
00479 }

Generated on Mon Nov 23 05:09:18 2009 for core/vil1 by  doxygen 1.5.1