Panda3D

pnmImage.cxx

00001 // Filename: pnmImage.cxx
00002 // Created by:  drose (14Jun00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "pnmImage.h"
00016 #include "pnmReader.h"
00017 #include "pnmWriter.h"
00018 #include "pnmBrush.h"
00019 #include "config_pnmimage.h"
00020 #include "perlinNoise2.h"
00021 #include "stackedPerlinNoise2.h"
00022 #include <algorithm>
00023 
00024 ////////////////////////////////////////////////////////////////////
00025 //     Function: PNMImage::Constructor
00026 //       Access: Published
00027 //  Description:
00028 ////////////////////////////////////////////////////////////////////
00029 PNMImage::
00030 PNMImage(const Filename &filename, PNMFileType *type) {
00031   _array = NULL;
00032   _alpha = NULL;
00033   _has_read_size = false;
00034 
00035   bool result = read(filename, type);
00036   if (!result) {
00037     pnmimage_cat.error()
00038       << "Could not read image " << filename << "\n";
00039   }
00040 }
00041 
00042 ////////////////////////////////////////////////////////////////////
00043 //     Function: PNMImage::clear
00044 //       Access: Published
00045 //  Description: Frees all memory allocated for the image, and clears
00046 //               all its parameters (size, color, type, etc).
00047 ////////////////////////////////////////////////////////////////////
00048 void PNMImage::
00049 clear() {
00050   if (_array != (xel *)NULL) {
00051     PANDA_FREE_ARRAY(_array);
00052     _array = (xel *)NULL;
00053   }
00054   if (_alpha != (xelval *)NULL) {
00055     PANDA_FREE_ARRAY(_alpha);
00056     _alpha = (xelval *)NULL;
00057   }
00058   _x_size = 0;
00059   _y_size = 0;
00060   _num_channels = 0;
00061   _maxval = 255;
00062   _comment.clear();
00063   _type = (PNMFileType *)NULL;
00064   _has_read_size = false;
00065 }
00066 
00067 ////////////////////////////////////////////////////////////////////
00068 //     Function: PNMImage::clear
00069 //       Access: Published
00070 //  Description: This flavor of clear() reinitializes the image to an
00071 //               empty (black) image with the given dimensions.
00072 ////////////////////////////////////////////////////////////////////
00073 void PNMImage::
00074 clear(int x_size, int y_size, int num_channels,
00075       xelval maxval, PNMFileType *type) {
00076   clear();
00077   nassertv(num_channels >= 1 && num_channels <= 4);
00078 
00079   _x_size = x_size;
00080   _y_size = y_size;
00081   _num_channels = num_channels;
00082   _maxval = maxval;
00083   _comment.clear();
00084   _type = type;
00085   _has_read_size = false;
00086 
00087   if (has_alpha()) {
00088     allocate_alpha();
00089     memset(_alpha, 0, sizeof(xelval) * _y_size * _x_size);
00090   }
00091 
00092   allocate_array();
00093   memset(_array, 0, sizeof(xel) * _y_size * _x_size);
00094 
00095   setup_rc();
00096 }
00097 
00098 ////////////////////////////////////////////////////////////////////
00099 //     Function: PNMImage::copy_from
00100 //       Access: Published
00101 //  Description: Makes this image become a copy of the other image.
00102 ////////////////////////////////////////////////////////////////////
00103 void PNMImage::
00104 copy_from(const PNMImage &copy) {
00105   clear();
00106   copy_header_from(copy);
00107 
00108   if (copy.is_valid()) {
00109     if (has_alpha()) {
00110       memcpy(_alpha, copy._alpha, sizeof(xelval) * _y_size * _x_size);
00111     }
00112     memcpy(_array, copy._array, sizeof(xel) * _y_size * _x_size);
00113   }
00114 }
00115 
00116 ////////////////////////////////////////////////////////////////////
00117 //     Function: PNMImage::copy_channel
00118 //       Access: Published
00119 //  Description: Copies a channel from one image into another.
00120 //               Images must be the same size
00121 ////////////////////////////////////////////////////////////////////
00122 void PNMImage::
00123 copy_channel(const PNMImage &copy, int src_channel, int dest_channel) {
00124   // Make sure the channels are in range
00125   nassertv(src_channel >= 0 && src_channel <= 3);
00126   nassertv(dest_channel >= 0 && dest_channel <= 3);
00127   // Make sure that images are valid
00128   if (!copy.is_valid() || !is_valid()) {
00129     pnmimage_cat.error() << "One of the images is invalid!\n";
00130     return;
00131   }
00132   // Make sure the images are the same size
00133   if (_x_size != copy.get_x_size() || _y_size != copy.get_y_size()){
00134     pnmimage_cat.error() << "Image size doesn't match!\n";
00135     return;
00136   }
00137   // Do the actual copying
00138   for (int x = 0; x < _x_size; x++) {
00139     for (int y = 0; y < _y_size; y++) {
00140       LVecBase4d t = get_xel_a(x, y);
00141       LVecBase4d o = copy.get_xel_a(x, y);
00142       t.set_cell(dest_channel,o.get_cell(src_channel));
00143       set_xel_a(x, y, t);
00144     }
00145   }
00146 }
00147 
00148 
00149 ////////////////////////////////////////////////////////////////////
00150 //     Function: PNMImage::copy_header_from
00151 //       Access: Published
00152 //  Description: Copies just the header information into this image.
00153 //               This will blow away any image data stored in the
00154 //               image.  The new image data will be allocated, but
00155 //               left unitialized.
00156 ////////////////////////////////////////////////////////////////////
00157 void PNMImage::
00158 copy_header_from(const PNMImageHeader &header) {
00159   clear();
00160   PNMImageHeader::operator = (header);
00161 
00162   if (has_alpha()) {
00163     allocate_alpha();
00164   }
00165 
00166   allocate_array();
00167   setup_rc();
00168 }
00169 
00170 ////////////////////////////////////////////////////////////////////
00171 //     Function: PNMImage::take_from
00172 //       Access: Published
00173 //  Description: Move the contents of the other image into this one,
00174 //               and empty the other image.
00175 ////////////////////////////////////////////////////////////////////
00176 void PNMImage::
00177 take_from(PNMImage &orig) {
00178   clear();
00179   PNMImageHeader::operator = (orig);
00180   setup_rc();
00181 
00182   if (has_alpha()) {
00183     _alpha = orig._alpha;
00184     orig._alpha = NULL;
00185   }
00186   _array = orig._array;
00187   orig._array = NULL;
00188 
00189   orig.clear();
00190 }
00191 
00192 ////////////////////////////////////////////////////////////////////
00193 //     Function: PNMImage::fill_val
00194 //       Access: Published
00195 //  Description: Sets the entire image (except the alpha channel) to
00196 //               the given color.
00197 ////////////////////////////////////////////////////////////////////
00198 void PNMImage::
00199 fill_val(xelval red, xelval green, xelval blue) {
00200   if (is_valid()) {
00201     for (int y = 0; y < get_y_size(); y++) {
00202       for (int x = 0; x < get_x_size(); x++) {
00203         set_xel_val(x, y, red, green, blue);
00204       }
00205     }
00206   }
00207 }
00208 
00209 ////////////////////////////////////////////////////////////////////
00210 //     Function: PNMImage::alpha_fill_val
00211 //       Access: Published
00212 //  Description: Sets the entire alpha channel to the given level.
00213 ////////////////////////////////////////////////////////////////////
00214 void PNMImage::
00215 alpha_fill_val(xelval alpha) {
00216   if (is_valid()) {
00217     if (!has_alpha()) {
00218       add_alpha();
00219     }
00220 
00221     for (int y = 0; y < get_y_size(); y++) {
00222       for (int x = 0; x < get_x_size(); x++) {
00223         set_alpha_val(x, y, alpha);
00224       }
00225     }
00226   }
00227 }
00228 
00229 ////////////////////////////////////////////////////////////////////
00230 //     Function: PNMImage::read
00231 //       Access: Published
00232 //  Description: Reads the indicated image filename.  If type is
00233 //               non-NULL, it is a suggestion for the type of file it
00234 //               is.  Returns true if successful, false on error.
00235 ////////////////////////////////////////////////////////////////////
00236 bool PNMImage::
00237 read(const Filename &filename, PNMFileType *type, bool report_unknown_type) {
00238   PNMReader *reader = make_reader(filename, type, report_unknown_type);
00239   if (reader == (PNMReader *)NULL) {
00240     clear();
00241     return false;
00242   }
00243 
00244   return read(reader);
00245 }
00246 
00247 ////////////////////////////////////////////////////////////////////
00248 //     Function: PNMImage::read
00249 //       Access: Published
00250 //  Description: Reads the image data from the indicated stream.
00251 //
00252 //               The filename is advisory only, and may be used
00253 //               to suggest a type if it has a known extension.
00254 //
00255 //               If type is non-NULL, it is a suggestion for the type
00256 //               of file it is (and a non-NULL type will override any
00257 //               magic number test or filename extension lookup).
00258 //
00259 //               Returns true if successful, false on error.
00260 ////////////////////////////////////////////////////////////////////
00261 bool PNMImage::
00262 read(istream &data, const string &filename, PNMFileType *type,
00263      bool report_unknown_type) {
00264   PNMReader *reader = PNMImageHeader::make_reader
00265     (&data, false, filename, string(), type, report_unknown_type);
00266   if (reader == (PNMReader *)NULL) {
00267     clear();
00268     return false;
00269   }
00270   return read(reader);
00271 }
00272 
00273 ////////////////////////////////////////////////////////////////////
00274 //     Function: PNMImage::read
00275 //       Access: Published
00276 //  Description: This flavor of read() uses an already-existing
00277 //               PNMReader to read the image file.  You can get a
00278 //               reader via the PNMImageHeader::make_reader() methods.
00279 //               This is a good way to examine the header of a file
00280 //               (for instance, to determine its size) before actually
00281 //               reading the entire image.
00282 //
00283 //               The PNMReader is always deleted upon completion,
00284 //               whether successful or not.
00285 ////////////////////////////////////////////////////////////////////
00286 bool PNMImage::
00287 read(PNMReader *reader) {
00288   bool has_read_size = _has_read_size;
00289   int read_x_size = _read_x_size;
00290   int read_y_size = _read_y_size;
00291 
00292   clear();
00293 
00294   if (reader == NULL) {
00295     return false;
00296   }
00297 
00298   if (!reader->is_valid()) {
00299     delete reader;
00300     return false;
00301   }
00302 
00303   if (has_read_size) {
00304     reader->set_read_size(read_x_size, read_y_size);
00305   }
00306   reader->prepare_read();
00307 
00308   copy_header_from(*reader);
00309 
00310   // We reassign y_size after reading because we might have read a
00311   // truncated file.
00312   _y_size = reader->read_data(_array, _alpha);
00313   delete reader;
00314 
00315   if (_y_size == 0) {
00316     clear();
00317     return false;
00318   }
00319 
00320   setup_rc();
00321 
00322   if (has_read_size && (_x_size != read_x_size || _y_size != read_y_size)) {
00323     // The Reader didn't comply with our size request.  Do the sizing
00324     // explicitly, then.
00325     PNMImage new_image(read_x_size, read_y_size, get_num_channels(),
00326                        get_maxval(), get_type());
00327     new_image.quick_filter_from(*this);
00328     take_from(new_image);
00329   }
00330 
00331   return true;
00332 }
00333 
00334 ////////////////////////////////////////////////////////////////////
00335 //     Function: PNMImage::write
00336 //       Access: Published
00337 //  Description: Writes the image to the indicated filename.  If type
00338 //               is non-NULL, it is a suggestion for the type of image
00339 //               file to write.
00340 ////////////////////////////////////////////////////////////////////
00341 bool PNMImage::
00342 write(const Filename &filename, PNMFileType *type) const {
00343   if (!is_valid()) {
00344     return false;
00345   }
00346 
00347   PNMWriter *writer = PNMImageHeader::make_writer(filename, type);
00348   if (writer == (PNMWriter *)NULL) {
00349     return false;
00350   }
00351 
00352   return write(writer);
00353 }
00354 
00355 ////////////////////////////////////////////////////////////////////
00356 //     Function: PNMImage::write
00357 //       Access: Published
00358 //  Description: Writes the image to the indicated ostream.
00359 //
00360 //               The filename is advisory only, and may be used
00361 //               suggest a type if it has a known extension.
00362 //
00363 //               If type is non-NULL, it is a suggestion for the type
00364 //               of image file to write.
00365 ////////////////////////////////////////////////////////////////////
00366 bool PNMImage::
00367 write(ostream &data, const string &filename, PNMFileType *type) const {
00368   if (!is_valid()) {
00369     return false;
00370   }
00371 
00372   PNMWriter *writer = PNMImageHeader::make_writer
00373     (&data, false, filename, type);
00374   if (writer == (PNMWriter *)NULL) {
00375     return false;
00376   }
00377 
00378   return write(writer);
00379 }
00380 
00381 ////////////////////////////////////////////////////////////////////
00382 //     Function: PNMImage::write
00383 //       Access: Published
00384 //  Description: This flavor of write() uses an already-existing
00385 //               PNMWriter to write the image file.  You can get a
00386 //               writer via the PNMImageHeader::make_writer() methods.
00387 //
00388 //               The PNMWriter is always deleted upon completion,
00389 //               whether successful or not.
00390 ////////////////////////////////////////////////////////////////////
00391 bool PNMImage::
00392 write(PNMWriter *writer) const {
00393   if (writer == NULL) {
00394     return false;
00395   }
00396 
00397   if (!is_valid()) {
00398     delete writer;
00399     return false;
00400   }
00401 
00402   writer->copy_header_from(*this);
00403   if (is_grayscale() && !writer->supports_grayscale()) {
00404     // Copy the gray values to all channels to help out the writer.
00405     for (int y = 0; y < get_y_size(); y++) {
00406       for (int x = 0; x<get_x_size(); x++) {
00407         ((PNMImage *)this)->set_xel_val(x, y, get_gray_val(x, y));
00408       }
00409     }
00410   }
00411 
00412   int result = writer->write_data(_array, _alpha);
00413   delete writer;
00414 
00415   return (result == _y_size);
00416 }
00417 
00418 
00419 
00420 ////////////////////////////////////////////////////////////////////
00421 //     Function: PNMImage::set_color_type
00422 //       Access: Published
00423 //  Description: Translates the image to or from grayscale, color, or
00424 //               four-color mode.  Grayscale images are converted to
00425 //               full-color images with R, G, B set to the original
00426 //               gray level; color images are converted to grayscale
00427 //               according to the value of Bright().  The alpha
00428 //               channel, if added, is initialized to zero.
00429 ////////////////////////////////////////////////////////////////////
00430 void PNMImage::
00431 set_color_type(PNMImage::ColorType color_type) {
00432   nassertv((int)color_type >= 1 && (int)color_type <= 4);
00433   if (color_type == get_color_type()) {
00434     return;
00435   }
00436 
00437   if (!is_grayscale() && is_grayscale(color_type)) {
00438     // convert to grayscale from color
00439     for (int y = 0; y < get_y_size(); y++) {
00440       for (int x = 0; x < get_x_size(); x++) {
00441         set_gray(x, y, get_bright(x, y));
00442       }
00443     }
00444 
00445   } else if (is_grayscale() && !is_grayscale(color_type)) {
00446     // convert to color from grayscale
00447     for (int y = 0; y < get_y_size(); y++) {
00448       for (int x = 0; x<get_x_size(); x++) {
00449         set_xel_val(x, y, get_gray_val(x, y));
00450       }
00451     }
00452   }
00453 
00454   if (has_alpha() && !has_alpha(color_type)) {
00455     // discard the alpha channel
00456     if (_alpha!=NULL) {
00457       PANDA_FREE_ARRAY(_alpha);
00458       _alpha = NULL;
00459     }
00460 
00461   } else if (!has_alpha() && has_alpha(color_type)) {
00462     // create a new alpha channel
00463     allocate_alpha();
00464     memset(_alpha, 0, sizeof(xelval) * (_x_size * _y_size));
00465   }
00466 
00467   _num_channels = (int)color_type;
00468   setup_rc();
00469 }
00470 
00471 ////////////////////////////////////////////////////////////////////
00472 //     Function: PNMImage::make_grayscale
00473 //       Access: Published
00474 //  Description: Converts the image from RGB to grayscale.  Any alpha
00475 //               channel, if present, is left undisturbed.  The
00476 //               optional rc, gc, bc values represent the relative
00477 //               weights to apply to each channel to convert it to
00478 //               grayscale.
00479 ////////////////////////////////////////////////////////////////////
00480 void PNMImage::
00481 make_grayscale(double rc, double gc, double bc) {
00482   if (is_grayscale()) {
00483     return;
00484   }
00485 
00486   for (int y = 0; y < get_y_size(); y++) {
00487     for (int x = 0; x < get_x_size(); x++) {
00488       set_gray(x, y, min(get_bright(x, y, rc, gc, bc), 1.0));
00489     }
00490   }
00491 
00492   _num_channels = has_alpha() ? 2 : 1;
00493   setup_rc();
00494 }
00495 
00496 ////////////////////////////////////////////////////////////////////
00497 //     Function: PNMImage::reverse_rows
00498 //       Access: Published
00499 //  Description: Performs an in-place reversal of the row (y) data.
00500 ////////////////////////////////////////////////////////////////////
00501 void PNMImage::
00502 reverse_rows() {
00503   if (_array != NULL) {
00504     xel *new_array = (xel *)PANDA_MALLOC_ARRAY(_x_size * _y_size * sizeof(xel));
00505     for (int y = 0; y < _y_size; y++) {
00506       int new_y = _y_size - 1 - y;
00507       memcpy(new_array + new_y * _x_size, _array + y * _x_size, _x_size * sizeof(xel));
00508     }
00509     PANDA_FREE_ARRAY(_array);
00510     _array = new_array;
00511   }
00512 
00513   if (_alpha != NULL) {
00514     xelval *new_alpha = (xelval *)PANDA_MALLOC_ARRAY(_x_size * _y_size * sizeof(xelval));
00515     for (int y = 0; y < _y_size; y++) {
00516       int new_y = _y_size - 1 - y;
00517       memcpy(new_alpha + new_y * _x_size, _alpha + y * _x_size, _x_size * sizeof(xelval));
00518     }
00519     PANDA_FREE_ARRAY(_alpha);
00520     _alpha = new_alpha;
00521   }
00522 }
00523 
00524 ////////////////////////////////////////////////////////////////////
00525 //     Function: PNMImage::set_maxval
00526 //       Access: Published
00527 //  Description: Rescales the image to the indicated maxval.
00528 ////////////////////////////////////////////////////////////////////
00529 void PNMImage::
00530 set_maxval(xelval maxval) {
00531   nassertv(maxval > 0);
00532 
00533   if (maxval != _maxval) {
00534     double ratio = (double)maxval / (double)_maxval;
00535 
00536     if (is_grayscale()) {
00537       for (int y = 0; y < get_y_size(); y++) {
00538         for (int x = 0; x < get_x_size(); x++) {
00539           set_gray_val(x, y, (xelval)((long)get_gray_val(x, y) * ratio));
00540         }
00541       }
00542     } else {
00543       for (int y = 0; y < get_y_size(); y++) {
00544         for (int x = 0; x < get_x_size(); x++) {
00545           set_red_val(x, y, (xelval)((long)get_red_val(x, y) * ratio));
00546           set_green_val(x, y, (xelval)((long)get_green_val(x, y) * ratio));
00547           set_blue_val(x, y, (xelval)((long)get_blue_val(x, y) * ratio));
00548         }
00549       }
00550     }
00551 
00552     if (has_alpha()) {
00553       for (int y = 0; y < get_y_size(); y++) {
00554         for (int x = 0; x < get_x_size(); x++) {
00555           set_alpha_val(x, y,
00556                         (xelval)((long)get_alpha_val(x, y) * ratio));
00557         }
00558       }
00559     }
00560     _maxval = maxval;
00561   }
00562 }
00563 
00564 ////////////////////////////////////////////////////////////////////
00565 //     Function: PNMImage::get_channel_val
00566 //       Access: Published
00567 //  Description: Returns the nth component color at the indicated
00568 //               pixel.  The channel index should be in the range
00569 //               0..(get_num_channels()-1).  The channels are ordered B,
00570 //               G, R, A.  This is slightly less optimal than
00571 //               accessing the component values directly by named
00572 //               methods.  The value returned is in the range
00573 //               0..maxval.
00574 ////////////////////////////////////////////////////////////////////
00575 xelval PNMImage::
00576 get_channel_val(int x, int y, int channel) const {
00577   switch (channel) {
00578   case 0:
00579     return get_blue_val(x, y);
00580 
00581   case 1:
00582     return (_num_channels == 2) ? get_alpha_val(x, y) : get_green_val(x, y);
00583 
00584   case 2:
00585     return get_red_val(x, y);
00586 
00587   case 3:
00588     return get_alpha_val(x, y);
00589 
00590   default:
00591     pnmimage_cat.error()
00592       << "Invalid request for channel " << channel << " in "
00593       << get_num_channels() << "-channel image.\n";
00594     nassertr(false, 0);
00595     return 0;
00596   }
00597 }
00598 
00599 ////////////////////////////////////////////////////////////////////
00600 //     Function: PNMImage::set_channel_val
00601 //       Access: Published
00602 //  Description: Sets the nth component color at the indicated
00603 //               pixel.  The channel index should be in the range
00604 //               0..(get_num_channels()-1).  The channels are ordered B,
00605 //               G, R, A.  This is slightly less optimal than
00606 //               setting the component values directly by named
00607 //               methods.  The value given should be in the range
00608 //               0..maxval.
00609 ////////////////////////////////////////////////////////////////////
00610 void PNMImage::
00611 set_channel_val(int x, int y, int channel, xelval value) {
00612   switch (channel) {
00613   case 0:
00614     set_blue_val(x, y, value);
00615     break;
00616 
00617   case 1:
00618     if (_num_channels == 2) {
00619       set_alpha_val(x, y, value);
00620     } else {
00621       set_green_val(x, y, value);
00622     }
00623     break;
00624 
00625   case 2:
00626     set_red_val(x, y, value);
00627     break;
00628 
00629   case 3:
00630     set_alpha_val(x, y, value);
00631     break;
00632 
00633   default:
00634     nassertv(false);
00635   }
00636 }
00637 
00638 ////////////////////////////////////////////////////////////////////
00639 //     Function: PNMImage::get_pixel
00640 //       Access: Published
00641 //  Description: Returns the (r, g, b, a) pixel value at the indicated
00642 //               pixel, using a PixelSpec object.
00643 ////////////////////////////////////////////////////////////////////
00644 PNMImage::PixelSpec PNMImage::
00645 get_pixel(int x, int y) const {
00646   switch (_num_channels) {
00647   case 1:
00648     return PixelSpec(get_gray_val(x, y));
00649   case 2:
00650     return PixelSpec(get_gray_val(x, y), get_alpha_val(x, y));
00651   case 3:
00652     return PixelSpec(get_xel_val(x, y));
00653   case 4:
00654     return PixelSpec(get_xel_val(x, y), get_alpha_val(x, y));
00655   }
00656 
00657   return PixelSpec(0);
00658 }
00659 
00660 ////////////////////////////////////////////////////////////////////
00661 //     Function: PNMImage::set_pixel
00662 //       Access: Published
00663 //  Description: Sets the (r, g, b, a) pixel value at the indicated
00664 //               pixel, using a PixelSpec object.
00665 ////////////////////////////////////////////////////////////////////
00666 void PNMImage::
00667 set_pixel(int x, int y, const PixelSpec &pixel) {
00668   xel p;
00669   PPM_ASSIGN(p, pixel._red, pixel._green, pixel._blue);
00670   set_xel_val(x, y, p);
00671   if (_alpha != NULL) {
00672     set_alpha_val(x, y, pixel._alpha);
00673   }
00674 }
00675 
00676 ////////////////////////////////////////////////////////////////////
00677 //     Function: PNMImage::blend
00678 //       Access: Published
00679 //  Description: Smoothly blends the indicated pixel value in with
00680 //               whatever was already in the image, based on the given
00681 //               alpha value.  An alpha of 1.0 is fully opaque and
00682 //               completely replaces whatever was there previously;
00683 //               alpha of 0.0 is fully transparent and does nothing.
00684 ////////////////////////////////////////////////////////////////////
00685 void PNMImage::
00686 blend(int x, int y, double r, double g, double b, double alpha) {
00687   if (alpha >= 1.0) {
00688     // Completely replace the previous color.
00689     if (has_alpha()) {
00690       set_alpha(x, y, 1.0);
00691     }
00692     set_xel(x, y, r, g, b);
00693 
00694   } else if (alpha > 0.0) {
00695     // Blend with the previous color.
00696     double prev_alpha = has_alpha() ? get_alpha(x, y) : 1.0;
00697 
00698     if (prev_alpha == 0.0) {
00699       // Nothing there previously; replace with this new color.
00700       set_alpha(x, y, alpha);
00701       set_xel(x, y, r, g, b);
00702 
00703     } else {
00704       // Blend the color with the previous color.
00705       LRGBColord prev_rgb = get_xel(x, y);
00706       r = r + (1.0 - alpha) * (get_red(x, y) - r);
00707       g = g + (1.0 - alpha) * (get_green(x, y) - g);
00708       b = b + (1.0 - alpha) * (get_blue(x, y) - b);
00709       alpha = prev_alpha + alpha * (1.0 - prev_alpha);
00710 
00711       if (has_alpha()) {
00712         set_alpha(x, y, alpha);
00713       }
00714       set_xel(x, y, r, g, b);
00715     }
00716   }
00717 }
00718 
00719 ////////////////////////////////////////////////////////////////////
00720 //     Function: PNMImage::copy_sub_image
00721 //       Access: Published
00722 //  Description: Copies a rectangular area of another image into a
00723 //               rectangular area of this image.  Both images must
00724 //               already have been initialized.  The upper-left corner
00725 //               of the region in both images is specified, and the
00726 //               size of the area; if the size is omitted, it defaults
00727 //               to the entire other image, or the largest piece that
00728 //               will fit.
00729 ////////////////////////////////////////////////////////////////////
00730 void PNMImage::
00731 copy_sub_image(const PNMImage &copy, int xto, int yto,
00732                int xfrom, int yfrom, int x_size, int y_size) {
00733   int xmin, ymin, xmax, ymax;
00734   setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
00735                   xmin, ymin, xmax, ymax);
00736 
00737   if (get_maxval() == copy.get_maxval()) {
00738     // The simple case: no pixel value rescaling is required.
00739     int x, y;
00740     for (y = ymin; y < ymax; y++) {
00741       for (x = xmin; x < xmax; x++) {
00742         set_xel_val(x, y, copy.get_xel_val(x - xmin + xfrom, y - ymin + yfrom));
00743       }
00744     }
00745 
00746     if (has_alpha() && copy.has_alpha()) {
00747       for (y = ymin; y < ymax; y++) {
00748         for (x = xmin; x < xmax; x++) {
00749           set_alpha_val(x, y, copy.get_alpha_val(x - xmin + xfrom, y - ymin + yfrom));
00750         }
00751       }
00752     }
00753 
00754   } else {
00755     // The harder case: rescale pixel values according to maxval.
00756     int x, y;
00757     for (y = ymin; y < ymax; y++) {
00758       for (x = xmin; x < xmax; x++) {
00759         set_xel(x, y, copy.get_xel(x - xmin + xfrom, y - ymin + yfrom));
00760       }
00761     }
00762 
00763     if (has_alpha() && copy.has_alpha()) {
00764       for (y = ymin; y < ymax; y++) {
00765         for (x = xmin; x < xmax; x++) {
00766           set_alpha(x, y, copy.get_alpha(x - xmin + xfrom, y - ymin + yfrom));
00767         }
00768       }
00769     }
00770   }
00771 }
00772 
00773 ////////////////////////////////////////////////////////////////////
00774 //     Function: PNMImage::blend_sub_image
00775 //       Access: Published
00776 //  Description: Behaves like copy_sub_image(), except the alpha
00777 //               channel of the copy is used to blend the copy into
00778 //               the destination image, instead of overwriting pixels
00779 //               unconditionally.
00780 //
00781 //               If pixel_scale is not 1.0, it specifies an amount to
00782 //               scale each *alpha* value of the source image before
00783 //               applying it to the target image.
00784 //
00785 //               If pixel_scale is 1.0 and the copy has no alpha
00786 //               channel, this degenerates into copy_sub_image().
00787 ////////////////////////////////////////////////////////////////////
00788 void PNMImage::
00789 blend_sub_image(const PNMImage &copy, int xto, int yto,
00790                 int xfrom, int yfrom, int x_size, int y_size,
00791                 double pixel_scale) {
00792   if (!copy.has_alpha() && pixel_scale == 1.0) {
00793     copy_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size);
00794     return;
00795   }
00796 
00797   int xmin, ymin, xmax, ymax;
00798   setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
00799                   xmin, ymin, xmax, ymax);
00800 
00801   int x, y;
00802   if (copy.has_alpha()) {
00803     for (y = ymin; y < ymax; y++) {
00804       for (x = xmin; x < xmax; x++) {
00805         blend(x, y, copy.get_xel(x - xmin + xfrom, y - ymin + yfrom),
00806               copy.get_alpha(x - xmin + xfrom, y - ymin + yfrom) * pixel_scale);
00807       }
00808     }
00809   } else {
00810     for (y = ymin; y < ymax; y++) {
00811       for (x = xmin; x < xmax; x++) {
00812         blend(x, y, copy.get_xel(x - xmin + xfrom, y - ymin + yfrom),
00813               pixel_scale);
00814       }
00815     }
00816   }
00817 }
00818 
00819 ////////////////////////////////////////////////////////////////////
00820 //     Function: PNMImage::darken_sub_image
00821 //       Access: Published
00822 //  Description: Behaves like copy_sub_image(), but the resulting
00823 //               color will be the darker of the source and
00824 //               destination colors at each pixel (and at each R, G,
00825 //               B, A component value).
00826 //
00827 //               If pixel_scale is not 1.0, it specifies an amount to
00828 //               scale each pixel value of the source image before
00829 //               applying it to the target image.  The scale is
00830 //               applied with the center at 1.0: scaling the pixel
00831 //               value smaller brings it closer to 1.0.
00832 ////////////////////////////////////////////////////////////////////
00833 void PNMImage::
00834 darken_sub_image(const PNMImage &copy, int xto, int yto,
00835                  int xfrom, int yfrom, int x_size, int y_size,
00836                  double pixel_scale) {
00837   int xmin, ymin, xmax, ymax;
00838   setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
00839                   xmin, ymin, xmax, ymax);
00840 
00841   if (get_maxval() == copy.get_maxval() && pixel_scale == 1.0) {
00842     // The simple case: no pixel value rescaling is required.
00843     int x, y;
00844     for (y = ymin; y < ymax; y++) {
00845       for (x = xmin; x < xmax; x++) {
00846         xel c = copy.get_xel_val(x - xmin + xfrom, y - ymin + yfrom);
00847         xel o = get_xel_val(x, y);
00848         xel p;
00849         PPM_ASSIGN(p, min(c.r, o.r), min(c.g, o.g), min(c.b, o.b));
00850         set_xel_val(x, y, p);
00851       }
00852     }
00853 
00854     if (has_alpha() && copy.has_alpha()) {
00855       for (y = ymin; y < ymax; y++) {
00856         for (x = xmin; x < xmax; x++) {
00857           xelval c = copy.get_alpha_val(x - xmin + xfrom, y - ymin + yfrom);
00858           xelval o = get_alpha_val(x, y);
00859           set_alpha_val(x, y, min(c, o));
00860         }
00861       }
00862     }
00863 
00864   } else {
00865     // The harder case: rescale pixel values according to maxval.
00866     int x, y;
00867     for (y = ymin; y < ymax; y++) {
00868       for (x = xmin; x < xmax; x++) {
00869         LRGBColord c = copy.get_xel(x - xmin + xfrom, y - ymin + yfrom);
00870         LRGBColord o = get_xel(x, y);
00871         LRGBColord p;
00872         p.set(min(1.0 - ((1.0 - c[0]) * pixel_scale), o[0]),
00873               min(1.0 - ((1.0 - c[1]) * pixel_scale), o[1]),
00874               min(1.0 - ((1.0 - c[2]) * pixel_scale), o[2]));
00875         set_xel(x, y, p);
00876       }
00877     }
00878 
00879     if (has_alpha() && copy.has_alpha()) {
00880       for (y = ymin; y < ymax; y++) {
00881         for (x = xmin; x < xmax; x++) {
00882           double c = copy.get_alpha(x - xmin + xfrom, y - ymin + yfrom);
00883           double o = get_alpha(x, y);
00884           set_alpha(x, y, min(1.0 - ((1.0 - c) * pixel_scale), o));
00885         }
00886       }
00887     }
00888   }
00889 }
00890 
00891 ////////////////////////////////////////////////////////////////////
00892 //     Function: PNMImage::lighten_sub_image
00893 //       Access: Published
00894 //  Description: Behaves like copy_sub_image(), but the resulting
00895 //               color will be the lighter of the source and
00896 //               destination colors at each pixel (and at each R, G,
00897 //               B, A component value).
00898 //
00899 //               If pixel_scale is not 1.0, it specifies an amount to
00900 //               scale each pixel value of the source image before
00901 //               applying it to the target image.
00902 ////////////////////////////////////////////////////////////////////
00903 void PNMImage::
00904 lighten_sub_image(const PNMImage &copy, int xto, int yto,
00905                   int xfrom, int yfrom, int x_size, int y_size,
00906                   double pixel_scale) {
00907   int xmin, ymin, xmax, ymax;
00908   setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
00909                   xmin, ymin, xmax, ymax);
00910 
00911   if (get_maxval() == copy.get_maxval() && pixel_scale == 1.0) {
00912     // The simple case: no pixel value rescaling is required.
00913     int x, y;
00914     for (y = ymin; y < ymax; y++) {
00915       for (x = xmin; x < xmax; x++) {
00916         xel c = copy.get_xel_val(x - xmin + xfrom, y - ymin + yfrom);
00917         xel o = get_xel_val(x, y);
00918         xel p;
00919         PPM_ASSIGN(p, max(c.r, o.r), max(c.g, o.g), max(c.b, o.b));
00920         set_xel_val(x, y, p);
00921       }
00922     }
00923 
00924     if (has_alpha() && copy.has_alpha()) {
00925       for (y = ymin; y < ymax; y++) {
00926         for (x = xmin; x < xmax; x++) {
00927           xelval c = copy.get_alpha_val(x - xmin + xfrom, y - ymin + yfrom);
00928           xelval o = get_alpha_val(x, y);
00929           set_alpha_val(x, y, max(c, o));
00930         }
00931       }
00932     }
00933 
00934   } else {
00935     // The harder case: rescale pixel values according to maxval.
00936     int x, y;
00937     for (y = ymin; y < ymax; y++) {
00938       for (x = xmin; x < xmax; x++) {
00939         LRGBColord c = copy.get_xel(x - xmin + xfrom, y - ymin + yfrom);
00940         LRGBColord o = get_xel(x, y);
00941         LRGBColord p;
00942         p.set(max(c[0] * pixel_scale, o[0]),
00943               max(c[1] * pixel_scale, o[1]),
00944               max(c[2] * pixel_scale, o[2]));
00945         set_xel(x, y, p);
00946       }
00947     }
00948 
00949     if (has_alpha() && copy.has_alpha()) {
00950       for (y = ymin; y < ymax; y++) {
00951         for (x = xmin; x < xmax; x++) {
00952           double c = copy.get_alpha(x - xmin + xfrom, y - ymin + yfrom);
00953           double o = get_alpha(x, y);
00954           set_alpha(x, y, max(c * pixel_scale, o));
00955         }
00956       }
00957     }
00958   }
00959 }
00960 
00961 ////////////////////////////////////////////////////////////////////
00962 //     Function: PNMImage::threshold
00963 //       Access: Published
00964 //  Description: Selectively copies each pixel from either one source
00965 //               or another source, depending on the pixel value of
00966 //               the indicated channel of select_image.
00967 //
00968 //               For each pixel (x, y):
00969 //
00970 //               s = select_image.get_channel(x, y). Set this image's
00971 //               (x, y) to:
00972 //
00973 //               lt.get_xel(x, y) if s <= threshold, or
00974 //
00975 //               ge.get_xel(x, y) if s > threshold
00976 //
00977 //               Any of select_image, lt, or ge may be the same
00978 //               PNMImge object as this image, or the same as each
00979 //               other; or they may all be different. All images must
00980 //               be the same size.
00981 ////////////////////////////////////////////////////////////////////
00982 void PNMImage::
00983 threshold(const PNMImage &select_image, int channel, double threshold,
00984           const PNMImage &lt, const PNMImage &ge) {
00985   nassertv(get_x_size() <= select_image.get_x_size() && get_y_size() <= select_image.get_y_size());
00986   nassertv(get_x_size() <= lt.get_x_size() && get_y_size() <= lt.get_y_size());
00987   nassertv(get_x_size() <= ge.get_x_size() && get_y_size() <= ge.get_y_size());
00988   nassertv(channel >= 0 && channel < select_image.get_num_channels());
00989 
00990   xelval threshold_val = (xelval)(select_image.get_maxval() * threshold + 0.5);
00991 
00992   if (get_maxval() == lt.get_maxval() && get_maxval() == ge.get_maxval()) {
00993     // Simple case: the maxvals are all equal.  Copy by integer value.
00994     int x, y;
00995 
00996     if (channel == 3) {
00997       // Further special case: the alpha channel.
00998       if (has_alpha() && lt.has_alpha() && ge.has_alpha()) {
00999         // Copy alpha channel too.
01000         for (y = 0; y < get_y_size(); y++) {
01001           for (x = 0; x < get_x_size(); x++) {
01002             if (select_image.get_alpha_val(x, y) < threshold_val) {
01003               set_xel_val(x, y, lt.get_xel_val(x, y));
01004               set_alpha_val(x, y, lt.get_alpha_val(x, y));
01005             } else {
01006               set_xel_val(x, y, ge.get_xel_val(x, y));
01007               set_alpha_val(x, y, ge.get_alpha_val(x, y));
01008             }
01009           }
01010         }
01011 
01012       } else {
01013         // Don't copy alpha channel.
01014         for (y = 0; y < get_y_size(); y++) {
01015           for (x = 0; x < get_x_size(); x++) {
01016             if (select_image.get_alpha_val(x, y) < threshold_val) {
01017               set_xel_val(x, y, lt.get_xel_val(x, y));
01018             } else {
01019               set_xel_val(x, y, ge.get_xel_val(x, y));
01020             }
01021           }
01022         }
01023       }
01024     } else {
01025       // Any generic channel.
01026       if (has_alpha() && lt.has_alpha() && ge.has_alpha()) {
01027         // Copy alpha channel too.
01028         for (y = 0; y < get_y_size(); y++) {
01029           for (x = 0; x < get_x_size(); x++) {
01030             if (select_image.get_channel_val(x, y, channel) < threshold_val) {
01031               set_xel_val(x, y, lt.get_xel_val(x, y));
01032               set_alpha_val(x, y, lt.get_alpha_val(x, y));
01033             } else {
01034               set_xel_val(x, y, ge.get_xel_val(x, y));
01035               set_alpha_val(x, y, ge.get_alpha_val(x, y));
01036             }
01037           }
01038         }
01039 
01040       } else {
01041         // Don't copy alpha channel.
01042         for (y = 0; y < get_y_size(); y++) {
01043           for (x = 0; x < get_x_size(); x++) {
01044             if (select_image.get_channel_val(x, y, channel) < threshold_val) {
01045               set_xel_val(x, y, lt.get_xel_val(x, y));
01046             } else {
01047               set_xel_val(x, y, ge.get_xel_val(x, y));
01048             }
01049           }
01050         }
01051       }
01052     }
01053 
01054   } else {
01055     // General case: the maxvals are different.  Copy by floating-point value.
01056     int x, y;
01057 
01058     if (has_alpha() && lt.has_alpha() && ge.has_alpha()) {
01059       for (y = 0; y < get_y_size(); y++) {
01060         for (x = 0; x < get_x_size(); x++) {
01061           if (select_image.get_channel_val(x, y, channel) < threshold_val) {
01062             set_xel(x, y, lt.get_xel(x, y));
01063             set_alpha(x, y, lt.get_alpha(x, y));
01064           } else {
01065             set_xel(x, y, ge.get_xel(x, y));
01066             set_alpha(x, y, ge.get_alpha(x, y));
01067           }
01068         }
01069       }
01070     } else {
01071       for (y = 0; y < get_y_size(); y++) {
01072         for (x = 0; x < get_x_size(); x++) {
01073           if (select_image.get_channel_val(x, y, channel) < threshold_val) {
01074             set_xel(x, y, lt.get_xel(x, y));
01075           } else {
01076             set_xel(x, y, ge.get_xel(x, y));
01077           }
01078         }
01079       }
01080     }
01081   }
01082 }
01083 
01084 ////////////////////////////////////////////////////////////////////
01085 //     Function: PNMImage::copy_channel
01086 //       Access: Published
01087 //  Description: Copies just a single channel from the source image
01088 //               into a single channel of this image, leaving the
01089 //               remaining channels alone.
01090 ////////////////////////////////////////////////////////////////////
01091 void PNMImage::
01092 copy_channel(const PNMImage &copy, int xto, int yto, int cto,
01093              int xfrom, int yfrom, int cfrom,
01094              int x_size, int y_size) {
01095   int xmin, ymin, xmax, ymax;
01096   setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
01097                   xmin, ymin, xmax, ymax);
01098 
01099   if (get_maxval() == copy.get_maxval()) {
01100     // The simple case: no pixel value rescaling is required.
01101     int x, y;
01102     for (y = ymin; y < ymax; y++) {
01103       if (cto == 3 && cfrom == 3) {
01104         // To alpha channel, from alpha channel.
01105         for (x = xmin; x < xmax; x++) {
01106           set_alpha_val(x, y, copy.get_alpha_val(x - xmin + xfrom, y - ymin + yfrom));
01107         }
01108       } else if (cto == 3 && cfrom == 0) {
01109         // To alpha channel, from blue (or gray) channel.
01110         for (x = xmin; x < xmax; x++) {
01111           set_alpha_val(x, y, copy.get_blue_val(x - xmin + xfrom, y - ymin + yfrom));
01112         }
01113       } else if (cto == 0 && cfrom == 3) {
01114         // To blue (or gray) channel, from alpha channel.
01115         for (x = xmin; x < xmax; x++) {
01116           set_blue_val(x, y, copy.get_alpha_val(x - xmin + xfrom, y - ymin + yfrom));
01117         }
01118       } else {
01119         // Generic channels.
01120         for (x = xmin; x < xmax; x++) {
01121           set_channel_val(x, y, cto, copy.get_channel_val(x - xmin + xfrom, y - ymin + yfrom, cfrom));
01122         }
01123       }
01124     }
01125 
01126   } else {
01127     // The harder case: rescale pixel values according to maxval.
01128     int x, y;
01129     for (y = ymin; y < ymax; y++) {
01130       for (x = xmin; x < xmax; x++) {
01131         set_channel(x, y, cto, copy.get_channel(x - xmin + xfrom, y - ymin + yfrom, cfrom));
01132       }
01133     }
01134   }
01135 }
01136 
01137 ////////////////////////////////////////////////////////////////////
01138 //     Function: PNMImage::render_spot
01139 //       Access: Published
01140 //  Description: Renders a solid-color circle, with a fuzzy edge, into
01141 //               the center of the PNMImage.  If the PNMImage is
01142 //               non-square, this actually renders an ellipse.
01143 //
01144 //               The min_radius and max_radius are in the scale 0..1,
01145 //               where 1.0 means the full width of the image.  If
01146 //               min_radius == max_radius, the edge is sharp (but
01147 //               still antialiased); otherwise, the pixels between
01148 //               min_radius and max_radius are smoothly blended
01149 //               between fg and bg colors.
01150 ////////////////////////////////////////////////////////////////////
01151 void PNMImage::
01152 render_spot(const LColord &fg, const LColord &bg,
01153             double min_radius, double max_radius) {
01154   if (_x_size == 0 || _y_size == 0) {
01155     return;
01156   }
01157 
01158   double x_scale = 2.0 / _x_size;
01159   double y_scale = 2.0 / _y_size;
01160 
01161   // If the width is even, x_center1 == x_center0.  If the width is
01162   // odd, x_center1 == x_center0 + 1.
01163   int x_center0 = _x_size / 2;
01164   int y_center0 = _y_size / 2;
01165   int x_center1 = (_x_size + 1) / 2;
01166   int y_center1 = (_y_size + 1) / 2;
01167 
01168   double min_r2 = min_radius * min_radius;
01169   double max_r2 = max_radius * max_radius;
01170 
01171   for (int yi = 0; yi < y_center1; ++yi) {
01172     double y = yi * y_scale;
01173     double y2_inner = y * y;
01174     double y2_outer = (y + y_scale) * (y + y_scale);
01175     for (int xi = 0; xi < x_center1; ++xi) {
01176       double x = xi * x_scale;
01177       double d2_inner = (x * x + y2_inner);
01178       double d2_outer = ((x + x_scale) * (x + x_scale) + y2_outer);
01179       double d2_a = ((x + x_scale) * (x + x_scale) + y2_inner);
01180       double d2_b = (x * x + y2_outer);
01181 
01182       if ((d2_inner <= min_r2) &&
01183           (d2_outer <= min_r2) &&
01184           (d2_a <= min_r2) &&
01185           (d2_b <= min_r2)) {
01186         // This pixel is solidly in the center of the spot.
01187         set_xel_a(x_center1 - 1 - xi, y_center1 - 1 - yi, fg);
01188         set_xel_a(x_center0 + xi, y_center1 - 1 - yi, fg);
01189         set_xel_a(x_center1 - 1 - xi, y_center0 + yi, fg);
01190         set_xel_a(x_center0 + xi, y_center0 + yi, fg);
01191 
01192       } else if ((d2_inner > max_r2) &&
01193                  (d2_outer > max_r2) &&
01194                  (d2_a > max_r2) &&
01195                  (d2_b > max_r2)) {
01196         // This pixel is solidly outside the spot.
01197         set_xel_a(x_center1 - 1 - xi, y_center1 - 1 - yi, bg);
01198         set_xel_a(x_center0 + xi, y_center1 - 1 - yi, bg);
01199         set_xel_a(x_center1 - 1 - xi, y_center0 + yi, bg);
01200         set_xel_a(x_center0 + xi, y_center0 + yi, bg);
01201 
01202       } else {
01203         // This pixel is in a feathered area or along the antialiased edge.
01204         LColord c_outer, c_inner, c_a, c_b;
01205         compute_spot_pixel(c_outer, d2_outer, min_radius, max_radius, fg, bg);
01206         compute_spot_pixel(c_inner, d2_inner, min_radius, max_radius, fg, bg);
01207         compute_spot_pixel(c_a, d2_a, min_radius, max_radius, fg, bg);
01208         compute_spot_pixel(c_b, d2_b, min_radius, max_radius, fg, bg);
01209 
01210         // Now average all four pixels for the antialiased result.
01211         LColord c;
01212         c = (c_outer + c_inner + c_a + c_b) * 0.25;
01213 
01214         set_xel_a(x_center1 - 1 - xi, y_center1 - 1 - yi, c);
01215         set_xel_a(x_center0 + xi, y_center1 - 1 - yi, c);
01216         set_xel_a(x_center1 - 1 - xi, y_center0 + yi, c);
01217         set_xel_a(x_center0 + xi, y_center0 + yi, c);
01218       }
01219     }
01220   }
01221 }
01222 
01223 ////////////////////////////////////////////////////////////////////
01224 //     Function: PNMImage::expand_border
01225 //       Access: Published
01226 //  Description: Expands the image by the indicated number of pixels
01227 //               on each edge.  The new pixels are set to the
01228 //               indicated color.
01229 //
01230 //               If any of the values is negative, this actually crops
01231 //               the image.
01232 ////////////////////////////////////////////////////////////////////
01233 void PNMImage::
01234 expand_border(int left, int right, int bottom, int top,
01235               const LColord &color) {
01236   PNMImage new_image(get_x_size() + left + right,
01237                      get_y_size() + bottom + top,
01238                      get_num_channels(), get_maxval(), get_type());
01239   new_image.fill(color[0], color[1], color[2]);
01240   if (has_alpha()) {
01241     new_image.alpha_fill(color[3]);
01242   }
01243   new_image.copy_sub_image(*this, left, top);
01244 
01245   take_from(new_image);
01246 }
01247 
01248 ////////////////////////////////////////////////////////////////////
01249 //     Function: PNMImage::make_histogram
01250 //       Access: Published
01251 //  Description: Computes a histogram of the colors used in the
01252 //               image.
01253 ////////////////////////////////////////////////////////////////////
01254 void PNMImage::
01255 make_histogram(PNMImage::Histogram &histogram) {
01256   HistMap hist_map;
01257   PixelCount pixels;
01258 
01259   int num_pixels = _x_size * _y_size;
01260 
01261   compute_histogram(hist_map, _array, _alpha);
01262 
01263   pixels.reserve(hist_map.size());
01264   HistMap::const_iterator hi;
01265   for (hi = hist_map.begin(); hi != hist_map.end(); ++hi) {
01266     if ((*hi).second <= num_pixels) {
01267       pixels.push_back(PixelSpecCount((*hi).first, (*hi).second));
01268     }
01269   }
01270   ::sort(pixels.begin(), pixels.end());
01271 
01272   histogram.swap(pixels, hist_map);
01273 }
01274 
01275 ////////////////////////////////////////////////////////////////////
01276 //     Function: PNMImage::perlin_noise_fill
01277 //       Access: Published
01278 //  Description: Fills the image with a grayscale perlin noise
01279 //               pattern based on the indicated parameters.
01280 //               Uses set_xel to set the grayscale values.
01281 //               The sx and sy parameters are in multiples
01282 //               of the size of this image.
01283 //               See also the PerlinNoise2 class in mathutil.
01284 ////////////////////////////////////////////////////////////////////
01285 void PNMImage::
01286 perlin_noise_fill(double sx, double sy, int table_size, unsigned long seed) {
01287   double x, y;
01288   double noise;
01289   PerlinNoise2 perlin (sx * _x_size, sy * _y_size, table_size, seed);
01290   for (x = 0; x < _x_size; ++x) {
01291     for (y = 0; y < _y_size; ++y) {
01292       noise = perlin.noise(x, y);
01293       set_xel(x, y, 0.5 * (noise + 1.0));
01294     }
01295   }
01296 }
01297 
01298 ////////////////////////////////////////////////////////////////////
01299 //     Function: PNMImage::perlin_noise_fill
01300 //       Access: Published
01301 //  Description: Variant of perlin_noise_fill that uses an
01302 //               existing StackedPerlinNoise2 object.
01303 ////////////////////////////////////////////////////////////////////
01304 void PNMImage::
01305 perlin_noise_fill(StackedPerlinNoise2 &perlin) {
01306   double x, y;
01307   double noise;
01308   for (x = 0; x < _x_size; ++x) {
01309     for (y = 0; y < _y_size; ++y) {
01310       noise = perlin.noise(x / (double) _x_size, y / (double) _y_size);
01311       set_xel(x, y, 0.5 * (noise + 1.0));
01312     }
01313   }
01314 }
01315 
01316 ////////////////////////////////////////////////////////////////////
01317 //     Function: PNMImage::remix_channels
01318 //       Access: Published
01319 //  Description: Transforms every pixel using the operation
01320 //               (Ro,Go,Bo) = conv.xform_point(Ri,Gi,Bi);
01321 //               Input must be a color image.
01322 ////////////////////////////////////////////////////////////////////
01323 void PNMImage::
01324 remix_channels(const LMatrix4 &conv) {
01325   int nchannels = get_num_channels();
01326   nassertv((nchannels >= 3) && (nchannels <= 4));
01327   for (int y = 0; y < get_y_size(); y++) {
01328     for (int x = 0; x < get_x_size(); x++) {
01329       LVector3 inv(get_red(x,y), get_green(x,y), get_blue(x,y));
01330       LVector3 outv(conv.xform_point(inv));
01331       set_xel(x, y, outv[0], outv[1], outv[2]);
01332     }
01333   }
01334 }
01335 
01336 ////////////////////////////////////////////////////////////////////
01337 //     Function: PNMImage::apply_exponent
01338 //       Access: Published
01339 //  Description: Adjusts each channel of the image by raising the
01340 //               corresponding component value to the indicated
01341 //               exponent, such that L' = L ^ exponent.  For a
01342 //               grayscale image, the blue_exponent value is used for
01343 //               the grayscale value, and red_exponent and
01344 //               green_exponent are unused.
01345 ////////////////////////////////////////////////////////////////////
01346 void PNMImage::
01347 apply_exponent(double red_exponent, double green_exponent, double blue_exponent, 
01348                double alpha_exponent) {
01349   int num_channels = _num_channels;
01350   if (has_alpha() && alpha_exponent == 1.0) {
01351     // If the alpha_exponent is 1, don't bother to apply it.
01352     --num_channels;
01353   }
01354 
01355   int x, y;
01356 
01357   if (red_exponent == 1.0 && green_exponent == 1.0 && blue_exponent == 1.0) {
01358     // If the RGB components are all 1, apply only to the alpha channel.
01359     switch (num_channels) {
01360     case 1:
01361     case 3:
01362       break;
01363 
01364     case 2:
01365     case 4:
01366       for (y = 0; y < _y_size; ++y) {
01367         for (x = 0; x < _x_size; ++x) {
01368           double alpha = get_alpha(x, y);
01369           alpha = cpow(alpha, blue_exponent);
01370           set_alpha(x, y, alpha);
01371         }
01372       }
01373       break;
01374     }
01375 
01376   } else {
01377     // Apply to the color and/or alpha channels.
01378 
01379     switch (num_channels) {
01380     case 1:
01381       for (y = 0; y < _y_size; ++y) {
01382         for (x = 0; x < _x_size; ++x) {
01383           double gray = get_gray(x, y);
01384           gray = cpow(gray, blue_exponent);
01385           set_gray(x, y, gray);
01386         }
01387       }
01388       break;
01389 
01390     case 2:
01391       for (y = 0; y < _y_size; ++y) {
01392         for (x = 0; x < _x_size; ++x) {
01393           double gray = get_gray(x, y);
01394           gray = cpow(gray, blue_exponent);
01395           set_gray(x, y, gray);
01396 
01397           double alpha = get_alpha(x, y);
01398           alpha = cpow(alpha, blue_exponent);
01399           set_alpha(x, y, alpha);
01400         }
01401       }
01402       break;
01403 
01404     case 3:
01405       for (y = 0; y < _y_size; ++y) {
01406         for (x = 0; x < _x_size; ++x) {
01407           LRGBColord color = get_xel(x, y);
01408           color[0] = cpow(color[0], red_exponent);
01409           color[1] = cpow(color[1], green_exponent);
01410           color[2] = cpow(color[2], blue_exponent);
01411           set_xel(x, y, color);
01412         }
01413       }
01414       break;
01415 
01416     case 4:
01417       for (y = 0; y < _y_size; ++y) {
01418         for (x = 0; x < _x_size; ++x) {
01419           LColord color = get_xel_a(x, y);
01420           color[0] = cpow(color[0], red_exponent);
01421           color[1] = cpow(color[1], green_exponent);
01422           color[2] = cpow(color[2], blue_exponent);
01423           color[3] = cpow(color[3], alpha_exponent);
01424           set_xel_a(x, y, color);
01425         }
01426       }
01427       break;
01428     }
01429   }
01430 }
01431 
01432 ////////////////////////////////////////////////////////////////////
01433 //     Function: PNMImage::setup_rc
01434 //       Access: Private
01435 //  Description: Sets the _default_rc,bc,gc values appropriately
01436 //               according to the color type of the image, so that
01437 //               get_bright() will return a meaningful value for both
01438 //               color and grayscale images.
01439 ////////////////////////////////////////////////////////////////////
01440 void PNMImage::
01441 setup_rc() {
01442   if (is_grayscale()) {
01443     _default_rc = 0.0;
01444     _default_gc = 0.0;
01445     _default_bc = 1.0;
01446   } else {
01447     _default_rc = lumin_red;
01448     _default_gc = lumin_grn;
01449     _default_bc = lumin_blu;
01450   }
01451 }
01452 
01453 ////////////////////////////////////////////////////////////////////
01454 //     Function: PNMImage::get_average_xel
01455 //       Access: Published
01456 //  Description: Returns the average color of all of the pixels
01457 //               in the image.
01458 ////////////////////////////////////////////////////////////////////
01459 LRGBColord PNMImage::
01460 get_average_xel() const {
01461   LRGBColord color (LRGBColord::zero());
01462   if (_x_size == 0 || _y_size == 0) {
01463     return color;
01464   }
01465 
01466   int x, y;
01467   for (x = 0; x < _x_size; ++x) {
01468     for (y = 0; y < _y_size; ++y) {
01469       color += get_xel(x, y);
01470     }
01471   }
01472 
01473   color *= 1.0 / (_x_size * _y_size);
01474   return color;
01475 }
01476 
01477 ////////////////////////////////////////////////////////////////////
01478 //     Function: PNMImage::get_average_xel_a
01479 //       Access: Published
01480 //  Description: Returns the average color of all of the pixels
01481 //               in the image, including the alpha channel.
01482 ////////////////////////////////////////////////////////////////////
01483 LColord PNMImage::
01484 get_average_xel_a() const {
01485   LColord color (LColord::zero());
01486   if (_x_size == 0 || _y_size == 0) {
01487     return color;
01488   }
01489 
01490   int x, y;
01491   for (x = 0; x < _x_size; ++x) {
01492     for (y = 0; y < _y_size; ++y) {
01493       color += get_xel_a(x, y);
01494     }
01495   }
01496 
01497   color *= 1.0 / (_x_size * _y_size);
01498   return color;
01499 }
01500 
01501 ////////////////////////////////////////////////////////////////////
01502 //     Function: PNMImage::get_average_gray
01503 //       Access: Published
01504 //  Description: Returns the average grayscale component of all of
01505 //               the pixels in the image.
01506 ////////////////////////////////////////////////////////////////////
01507 double PNMImage::
01508 get_average_gray() const {
01509   double color = 0.0;
01510   if (_x_size == 0 || _y_size == 0) {
01511     return color;
01512   }
01513 
01514   int x, y;
01515   for (x = 0; x < _x_size; ++x) {
01516     for (y = 0; y < _y_size; ++y) {
01517       color += get_gray(x, y);
01518     }
01519   }
01520 
01521   color *= 1.0 / (_x_size * _y_size);
01522   return color;
01523 }
01524 
01525 ////////////////////////////////////////////////////////////////////
01526 //     Function: PNMImage::operator ~
01527 //       Access: Published
01528 //  Description: Returns a new PNMImage that is the
01529 //               complement of the current PNMImage.
01530 ////////////////////////////////////////////////////////////////////
01531 PNMImage PNMImage::
01532 operator ~ () const {
01533   PNMImage target (*this);
01534   size_t array_size = _x_size * _y_size;
01535 
01536   if (_array != NULL && _alpha != NULL) {
01537     for (size_t i = 0; i < array_size; ++i) {
01538       target._array[i].r = _maxval - _array[i].r;
01539       target._array[i].g = _maxval - _array[i].g;
01540       target._array[i].b = _maxval - _array[i].b;
01541       target._alpha[i] = _maxval - _alpha[i];
01542     }
01543   } else if (_array != NULL) {
01544     for (size_t i = 0; i < array_size; ++i) {
01545       target._array[i].r = _maxval - _array[i].r;
01546       target._array[i].g = _maxval - _array[i].g;
01547       target._array[i].b = _maxval - _array[i].b;
01548     }
01549   } else if (_alpha != NULL) {
01550     for (size_t i = 0; i < array_size; ++i) {
01551       target._alpha[i] = _maxval - _alpha[i];
01552     }
01553   }
01554   return target;
01555 }
01556 
01557 ////////////////////////////////////////////////////////////////////
01558 //     Function: PNMImage::operator +=
01559 //       Access: Published
01560 //  Description: Returns a new PNMImage in which each pixel value
01561 //               is the sum of the corresponding pixel values
01562 //               in the two given images.
01563 //               Only valid when both images have the same size.
01564 ////////////////////////////////////////////////////////////////////
01565 void PNMImage::
01566 operator += (const PNMImage &other) {
01567   nassertv(_x_size == other._x_size && _y_size == other._y_size);
01568   nassertv(_maxval == other._maxval && _maxval == other._maxval);
01569   size_t array_size = _x_size * _y_size;
01570 
01571   if (_array != NULL && _alpha != NULL) {
01572     for (size_t i = 0; i < array_size; ++i) {
01573       _array[i].r = clamp_val(_array[i].r + other._array[i].r);
01574       _array[i].g = clamp_val(_array[i].g + other._array[i].g);
01575       _array[i].b = clamp_val(_array[i].b + other._array[i].b);
01576       _alpha[i] = clamp_val(_alpha[i] + other._alpha[i]);
01577     }
01578   } else if (_array != NULL) {
01579     for (size_t i = 0; i < array_size; ++i) {
01580       _array[i].r = clamp_val(_array[i].r + other._array[i].r);
01581       _array[i].g = clamp_val(_array[i].g + other._array[i].g);
01582       _array[i].b = clamp_val(_array[i].b + other._array[i].b);
01583     }
01584   } else if (_alpha != NULL) {
01585     for (size_t i = 0; i < array_size; ++i) {
01586       _alpha[i] = clamp_val(_alpha[i] + other._alpha[i]);
01587     }
01588   }
01589 }
01590 
01591 ////////////////////////////////////////////////////////////////////
01592 //     Function: PNMImage::operator +=
01593 //       Access: Published
01594 //  Description: Returns a new PNMImage in which the provided color
01595 //               is added to each pixel in the provided image.
01596 ////////////////////////////////////////////////////////////////////
01597 void PNMImage::
01598 operator += (const LColord &other) {
01599   size_t array_size = _x_size * _y_size;
01600   // Note: don't use to_val here because it clamps values below 0
01601   int add_r = (int)(other.get_x() * get_maxval() + 0.5);
01602   int add_g = (int)(other.get_y() * get_maxval() + 0.5);
01603   int add_b = (int)(other.get_z() * get_maxval() + 0.5);
01604   int add_a = (int)(other.get_w() * get_maxval() + 0.5);
01605 
01606   if (_array != NULL && _alpha != NULL) {
01607     for (size_t i = 0; i < array_size; ++i) {
01608       _array[i].r = clamp_val(_array[i].r + add_r);
01609       _array[i].g = clamp_val(_array[i].g + add_g);
01610       _array[i].b = clamp_val(_array[i].b + add_b);
01611       _alpha[i] = clamp_val(_alpha[i] + add_a);
01612     }
01613   } else if (_array != NULL) {
01614     for (size_t i = 0; i < array_size; ++i) {
01615       _array[i].r = clamp_val(_array[i].r + add_r);
01616       _array[i].g = clamp_val(_array[i].g + add_g);
01617       _array[i].b = clamp_val(_array[i].b + add_b);
01618     }
01619   } else if (_alpha != NULL) {
01620     for (size_t i = 0; i < array_size; ++i) {
01621       _alpha[i] = clamp_val(_alpha[i] + add_a);
01622     }
01623   }
01624 }
01625 
01626 ////////////////////////////////////////////////////////////////////
01627 //     Function: PNMImage::operator -=
01628 //       Access: Published
01629 //  Description: Returns a new PNMImage in which each pixel value
01630 //               from the right image is subtracted from each
01631 //               pixel value from the left image.
01632 //               Only valid when both images have the same size.
01633 ////////////////////////////////////////////////////////////////////
01634 void PNMImage::
01635 operator -= (const PNMImage &other) {
01636   nassertv(_x_size == other._x_size && _y_size == other._y_size);
01637   nassertv(_maxval == other._maxval && _maxval == other._maxval);
01638   size_t array_size = _x_size * _y_size;
01639 
01640   if (_array != NULL && _alpha != NULL) {
01641     for (size_t i = 0; i < array_size; ++i) {
01642       _array[i].r = clamp_val(_array[i].r - other._array[i].r);
01643       _array[i].g = clamp_val(_array[i].g - other._array[i].g);
01644       _array[i].b = clamp_val(_array[i].b - other._array[i].b);
01645       _alpha[i] = clamp_val(_alpha[i] - other._alpha[i]);
01646     }
01647   } else if (_array != NULL) {
01648     for (size_t i = 0; i < array_size; ++i) {
01649       _array[i].r = clamp_val(_array[i].r - other._array[i].r);
01650       _array[i].g = clamp_val(_array[i].g - other._array[i].g);
01651       _array[i].b = clamp_val(_array[i].b - other._array[i].b);
01652     }
01653   } else if (_alpha != NULL) {
01654     for (size_t i = 0; i < array_size; ++i) {
01655       _alpha[i] = clamp_val(_alpha[i] - other._alpha[i]);
01656     }
01657   }
01658 }
01659 
01660 ////////////////////////////////////////////////////////////////////
01661 //     Function: PNMImage::operator -=
01662 //       Access: Published
01663 //  Description: Returns a new PNMImage in which the provided color
01664 //               is subtracted from each pixel in the provided image.
01665 ////////////////////////////////////////////////////////////////////
01666 void PNMImage::
01667 operator -= (const LColord &other) {
01668   (*this) += (-other);
01669 }
01670 
01671 ////////////////////////////////////////////////////////////////////
01672 //     Function: PNMImage::operator *=
01673 //       Access: Published
01674 //  Description: Returns a new PNMImage in which each pixel value
01675 //               from the left image is multiplied by each
01676 //               pixel value from the right image. Note that the
01677 //               floating-point values in the 0..1 range are
01678 //               multiplied, not in the 0..maxval range.
01679 //               Only valid when both images have the same size.
01680 ////////////////////////////////////////////////////////////////////
01681 void PNMImage::
01682 operator *= (const PNMImage &other) {
01683   nassertv(_x_size == other._x_size && _y_size == other._y_size);
01684   size_t array_size = _x_size * _y_size;
01685 
01686   if (_array != NULL && _alpha != NULL) {
01687     for (size_t i = 0; i < array_size; ++i) {
01688       _array[i].r = to_val(from_val(_array[i].r) * other.from_val(other._array[i].r));
01689       _array[i].g = to_val(from_val(_array[i].g) * other.from_val(other._array[i].g));
01690       _array[i].b = to_val(from_val(_array[i].b) * other.from_val(other._array[i].b));
01691       _alpha[i] = to_val(from_val(_alpha[i]) * other.from_val(other._alpha[i]));
01692     }
01693   } else if (_array != NULL) {
01694     for (size_t i = 0; i < array_size; ++i) {
01695       _array[i].r = to_val(from_val(_array[i].r) * other.from_val(other._array[i].r));
01696       _array[i].g = to_val(from_val(_array[i].g) * other.from_val(other._array[i].g));
01697       _array[i].b = to_val(from_val(_array[i].b) * other.from_val(other._array[i].b));
01698     }
01699   } else if (_alpha != NULL) {
01700     for (size_t i = 0; i < array_size; ++i) {
01701       _alpha[i] = to_val(from_val(_alpha[i]) * other.from_val(other._alpha[i]));
01702     }
01703   }
01704 }
01705 
01706 ////////////////////////////////////////////////////////////////////
01707 //     Function: PNMImage::operator *=
01708 //       Access: Published
01709 //  Description: Multiplies every pixel value in the image by
01710 //               a constant floating-point multiplier value.
01711 ////////////////////////////////////////////////////////////////////
01712 void PNMImage::
01713 operator *= (double multiplier) {
01714   size_t array_size = _x_size * _y_size;
01715 
01716   if (_array != NULL && _alpha != NULL) {
01717     for (size_t i = 0; i < array_size; ++i) {
01718       _array[i].r = clamp_val(_array[i].r * multiplier);
01719       _array[i].g = clamp_val(_array[i].g * multiplier);
01720       _array[i].b = clamp_val(_array[i].b * multiplier);
01721       _alpha[i] = clamp_val(_alpha[i] * multiplier);
01722     }
01723   } else if (_array != NULL) {
01724     for (size_t i = 0; i < array_size; ++i) {
01725       _array[i].r = clamp_val(_array[i].r * multiplier);
01726       _array[i].g = clamp_val(_array[i].g * multiplier);
01727       _array[i].b = clamp_val(_array[i].b * multiplier);
01728     }
01729   } else if (_alpha != NULL) {
01730     for (size_t i = 0; i < array_size; ++i) {
01731       _alpha[i] = clamp_val(_alpha[i] * multiplier);
01732     }
01733   }
01734 }
01735 
 All Classes Functions Variables Enumerations