diff --git a/pandatool/src/imageprogs/Sources.pp b/pandatool/src/imageprogs/Sources.pp index 85fcec14ea..2b411f829b 100644 --- a/pandatool/src/imageprogs/Sources.pp +++ b/pandatool/src/imageprogs/Sources.pp @@ -20,6 +20,12 @@ imageResize.cxx imageResize.h imageResize.I #end bin_target +#begin bin_target + #define TARGET image-fix-hidden-color + #define SOURCES \ + imageFixHiddenColor.cxx imageFixHiddenColor.h imageFixHiddenColor.I +#end bin_target + #begin bin_target #define TARGET image-info #define SOURCES \ diff --git a/pandatool/src/imageprogs/imageFixHiddenColor.I b/pandatool/src/imageprogs/imageFixHiddenColor.I new file mode 100644 index 0000000000..0efbb8d83e --- /dev/null +++ b/pandatool/src/imageprogs/imageFixHiddenColor.I @@ -0,0 +1,14 @@ +// Filename: imageFixHiddenColor.I +// Created by: drose (13Mar03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + diff --git a/pandatool/src/imageprogs/imageFixHiddenColor.cxx b/pandatool/src/imageprogs/imageFixHiddenColor.cxx new file mode 100644 index 0000000000..b867b440dc --- /dev/null +++ b/pandatool/src/imageprogs/imageFixHiddenColor.cxx @@ -0,0 +1,158 @@ +// Filename: imageFixHiddenColor.cxx +// Created by: drose (13Mar03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#include "imageFixHiddenColor.h" +#include "string_utils.h" +#include "pystub.h" + +//////////////////////////////////////////////////////////////////// +// Function: ImageFixHiddenColor::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +ImageFixHiddenColor:: +ImageFixHiddenColor() : ImageFilter(true) { + set_program_description + ("This program is designed to fix the color channels of an " + "alpha-cutout image, making the \"color\" of the invisible part of the " + "image consistent with the rest of the image. It does this by " + "analyzing the RGB values of the image where alpha == 1, and using the " + "average of these values as the overall image color, which it then " + "applies to the image wherever alpha == 0. When the alpha value is " + "neither 1 nor 0, the pixel is ignored.\n\n" + + "This process is important for applications that filter the texture " + "size down by averaging neighboring pixels. If the color under the " + "alpha == 0 pixels is very different from the color elsewhere, this " + "kind of filtering can have a visible effect on the image's color, even " + "where alpha != 0."); + + add_option + ("alpha", "filename", 0, + "Specifies a separate filename that will be used in lieu of the " + "alpha channel on the source image. If this file has an alpha " + "channel, that alpha channel is used; otherwise, the grayscale " + "value of the image is used.", + &ImageFixHiddenColor::dispatch_filename, NULL, &_alpha_filename); + + add_option + ("opaque", "alpha", 0, + "Specifies the minimum alpha value (in the range of 0 to 1) for a " + "pixel to be considered fully opaque. The default is 1.", + &ImageFixHiddenColor::dispatch_double, NULL, &_min_opaque_alpha); + + add_option + ("transparent", "alpha", 0, + "Specifies the maximum alpha value (in the range of 0 to 1) for a " + "pixel to be considered fully transparent. The default is 0.", + &ImageFixHiddenColor::dispatch_double, NULL, &_max_transparent_alpha); + + _min_opaque_alpha = 1.0; + _max_transparent_alpha = 0.0; +} + +//////////////////////////////////////////////////////////////////// +// Function: ImageFixHiddenColor::run +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void ImageFixHiddenColor:: +run() { + PNMImage alpha_image; + + if (_alpha_filename.empty()) { + // No separate alpha file is provided; use the base file's alpha + // channel. + if (!_image.has_alpha()) { + nout << "Image does not have an alpha channel.\n"; + exit(1); + } + alpha_image = _image; + + } else { + // In this case, the alpha channel is in a separate file. + if (!alpha_image.read(_alpha_filename)) { + nout << "Unable to read " << _alpha_filename << ".\n"; + exit(1); + } + + if (!alpha_image.has_alpha()) { + // Copy the grayscale value to the alpha channel for the benefit + // of the code below. + alpha_image.add_alpha(); + int xi, yi; + for (yi = 0; yi < alpha_image.get_y_size(); ++yi) { + for (xi = 0; xi < alpha_image.get_x_size(); ++xi) { + alpha_image.set_alpha(xi, yi, alpha_image.get_gray(xi, yi)); + } + } + } + + // Make sure the alpha image matches the size of the source image. + if (alpha_image.get_x_size() != _image.get_x_size() || + alpha_image.get_y_size() != _image.get_y_size()) { + PNMImage scaled(_image.get_x_size(), _image.get_y_size(), alpha_image.get_num_channels()); + scaled.quick_filter_from(alpha_image); + alpha_image = scaled; + } + } + + // First, get the average color of all the opaque pixels. + int count = 0; + RGBColord color(0.0, 0.0, 0.0); + int xi, yi; + for (yi = 0; yi < _image.get_y_size(); ++yi) { + for (xi = 0; xi < _image.get_x_size(); ++xi) { + if (alpha_image.get_alpha(xi, yi) >= _min_opaque_alpha) { + color += _image.get_xel(xi, yi); + ++count; + } + } + } + if (count == 0) { + nout << "Image has no opaque pixels.\n"; + exit(1); + } + color /= (double)count; + nout << " average color of " << count << " opaque pixels is " << color << "\n"; + + // Now, apply that wherever there are transparent pixels. + count = 0; + for (yi = 0; yi < _image.get_y_size(); ++yi) { + for (xi = 0; xi < _image.get_x_size(); ++xi) { + if (alpha_image.get_alpha(xi, yi) <= _max_transparent_alpha) { + _image.set_xel(xi, yi, color); + ++count; + } + } + } + if (count == 0) { + nout << "Image has no transparent pixels.\n"; + exit(1); + } + nout << " applied to " << count << " transparent pixels.\n"; + + write_image(_image); +} + + +int main(int argc, char *argv[]) { + // A call to pystub() to force libpystub.so to be linked in. + pystub(); + + ImageFixHiddenColor prog; + prog.parse_command_line(argc, argv); + prog.run(); + return 0; +} diff --git a/pandatool/src/imageprogs/imageFixHiddenColor.h b/pandatool/src/imageprogs/imageFixHiddenColor.h new file mode 100644 index 0000000000..242ebf1541 --- /dev/null +++ b/pandatool/src/imageprogs/imageFixHiddenColor.h @@ -0,0 +1,42 @@ +// Filename: imageFixHiddenColor.h +// Created by: drose (13Mar03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef IMAGEFIXHIDDENCOLOR_H +#define IMAGEFIXHIDDENCOLOR_H + +#include "pandatoolbase.h" + +#include "imageFilter.h" + +//////////////////////////////////////////////////////////////////// +// Class : ImageFixHiddenColor +// Description : This program repairs an image's RGB values hidden +// behind an A value of 0. +//////////////////////////////////////////////////////////////////// +class ImageFixHiddenColor : public ImageFilter { +public: + ImageFixHiddenColor(); + + void run(); + +private: + Filename _alpha_filename; + double _min_opaque_alpha; + double _max_transparent_alpha; +}; + +#include "imageFixHiddenColor.I" + +#endif +