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