Panda3D

pnmImageHeader.cxx

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 
 All Classes Functions Variables Enumerations