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 ¶ms) { 00377 return PNMFileTypeRegistry::get_global_ptr()->get_type_by_handle(get_class_type()); 00378 } 00379 00380 #endif // HAVE_IMG