Panda3D
|
00001 // Filename: pnmImageHeader.cxx 00002 // Created by: drose (14Jun00) 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 "pnmImageHeader.h" 00016 #include "pnmFileTypeRegistry.h" 00017 #include "pnmFileType.h" 00018 #include "pnmReader.h" 00019 #include "pnmWriter.h" 00020 #include "config_pnmimage.h" 00021 #include "virtualFileSystem.h" 00022 #include "zStream.h" 00023 00024 //////////////////////////////////////////////////////////////////// 00025 // Function: PNMImageHeader::read_header 00026 // Access: Published 00027 // Description: Opens up the image file and tries to read its header 00028 // information to determine its size, number of 00029 // channels, etc. If successful, updates the header 00030 // information and returns true; otherwise, returns 00031 // false. 00032 //////////////////////////////////////////////////////////////////// 00033 bool PNMImageHeader:: 00034 read_header(const Filename &filename, PNMFileType *type, 00035 bool report_unknown_type) { 00036 PNMReader *reader = make_reader(filename, type, report_unknown_type); 00037 if (reader != (PNMReader *)NULL) { 00038 (*this) = (*reader); 00039 delete reader; 00040 return true; 00041 } 00042 00043 return false; 00044 } 00045 00046 //////////////////////////////////////////////////////////////////// 00047 // Function: PNMImageHeader::read_header 00048 // Access: Published 00049 // Description: Reads the image header information only from the 00050 // indicated stream. 00051 // 00052 // The filename is advisory only, and may be used 00053 // to suggest a type if it has a known extension. 00054 // 00055 // If type is non-NULL, it is a suggestion for the type 00056 // of file it is (and a non-NULL type will override any 00057 // magic number test or filename extension lookup). 00058 // 00059 // Returns true if successful, false on error. 00060 //////////////////////////////////////////////////////////////////// 00061 bool PNMImageHeader:: 00062 read_header(istream &data, const string &filename, PNMFileType *type, 00063 bool report_unknown_type) { 00064 PNMReader *reader = PNMImageHeader::make_reader 00065 (&data, false, filename, string(), type, report_unknown_type); 00066 if (reader != (PNMReader *)NULL) { 00067 (*this) = (*reader); 00068 delete reader; 00069 return true; 00070 } 00071 00072 return false; 00073 } 00074 00075 //////////////////////////////////////////////////////////////////// 00076 // Function: PNMImageHeader::make_reader 00077 // Access: Published 00078 // Description: Returns a newly-allocated PNMReader of the suitable 00079 // type for reading from the indicated image filename, 00080 // or NULL if the filename cannot be read for some 00081 // reason. The filename "-" always stands for standard 00082 // input. If type is specified, it is a suggestion for 00083 // the file type to use. 00084 // 00085 // The PNMReader should be deleted when it is no longer 00086 // needed. 00087 //////////////////////////////////////////////////////////////////// 00088 PNMReader *PNMImageHeader:: 00089 make_reader(const Filename &filename, PNMFileType *type, 00090 bool report_unknown_type) const { 00091 if (pnmimage_cat.is_debug()) { 00092 pnmimage_cat.debug() 00093 << "Reading image from " << filename << "\n"; 00094 } 00095 bool owns_file = false; 00096 istream *file = (istream *)NULL; 00097 00098 if (filename == "-") { 00099 owns_file = false; 00100 file = &cin; 00101 00102 if (pnmimage_cat.is_debug()) { 00103 pnmimage_cat.debug() 00104 << "(reading standard input)\n"; 00105 } 00106 } else { 00107 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); 00108 owns_file = true; 00109 file = vfs->open_read_file(filename, true); 00110 } 00111 00112 if (file == (istream *)NULL) { 00113 if (pnmimage_cat.is_debug()) { 00114 pnmimage_cat.debug() 00115 << "Unable to open file.\n"; 00116 } 00117 return NULL; 00118 } 00119 00120 return make_reader(file, owns_file, filename, string(), type, 00121 report_unknown_type); 00122 } 00123 00124 00125 //////////////////////////////////////////////////////////////////// 00126 // Function: PNMImageHeader::make_reader 00127 // Access: Published 00128 // Description: Returns a newly-allocated PNMReader of the suitable 00129 // type for reading from the already-opened image file, 00130 // or NULL if the file cannot be read for some reason. 00131 // 00132 // owns_file should be set true if the PNMReader is to 00133 // be considered the owner of the stream pointer (in 00134 // which case the stream will be deleted on completion, 00135 // whether successful or not), or false if it should not 00136 // delete it. 00137 // 00138 // The filename parameter is optional here, since the 00139 // file has already been opened; it is only used to 00140 // examine the extension and attempt to guess the file 00141 // type. 00142 // 00143 // If magic_number is nonempty, it is assumed to 00144 // represent the first few bytes that have already been 00145 // read from the file. Some file types may have 00146 // difficulty if this is more than two bytes. 00147 // 00148 // If type is non-NULL, it is a suggestion for the file 00149 // type to use. 00150 // 00151 // The PNMReader should be deleted when it is no longer 00152 // needed. 00153 //////////////////////////////////////////////////////////////////// 00154 PNMReader *PNMImageHeader:: 00155 make_reader(istream *file, bool owns_file, const Filename &filename, 00156 string magic_number, PNMFileType *type, 00157 bool report_unknown_type) const { 00158 if (type == (PNMFileType *)NULL) { 00159 if (!read_magic_number(file, magic_number, 2)) { 00160 // No magic number. No image. 00161 if (pnmimage_cat.is_debug()) { 00162 pnmimage_cat.debug() 00163 << "Image file appears to be empty.\n"; 00164 } 00165 if (owns_file) { 00166 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); 00167 00168 // We're assuming here that the file was opened via VFS. That 00169 // may not necessarily be the case, but we don't make that 00170 // distinction. However, at the moment at least, that 00171 // distinction doesn't matter, since vfs->close_read_file() 00172 // just deletes the file pointer anyway. 00173 vfs->close_read_file(file); 00174 } 00175 return NULL; 00176 } 00177 00178 type = PNMFileTypeRegistry::get_global_ptr()-> 00179 get_type_from_magic_number(magic_number); 00180 00181 if (pnmimage_cat.is_debug()) { 00182 if (type != (PNMFileType *)NULL) { 00183 pnmimage_cat.debug() 00184 << "By magic number, image file appears to be type " 00185 << type->get_name() << ".\n"; 00186 } else { 00187 pnmimage_cat.debug() 00188 << "Unable to determine image file type from magic number.\n"; 00189 } 00190 } 00191 } 00192 00193 if (type == (PNMFileType *)NULL && !filename.empty()) { 00194 // We still don't know the type; attempt to guess it from the 00195 // filename extension. 00196 type = PNMFileTypeRegistry::get_global_ptr()->get_type_from_extension(filename); 00197 00198 if (pnmimage_cat.is_debug()) { 00199 if (type != (PNMFileType *)NULL) { 00200 pnmimage_cat.debug() 00201 << "From its extension, image file is probably type " 00202 << type->get_name() << ".\n"; 00203 } else { 00204 pnmimage_cat.debug() 00205 << "Unable to guess image file type from its extension.\n"; 00206 } 00207 } 00208 } 00209 00210 if (type == (PNMFileType *)NULL) { 00211 // No? How about the default type associated with this image header. 00212 type = _type; 00213 00214 if (pnmimage_cat.is_debug() && type != (PNMFileType *)NULL) { 00215 pnmimage_cat.debug() 00216 << "Assuming image file type is " << type->get_name() << ".\n"; 00217 } 00218 } 00219 00220 if (type == (PNMFileType *)NULL) { 00221 // We can't figure out what type the file is; give up. 00222 if (report_unknown_type && pnmimage_cat.is_error()) { 00223 pnmimage_cat.error() 00224 << "Cannot determine type of image file " << filename << ".\n" 00225 << "Currently supported image types:\n"; 00226 PNMFileTypeRegistry::get_global_ptr()-> 00227 write(pnmimage_cat.error(false), 2); 00228 } 00229 if (owns_file) { 00230 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); 00231 00232 // We're assuming here that the file was opened via VFS. That 00233 // may not necessarily be the case, but we don't make that 00234 // distinction. However, at the moment at least, that 00235 // distinction doesn't matter, since vfs->close_read_file() 00236 // just deletes the file pointer anyway. 00237 vfs->close_read_file(file); 00238 } 00239 return NULL; 00240 } 00241 00242 PNMReader *reader = type->make_reader(file, owns_file, magic_number); 00243 if (reader == NULL && owns_file) { 00244 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); 00245 vfs->close_read_file(file); 00246 } 00247 00248 if (!reader->is_valid()) { 00249 delete reader; 00250 reader = NULL; 00251 } 00252 00253 return reader; 00254 } 00255 00256 //////////////////////////////////////////////////////////////////// 00257 // Function: PNMImageHeader::make_writer 00258 // Access: Published 00259 // Description: Returns a newly-allocated PNMWriter of the suitable 00260 // type for writing an image to the indicated filename, 00261 // or NULL if the filename cannot be written for some 00262 // reason. The filename "-" always stands for standard 00263 // output. If type is specified, it is a suggestion for 00264 // the file type to use. 00265 // 00266 // The PNMWriter should be deleted when it is no longer 00267 // needed. 00268 //////////////////////////////////////////////////////////////////// 00269 PNMWriter *PNMImageHeader:: 00270 make_writer(const Filename &filename, PNMFileType *type) const { 00271 if (pnmimage_cat.is_debug()) { 00272 pnmimage_cat.debug() 00273 << "Writing image to " << filename << "\n"; 00274 } 00275 bool owns_file = false; 00276 ostream *file = (ostream *)NULL; 00277 00278 if (filename == "-") { 00279 owns_file = false; 00280 file = &cout; 00281 00282 if (pnmimage_cat.is_debug()) { 00283 pnmimage_cat.debug() 00284 << "(writing to standard output)\n"; 00285 } 00286 00287 } else { 00288 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); 00289 Filename actual_name = Filename::binary_filename(filename); 00290 file = vfs->open_write_file(actual_name, true, true); 00291 if (file != NULL) { 00292 owns_file = true; 00293 } 00294 } 00295 00296 if (file == (ostream *)NULL) { 00297 if (pnmimage_cat.is_debug()) { 00298 pnmimage_cat.debug() 00299 << "Unable to write to file.\n"; 00300 } 00301 return NULL; 00302 } 00303 00304 return make_writer(file, owns_file, filename, type); 00305 } 00306 00307 //////////////////////////////////////////////////////////////////// 00308 // Function: PNMImageHeader::make_writer 00309 // Access: Published 00310 // Description: Returns a newly-allocated PNMWriter of the suitable 00311 // type for writing to the already-opened image file, or 00312 // NULL if the file cannot be written for some reason. 00313 // 00314 // owns_file should be set true if the PNMWriter is to 00315 // be considered the owner of the stream pointer (in 00316 // which case the stream will be deleted on completion, 00317 // whether successful or not), or false if it should not 00318 // delete it. 00319 // 00320 // The filename parameter is optional here, since the 00321 // file has already been opened; it is only used to 00322 // examine the extension and attempt to guess the 00323 // intended file type. 00324 // 00325 // If type is non-NULL, it is a suggestion for the file 00326 // type to use. 00327 // 00328 // The PNMWriter should be deleted when it is no longer 00329 // needed. 00330 //////////////////////////////////////////////////////////////////// 00331 PNMWriter *PNMImageHeader:: 00332 make_writer(ostream *file, bool owns_file, const Filename &filename, 00333 PNMFileType *type) const { 00334 if (type == (PNMFileType *)NULL && !filename.empty()) { 00335 // We don't know the type; attempt to guess it from the filename 00336 // extension. 00337 type = PNMFileTypeRegistry::get_global_ptr()->get_type_from_extension(filename); 00338 00339 if (pnmimage_cat.is_debug()) { 00340 if (type != (PNMFileType *)NULL) { 00341 pnmimage_cat.debug() 00342 << "From its extension, image file is intended to be type " 00343 << type->get_name() << ".\n"; 00344 } else { 00345 pnmimage_cat.debug() 00346 << "Unable to guess image file type from its extension.\n"; 00347 } 00348 } 00349 } 00350 00351 if (type == (PNMFileType *)NULL) { 00352 // No? How about the default type associated with this image header. 00353 type = _type; 00354 00355 if (pnmimage_cat.is_debug() && type != (PNMFileType *)NULL) { 00356 pnmimage_cat.debug() 00357 << "Assuming image file type is " << type->get_name() << ".\n"; 00358 } 00359 } 00360 00361 if (type == (PNMFileType *)NULL) { 00362 // We can't figure out what type the file is; give up. 00363 if (pnmimage_cat.is_debug()) { 00364 pnmimage_cat.debug() 00365 << "Cannot determine type of image file " << filename << ".\n"; 00366 } 00367 if (owns_file) { 00368 delete file; 00369 } 00370 return NULL; 00371 } 00372 00373 PNMWriter *writer = type->make_writer(file, owns_file); 00374 if (writer == NULL && owns_file) { 00375 delete file; 00376 } 00377 00378 if (!writer->is_valid()) { 00379 delete writer; 00380 writer = NULL; 00381 } 00382 00383 return writer; 00384 } 00385 00386 //////////////////////////////////////////////////////////////////// 00387 // Function: PNMImageHeader::read_magic_number 00388 // Access: Published, Static 00389 // Description: Ensures that the first n bytes of the file are read 00390 // into magic_number. If magic_number is initially 00391 // nonempty, assumes these represent the first few bytes 00392 // already extracted. Returns true if successful, false 00393 // if an end of file or error occurred before num_bytes 00394 // could be read. 00395 //////////////////////////////////////////////////////////////////// 00396 bool PNMImageHeader:: 00397 read_magic_number(istream *file, string &magic_number, int num_bytes) { 00398 while ((int)magic_number.size() < num_bytes) { 00399 int ch = file->get(); 00400 if (file->eof() || file->fail()) { 00401 return false; 00402 } 00403 magic_number += (char)ch; 00404 } 00405 00406 return true; 00407 } 00408 00409 //////////////////////////////////////////////////////////////////// 00410 // Function: PNMImageHeader::output 00411 // Access: Published 00412 // Description: 00413 //////////////////////////////////////////////////////////////////// 00414 void PNMImageHeader:: 00415 output(ostream &out) const { 00416 out << "image: " << _x_size << " by " << _y_size << " pixels, " 00417 << _num_channels << " channels, " << _maxval << " maxval."; 00418 } 00419 00420 //////////////////////////////////////////////////////////////////// 00421 // Function: PNMImageHeader::compute_histogram 00422 // Access: Protected 00423 // Description: Computes a histogram of the colors used in the 00424 // indicated rgb/grayscale array and/or alpha array. 00425 // This is most likely to be useful in a PNMWriter 00426 // class, but it is defined at this level in case it has 00427 // general utilty for PNMImages. 00428 // 00429 // Also see PNMImage::make_histogram(), which is a 00430 // higher-level function. 00431 // 00432 // The max_colors parameter, if greater than zero, 00433 // limits the maximum number of colors we are interested 00434 // in. If we encounter more than this number of colors, 00435 // the function aborts before completion and returns 00436 // false; otherwise, it returns true. 00437 //////////////////////////////////////////////////////////////////// 00438 bool PNMImageHeader:: 00439 compute_histogram(PNMImageHeader::HistMap &hist, 00440 xel *array, xelval *alpha, int max_colors) { 00441 int num_pixels = _x_size * _y_size; 00442 int pi; 00443 00444 switch (get_color_type()) { 00445 case CT_invalid: 00446 return false; 00447 00448 case CT_grayscale: 00449 for (pi = 0; pi < num_pixels; pi++) { 00450 record_color(hist, PixelSpec(PPM_GETB(array[pi]))); 00451 if (max_colors > 0 && (int)hist.size() > max_colors) { 00452 return false; 00453 } 00454 } 00455 return true; 00456 00457 case CT_two_channel: 00458 for (pi = 0; pi < num_pixels; pi++) { 00459 record_color(hist, PixelSpec(PPM_GETB(array[pi]), alpha[pi])); 00460 if (max_colors > 0 && (int)hist.size() > max_colors) { 00461 return false; 00462 } 00463 } 00464 return true; 00465 00466 case CT_color: 00467 for (pi = 0; pi < num_pixels; pi++) { 00468 record_color(hist, PixelSpec(PPM_GETR(array[pi]), PPM_GETG(array[pi]), PPM_GETB(array[pi]))); 00469 if (max_colors > 0 && (int)hist.size() > max_colors) { 00470 return false; 00471 } 00472 } 00473 return true; 00474 00475 case CT_four_channel: 00476 for (pi = 0; pi < num_pixels; pi++) { 00477 record_color(hist, PixelSpec(PPM_GETR(array[pi]), PPM_GETG(array[pi]), PPM_GETB(array[pi]), alpha[pi])); 00478 if (max_colors > 0 && (int)hist.size() > max_colors) { 00479 return false; 00480 } 00481 } 00482 return true; 00483 } 00484 00485 return false; 00486 } 00487 00488 //////////////////////////////////////////////////////////////////// 00489 // Function: PNMImageHeader::compute_palette 00490 // Access: Protected 00491 // Description: Returns a linear list of all of the colors in the 00492 // image, similar to compute_histogram(). 00493 //////////////////////////////////////////////////////////////////// 00494 bool PNMImageHeader:: 00495 compute_palette(PNMImageHeader::Palette &palette, 00496 xel *array, xelval *alpha, int max_colors) { 00497 HistMap hist; 00498 00499 int num_pixels = _x_size * _y_size; 00500 00501 // In case there are already entries in the palette, preserve them. 00502 Palette::const_iterator pi; 00503 for (pi = palette.begin(); pi != palette.end(); ++pi) { 00504 hist.insert(HistMap::value_type(*pi, num_pixels + 1)); 00505 } 00506 00507 if (!compute_histogram(hist, array, alpha, max_colors)) { 00508 return false; 00509 } 00510 00511 // Now append the new entries discovered in the histogram onto the 00512 // end of the palette. 00513 palette.reserve(hist.size()); 00514 HistMap::const_iterator hi; 00515 for (hi = hist.begin(); hi != hist.end(); ++hi) { 00516 if ((*hi).second <= num_pixels) { 00517 palette.push_back((*hi).first); 00518 } 00519 } 00520 00521 return true; 00522 } 00523 00524 //////////////////////////////////////////////////////////////////// 00525 // Function: PNMImageHeader::PixelSpec::output 00526 // Access: Public 00527 // Description: 00528 //////////////////////////////////////////////////////////////////// 00529 void PNMImageHeader::PixelSpec:: 00530 output(ostream &out) const { 00531 out << "(" << _red << ", " << _green << ", " << _blue << ", " << _alpha << ")"; 00532 } 00533 00534 //////////////////////////////////////////////////////////////////// 00535 // Function: PNMImageHeader::Histogram::write 00536 // Access: Public 00537 // Description: 00538 //////////////////////////////////////////////////////////////////// 00539 void PNMImageHeader::Histogram:: 00540 write(ostream &out) const { 00541 out << "Histogram: {\n"; 00542 PixelCount::const_iterator pi; 00543 for (pi = _pixels.begin(); pi != _pixels.end(); ++pi) { 00544 out << " " << (*pi)._pixel << ": " << (*pi)._count << ",\n"; 00545 } 00546 out << "}\n"; 00547 } 00548