00001 // Filename: pnmFileTypeAlias.cxx 00002 // Created by: drose (17Jun00) 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 "pnmFileTypeAlias.h" 00020 #include "config_pnmimagetypes.h" 00021 00022 #include <pnmFileTypeRegistry.h> 00023 #include <bamReader.h> 00024 00025 // Since Alias image files don't have a magic number, we'll make a 00026 // little sanity check on the size of the image. If either the width 00027 // or height is larger than this, it must be bogus. 00028 #define INSANE_SIZE 20000 00029 00030 static const char * const extensions_alias[] = { 00031 "pix", "als" 00032 }; 00033 static const int num_extensions_alias = sizeof(extensions_alias) / sizeof(const char *); 00034 00035 TypeHandle PNMFileTypeAlias::_type_handle; 00036 00037 //////////////////////////////////////////////////////////////////// 00038 // Function: PNMFileTypeAlias::Constructor 00039 // Access: Public 00040 // Description: 00041 //////////////////////////////////////////////////////////////////// 00042 PNMFileTypeAlias:: 00043 PNMFileTypeAlias() { 00044 } 00045 00046 //////////////////////////////////////////////////////////////////// 00047 // Function: PNMFileTypeAlias::get_name 00048 // Access: Public, Virtual 00049 // Description: Returns a few words describing the file type. 00050 //////////////////////////////////////////////////////////////////// 00051 string PNMFileTypeAlias:: 00052 get_name() const { 00053 return "Alias"; 00054 } 00055 00056 //////////////////////////////////////////////////////////////////// 00057 // Function: PNMFileTypeAlias::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 PNMFileTypeAlias:: 00063 get_num_extensions() const { 00064 return num_extensions_alias; 00065 } 00066 00067 //////////////////////////////////////////////////////////////////// 00068 // Function: PNMFileTypeAlias::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 PNMFileTypeAlias:: 00075 get_extension(int n) const { 00076 nassertr(n >= 0 && n < num_extensions_alias, string()); 00077 return extensions_alias[n]; 00078 } 00079 00080 //////////////////////////////////////////////////////////////////// 00081 // Function: PNMFileTypeAlias::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 PNMFileTypeAlias:: 00088 get_suggested_extension() const { 00089 return "pix"; 00090 } 00091 00092 //////////////////////////////////////////////////////////////////// 00093 // Function: PNMFileTypeAlias::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 *PNMFileTypeAlias:: 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: PNMFileTypeAlias::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 *PNMFileTypeAlias:: 00113 make_writer(ostream *file, bool owns_file) { 00114 init_pnm(); 00115 return new Writer(this, file, owns_file); 00116 } 00117 00118 00119 00120 inline unsigned short 00121 read_ushort(istream *file) { 00122 unsigned short x; 00123 return pm_readbigshort(file, (short *)&x)==0 ? x : 0; 00124 } 00125 00126 inline unsigned char 00127 read_uchar_ALIAS(istream *file) { 00128 int x; 00129 x = file->get(); 00130 return (x!=EOF) ? (unsigned char)x : 0; 00131 } 00132 00133 inline void 00134 write_ushort(ostream *file, unsigned short x) { 00135 pm_writebigshort(file, (short)x); 00136 } 00137 00138 inline void 00139 write_uchar_ALIAS(ostream *file, unsigned char x) { 00140 file->put(x); 00141 } 00142 00143 //////////////////////////////////////////////////////////////////// 00144 // Function: PNMFileTypeAlias::Reader::Constructor 00145 // Access: Public 00146 // Description: 00147 //////////////////////////////////////////////////////////////////// 00148 PNMFileTypeAlias::Reader:: 00149 Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) : 00150 PNMReader(type, file, owns_file) 00151 { 00152 if (!read_magic_number(_file, magic_number, 4)) { 00153 // Although Alias files have no magic number, they do have a 00154 // number of ushorts at the beginning. If these aren't present, 00155 // we have a problem. 00156 if (pnmimage_alias_cat.is_debug()) { 00157 pnmimage_alias_cat.debug() 00158 << "Alias image file appears to be empty.\n"; 00159 } 00160 _is_valid = false; 00161 return; 00162 } 00163 00164 _x_size = 00165 ((unsigned char)magic_number[0] << 8) | 00166 ((unsigned char)magic_number[1]); 00167 _y_size = 00168 ((unsigned char)magic_number[2] << 8) | 00169 ((unsigned char)magic_number[3]); 00170 00171 if (_x_size == 0 || _y_size == 0 || 00172 _x_size > INSANE_SIZE || _y_size > INSANE_SIZE) { 00173 _is_valid = false; 00174 pnmimage_alias_cat.debug() 00175 << "File is not a valid Alias image.\n"; 00176 return; 00177 } 00178 00179 read_ushort(_file); 00180 read_ushort(_file); 00181 00182 int bpp = read_ushort(_file); 00183 00184 switch (bpp) { 00185 case 8: 00186 _num_channels = 1; 00187 break; 00188 00189 case 24: 00190 _num_channels = 3; 00191 break; 00192 00193 default: 00194 _is_valid = false; 00195 return; 00196 } 00197 00198 _maxval = 255; 00199 00200 if (pnmimage_alias_cat.is_debug()) { 00201 pnmimage_alias_cat.debug() 00202 << "Reading Alias " << *this << "\n"; 00203 } 00204 } 00205 00206 00207 //////////////////////////////////////////////////////////////////// 00208 // Function: PNMFileTypeAlias::Reader::supports_read_row 00209 // Access: Public, Virtual 00210 // Description: Returns true if this particular PNMReader supports a 00211 // streaming interface to reading the data: that is, it 00212 // is capable of returning the data one row at a time, 00213 // via repeated calls to read_row(). Returns false if 00214 // the only way to read from this file is all at once, 00215 // via read_data(). 00216 //////////////////////////////////////////////////////////////////// 00217 bool PNMFileTypeAlias::Reader:: 00218 supports_read_row() const { 00219 return true; 00220 } 00221 00222 //////////////////////////////////////////////////////////////////// 00223 // Function: PNMFileTypeAlias::Reader::read_row 00224 // Access: Public, Virtual 00225 // Description: If supports_read_row(), above, returns true, this 00226 // function may be called repeatedly to read the image, 00227 // one horizontal row at a time, beginning from the top. 00228 // Returns true if the row is successfully read, false 00229 // if there is an error or end of file. 00230 //////////////////////////////////////////////////////////////////// 00231 bool PNMFileTypeAlias::Reader:: 00232 read_row(xel *row_data, xelval *) { 00233 if (!is_valid()) { 00234 return false; 00235 } 00236 00237 int x; 00238 int num; 00239 unsigned char red, grn, blu; 00240 00241 x = 0; 00242 while (x < _x_size) { 00243 num = read_uchar_ALIAS(_file); 00244 if (num==0 || x+num > _x_size) { 00245 return false; 00246 } 00247 blu = read_uchar_ALIAS(_file); 00248 00249 if (get_color_type() == PNMImageHeader::CT_color) { 00250 grn = read_uchar_ALIAS(_file); 00251 red = read_uchar_ALIAS(_file); 00252 while (num>0) { 00253 PPM_ASSIGN(row_data[x], red, grn, blu); 00254 x++; 00255 num--; 00256 } 00257 } else { 00258 while (num>0) { 00259 PPM_PUTB(row_data[x], blu); 00260 x++; 00261 num--; 00262 } 00263 } 00264 } 00265 00266 return true; 00267 } 00268 00269 static unsigned char last_red = 0, last_blu = 0, last_grn = 0; 00270 static int num_count = 0; 00271 00272 static void 00273 flush_color(ostream *file) { 00274 if (num_count>0) { 00275 write_uchar_ALIAS(file, num_count); 00276 write_uchar_ALIAS(file, last_blu); 00277 write_uchar_ALIAS(file, last_grn); 00278 write_uchar_ALIAS(file, last_red); 00279 num_count = 0; 00280 } 00281 } 00282 00283 static void 00284 write_color(ostream *file, 00285 unsigned char red, unsigned char blu, unsigned char grn) { 00286 if (red==last_red && blu==last_blu && grn==last_grn && num_count<0377) { 00287 num_count++; 00288 } else { 00289 flush_color(file); 00290 last_red = red; 00291 last_grn = grn; 00292 last_blu = blu; 00293 num_count = 1; 00294 } 00295 } 00296 00297 00298 //////////////////////////////////////////////////////////////////// 00299 // Function: PNMFileTypeAlias::Writer::Constructor 00300 // Access: Public 00301 // Description: 00302 //////////////////////////////////////////////////////////////////// 00303 PNMFileTypeAlias::Writer:: 00304 Writer(PNMFileType *type, ostream *file, bool owns_file) : 00305 PNMWriter(type, file, owns_file) 00306 { 00307 } 00308 00309 //////////////////////////////////////////////////////////////////// 00310 // Function: PNMFileTypeAlias::Writer::supports_write_row 00311 // Access: Public, Virtual 00312 // Description: Returns true if this particular PNMWriter supports a 00313 // streaming interface to writing the data: that is, it 00314 // is capable of writing the image one row at a time, 00315 // via repeated calls to write_row(). Returns false if 00316 // the only way to write from this file is all at once, 00317 // via write_data(). 00318 //////////////////////////////////////////////////////////////////// 00319 bool PNMFileTypeAlias::Writer:: 00320 supports_write_row() const { 00321 return true; 00322 } 00323 00324 //////////////////////////////////////////////////////////////////// 00325 // Function: PNMFileTypeAlias::Writer::write_header 00326 // Access: Public, Virtual 00327 // Description: If supports_write_row(), above, returns true, this 00328 // function may be called to write out the image header 00329 // in preparation to writing out the image data one row 00330 // at a time. Returns true if the header is 00331 // successfully written, false if there is an error. 00332 // 00333 // It is the user's responsibility to fill in the header 00334 // data via calls to set_x_size(), set_num_channels(), 00335 // etc., or copy_header_from(), before calling 00336 // write_header(). 00337 //////////////////////////////////////////////////////////////////// 00338 bool PNMFileTypeAlias::Writer:: 00339 write_header() { 00340 write_ushort(_file, _x_size); 00341 write_ushort(_file, _y_size); 00342 00343 write_ushort(_file, 0); 00344 write_ushort(_file, 0); 00345 00346 // We'll always write full-color Alias images, even if the source 00347 // was grayscale. Many programs don't seem to understand grayscale 00348 // Alias images. 00349 write_ushort(_file, 24); 00350 return true; 00351 } 00352 00353 //////////////////////////////////////////////////////////////////// 00354 // Function: PNMFileTypeAlias::Writer::write_row 00355 // Access: Public, Virtual 00356 // Description: If supports_write_row(), above, returns true, this 00357 // function may be called repeatedly to write the image, 00358 // one horizontal row at a time, beginning from the top. 00359 // Returns true if the row is successfully written, 00360 // false if there is an error. 00361 // 00362 // You must first call write_header() before writing the 00363 // individual rows. It is also important to delete the 00364 // PNMWriter class after successfully writing the last 00365 // row. Failing to do this may result in some data not 00366 // getting flushed! 00367 //////////////////////////////////////////////////////////////////// 00368 bool PNMFileTypeAlias::Writer:: 00369 write_row(xel *row_data, xelval *) { 00370 int x; 00371 unsigned char red, grn, blu; 00372 00373 bool grayscale = is_grayscale(); 00374 00375 for (x = 0; x < _x_size; x++) { 00376 if (grayscale) { 00377 red = grn = blu = (unsigned char)(255*PPM_GETB(row_data[x]) / _maxval); 00378 } else { 00379 red = (unsigned char)(255*PPM_GETR(row_data[x]) / _maxval); 00380 grn = (unsigned char)(255*PPM_GETG(row_data[x]) / _maxval); 00381 blu = (unsigned char)(255*PPM_GETB(row_data[x]) / _maxval); 00382 } 00383 00384 write_color(_file, red, blu, grn); 00385 } 00386 flush_color(_file); 00387 00388 return true; 00389 } 00390 00391 00392 00393 //////////////////////////////////////////////////////////////////// 00394 // Function: PNMFileTypeAlias::register_with_read_factory 00395 // Access: Public, Static 00396 // Description: Registers the current object as something that can be 00397 // read from a Bam file. 00398 //////////////////////////////////////////////////////////////////// 00399 void PNMFileTypeAlias:: 00400 register_with_read_factory() { 00401 BamReader::get_factory()-> 00402 register_factory(get_class_type(), make_PNMFileTypeAlias); 00403 } 00404 00405 //////////////////////////////////////////////////////////////////// 00406 // Function: PNMFileTypeAlias::make_PNMFileTypeAlias 00407 // Access: Protected, Static 00408 // Description: This method is called by the BamReader when an object 00409 // of this type is encountered in a Bam file; it should 00410 // allocate and return a new object with all the data 00411 // read. 00412 // 00413 // In the case of the PNMFileType objects, since these 00414 // objects are all shared, we just pull the object from 00415 // the registry. 00416 //////////////////////////////////////////////////////////////////// 00417 TypedWritable *PNMFileTypeAlias:: 00418 make_PNMFileTypeAlias(const FactoryParams ¶ms) { 00419 return PNMFileTypeRegistry::get_ptr()->get_type_by_handle(get_class_type()); 00420 }