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 pofstream *new_ostream = new pofstream; 00289 Filename actual_name = Filename::binary_filename(filename); 00290 if (!actual_name.open_write(*new_ostream)) { 00291 delete new_ostream; 00292 00293 } else { 00294 owns_file = true; 00295 file = new_ostream; 00296 00297 #ifdef HAVE_ZLIB 00298 if (filename.get_extension() == "pz") { 00299 // The filename ends in .pz, which means to automatically 00300 // compress the image file that we write. 00301 file = new OCompressStream(file, true); 00302 } 00303 #endif // HAVE_ZLIB 00304 } 00305 } 00306 00307 if (file == (ostream *)NULL) { 00308 if (pnmimage_cat.is_debug()) { 00309 pnmimage_cat.debug() 00310 << "Unable to write to file.\n"; 00311 } 00312 return NULL; 00313 } 00314 00315 return make_writer(file, owns_file, filename, type); 00316 } 00317 00318 //////////////////////////////////////////////////////////////////// 00319 // Function: PNMImageHeader::make_writer 00320 // Access: Published 00321 // Description: Returns a newly-allocated PNMWriter of the suitable 00322 // type for writing to the already-opened image file, or 00323 // NULL if the file cannot be written for some reason. 00324 // 00325 // owns_file should be set true if the PNMWriter is to 00326 // be considered the owner of the stream pointer (in 00327 // which case the stream will be deleted on completion, 00328 // whether successful or not), or false if it should not 00329 // delete it. 00330 // 00331 // The filename parameter is optional here, since the 00332 // file has already been opened; it is only used to 00333 // examine the extension and attempt to guess the 00334 // intended file type. 00335 // 00336 // If type is non-NULL, it is a suggestion for the file 00337 // type to use. 00338 // 00339 // The PNMWriter should be deleted when it is no longer 00340 // needed. 00341 //////////////////////////////////////////////////////////////////// 00342 PNMWriter *PNMImageHeader:: 00343 make_writer(ostream *file, bool owns_file, const Filename &filename, 00344 PNMFileType *type) const { 00345 if (type == (PNMFileType *)NULL && !filename.empty()) { 00346 // We don't know the type; attempt to guess it from the filename 00347 // extension. 00348 type = PNMFileTypeRegistry::get_global_ptr()->get_type_from_extension(filename); 00349 00350 if (pnmimage_cat.is_debug()) { 00351 if (type != (PNMFileType *)NULL) { 00352 pnmimage_cat.debug() 00353 << "From its extension, image file is intended to be type " 00354 << type->get_name() << ".\n"; 00355 } else { 00356 pnmimage_cat.debug() 00357 << "Unable to guess image file type from its extension.\n"; 00358 } 00359 } 00360 } 00361 00362 if (type == (PNMFileType *)NULL) { 00363 // No? How about the default type associated with this image header. 00364 type = _type; 00365 00366 if (pnmimage_cat.is_debug() && type != (PNMFileType *)NULL) { 00367 pnmimage_cat.debug() 00368 << "Assuming image file type is " << type->get_name() << ".\n"; 00369 } 00370 } 00371 00372 if (type == (PNMFileType *)NULL) { 00373 // We can't figure out what type the file is; give up. 00374 if (pnmimage_cat.is_debug()) { 00375 pnmimage_cat.debug() 00376 << "Cannot determine type of image file " << filename << ".\n"; 00377 } 00378 if (owns_file) { 00379 delete file; 00380 } 00381 return NULL; 00382 } 00383 00384 PNMWriter *writer = type->make_writer(file, owns_file); 00385 if (writer == NULL && owns_file) { 00386 delete file; 00387 } 00388 00389 if (!writer->is_valid()) { 00390 delete writer; 00391 writer = NULL; 00392 } 00393 00394 return writer; 00395 } 00396 00397 //////////////////////////////////////////////////////////////////// 00398 // Function: PNMImageHeader::read_magic_number 00399 // Access: Published, Static 00400 // Description: Ensures that the first n bytes of the file are read 00401 // into magic_number. If magic_number is initially 00402 // nonempty, assumes these represent the first few bytes 00403 // already extracted. Returns true if successful, false 00404 // if an end of file or error occurred before num_bytes 00405 // could be read. 00406 //////////////////////////////////////////////////////////////////// 00407 bool PNMImageHeader:: 00408 read_magic_number(istream *file, string &magic_number, int num_bytes) { 00409 while ((int)magic_number.size() < num_bytes) { 00410 int ch = file->get(); 00411 if (file->eof() || file->fail()) { 00412 return false; 00413 } 00414 magic_number += (char)ch; 00415 } 00416 00417 return true; 00418 } 00419 00420 //////////////////////////////////////////////////////////////////// 00421 // Function: PNMImageHeader::output 00422 // Access: Published 00423 // Description: 00424 //////////////////////////////////////////////////////////////////// 00425 void PNMImageHeader:: 00426 output(ostream &out) const { 00427 out << "image: " << _x_size << " by " << _y_size << " pixels, " 00428 << _num_channels << " channels, " << _maxval << " maxval."; 00429 } 00430 00431 //////////////////////////////////////////////////////////////////// 00432 // Function: PNMImageHeader::compute_histogram 00433 // Access: Protected 00434 // Description: Computes a histogram of the colors used in the 00435 // indicated rgb/grayscale array and/or alpha array. 00436 // This is most likely to be useful in a PNMWriter 00437 // class, but it is defined at this level in case it has 00438 // general utilty for PNMImages. 00439 // 00440 // Also see PNMImage::make_histogram(), which is a 00441 // higher-level function. 00442 // 00443 // The max_colors parameter, if greater than zero, 00444 // limits the maximum number of colors we are interested 00445 // in. If we encounter more than this number of colors, 00446 // the function aborts before completion and returns 00447 // false; otherwise, it returns true. 00448 //////////////////////////////////////////////////////////////////// 00449 bool PNMImageHeader:: 00450 compute_histogram(PNMImageHeader::HistMap &hist, 00451 xel *array, xelval *alpha, int max_colors) { 00452 int num_pixels = _x_size * _y_size; 00453 int pi; 00454 00455 switch (get_color_type()) { 00456 case CT_invalid: 00457 return false; 00458 00459 case CT_grayscale: 00460 for (pi = 0; pi < num_pixels; pi++) { 00461 record_color(hist, PixelSpec(PPM_GETB(array[pi]))); 00462 if (max_colors > 0 && (int)hist.size() > max_colors) { 00463 return false; 00464 } 00465 } 00466 return true; 00467 00468 case CT_two_channel: 00469 for (pi = 0; pi < num_pixels; pi++) { 00470 record_color(hist, PixelSpec(PPM_GETB(array[pi]), alpha[pi])); 00471 if (max_colors > 0 && (int)hist.size() > max_colors) { 00472 return false; 00473 } 00474 } 00475 return true; 00476 00477 case CT_color: 00478 for (pi = 0; pi < num_pixels; pi++) { 00479 record_color(hist, PixelSpec(PPM_GETR(array[pi]), PPM_GETG(array[pi]), PPM_GETB(array[pi]))); 00480 if (max_colors > 0 && (int)hist.size() > max_colors) { 00481 return false; 00482 } 00483 } 00484 return true; 00485 00486 case CT_four_channel: 00487 for (pi = 0; pi < num_pixels; pi++) { 00488 record_color(hist, PixelSpec(PPM_GETR(array[pi]), PPM_GETG(array[pi]), PPM_GETB(array[pi]), alpha[pi])); 00489 if (max_colors > 0 && (int)hist.size() > max_colors) { 00490 return false; 00491 } 00492 } 00493 return true; 00494 } 00495 00496 return false; 00497 } 00498 00499 //////////////////////////////////////////////////////////////////// 00500 // Function: PNMImageHeader::compute_palette 00501 // Access: Protected 00502 // Description: Returns a linear list of all of the colors in the 00503 // image, similar to compute_histogram(). 00504 //////////////////////////////////////////////////////////////////// 00505 bool PNMImageHeader:: 00506 compute_palette(PNMImageHeader::Palette &palette, 00507 xel *array, xelval *alpha, int max_colors) { 00508 HistMap hist; 00509 00510 int num_pixels = _x_size * _y_size; 00511 00512 // In case there are already entries in the palette, preserve them. 00513 Palette::const_iterator pi; 00514 for (pi = palette.begin(); pi != palette.end(); ++pi) { 00515 hist.insert(HistMap::value_type(*pi, num_pixels + 1)); 00516 } 00517 00518 if (!compute_histogram(hist, array, alpha, max_colors)) { 00519 return false; 00520 } 00521 00522 // Now append the new entries discovered in the histogram onto the 00523 // end of the palette. 00524 palette.reserve(hist.size()); 00525 HistMap::const_iterator hi; 00526 for (hi = hist.begin(); hi != hist.end(); ++hi) { 00527 if ((*hi).second <= num_pixels) { 00528 palette.push_back((*hi).first); 00529 } 00530 } 00531 00532 return true; 00533 } 00534 00535 //////////////////////////////////////////////////////////////////// 00536 // Function: PNMImageHeader::PixelSpec::output 00537 // Access: Public 00538 // Description: 00539 //////////////////////////////////////////////////////////////////// 00540 void PNMImageHeader::PixelSpec:: 00541 output(ostream &out) const { 00542 out << "(" << _red << ", " << _green << ", " << _blue << ", " << _alpha << ")"; 00543 } 00544 00545 //////////////////////////////////////////////////////////////////// 00546 // Function: PNMImageHeader::Histogram::write 00547 // Access: Public 00548 // Description: 00549 //////////////////////////////////////////////////////////////////// 00550 void PNMImageHeader::Histogram:: 00551 write(ostream &out) const { 00552 out << "Histogram: {\n"; 00553 PixelCount::const_iterator pi; 00554 for (pi = _pixels.begin(); pi != _pixels.end(); ++pi) { 00555 out << " " << (*pi)._pixel << ": " << (*pi)._count << ",\n"; 00556 } 00557 out << "}\n"; 00558 } 00559