From b38732a6e1270ba3759ec7016b814acd78ca31fe Mon Sep 17 00:00:00 2001 From: David Rose Date: Fri, 19 Mar 2004 01:49:12 +0000 Subject: [PATCH] add histogram/palette options --- panda/src/pnmimage/pnmImageHeader.I | 118 ++++++++++++++++++++++++++ panda/src/pnmimage/pnmImageHeader.cxx | 116 +++++++++++++++++++++++++ panda/src/pnmimage/pnmImageHeader.h | 31 +++++++ 3 files changed, 265 insertions(+) diff --git a/panda/src/pnmimage/pnmImageHeader.I b/panda/src/pnmimage/pnmImageHeader.I index 81ade31c0c..5caaaa499a 100644 --- a/panda/src/pnmimage/pnmImageHeader.I +++ b/panda/src/pnmimage/pnmImageHeader.I @@ -217,3 +217,121 @@ INLINE void PNMImageHeader:: set_type(PNMFileType *type) { _type = type; } + +//////////////////////////////////////////////////////////////////// +// Function: PNMImageHeader::record_color +// Access: Protected +// Description: Records the indicated color in the histogram. +//////////////////////////////////////////////////////////////////// +INLINE void PNMImageHeader:: +record_color(PNMImageHeader::Histogram &hist, + const PNMImageHeader::PixelSpec &color) { + Histogram::iterator hi = hist.find(color); + if (hi == hist.end()) { + hist.insert(Histogram::value_type(color, 1)); + } else { + (*hi).second++; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMImageHeader::PixelSpec::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PNMImageHeader::PixelSpec:: +PixelSpec(xelval gray) : + _red(gray), + _green(gray), + _blue(gray), + _alpha(0) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMImageHeader::PixelSpec::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PNMImageHeader::PixelSpec:: +PixelSpec(xelval gray, xelval alpha) : + _red(gray), + _green(gray), + _blue(gray), + _alpha(alpha) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMImageHeader::PixelSpec::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PNMImageHeader::PixelSpec:: +PixelSpec(xelval red, xelval green, xelval blue) : + _red(red), + _green(green), + _blue(blue), + _alpha(0) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMImageHeader::PixelSpec::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PNMImageHeader::PixelSpec:: +PixelSpec(xelval red, xelval green, xelval blue, xelval alpha) : + _red(red), + _green(green), + _blue(blue), + _alpha(alpha) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMImageHeader::PixelSpec::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PNMImageHeader::PixelSpec:: +PixelSpec(const PixelSpec ©) : + _red(copy._red), + _green(copy._green), + _blue(copy._blue), + _alpha(copy._alpha) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMImageHeader::PixelSpec::Copy Assignment Operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void PNMImageHeader::PixelSpec:: +operator = (const PixelSpec ©) { + _red = copy._red; + _green = copy._green; + _blue = copy._blue; + _alpha = copy._alpha; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMImageHeader::PixelSpec::Comparison Operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool PNMImageHeader::PixelSpec:: +operator < (const PixelSpec &other) const { + if (_red != other._red) { + return _red < other._red; + } + if (_green != other._green) { + return _green < other._green; + } + if (_blue != other._blue) { + return _blue < other._blue; + } + return _alpha < other._alpha; +} diff --git a/panda/src/pnmimage/pnmImageHeader.cxx b/panda/src/pnmimage/pnmImageHeader.cxx index 49754a7297..74ee5decae 100644 --- a/panda/src/pnmimage/pnmImageHeader.cxx +++ b/panda/src/pnmimage/pnmImageHeader.cxx @@ -347,6 +347,11 @@ make_writer(ostream *file, bool owns_file, const Filename &filename, delete file; } + if (!writer->is_valid()) { + delete writer; + writer = NULL; + } + return writer; } @@ -383,3 +388,114 @@ output(ostream &out) const { out << "image: " << _x_size << " by " << _y_size << " pixels, " << _num_channels << " channels, " << _maxval << " maxval."; } + +//////////////////////////////////////////////////////////////////// +// Function: PNMImageHeader::compute_histogram +// Access: Protected +// Description: Computes a histogram of the colors used in the +// indicated rgb/grayscale array and/or alpha array. +// This is most likely to be useful in a PNMWriter +// class, but it is defined at this level in case it has +// general utilty for PNMImages. +// +// The max_colors parameter, if greater than zero, +// limits the maximum number of colors we are interested +// in. If we encounter more than this number of colors, +// the function aborts before completion and returns +// false; otherwise, it returns true. +//////////////////////////////////////////////////////////////////// +bool PNMImageHeader:: +compute_histogram(PNMImageHeader::Histogram &hist, + xel *array, xelval *alpha, int max_colors) { + int num_pixels = _x_size * _y_size; + + switch (get_color_type()) { + case CT_invalid: + return false; + + case CT_grayscale: + for (int pi = 0; pi < num_pixels; pi++) { + record_color(hist, PixelSpec(PPM_GETB(array[pi]))); + if (max_colors > 0 && (int)hist.size() > max_colors) { + return false; + } + } + return true; + + case CT_two_channel: + for (int pi = 0; pi < num_pixels; pi++) { + record_color(hist, PixelSpec(PPM_GETB(array[pi]), alpha[pi])); + if (max_colors > 0 && (int)hist.size() > max_colors) { + return false; + } + } + return true; + + case CT_color: + for (int pi = 0; pi < num_pixels; pi++) { + record_color(hist, PixelSpec(PPM_GETR(array[pi]), PPM_GETG(array[pi]), PPM_GETB(array[pi]))); + if (max_colors > 0 && (int)hist.size() > max_colors) { + return false; + } + } + return true; + + case CT_four_channel: + for (int pi = 0; pi < num_pixels; pi++) { + record_color(hist, PixelSpec(PPM_GETR(array[pi]), PPM_GETG(array[pi]), PPM_GETB(array[pi]), alpha[pi])); + if (max_colors > 0 && (int)hist.size() > max_colors) { + return false; + } + } + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMImageHeader::compute_palette +// Access: Protected +// Description: Returns a linear list of all of the colors in the +// image, similar to compute_histogram(). +//////////////////////////////////////////////////////////////////// +bool PNMImageHeader:: +compute_palette(PNMImageHeader::Palette &palette, + xel *array, xelval *alpha, int max_colors) { + Histogram hist; + + int num_pixels = _x_size * _y_size; + + // In case there are already entries in the palette, preserve them. + Palette::const_iterator pi; + for (pi = palette.begin(); pi != palette.end(); ++pi) { + hist.insert(Histogram::value_type(*pi, num_pixels + 1)); + } + + if (!compute_histogram(hist, array, alpha, max_colors)) { + return false; + } + + // Now append the new entries discovered in the histogram onto the + // end of the palette. + palette.reserve(hist.size()); + Histogram::const_iterator hi; + for (hi = hist.begin(); hi != hist.end(); ++hi) { + if ((*hi).second <= num_pixels) { + palette.push_back((*hi).first); + } + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMImageHeader::PixelSpec::output +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void PNMImageHeader::PixelSpec:: +output(ostream &out) const { + out << "(" << _red << ", " << _green << ", " << _blue << ", " << _alpha << ")"; +} + diff --git a/panda/src/pnmimage/pnmImageHeader.h b/panda/src/pnmimage/pnmImageHeader.h index 6a5a3fd000..82f3be0123 100644 --- a/panda/src/pnmimage/pnmImageHeader.h +++ b/panda/src/pnmimage/pnmImageHeader.h @@ -96,7 +96,33 @@ public: void output(ostream &out) const; +public: + // These classes are used internally, but must be declared public + // for fiddly reasons. + class PixelSpec { + public: + INLINE PixelSpec(xelval gray); + INLINE PixelSpec(xelval gray, xelval alpha); + INLINE PixelSpec(xelval red, xelval green, xelval blue); + INLINE PixelSpec(xelval red, xelval green, xelval blue, xelval alpha); + INLINE PixelSpec(const PixelSpec ©); + INLINE void operator = (const PixelSpec ©); + + INLINE bool operator < (const PixelSpec &other) const; + void output(ostream &out) const; + + xelval _red, _green, _blue, _alpha; + }; + typedef pmap Histogram; + typedef pvector Palette; + protected: + bool compute_histogram(Histogram &hist, xel *array, xelval *alpha, + int max_colors = 0); + bool compute_palette(Palette &palette, xel *array, xelval *alpha, + int max_colors = 0); + INLINE void record_color(Histogram &hist, const PixelSpec &color); + int _x_size, _y_size; int _num_channels; xelval _maxval; @@ -108,6 +134,11 @@ INLINE ostream &operator << (ostream &out, const PNMImageHeader &header) { return out; } +INLINE ostream &operator << (ostream &out, const PNMImageHeader::PixelSpec &pixel) { + pixel.output(out); + return out; +} + #include "pnmImageHeader.I" #endif