Panda3D

pnmFileTypeIMG.cxx

00001 // Filename: pnmFileTypeIMG.cxx
00002 // Created by:  drose (19Jun00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "pnmFileTypeIMG.h"
00016 
00017 #ifdef HAVE_IMG
00018 
00019 #include "config_pnmimagetypes.h"
00020 
00021 #include "pnmFileTypeRegistry.h"
00022 #include "bamReader.h"
00023 
00024 // Since raw image files don't have a magic number, we'll make a little
00025 // sanity check on the size of the image.  If either the width or height is
00026 // larger than this, it must be bogus.
00027 #define INSANE_SIZE 20000
00028 
00029 static const char * const extensions_img[] = {
00030   "img"
00031 };
00032 static const int num_extensions_img = sizeof(extensions_img) / sizeof(const char *);
00033 
00034 TypeHandle PNMFileTypeIMG::_type_handle;
00035 
00036 ////////////////////////////////////////////////////////////////////
00037 //     Function: PNMFileTypeIMG::Constructor
00038 //       Access: Public
00039 //  Description:
00040 ////////////////////////////////////////////////////////////////////
00041 PNMFileTypeIMG::
00042 PNMFileTypeIMG() {
00043 }
00044 
00045 ////////////////////////////////////////////////////////////////////
00046 //     Function: PNMFileTypeIMG::get_name
00047 //       Access: Public, Virtual
00048 //  Description: Returns a few words describing the file type.
00049 ////////////////////////////////////////////////////////////////////
00050 string PNMFileTypeIMG::
00051 get_name() const {
00052   return "Raw binary RGB";
00053 }
00054 
00055 ////////////////////////////////////////////////////////////////////
00056 //     Function: PNMFileTypeIMG::get_num_extensions
00057 //       Access: Public, Virtual
00058 //  Description: Returns the number of different possible filename
00059 //               extensions associated with this particular file type.
00060 ////////////////////////////////////////////////////////////////////
00061 int PNMFileTypeIMG::
00062 get_num_extensions() const {
00063   return num_extensions_img;
00064 }
00065 
00066 ////////////////////////////////////////////////////////////////////
00067 //     Function: PNMFileTypeIMG::get_extension
00068 //       Access: Public, Virtual
00069 //  Description: Returns the nth possible filename extension
00070 //               associated with this particular file type, without a
00071 //               leading dot.
00072 ////////////////////////////////////////////////////////////////////
00073 string PNMFileTypeIMG::
00074 get_extension(int n) const {
00075   nassertr(n >= 0 && n < num_extensions_img, string());
00076   return extensions_img[n];
00077 }
00078 
00079 ////////////////////////////////////////////////////////////////////
00080 //     Function: PNMFileTypeIMG::get_suggested_extension
00081 //       Access: Public, Virtual
00082 //  Description: Returns a suitable filename extension (without a
00083 //               leading dot) to suggest for files of this type, or
00084 //               empty string if no suggestions are available.
00085 ////////////////////////////////////////////////////////////////////
00086 string PNMFileTypeIMG::
00087 get_suggested_extension() const {
00088   return "img";
00089 }
00090 
00091 ////////////////////////////////////////////////////////////////////
00092 //     Function: PNMFileTypeIMG::make_reader
00093 //       Access: Public, Virtual
00094 //  Description: Allocates and returns a new PNMReader suitable for
00095 //               reading from this file type, if possible.  If reading
00096 //               from this file type is not supported, returns NULL.
00097 ////////////////////////////////////////////////////////////////////
00098 PNMReader *PNMFileTypeIMG::
00099 make_reader(istream *file, bool owns_file, const string &magic_number) {
00100   init_pnm();
00101   return new Reader(this, file, owns_file, magic_number);
00102 }
00103 
00104 ////////////////////////////////////////////////////////////////////
00105 //     Function: PNMFileTypeIMG::make_writer
00106 //       Access: Public, Virtual
00107 //  Description: Allocates and returns a new PNMWriter suitable for
00108 //               reading from this file type, if possible.  If writing
00109 //               files of this type is not supported, returns NULL.
00110 ////////////////////////////////////////////////////////////////////
00111 PNMWriter *PNMFileTypeIMG::
00112 make_writer(ostream *file, bool owns_file) {
00113   init_pnm();
00114   return new Writer(this, file, owns_file);
00115 }
00116 
00117 
00118 inline unsigned long
00119 read_ulong(istream *file) {
00120   unsigned long x;
00121   return pm_readbiglong(file, (long *)&x)==0 ? x : 0;
00122 }
00123 
00124 inline unsigned short
00125 read_ushort_IMG(istream *file) {
00126   unsigned short x;
00127   return pm_readbigshort(file, (short *)&x)==0 ? x : 0;
00128 }
00129 
00130 inline unsigned char
00131 read_uchar_IMG(istream *file) {
00132   int x;
00133   x = file->get();
00134   return (x!=EOF) ? (unsigned char)x : 0;
00135 }
00136 
00137 inline void
00138 write_ulong(ostream *file, unsigned long x) {
00139   pm_writebiglong(file, (long)x);
00140 }
00141 
00142 inline void
00143 write_ushort_IMG(ostream *file, unsigned long x) {
00144   pm_writebigshort(file, (short)(long)x);
00145 }
00146 
00147 inline void
00148 write_uchar_IMG(ostream *file, unsigned char x) {
00149   file->put(x);
00150 }
00151 
00152 ////////////////////////////////////////////////////////////////////
00153 //     Function: PNMFileTypeIMG::Reader::Constructor
00154 //       Access: Public
00155 //  Description:
00156 ////////////////////////////////////////////////////////////////////
00157 PNMFileTypeIMG::Reader::
00158 Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
00159   PNMReader(type, file, owns_file)
00160 {
00161   if (img_header_type == IHT_long) {
00162     if (!read_magic_number(_file, magic_number, 8)) {
00163       // Although raw IMG files have no magic number, they may have a
00164       // pair of ushorts or ulongs at the beginning to indicate the file
00165       // size.
00166       if (pnmimage_img_cat.is_debug()) {
00167         pnmimage_img_cat.debug()
00168           << "IMG image file appears to be empty.\n";
00169       }
00170       _is_valid = false;
00171       return;
00172     }
00173 
00174     _x_size =
00175       ((unsigned char)magic_number[0] << 24) |
00176       ((unsigned char)magic_number[1] << 16) |
00177       ((unsigned char)magic_number[2] << 8) |
00178       ((unsigned char)magic_number[3]);
00179 
00180     _y_size =
00181       ((unsigned char)magic_number[4] << 24) |
00182       ((unsigned char)magic_number[5] << 16) |
00183       ((unsigned char)magic_number[6] << 8) |
00184       ((unsigned char)magic_number[7]);
00185 
00186   } else if (img_header_type == IHT_short) {
00187     if (!read_magic_number(_file, magic_number, 4)) {
00188       if (pnmimage_img_cat.is_debug()) {
00189         pnmimage_img_cat.debug()
00190           << "IMG image file appears to be empty.\n";
00191       }
00192       _is_valid = false;
00193       return;
00194     }
00195 
00196     _x_size =
00197       ((unsigned char)magic_number[0] << 8) |
00198       ((unsigned char)magic_number[1]);
00199 
00200     _y_size =
00201       ((unsigned char)magic_number[2] << 8) |
00202       ((unsigned char)magic_number[3]);
00203 
00204   } else {
00205     _x_size = img_size[0];
00206     _y_size = img_size[1];
00207   }
00208 
00209   if (_x_size == 0 || _y_size == 0 ||
00210       _x_size > INSANE_SIZE || _y_size > INSANE_SIZE) {
00211     _is_valid = false;
00212     if (img_header_type == IHT_none) {
00213       pnmimage_img_cat.error()
00214         << "Must specify img-xsize and img-ysize to load headerless raw files.\n";
00215     } else {
00216       pnmimage_img_cat.debug()
00217         << "IMG file does not have a valid xsize,ysize header.\n";
00218     }
00219     return;
00220   }
00221 
00222   _maxval = 255;
00223   _num_channels = 3;
00224 
00225   if (pnmimage_img_cat.is_debug()) {
00226     pnmimage_img_cat.debug()
00227       << "Reading IMG " << *this << "\n";
00228   }
00229 }
00230 
00231 ////////////////////////////////////////////////////////////////////
00232 //     Function: PNMFileTypeIMG::Reader::supports_read_row
00233 //       Access: Public, Virtual
00234 //  Description: Returns true if this particular PNMReader supports a
00235 //               streaming interface to reading the data: that is, it
00236 //               is capable of returning the data one row at a time,
00237 //               via repeated calls to read_row().  Returns false if
00238 //               the only way to read from this file is all at once,
00239 //               via read_data().
00240 ////////////////////////////////////////////////////////////////////
00241 bool PNMFileTypeIMG::Reader::
00242 supports_read_row() const {
00243   return true;
00244 }
00245 
00246 ////////////////////////////////////////////////////////////////////
00247 //     Function: PNMFileTypeIMG::Reader::read_row
00248 //       Access: Public, Virtual
00249 //  Description: If supports_read_row(), above, returns true, this
00250 //               function may be called repeatedly to read the image,
00251 //               one horizontal row at a time, beginning from the top.
00252 //               Returns true if the row is successfully read, false
00253 //               if there is an error or end of file.
00254 ////////////////////////////////////////////////////////////////////
00255 bool PNMFileTypeIMG::Reader::
00256 read_row(xel *row_data, xelval *, int x_size, int) {
00257   int x;
00258   xelval red, grn, blu;
00259   for (x = 0; x < x_size; x++) {
00260     red = read_uchar_IMG(_file);
00261     grn = read_uchar_IMG(_file);
00262     blu = read_uchar_IMG(_file);
00263 
00264     PPM_ASSIGN(row_data[x], red, grn, blu);
00265   }
00266 
00267   return true;
00268 }
00269 
00270 ////////////////////////////////////////////////////////////////////
00271 //     Function: PNMFileTypeIMG::Writer::Constructor
00272 //       Access: Public
00273 //  Description:
00274 ////////////////////////////////////////////////////////////////////
00275 PNMFileTypeIMG::Writer::
00276 Writer(PNMFileType *type, ostream *file, bool owns_file) :
00277   PNMWriter(type, file, owns_file)
00278 {
00279 }
00280 
00281 ////////////////////////////////////////////////////////////////////
00282 //     Function: PNMFileTypeIMG::Writer::supports_write_row
00283 //       Access: Public, Virtual
00284 //  Description: Returns true if this particular PNMWriter supports a
00285 //               streaming interface to writing the data: that is, it
00286 //               is capable of writing the image one row at a time,
00287 //               via repeated calls to write_row().  Returns false if
00288 //               the only way to write from this file is all at once,
00289 //               via write_data().
00290 ////////////////////////////////////////////////////////////////////
00291 bool PNMFileTypeIMG::Writer::
00292 supports_write_row() const {
00293   return true;
00294 }
00295 
00296 ////////////////////////////////////////////////////////////////////
00297 //     Function: PNMFileTypeIMG::Writer::write_header
00298 //       Access: Public, Virtual
00299 //  Description: If supports_write_row(), above, returns true, this
00300 //               function may be called to write out the image header
00301 //               in preparation to writing out the image data one row
00302 //               at a time.  Returns true if the header is
00303 //               successfully written, false if there is an error.
00304 //
00305 //               It is the user's responsibility to fill in the header
00306 //               data via calls to set_x_size(), set_num_channels(),
00307 //               etc., or copy_header_from(), before calling
00308 //               write_header().
00309 ////////////////////////////////////////////////////////////////////
00310 bool PNMFileTypeIMG::Writer::
00311 write_header() {
00312   if (img_header_type == IHT_long) {
00313     write_ulong(_file, _x_size);
00314     write_ulong(_file, _y_size);
00315   } else if (img_header_type == IHT_short) {
00316     write_ushort_IMG(_file, _x_size);
00317     write_ushort_IMG(_file, _y_size);
00318   }
00319   return true;
00320 }
00321 
00322 ////////////////////////////////////////////////////////////////////
00323 //     Function: PNMFileTypeIMG::Writer::write_row
00324 //       Access: Public, Virtual
00325 //  Description: If supports_write_row(), above, returns true, this
00326 //               function may be called repeatedly to write the image,
00327 //               one horizontal row at a time, beginning from the top.
00328 //               Returns true if the row is successfully written,
00329 //               false if there is an error.
00330 //
00331 //               You must first call write_header() before writing the
00332 //               individual rows.  It is also important to delete the
00333 //               PNMWriter class after successfully writing the last
00334 //               row.  Failing to do this may result in some data not
00335 //               getting flushed!
00336 ////////////////////////////////////////////////////////////////////
00337 bool PNMFileTypeIMG::Writer::
00338 write_row(xel *row_data, xelval *) {
00339   int x;
00340   for (x = 0; x < _x_size; x++) {
00341     write_uchar_IMG(_file, (unsigned char)(255*PPM_GETR(row_data[x])/_maxval));
00342     write_uchar_IMG(_file, (unsigned char)(255*PPM_GETG(row_data[x])/_maxval));
00343     write_uchar_IMG(_file, (unsigned char)(255*PPM_GETB(row_data[x])/_maxval));
00344   }
00345 
00346   return true;
00347 }
00348 
00349 
00350 
00351 ////////////////////////////////////////////////////////////////////
00352 //     Function: PNMFileTypeIMG::register_with_read_factory
00353 //       Access: Public, Static
00354 //  Description: Registers the current object as something that can be
00355 //               read from a Bam file.
00356 ////////////////////////////////////////////////////////////////////
00357 void PNMFileTypeIMG::
00358 register_with_read_factory() {
00359   BamReader::get_factory()->
00360     register_factory(get_class_type(), make_PNMFileTypeIMG);
00361 }
00362 
00363 ////////////////////////////////////////////////////////////////////
00364 //     Function: PNMFileTypeIMG::make_PNMFileTypeIMG
00365 //       Access: Protected, Static
00366 //  Description: This method is called by the BamReader when an object
00367 //               of this type is encountered in a Bam file; it should
00368 //               allocate and return a new object with all the data
00369 //               read.
00370 //
00371 //               In the case of the PNMFileType objects, since these
00372 //               objects are all shared, we just pull the object from
00373 //               the registry.
00374 ////////////////////////////////////////////////////////////////////
00375 TypedWritable *PNMFileTypeIMG::
00376 make_PNMFileTypeIMG(const FactoryParams &params) {
00377   return PNMFileTypeRegistry::get_global_ptr()->get_type_by_handle(get_class_type());
00378 }
00379 
00380 #endif  // HAVE_IMG
 All Classes Functions Variables Enumerations