|
@@ -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;
|
|
|
|
|
+}
|