Pārlūkot izejas kodu

add histogram/palette options

David Rose 22 gadi atpakaļ
vecāks
revīzija
b38732a6e1

+ 118 - 0
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 &copy) :
+  _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 &copy) {
+  _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;
+}

+ 116 - 0
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 << ")";
+}
+

+ 31 - 0
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 &copy);
+    INLINE void operator = (const PixelSpec &copy);
+
+    INLINE bool operator < (const PixelSpec &other) const;
+    void output(ostream &out) const;
+
+    xelval _red, _green, _blue, _alpha;
+  };
+  typedef pmap<PixelSpec, int> Histogram;
+  typedef pvector<PixelSpec> 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