Prechádzať zdrojové kódy

robustify image tools

David Rose 23 rokov pred
rodič
commit
f0eaf0b109

+ 4 - 4
pandatool/src/imagebase/imageBase.h

@@ -19,11 +19,11 @@
 #ifndef IMAGEBASE_H
 #define IMAGEBASE_H
 
-#include <pandatoolbase.h>
+#include "pandatoolbase.h"
 
-#include <programBase.h>
-#include <coordinateSystem.h>
-#include <pnmImage.h>
+#include "programBase.h"
+#include "coordinateSystem.h"
+#include "pnmImage.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : ImageBase

+ 8 - 17
pandatool/src/imagebase/imageFilter.cxx

@@ -24,9 +24,13 @@
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ImageFilter::
-ImageFilter() {
+ImageFilter(bool allow_last_param) :
+  ImageWriter(allow_last_param)
+{
   clear_runlines();
-  add_runline("[opts] inputimage outputimage");
+  if (_allow_last_param) {
+    add_runline("[opts] inputimage outputimage");
+  }
   add_runline("[opts] -o outputimage inputimage");
 }
 
@@ -40,21 +44,8 @@ ImageFilter() {
 ////////////////////////////////////////////////////////////////////
 bool ImageFilter::
 handle_args(ProgramBase::Args &args) {
-  if (!_got_output_filename) {
-    if (args.size() != 2) {
-      nout << "You must specify the input and output filenames on the "
-           << "command line, or use -o to specify the output filename.\n";
-      return false;
-    }
-
-    if (!_image.read(args[0])) {
-      nout << "Unable to read image file.\n";
-      return false;
-    }
-
-    _output_filename = args[1];
-    _got_output_filename = true;
-    return true;
+  if (!check_last_arg(args, 1)) {
+    return false;
   }
 
   return ImageReader::handle_args(args);

+ 1 - 1
pandatool/src/imagebase/imageFilter.h

@@ -32,7 +32,7 @@
 ////////////////////////////////////////////////////////////////////
 class ImageFilter : public ImageReader, public ImageWriter {
 public:
-  ImageFilter();
+  ImageFilter(bool allow_last_param);
 
 protected:
   virtual bool handle_args(Args &args);

+ 1 - 1
pandatool/src/imagebase/imageReader.cxx

@@ -47,7 +47,7 @@ handle_args(ProgramBase::Args &args) {
   }
 
   if (!_image.read(args[0])) {
-    nout << "Unable to read image file.\n";
+    nout << "Unable to read image file " << args[0] << ".\n";
     return false;
   }
 

+ 31 - 64
pandatool/src/imagebase/imageWriter.cxx

@@ -25,39 +25,29 @@
 //               output file using -o.
 ////////////////////////////////////////////////////////////////////
 ImageWriter::
-ImageWriter() {
+ImageWriter(bool allow_last_param) :
+  WithOutputFile(allow_last_param, false, true)
+{
   clear_runlines();
-  add_runline("[opts] outputimage");
+  if (_allow_last_param) {
+    add_runline("[opts] outputimage");
+  }
   add_runline("[opts] -o outputimage");
-  add_runline("[opts] -s newimagesize");
-  add_runline("[opts] -hq");
-  add_runline("[opts] -filter_radius filter-radius");
 
-  add_option
-    ("o", "filename", 50,
-     "Specify the filename to which the resulting image file will be written.  "
-     "If this is omitted, the last parameter on the command line is taken as "
-     "the output filename.",
-     &ImageWriter::dispatch_filename, &_got_output_filename, &_output_filename);
-
-  add_option
-    ("s", "new size", 50,
-     "Specify the width & height of the output image using the next 2 integers.  "
-     "Ex: '-s 200,100' resizes to 200x100",
-     &ImageWriter::dispatch_int_pair, &_bDoResize, &_newsize);
-
-  add_option
-    ("hq", "", 50,
-     "Use High-Quality filtering to do image-resizing",
-     &ImageWriter::dispatch_none, &_bUseHighQualityFiltering);
+  string o_description;
+  if (_allow_last_param) {
+    o_description =
+      "Specify the filename to which the resulting image file will be written.  "
+      "If this option is omitted, the last parameter name is taken to be the "
+      "name of the output file.";
+  } else {
+    o_description =
+      "Specify the filename to which the resulting image file will be written.";
+  }
 
   add_option
-    ("filter_radius", "filter-radius", 50,
-     "float value specifying a filter radius to use for the High-Quality filter (ex: 1.0)",
-     &ImageWriter::dispatch_double, NULL, &_filter_radius);
-
-  _filter_radius = 1.0;
-  _bDoResize = false;
+    ("o", "filename", 50, o_description,
+     &ImageWriter::dispatch_filename, &_got_output_filename, &_output_filename);
 }
 
 
@@ -69,24 +59,9 @@ ImageWriter() {
 ////////////////////////////////////////////////////////////////////
 void ImageWriter::
 write_image(const PNMImage &image) {
-  if(_bDoResize) {
-      PNMImage resized_image(_newsize[0], _newsize[1], image.get_num_channels(), image.get_maxval());
-      if(_bUseHighQualityFiltering) {
-          nout << "HQ filtering using filter-radius: " << _filter_radius << endl;
-          resized_image.gaussian_filter_from(_filter_radius, image);
-      } else {
-          resized_image.quick_filter_from(image);
-      }
-
-      if (!resized_image.write(_output_filename)) {
-          nout << "Unable to write output image to " << _output_filename << "\n";
-          exit(1);
-      }
-      return;
-  }
-
-  if (!image.write(_output_filename)) {
-    nout << "Unable to write output image to " << _output_filename << "\n";
+  if (!image.write(get_output_filename())) {
+    nout << "Unable to write output image to " 
+         << get_output_filename() << "\n";
     exit(1);
   }
 }
@@ -101,27 +76,19 @@ write_image(const PNMImage &image) {
 ////////////////////////////////////////////////////////////////////
 bool ImageWriter::
 handle_args(ProgramBase::Args &args) {
-  if (!_got_output_filename) {
-    if (args.size() != 1) {
-      nout << "You must specify the filename to write with -o, or as "
-           << "the last parameter on the command line.\n";
-      return false;
-    }
-    _output_filename = Filename::from_os_specific(args[0]);
-    _got_output_filename = true;
+  if (!check_last_arg(args, 0)) {
+    return false;
+  }
 
-  } else {
-    if (!args.empty()) {
-      nout << "Unexpected arguments on command line:\n";
-      Args::const_iterator ai;
-      for (ai = args.begin(); ai != args.end(); ++ai) {
-	nout << (*ai) << " ";
-      }
-      nout << "\r";
-      return false;
+  if (!args.empty()) {
+    nout << "Unexpected arguments on command line:\n";
+    Args::const_iterator ai;
+    for (ai = args.begin(); ai != args.end(); ++ai) {
+      nout << (*ai) << " ";
     }
+    nout << "\r";
+    return false;
   }
 
   return true;
 }
-

+ 5 - 11
pandatool/src/imagebase/imageWriter.h

@@ -19,32 +19,26 @@
 #ifndef IMAGEWRITER_H
 #define IMAGEWRITER_H
 
-#include <pandatoolbase.h>
-
+#include "pandatoolbase.h"
 #include "imageBase.h"
+#include "withOutputFile.h"
 
-#include <filename.h>
+#include "filename.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : ImageWriter
 // Description : This is the base class for a program that generates
 //               an image file output, but doesn't read any for input.
 ////////////////////////////////////////////////////////////////////
-class ImageWriter : virtual public ImageBase {
+class ImageWriter : virtual public ImageBase, public WithOutputFile {
 public:
-  ImageWriter();
+  ImageWriter(bool allow_last_param);
 
   INLINE void write_image();
   void write_image(const PNMImage &image);
 
 protected:
   virtual bool handle_args(Args &args);
-
-protected:
-  bool _got_output_filename, _bDoResize, _bUseHighQualityFiltering;
-  int _newsize[2];
-  double _filter_radius;
-  Filename _output_filename;
 };
 
 #include "imageWriter.I"

+ 22 - 15
pandatool/src/imageprogs/Sources.pp

@@ -1,21 +1,28 @@
-// We won't install image-trans for now, since the one in $DWDTOOL
-// is better.
-#begin noinst_bin_target
-  #define TARGET image-trans
-  #define LOCAL_LIBS \
-    imagebase progbase
-  #define OTHER_LIBS \
-    egg:c pandaegg:m \
-    pnmimagetypes:c pnmimage:c putil:c express:c panda:m \
-    pandaexpress:m \
-    dtoolutil:c dtoolbase:c dconfig:c dtoolconfig:m dtool:m pystub
-  #define UNIX_SYS_LIBS \
-    m
+#define LOCAL_LIBS \
+  imagebase progbase
+#define OTHER_LIBS \
+  egg:c pandaegg:m \
+  pnmimagetypes:c pnmimage:c putil:c express:c panda:m \
+  pandaexpress:m \
+  dtoolutil:c dtoolbase:c dconfig:c dtoolconfig:m dtool:m pystub
+#define UNIX_SYS_LIBS \
+  m
 
+#begin bin_target
+  #define TARGET image-trans
   #define SOURCES \
     imageTrans.cxx imageTrans.h
+#end bin_target
 
-  #define INSTALL_HEADERS \
+#begin bin_target
+  #define TARGET image-resize
+  #define SOURCES \
+    imageResize.cxx imageResize.h imageResize.I
+#end bin_target
 
-#end noinst_bin_target
+#begin bin_target
+  #define TARGET image-info
+  #define SOURCES \
+    imageInfo.cxx imageInfo.h
+#end bin_target
 

+ 86 - 0
pandatool/src/imageprogs/imageInfo.cxx

@@ -0,0 +1,86 @@
+// Filename: imageInfo.cxx
+// Created by:  drose (13Mar03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "imageInfo.h"
+#include "pnmImageHeader.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: ImageInfo::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+ImageInfo::
+ImageInfo() {
+  set_program_description
+    ("This program reads the headers of a series of one or more "
+     "image files and reports the image sizes to standard output.");
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ImageInfo::run
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+void ImageInfo::
+run() {
+  Args::const_iterator ai;
+  for (ai = _filenames.begin(); ai != _filenames.end(); ++ai) {
+    Filename filename = (*ai);
+    PNMImageHeader header;
+    if (!header.read_header(filename)) {
+      // Could not read the image header.
+      if (filename.exists()) {
+        nout << filename << ": could not read image.\n";
+      } else {
+        nout << filename << ": does not exist.\n";
+      }
+    } else {
+      // Successfully read the image header.
+      nout << filename << ": " << header.get_x_size() << " x "
+           << header.get_y_size() << " x " << header.get_num_channels()
+           << "\n";
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ImageInfo::handle_args
+//       Access: Protected, Virtual
+//  Description: Does something with the additional arguments on the
+//               command line (after all the -options have been
+//               parsed).  Returns true if the arguments are good,
+//               false otherwise.
+////////////////////////////////////////////////////////////////////
+bool ImageInfo::
+handle_args(ProgramBase::Args &args) {
+  if (args.empty()) {
+    nout << "List one or more image filenames on command line.\n";
+    return false;
+  }
+  _filenames = args;
+
+  return true;
+}
+
+
+int main(int argc, char *argv[]) {
+  ImageInfo prog;
+  prog.parse_command_line(argc, argv);
+  prog.run();
+  return 0;
+}

+ 45 - 0
pandatool/src/imageprogs/imageInfo.h

@@ -0,0 +1,45 @@
+// Filename: imageInfo.h
+// Created by:  drose (13Mar03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef IMAGEINFO_H
+#define IMAGEINFO_H
+
+#include "pandatoolbase.h"
+
+#include "programBase.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : ImageInfo
+// Description : This program reads the headers of a series of one or
+//               more images and reports their sizes to standard
+//               output.
+////////////////////////////////////////////////////////////////////
+class ImageInfo : public ProgramBase {
+public:
+  ImageInfo();
+
+  void run();
+
+protected:
+  virtual bool handle_args(Args &args);
+
+  Args _filenames;
+};
+
+#endif
+

+ 125 - 0
pandatool/src/imageprogs/imageResize.I

@@ -0,0 +1,125 @@
+// Filename: imageResize.I
+// Created by:  drose (13Mar03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ImageResize::SizeRequest::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE ImageResize::SizeRequest::
+SizeRequest() {
+  _type = RT_none;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ImageResize::SizeRequest::get_type
+//       Access: Public
+//  Description: Returns the type of the size request, or RT_none if
+//               the request has not been specified.
+////////////////////////////////////////////////////////////////////
+INLINE ImageResize::RequestType ImageResize::SizeRequest::
+get_type() const {
+  return _type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ImageResize::SizeRequest::set_pixel_size
+//       Access: Public
+//  Description: Sets the size request to store an explicit pixel
+//               size.
+////////////////////////////////////////////////////////////////////
+INLINE void ImageResize::SizeRequest::
+set_pixel_size(int pixel_size) {
+  _type = RT_pixel_size;
+  _e._pixel_size = pixel_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ImageResize::SizeRequest::get_pixel_size
+//       Access: Public
+//  Description: Returns the explicit pixel size stored within the
+//               size request.
+////////////////////////////////////////////////////////////////////
+INLINE int ImageResize::SizeRequest::
+get_pixel_size() const {
+  nassertr(_type == RT_pixel_size, 0);
+  return _e._pixel_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ImageResize::SizeRequest::get_pixel_size
+//       Access: Public
+//  Description: Returns the explicit pixel size stored within the
+//               size request, or if a ratio has been stored, returns
+//               the computed pixel size based on the original size.
+////////////////////////////////////////////////////////////////////
+INLINE int ImageResize::SizeRequest::
+get_pixel_size(int orig_pixel_size) const {
+  switch (_type) {
+  case RT_pixel_size:
+    return _e._pixel_size;
+  case RT_ratio:
+    return (int)(_e._ratio * orig_pixel_size + 0.5);
+  default:
+    return orig_pixel_size;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ImageResize::SizeRequest::set_ratio
+//       Access: Public
+//  Description: Sets the size request to store a specific ratio.
+////////////////////////////////////////////////////////////////////
+INLINE void ImageResize::SizeRequest::
+set_ratio(double ratio) {
+  _type = RT_ratio;
+  _e._ratio = ratio;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ImageResize::SizeRequest::get_ratio
+//       Access: Public
+//  Description: Returns the specific ratio stored within the
+//               size request.
+////////////////////////////////////////////////////////////////////
+INLINE double ImageResize::SizeRequest::
+get_ratio() const {
+  nassertr(_type == RT_ratio, 0);
+  return _e._ratio;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ImageResize::SizeRequest::get_ratio
+//       Access: Public
+//  Description: Returns the specific ratio stored within the
+//               size request, or if a pixel size has been stored,
+//               returns the computed ratio based on the original
+//               size.
+////////////////////////////////////////////////////////////////////
+INLINE double ImageResize::SizeRequest::
+get_ratio(int orig_pixel_size) const {
+  switch (_type) {
+  case RT_ratio:
+    return _e._ratio;
+  case RT_pixel_size:
+    return (double)_e._pixel_size / (double)orig_pixel_size;
+  default:
+    return 1.0;
+  }
+}

+ 127 - 0
pandatool/src/imageprogs/imageResize.cxx

@@ -0,0 +1,127 @@
+// Filename: imageResize.cxx
+// Created by:  drose (13Mar03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "imageResize.h"
+#include "string_utils.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: ImageResize::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+ImageResize::
+ImageResize() : ImageFilter(true) {
+  set_program_description
+    ("This program reads an image file and resizes it to a larger or smaller "
+     "image file.");
+
+  add_option
+    ("x", "xsize", 0,
+     "Specify the width of the output image in pixels, or as a percentage "
+     "of the original width (if a trailing percent sign is included).  "
+     "If this is omitted, the ratio is taken from the ysize parameter.",
+     &ImageResize::dispatch_size_request, NULL, &_x_size);
+
+  add_option
+    ("y", "ysize", 0,
+     "Specify the height of the output image in pixels, or as a percentage "
+     "of the original height (if a trailing percent sign is included).  "
+     "If this is omitted, the ratio is taken from the xsize parameter.",
+     &ImageResize::dispatch_size_request, NULL, &_y_size);
+
+  add_option
+    ("g", "radius", 0,
+     "Use Gaussian filtering to resize the image, with the indicated radius.",
+     &ImageResize::dispatch_double, &_use_gaussian_filter, &_filter_radius);
+
+  _filter_radius = 1.0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ImageResize::run
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+void ImageResize::
+run() {
+  if (_x_size.get_type() == RT_none && _y_size.get_type() == RT_none) {
+    _x_size.set_ratio(1.0);
+    _y_size.set_ratio(1.0);
+  } else if (_x_size.get_type() == RT_none) {
+    _x_size.set_ratio(_y_size.get_ratio(_image.get_y_size()));
+  } else if (_y_size.get_type() == RT_none) {
+    _y_size.set_ratio(_x_size.get_ratio(_image.get_x_size()));
+  }
+
+  int x_size = _x_size.get_pixel_size(_image.get_x_size());
+  int y_size = _y_size.get_pixel_size(_image.get_y_size());
+
+  nout << "Resizing to " << x_size << " x " << y_size << "\n";
+  PNMImage new_image(x_size, y_size,
+                     _image.get_num_channels(), 
+                     _image.get_maxval(), _image.get_type());
+
+  if (_use_gaussian_filter) {
+    new_image.gaussian_filter_from(_filter_radius, _image);
+  } else {
+    new_image.quick_filter_from(_image);
+  }
+
+  write_image(new_image);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ImageResize::dispatch_size_request
+//       Access: Private, Static
+//  Description: Interprets the -x or -y parameters.
+////////////////////////////////////////////////////////////////////
+bool ImageResize::
+dispatch_size_request(const string &opt, const string &arg, void *var) {
+  SizeRequest *ip = (SizeRequest *)var;
+  if (!arg.empty() && arg[arg.length() - 1] == '%') {
+    // A ratio.
+    string str = arg.substr(0, arg.length() - 1);
+    double ratio;
+    if (!string_to_double(str, ratio)) {
+      nout << "Invalid ratio for -" << opt << ": "
+           << str << "\n";
+      return false;
+    }
+    ip->set_ratio(ratio / 100.0);
+
+  } else {
+    // A pixel size.
+    int pixel_size;
+    if (!string_to_int(arg, pixel_size)) {
+      nout << "Invalid pixel size for -" << opt << ": "
+           << arg << "\n";
+      return false;
+    }
+    ip->set_pixel_size(pixel_size);
+  }
+
+  return true;
+}
+
+
+int main(int argc, char *argv[]) {
+  ImageResize prog;
+  prog.parse_command_line(argc, argv);
+  prog.run();
+  return 0;
+}

+ 75 - 0
pandatool/src/imageprogs/imageResize.h

@@ -0,0 +1,75 @@
+// Filename: imageResize.h
+// Created by:  drose (13Mar03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef IMAGERESIZE_H
+#define IMAGERESIZE_H
+
+#include "pandatoolbase.h"
+
+#include "imageFilter.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : ImageResize
+// Description : A program to read an image file and resize it to a
+//               larger or smaller image file.
+////////////////////////////////////////////////////////////////////
+class ImageResize : public ImageFilter {
+public:
+  ImageResize();
+
+  void run();
+
+private:
+  static bool dispatch_size_request(const string &opt, const string &arg, void *var);
+
+  enum RequestType {
+    RT_none,
+    RT_pixel_size,
+    RT_ratio,
+  };
+  class SizeRequest {
+  public:
+    INLINE SizeRequest();
+    INLINE RequestType get_type() const;
+
+    INLINE void set_pixel_size(int pixel_size);
+    INLINE int get_pixel_size() const;
+    INLINE int get_pixel_size(int orig_pixel_size) const;
+    INLINE void set_ratio(double ratio);
+    INLINE double get_ratio() const;
+    INLINE double get_ratio(int orig_pixel_size) const;
+
+  private:
+    RequestType _type;
+    union {
+      int _pixel_size;
+      double _ratio;
+    } _e;
+  };
+
+  SizeRequest _x_size;
+  SizeRequest _y_size;
+
+  bool _use_gaussian_filter;
+  double _filter_radius;
+};
+
+#include "imageResize.I"
+
+#endif
+

+ 109 - 1
pandatool/src/imageprogs/imageTrans.cxx

@@ -17,6 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "imageTrans.h"
+#include "string_utils.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ImageTrans::Constructor
@@ -24,10 +25,21 @@
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ImageTrans::
-ImageTrans() {
+ImageTrans() : ImageFilter(true) {
   set_program_description
     ("This program reads an image file and writes an essentially equivalent "
      "image file to the file specified with -o.");
+
+  add_option
+    ("chan", "channels", 50,
+     "Elevate (or truncate) the image to the indicated number of channels.  "
+     "This may be 1, 2, 3, or 4.  You may also specify one of the keywords "
+     "l, la, rgb, or rgba, respectively, or any of the keywords r, g, b, or "
+     "a to extract out just the indicated channel as a single grayscale "
+     "image.",
+     &ImageTrans::dispatch_channels, NULL, &_channels);
+
+  _channels = C_default;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -37,9 +49,105 @@ ImageTrans() {
 ////////////////////////////////////////////////////////////////////
 void ImageTrans::
 run() {
+  switch (_channels) {
+  case C_default:
+    break;
+
+  case C_l:
+  case C_la:
+  case C_rgb:
+  case C_rgba:
+    _image.set_num_channels((int)_channels);
+    break;
+    
+  case C_r:
+    _image.make_grayscale(1.0, 0.0, 0.0);
+    _image.remove_alpha();
+    break;
+
+  case C_g:
+    _image.make_grayscale(0.0, 1.0, 0.0);
+    _image.remove_alpha();
+    break;
+
+  case C_b:
+    _image.make_grayscale(0.0, 0.0, 1.0);
+    _image.remove_alpha();
+    break;
+
+  case C_a:
+    extract_alpha();
+    break;
+  }
+
   write_image();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ImageTrans::dispatch_channels
+//       Access: Private, Static
+//  Description: Interprets the -chan parameter.
+////////////////////////////////////////////////////////////////////
+bool ImageTrans::
+dispatch_channels(const string &opt, const string &arg, void *var) {
+  Channels *ip = (Channels *)var;
+  if (cmp_nocase(arg, "l") == 0) {
+    (*ip) = C_l;
+  } else if (cmp_nocase(arg, "la") == 0) {
+    (*ip) = C_la;
+  } else if (cmp_nocase(arg, "rgb") == 0) {
+    (*ip) = C_rgb;
+  } else if (cmp_nocase(arg, "rgba") == 0) {
+    (*ip) = C_rgba;
+  } else if (cmp_nocase(arg, "r") == 0) {
+    (*ip) = C_r;
+  } else if (cmp_nocase(arg, "g") == 0) {
+    (*ip) = C_g;
+  } else if (cmp_nocase(arg, "b") == 0) {
+    (*ip) = C_b;
+  } else if (cmp_nocase(arg, "a") == 0) {
+    (*ip) = C_a;
+  } else {
+    int value;
+    if (!string_to_int(arg, value)) {
+      nout << "Invalid parameter for -" << opt << ": "
+           << arg << "\n";
+      return false;
+    }
+    if (value < 1 || value > 4) {
+      nout << "Number of channels must be one of 1, 2, 3, or 4.\n";
+      return false;
+    }
+    (*ip) = (Channels)value;
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ImageTrans::extract_alpha
+//       Access: Private
+//  Description: Extracts out just the alpha channel and stores it as
+//               a grayscale image.
+////////////////////////////////////////////////////////////////////
+void ImageTrans::
+extract_alpha() {
+  if (!_image.has_alpha()) {
+    nout << "Source image does not have an alpha channel!\n";
+    _image.make_grayscale();
+    _image.fill();
+    return;
+  }
+
+  _image.make_grayscale();
+  for (int y = 0; y < _image.get_y_size(); y++) {
+    for (int x = 0; x < _image.get_x_size(); x++) {
+      _image.set_gray_val(x, y, _image.get_alpha_val(x, y));
+    }
+  }
+  _image.remove_alpha();
+}
+
 
 int main(int argc, char *argv[]) {
   ImageTrans prog;

+ 20 - 2
pandatool/src/imageprogs/imageTrans.h

@@ -19,9 +19,9 @@
 #ifndef IMAGETRANS_H
 #define IMAGETRANS_H
 
-#include <pandatoolbase.h>
+#include "pandatoolbase.h"
 
-#include <imageFilter.h>
+#include "imageFilter.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : ImageTrans
@@ -34,6 +34,24 @@ public:
   ImageTrans();
 
   void run();
+
+private:
+  static bool dispatch_channels(const string &opt, const string &arg, void *var);
+  void extract_alpha();
+
+  enum Channels {
+    C_default,
+    C_l = 1,
+    C_la = 2,
+    C_rgb = 3,
+    C_rgba = 4,
+    C_r,
+    C_g,
+    C_b,
+    C_a
+  };
+    
+  Channels _channels;
 };
 
 #endif