core/vil/file_formats/vil_pnm.cxx
Go to the documentation of this file.
00001 // This is core/vil/file_formats/vil_pnm.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 
00008 #include "vil_pnm.h"
00009 
00010 #include <vcl_cassert.h>
00011 #include <vcl_cstdio.h> // for sprintf
00012 #include <vcl_vector.h>
00013 
00014 #include <vcl_iostream.h>
00015 #include <vcl_cstring.h>
00016 
00017 #include <vxl_config.h> // for VXL_BIG_ENDIAN and vxl_byte
00018 
00019 #include <vil/vil_property.h>
00020 #include <vil/vil_stream.h>
00021 #include <vil/vil_image_resource.h>
00022 #include <vil/vil_image_view.h>
00023 #include <vil/vil_memory_chunk.h>
00024 #include <vil/vil_exception.h>
00025 
00026 #if 0 // see comment below
00027 # include <vil/vil_rgb.h>
00028 #endif
00029 
00030 char const* vil_pnm_format_tag = "pnm";
00031 
00032 static inline bool iseol(int c)
00033 {
00034   return c == 10 || c == 13;
00035 }
00036 
00037 static inline bool isws(int c)
00038 {
00039   return c == ' ' || c == '\t' || c == 10 || c == 13;
00040 }
00041 
00042 vil_image_resource_sptr vil_pnm_file_format::make_input_image(vil_stream* vs)
00043 {
00044   // Attempt to read header
00045   unsigned char buf[3];
00046   if (vs->read(buf, 3L) != 3L)
00047     return 0;
00048   bool ok = ((buf[0] == 'P') &&
00049              isws(buf[2]) &&
00050              (buf[1] >= '1' && buf[2] <= '6'));
00051   if (!ok)
00052     return 0;
00053 
00054   return new vil_pnm_image(vs);
00055 }
00056 
00057 vil_image_resource_sptr vil_pnm_file_format::make_output_image(vil_stream* vs,
00058                                                                unsigned ni,
00059                                                                unsigned nj,
00060                                                                unsigned nplanes,
00061                                                                vil_pixel_format format)
00062 {
00063   return new vil_pnm_image(vs, ni, nj, nplanes, format);
00064 }
00065 
00066 char const* vil_pnm_file_format::tag() const
00067 {
00068   return vil_pnm_format_tag;
00069 }
00070 
00071 /////////////////////////////////////////////////////////////////////////////
00072 
00073 vil_pnm_image::vil_pnm_image(vil_stream* vs):
00074   vs_(vs)
00075 {
00076   vs_->ref();
00077   read_header();
00078 }
00079 
00080 bool vil_pnm_image::get_property(char const * tag, void * value) const
00081 {
00082   if (vcl_strcmp(vil_property_quantisation_depth, tag)==0)
00083   {
00084     if (value)
00085       *static_cast<unsigned int*>(value) = bits_per_component_;
00086     return true;
00087   }
00088 
00089   return false;
00090 }
00091 
00092 char const* vil_pnm_image::file_format() const
00093 {
00094   return vil_pnm_format_tag;
00095 }
00096 
00097 vil_pnm_image::vil_pnm_image(vil_stream* vs, unsigned ni, unsigned nj,
00098                              unsigned nplanes, vil_pixel_format format):
00099   vs_(vs)
00100 {
00101   vs_->ref();
00102   ni_ = ni;
00103   nj_ = nj;
00104 
00105   ncomponents_ = nplanes;
00106   format_ = vil_pixel_format_component_format(format);
00107   if (nplanes == 1 &&
00108       (format==VIL_PIXEL_FORMAT_RGB_BYTE ||
00109        format==VIL_PIXEL_FORMAT_RGB_SBYTE ||
00110        format==VIL_PIXEL_FORMAT_RGB_INT_16 ||
00111        format==VIL_PIXEL_FORMAT_RGB_INT_16 ||
00112        format==VIL_PIXEL_FORMAT_RGB_INT_32 ||
00113        format==VIL_PIXEL_FORMAT_RGB_INT_32 ||
00114        format==VIL_PIXEL_FORMAT_RGB_FLOAT ||
00115        format==VIL_PIXEL_FORMAT_RGB_DOUBLE
00116      ))
00117     ncomponents_ = 3;
00118   if (format==VIL_PIXEL_FORMAT_BOOL)
00119     bits_per_component_ = 1;
00120   else
00121     bits_per_component_ = 8*vil_pixel_format_sizeof_components(format);
00122 
00123   if (ncomponents_ == 3)
00124     magic_ = 6;
00125   else if (ncomponents_ == 1)
00126   {
00127     if (bits_per_component_ == 1)
00128       magic_ = 4;
00129     else
00130       magic_ = 5;
00131   }
00132   else assert(!"nplanes must be 1 or 3");
00133 
00134   // pnm allows 16 bit samples in rawbits format, stored MSB, but not 32 bit.
00135   if (bits_per_component_ > 16) magic_ -= 3;
00136 
00137   if (bits_per_component_ < 31)
00138     maxval_ = (1L<<bits_per_component_)-1;
00139   else
00140     maxval_ = 0x7FFFFFFF; // not 0xFFFFFFFF as the pnm format does not allow values > MAX_INT
00141 
00142   write_header();
00143 }
00144 
00145 vil_pnm_image::~vil_pnm_image()
00146 {
00147   vs_->unref();
00148 }
00149 
00150 // Skip over spaces and comments; temp is the current vs character
00151 static void SkipSpaces(vil_stream* vs, char& temp)
00152 {
00153   while (isws(temp) || temp == '#')
00154   {
00155     if (temp == '#') // skip this line:
00156       while (!iseol(temp))
00157         if (1L > vs->read(&temp,1L)) return; // at end-of-file?
00158     // skip this `whitespace' byte by reading the next byte:
00159     if (1L > vs->read(&temp,1L)) return;
00160   }
00161 }
00162 
00163 // Get a nonnegative integer from the vs stream; temp is the current vs byte
00164 static int ReadInteger(vil_stream* vs, char& temp)
00165 {
00166   int n = 0;
00167   while ((temp >= '0') && (temp <= '9'))
00168   {
00169     n *= 10; n += (temp - '0');
00170     if (1L > vs->read(&temp,1L)) return n; // at end-of-file?
00171   }
00172   return n;
00173 }
00174 
00175 #if VXL_LITTLE_ENDIAN
00176 
00177 // Convert the buffer of 16 bit words from MSB to host order
00178 static void ConvertMSBToHost( void* buf, int num_words )
00179 {
00180   unsigned char* ptr = static_cast<unsigned char*>(buf);
00181   for ( int i=0; i < num_words; ++i )
00182   {
00183     unsigned char t = *ptr;
00184     *ptr = *(ptr+1);
00185     *(ptr+1) = t;
00186     ptr += 2;
00187   }
00188 }
00189 
00190 // Convert the buffer of 16 bit words from host order to MSB
00191 static void ConvertHostToMSB( void* buf, int num_words )
00192 {
00193   unsigned char* ptr = static_cast<unsigned char*>(buf);
00194   for ( int i=0; i < num_words; ++i )
00195   {
00196     unsigned char t = *ptr;
00197     *ptr = *(ptr+1);
00198     *(ptr+1) = t;
00199     ptr += 2;
00200   }
00201 }
00202 
00203 #endif // VXL_LITTLE_ENDIAN
00204 
00205 
00206 //: This method accepts any valid PNM file (first 3 bytes "P1\n" to "P6\n")
00207 bool vil_pnm_image::read_header()
00208 {
00209   char temp;
00210 
00211   // Go to start of file
00212   vs_->seek(0L);
00213 
00214   char buf[3];
00215   if (3L > vs_->read(buf, 3L)) return false; // at end-of-file?
00216   if (buf[0] != 'P') return false;
00217   if (!isws(buf[2])) return false;
00218   magic_ = buf[1] - '0';
00219   if (magic_ < 1 || magic_ > 6) return false;
00220 
00221   // read 1 byte
00222   vs_->read(&temp, 1L);
00223 
00224   // Skip over spaces and comments
00225   SkipSpaces(vs_,temp);
00226 
00227   // Read in Width
00228   ni_ = ReadInteger(vs_,temp);
00229 
00230   // Skip over spaces and comments
00231   SkipSpaces(vs_,temp);
00232 
00233   // Read in Height
00234   nj_ = ReadInteger(vs_,temp);
00235 
00236   // a pbm (bitmap) image does not have a maxval field
00237   if (magic_ == 1 || magic_ == 4)
00238     maxval_ = 1;
00239   else
00240   {
00241     // Skip over spaces and comments
00242     SkipSpaces(vs_,temp);
00243 
00244     // Read in Maxval
00245     maxval_ = ReadInteger(vs_,temp);
00246   }
00247 
00248   start_of_data_ = vs_->tell() - 1L;
00249 
00250   // Final end-of-line or other white space (1 byte) before the data section begins
00251   if (isws(temp))
00252     ++start_of_data_;
00253 
00254   ncomponents_ = ((magic_ == 3 || magic_ == 6) ? 3 : 1);
00255 
00256   if (magic_ == 1 || magic_ == 4) bits_per_component_ = 1;
00257   else if (maxval_ == 0) assert(!"problem reading maxval from PNM file");
00258   else if (maxval_ <= 0xFF) bits_per_component_ = 8;
00259   else if (maxval_ <= 0xFFFF) bits_per_component_ = 16;
00260   else if (maxval_ <= 0xFFFFFF) bits_per_component_ = 24;
00261   else if (maxval_ <= 0x7FFFFFFF) bits_per_component_ = 32;
00262   else assert(!"vil_pnm_image: maxval is too big");
00263 
00264   switch (magic_)
00265   {
00266    case 1:  // pbm format
00267    case 4:
00268     format_ = VIL_PIXEL_FORMAT_BOOL;
00269     break;
00270    case 2:  // pgm format
00271    case 5:
00272    case 3:  // ppm format
00273    case 6:
00274     if (bits_per_component_ <= 8)
00275       format_ = VIL_PIXEL_FORMAT_BYTE;
00276     else if (bits_per_component_ <= 16)
00277       format_ = VIL_PIXEL_FORMAT_UINT_16;
00278     else
00279       format_ = VIL_PIXEL_FORMAT_UINT_32;
00280     break;
00281    default: // this should never happen
00282     break;
00283   }
00284 
00285   return true;
00286 }
00287 
00288 bool vil_pnm_image::write_header()
00289 {
00290   vs_->seek(0L);
00291 
00292   char buf[1024];
00293   vcl_sprintf(buf, "P%d\n#vil pnm image, #c=%u, bpc=%u\n%u %u\n",
00294               magic_, ncomponents_, bits_per_component_, ni_, nj_);
00295   vs_->write(buf, vcl_strlen(buf));
00296   if (magic_ != 1 && magic_ != 4)
00297   {
00298     vcl_sprintf(buf, "%lu\n", maxval_);
00299     vs_->write(buf, vcl_strlen(buf));
00300   }
00301   start_of_data_ = vs_->tell();
00302   return true;
00303 }
00304 
00305 static bool operator>>(vil_stream& vs, int& a)
00306 {
00307   char c; vs.read(&c,1L);
00308   SkipSpaces(&vs,c);
00309   if (c < '0' || c > '9') return false; // non-digit found
00310   a = ReadInteger(&vs,c);
00311   return true;
00312 }
00313 
00314 vil_image_view_base_sptr vil_pnm_image::get_copy_view(
00315   unsigned x0, unsigned ni, unsigned y0, unsigned nj) const
00316 {
00317   bool* bb = 0;
00318   unsigned char* ib = 0;
00319   unsigned short* jb = 0;
00320   unsigned int* kb = 0;
00321 
00322   vil_memory_chunk_sptr buf;
00323 
00324   if (bits_per_component_ == 1)
00325   {
00326     buf = new vil_memory_chunk(ni * nj* nplanes() * sizeof(bool),VIL_PIXEL_FORMAT_BOOL);
00327     bb = reinterpret_cast<bool *>(buf->data());
00328   }
00329   else if (bits_per_component_ <= 8)
00330   {
00331     buf = new vil_memory_chunk(ni * nj* nplanes() * 1,VIL_PIXEL_FORMAT_BYTE);
00332     ib = reinterpret_cast<vxl_byte*>(buf->data());
00333   }
00334   else if (bits_per_component_ <= 16)
00335   {
00336     buf = new vil_memory_chunk(ni * nj* nplanes() * 2,VIL_PIXEL_FORMAT_UINT_16);
00337     jb = reinterpret_cast<vxl_uint_16*>(buf->data());
00338   }
00339   else
00340   {
00341     buf = new vil_memory_chunk(ni * nj* nplanes() * 4,VIL_PIXEL_FORMAT_UINT_32);
00342     kb = reinterpret_cast<vxl_uint_32*>(buf->data());
00343   }
00344 
00345   if (magic_ > 4) // pgm or ppm raw image
00346   {
00347     unsigned bytes_per_sample = (bits_per_component_+7)/8;
00348     unsigned bytes_per_pixel = nplanes() * bytes_per_sample;
00349     vil_streampos byte_start = start_of_data_ + (y0 * ni_ + x0) * bytes_per_pixel;
00350     unsigned byte_width = ni_ * bytes_per_pixel;
00351     unsigned byte_out_width = ni * bytes_per_pixel;
00352 
00353     for (unsigned y = 0; y < nj; ++y)
00354     {
00355       vs_->seek(byte_start);
00356       vs_->read((unsigned char *)buf->data() + y * byte_out_width, byte_out_width);
00357       byte_start += byte_width;
00358     }
00359     if ( bytes_per_sample > 2 )
00360     {
00361       vcl_cerr << "ERROR: pnm: reading rawbits format with > 16bit samples\n";
00362       return 0;
00363     }
00364 #if VXL_LITTLE_ENDIAN
00365     else if ( bytes_per_sample==2 )
00366       ConvertMSBToHost( reinterpret_cast<unsigned char *>(buf->data()), ni*nj*nplanes() );
00367 #endif
00368 #if 0 // see comment below
00369     if (ncomponents_ == 1) {
00370 #endif
00371       if (bits_per_component_ <= 1)
00372         return new vil_image_view<bool>(buf, bb, ni, nj, nplanes(), nplanes(), ni*nplanes(), 1);
00373       if (bits_per_component_ <= 8)
00374         return new vil_image_view<vxl_byte>(buf, ib, ni, nj, nplanes(), nplanes(), ni*nplanes(), 1);
00375       else if (bits_per_component_ <= 16)
00376         return new vil_image_view<vxl_uint_16>(buf, jb, ni, nj, nplanes(), nplanes(), ni*nplanes(), 1);
00377       else
00378         return new vil_image_view<vxl_uint_32>(buf, kb, ni, nj, nplanes(), nplanes(), ni*nplanes(), 1);
00379 #if 0 // never return vil_image_view<vil_rgb<T> > : default image representation is planar
00380     }
00381     else if (ncomponents_ == 3) {
00382       if (bits_per_component_ <= 8)
00383         return new vil_image_view<vil_rgb<vxl_byte> >(buf, (vil_rgb<vxl_byte>*)ib, ni, nj, 1, 1, ni, 1);
00384       else if (bits_per_component_ <= 16)
00385         return new vil_image_view<vil_rgb<vxl_uint_16> >(buf, (vil_rgb<vxl_uint_16>*)jb, ni, nj, 1, 1, ni, 1);
00386       else
00387         return new vil_image_view<vil_rgb<vxl_uint_32> >(buf, (vil_rgb<vxl_uint_32>*)kb, ni, nj, 1, 1, ni, 1);
00388     }
00389     else return 0;
00390 #endif // 0
00391   }
00392   else if (magic_ == 4) // pbm (bitmap) raw image
00393   {
00394     unsigned byte_width = (ni_+7)/8;
00395 
00396     for (unsigned y = 0; y < nj; ++y)
00397     {
00398       vil_streampos byte_start = start_of_data_ + (y0+y) * byte_width + x0/8;
00399       vs_->seek(byte_start);
00400       unsigned char a; vs_->read(&a, 1L);
00401       for (unsigned x = 0; x < ni+x0; ++x)
00402       {
00403         if ( x >= x0 )
00404           bb[y * ni + x-x0] = (a & 0x80) != 0;
00405         a <<= 1;
00406         if (x%8 == 7)
00407           vs_->read(&a, 1L);
00408       }
00409     }
00410     assert (buf->size() == ni*nj*sizeof(bool));
00411     return new vil_image_view<bool>(buf, bb, ni, nj, 1, 1, ni, ni*nj);
00412   }
00413   else // ascii (non-raw) image data
00414   {
00415     vs_->seek(start_of_data_);
00416     // 0. Skip to the starting line
00417     //
00418     for (unsigned t = 0; t < y0*ni_*nplanes(); ++t) { int a; (*vs_) >> a; }
00419     for (unsigned y = 0; y < nj; ++y)
00420     {
00421       // 1. Skip to column x0
00422       for (unsigned t = 0; t < x0*nplanes(); ++t) { int a; (*vs_) >> a; }
00423       for (unsigned x = 0; x < ni; ++x)
00424       {
00425         // 3. Read the data
00426         if (bits_per_component_ <= 1)
00427           for (unsigned p = 0; p < nplanes(); ++p) { int a; (*vs_) >> a; *(bb++)=(a!=0); }
00428         else if (bits_per_component_ <= 8)
00429           for (unsigned p = 0; p < nplanes(); ++p) { int a; (*vs_) >> a; *(ib++)=vxl_byte(a); }
00430         else if (bits_per_component_ <= 16)
00431           for (unsigned p = 0; p < nplanes(); ++p) { int a; (*vs_) >> a; *(jb++)=vxl_uint_16(a); }
00432         else
00433           for (unsigned p = 0; p < nplanes(); ++p) { int a; (*vs_) >> a; *(kb++)=vxl_uint_32(a); }
00434       }
00435       // 5. Skip to the next line
00436       for (unsigned t = 0; t < (ni_-x0-ni)*nplanes(); ++t) { int a; (*vs_) >> a; }
00437     }
00438 #if 0 // see comment below
00439     if (ncomponents_ == 1)
00440     {
00441 #endif
00442       if (bits_per_component_ <= 1)
00443         return new vil_image_view<bool>(buf, reinterpret_cast<bool*>(buf->data()), ni, nj, nplanes(), nplanes(), ni*nplanes(), 1);
00444       if (bits_per_component_ <= 8)
00445         return new vil_image_view<vxl_byte>(buf,reinterpret_cast<vxl_byte*>(buf->data()),ni,nj,nplanes(),nplanes(),ni*nplanes(),1);
00446       else if (bits_per_component_ <= 16)
00447        return new
00448          vil_image_view<vxl_uint_16>(buf,reinterpret_cast<vxl_uint_16*>(buf->data()),ni,nj,nplanes(),nplanes(),ni*nplanes(),1);
00449       else
00450        return new
00451          vil_image_view<vxl_uint_32>(buf,reinterpret_cast<vxl_uint_32*>(buf->data()),ni,nj,nplanes(),nplanes(),ni*nplanes(),1);
00452 #if 0 // never return vil_image_view<vil_rgb<T> > : default image representation is planar
00453     }
00454     else if (ncomponents_ == 3)
00455     {
00456       if (bits_per_component_ <= 8)
00457         return new vil_image_view<vil_rgb<vxl_byte> >(buf, reinterpret_cast<vil_rgb<vxl_byte>*>(buf->data()), ni,nj,1, 1,ni,1);
00458       else if (bits_per_component_ <= 16)
00459        return new vil_image_view<vil_rgb<vxl_uint_16> >(buf,reinterpret_cast<vil_rgb<vxl_uint_16>*>(buf->data()),ni,nj,1,1,ni,1);
00460       else
00461        return new vil_image_view<vil_rgb<vxl_uint_32> >(buf,reinterpret_cast<vil_rgb<vxl_uint_32>*>(buf->data()),ni,nj,1,1,ni,1);
00462     }
00463     else return 0;
00464 #endif // 0
00465   }
00466 }
00467 
00468 
00469 static void operator<<(vil_stream& vs, int a)
00470 {
00471   char buf[128]; vcl_sprintf(buf, " %d\n", a); vs.write(buf,vcl_strlen(buf));
00472 }
00473 
00474 bool vil_pnm_image::put_view(const vil_image_view_base& view,
00475                              unsigned x0, unsigned y0)
00476 {
00477   if (!view_fits(view, x0, y0))
00478   {
00479     vil_exception_warning(vil_exception_out_of_bounds("vil_pnm_image::put_view"));
00480     return false;
00481   }
00482 
00483   if ((view.pixel_format() == VIL_PIXEL_FORMAT_UINT_32 && bits_per_component_ < 32) ||
00484       (view.pixel_format() == VIL_PIXEL_FORMAT_INT_32  && bits_per_component_ < 32) ||
00485       (view.pixel_format() == VIL_PIXEL_FORMAT_UINT_16 && bits_per_component_ < 16) ||
00486       (view.pixel_format() == VIL_PIXEL_FORMAT_INT_16  && bits_per_component_ < 16) ||
00487       (view.pixel_format() == VIL_PIXEL_FORMAT_BYTE    && bits_per_component_ <  8) ||
00488       (view.pixel_format() == VIL_PIXEL_FORMAT_SBYTE   && bits_per_component_ <  8) ||
00489       (view.pixel_format() == VIL_PIXEL_FORMAT_BOOL    && bits_per_component_ <  1) ||
00490        view.pixel_format() == VIL_PIXEL_FORMAT_DOUBLE ||
00491        view.pixel_format() == VIL_PIXEL_FORMAT_FLOAT )
00492   {
00493     vcl_cerr << "ERROR: " << __FILE__ << ":\n Can't fit view into pnm component size\n";
00494     return false;
00495   }
00496 
00497   const vil_image_view<bool>*  bb=0;
00498   const vil_image_view<vxl_byte>*  ob = 0;
00499   const vil_image_view<vxl_uint_16>* pb = 0;
00500   const vil_image_view<vxl_uint_32>*   qb = 0;
00501 
00502   if (view.pixel_format() == VIL_PIXEL_FORMAT_BOOL)
00503     bb = &static_cast<const vil_image_view<bool>& >(view);
00504   else if (view.pixel_format() == VIL_PIXEL_FORMAT_BYTE)
00505     ob = &static_cast<const vil_image_view<vxl_byte>& >(view);
00506   else if (view.pixel_format() == VIL_PIXEL_FORMAT_UINT_16)
00507     pb = &static_cast<const vil_image_view<vxl_uint_16>& >(view);
00508   else if (view.pixel_format() == VIL_PIXEL_FORMAT_UINT_32)
00509     qb = &static_cast<const vil_image_view<vxl_uint_32>& >(view);
00510   else
00511   {
00512     vcl_cerr << "ERROR: " << __FILE__ << ":\n Do not support putting "
00513              << view.is_a() << " views into pnm image_resource objects\n";
00514     return false;
00515   }
00516 
00517   if (magic_ == 5) // pgm raw image ==> nplanes() == 1
00518   {
00519     unsigned bytes_per_sample = (bits_per_component_+7)/8;
00520     unsigned bytes_per_pixel = bytes_per_sample;
00521     vil_streampos byte_start = start_of_data_ + (y0 * ni_ + x0) * bytes_per_pixel;
00522     unsigned byte_width = ni_ * bytes_per_pixel;
00523     unsigned byte_out_width = view.ni() * bytes_per_pixel;
00524 
00525     if ( bytes_per_sample==1 )
00526     {
00527       assert(ob!=0);
00528       for (unsigned y = 0; y < view.nj(); ++y)
00529       {
00530         vs_->seek(byte_start);
00531         vs_->write(ob->top_left_ptr() + y * ob->jstep(), byte_out_width);
00532         byte_start += byte_width;
00533       }
00534     }
00535     else if ( bytes_per_sample==2 && VXL_BIG_ENDIAN )
00536     {
00537       assert(pb!=0);
00538       for (unsigned y = 0; y < view.nj(); ++y)
00539       {
00540         vs_->seek(byte_start);
00541         vs_->write(pb->top_left_ptr() + y * pb->jstep(), byte_out_width);
00542         byte_start += byte_width;
00543       }
00544     }
00545     else if ( bytes_per_sample==2 )
00546     {
00547       // Little endian host; must convert words to have MSB first.
00548       //
00549       // Convert line by line to avoid duplicating a potentially large image.
00550       vcl_vector<vxl_byte> tempbuf(byte_out_width);
00551       assert(pb!=0);
00552       for (unsigned y = 0; y < view.nj(); ++y)
00553       {
00554         vs_->seek(byte_start);
00555         vcl_memcpy(&tempbuf[0], pb->top_left_ptr() + y * pb->jstep(), byte_out_width);
00556 #if VXL_LITTLE_ENDIAN
00557         ConvertHostToMSB(&tempbuf[0], view.ni());
00558 #endif
00559         vs_->write(&tempbuf[0], byte_out_width);
00560         byte_start += byte_width;
00561       }
00562     }
00563     else { // This should never occur...
00564       vcl_cerr << "ERROR: pgm: writing rawbits format with > 16bit samples\n";
00565       return false;
00566     }
00567   }
00568   else if (magic_ == 6) // ppm raw image; cannot be written as efficiently as pgm
00569   {
00570     unsigned bytes_per_sample = (bits_per_component_+7)/8;
00571     unsigned bytes_per_pixel = nplanes() * bytes_per_sample;
00572     vil_streampos byte_start = start_of_data_ + (y0 * ni_ + x0) * bytes_per_pixel;
00573     unsigned byte_width = ni_ * bytes_per_pixel;
00574 
00575     if ( bytes_per_sample==1 )
00576     {
00577       assert(ob!=0);
00578 
00579       // capes_at_robots - Modified to write a scan-line at once. Writing single bytes
00580       // to disk was extremely slow.
00581       vcl_vector<vxl_byte> scanline( byte_width );
00582 
00583       for (unsigned y = 0; y < view.nj(); ++y)
00584       {
00585         vs_->seek(byte_start);
00586         for (unsigned x = 0, c = 0; x < view.ni(); ++x)
00587           for (unsigned p = 0; p < ncomponents_; ++p, ++c)
00588             scanline[c] = (*ob)(x,y,p);
00589         vs_->write(&scanline[0], byte_width);
00590         byte_start += byte_width;
00591       }
00592     }
00593     else if ( bytes_per_sample==2 )
00594     {
00595       assert(pb!=0);
00596       for (unsigned y = y0; y < view.nj(); ++y)
00597       {
00598         vs_->seek(byte_start);
00599         for (unsigned x = x0; x < view.ni(); ++x)
00600         {
00601           vxl_uint_16 tempbuf[3];
00602           for (unsigned p = 0; p < ncomponents_; ++p)
00603             tempbuf[p] = (*pb)(x,y,p);
00604 #if VXL_LITTLE_ENDIAN
00605           ConvertHostToMSB(tempbuf, ncomponents_);
00606 #endif
00607           vs_->write(tempbuf, bytes_per_pixel);
00608         }
00609         byte_start += byte_width;
00610       }
00611     }
00612     else { // This should never occur...
00613       vcl_cerr << "ERROR: pgm: writing rawbits format with > 16bit samples\n";
00614       return false;
00615     }
00616   }
00617   else if (magic_ == 4) // pbm (bitmap) raw image
00618   {
00619     int byte_width = (ni_+7)/8;
00620 
00621     assert(bb!=0);
00622     for (unsigned y = 0; y < view.nj(); ++y)
00623     {
00624       vil_streampos byte_start = start_of_data_ + (y0+y) * byte_width + x0/8;
00625       int s = x0&7; // = x0%8;
00626       unsigned char a = 0;
00627       if (s)
00628       {
00629         vs_->read(&a, 1L);
00630         vs_->seek(byte_start);
00631         a &= ((1<<s)-1)<<(8-s); // clear the last 8-s bits of a
00632       }
00633       for (unsigned x = 0; x < view.ni(); ++x)
00634       {
00635         if ((*bb)(x,y)) a |= 1<<(7-s); // single bit; high bit = first
00636         if (s >= 7) { vs_->write(&a, 1L); ++byte_start; s = 0; a = 0; }
00637         else ++s;
00638       }
00639       if (s)
00640       {
00641         if (x0+view.ni() < ni_)
00642         {
00643           vs_->seek(byte_start);
00644           unsigned char c; vs_->read(&c, 1L);
00645           vs_->seek(byte_start);
00646           c &= ((1<<(8-s))-1); // clear the first s bits of c
00647           a |= c;
00648         }
00649         vs_->write(&a, 1L);
00650       }
00651     }
00652   }
00653   else // ascii (non-raw) image data
00654   {
00655     if (x0 > 0 || y0 > 0 || view.ni() < ni_ || view.nj() < nj_)
00656       return false; // can only write the full image in this mode
00657     vs_->seek(start_of_data_);
00658     for (unsigned y = 0; y < view.nj(); ++y)
00659       for (unsigned x = 0; x < view.ni(); ++x)
00660         for (unsigned p = 0; p < ncomponents_; ++p)
00661         {
00662           if (bits_per_component_ <= 1)       (*vs_) << (*bb)(x,y,p);
00663           else if (bits_per_component_ <= 8)  (*vs_) << (*ob)(x,y,p);
00664           else if (bits_per_component_ <= 16) (*vs_) << (*pb)(x,y,p);
00665           else                                (*vs_) << (*qb)(x,y,p);
00666         }
00667   }
00668 
00669   return true;
00670 }