Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/pnmimage/pnmImage.cxx

Go to the documentation of this file.
00001 // Filename: pnmImage.cxx
00002 // Created by:  drose (14Jun00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "pnmImage.h"
00020 #include "pnmReader.h"
00021 #include "pnmWriter.h"
00022 #include "config_pnmimage.h"
00023 
00024 ////////////////////////////////////////////////////////////////////
00025 //     Function: PNMImage::clear
00026 //       Access: Public
00027 //  Description: Frees all memory allocated for the image, and clears
00028 //               all its parameters (size, color, type, etc).
00029 ////////////////////////////////////////////////////////////////////
00030 void PNMImage::
00031 clear() {
00032   if (_array != (xel *)NULL) {
00033     delete[] _array;
00034     _array = (xel *)NULL;
00035   }
00036   if (_alpha != (xelval *)NULL) {
00037     delete[] _alpha;
00038     _alpha = (xelval *)NULL;
00039   }
00040   _x_size = 0;
00041   _y_size = 0;
00042   _num_channels = 0;
00043   _maxval = 255;
00044   _type = (PNMFileType *)NULL;
00045 }
00046 
00047 ////////////////////////////////////////////////////////////////////
00048 //     Function: PNMImage::clear
00049 //       Access: Public
00050 //  Description: This flavor of clear() reinitializes the image to an
00051 //               empty (black) image with the given dimensions.
00052 ////////////////////////////////////////////////////////////////////
00053 void PNMImage::
00054 clear(int x_size, int y_size, int num_channels,
00055       xelval maxval, PNMFileType *type) {
00056   clear();
00057   nassertv(num_channels >= 1 && num_channels <= 4);
00058 
00059   _x_size = x_size;
00060   _y_size = y_size;
00061   _num_channels = num_channels;
00062   _maxval = maxval;
00063   _type = type;
00064 
00065   if (has_alpha()) {
00066     allocate_alpha();
00067     memset(_alpha, 0, sizeof(xelval) * _y_size * _x_size);
00068   }
00069 
00070   allocate_array();
00071   memset(_array, 0, sizeof(xel) * _y_size * _x_size);
00072 
00073   setup_rc();
00074 }
00075 
00076 ////////////////////////////////////////////////////////////////////
00077 //     Function: PNMImage::copy_from
00078 //       Access: Public
00079 //  Description: Makes this image become a copy of the other image.
00080 ////////////////////////////////////////////////////////////////////
00081 void PNMImage::
00082 copy_from(const PNMImage &copy) {
00083   clear();
00084 
00085   if (copy.is_valid()) {
00086     copy_header_from(copy);
00087 
00088     if (has_alpha()) {
00089       memcpy(_alpha, copy._alpha, sizeof(xelval) * _y_size * _x_size);
00090     }
00091     memcpy(_array, copy._array, sizeof(xel) * _y_size * _x_size);
00092   }
00093 }
00094 
00095 ////////////////////////////////////////////////////////////////////
00096 //     Function: PNMImage::copy_header_from
00097 //       Access: Public
00098 //  Description: Copies just the header information into this image.
00099 //               This will blow away any image data stored in the
00100 //               image.  The new image data will be allocated, but
00101 //               left unitialized.
00102 ////////////////////////////////////////////////////////////////////
00103 void PNMImage::
00104 copy_header_from(const PNMImageHeader &header) {
00105   clear();
00106   PNMImageHeader::operator = (header);
00107 
00108   if (has_alpha()) {
00109     allocate_alpha();
00110   }
00111 
00112   allocate_array();
00113   setup_rc();
00114 }
00115 
00116 ////////////////////////////////////////////////////////////////////
00117 //     Function: PNMImage::fill_val
00118 //       Access: Public
00119 //  Description: Sets the entire image (except the alpha channel) to
00120 //               the given color.
00121 ////////////////////////////////////////////////////////////////////
00122 void PNMImage::
00123 fill_val(xelval red, xelval green, xelval blue) {
00124   if (is_valid()) {
00125     for (int y = 0; y < get_y_size(); y++) {
00126       for (int x = 0; x < get_x_size(); x++) {
00127         set_xel_val(x, y, red, green, blue);
00128       }
00129     }
00130   }
00131 }
00132 
00133 ////////////////////////////////////////////////////////////////////
00134 //     Function: PNMImage::alpha_fill_val
00135 //       Access: Public
00136 //  Description: Sets the entire alpha channel to the given level.
00137 ////////////////////////////////////////////////////////////////////
00138 void PNMImage::
00139 alpha_fill_val(xelval alpha) {
00140   if (is_valid()) {
00141     if (!has_alpha()) {
00142       add_alpha();
00143     }
00144 
00145     for (int y = 0; y < get_y_size(); y++) {
00146       for (int x = 0; x < get_x_size(); x++) {
00147         set_alpha_val(x, y, alpha);
00148       }
00149     }
00150   }
00151 }
00152 
00153 ////////////////////////////////////////////////////////////////////
00154 //     Function: PNMImage::read
00155 //       Access: Public
00156 //  Description: Reads the indicated image filename.  If type is
00157 //               non-NULL, it is a suggestion for the type of file it
00158 //               is.  Returns true if successful, false on error.
00159 ////////////////////////////////////////////////////////////////////
00160 bool PNMImage::
00161 read(const Filename &filename, PNMFileType *type) {
00162   clear();
00163 
00164   PNMReader *reader = PNMImageHeader::make_reader(filename, type);
00165   if (reader == (PNMReader *)NULL) {
00166     return false;
00167   }
00168   return read(reader);
00169 }
00170 
00171 ////////////////////////////////////////////////////////////////////
00172 //     Function: PNMImage::read
00173 //       Access: Public
00174 //  Description: This flavor of read() uses an already-existing
00175 //               PNMReader to read the image file.  You can get a
00176 //               reader via the PNMImageHeader::make_reader() methods.
00177 //               This is a good way to examine the header of a file
00178 //               (for instance, to determine its size) before actually
00179 //               reading the entire image.
00180 //
00181 //               The PNMReader is always deleted upon completion,
00182 //               whether succesful or not.
00183 ////////////////////////////////////////////////////////////////////
00184 bool PNMImage::
00185 read(PNMReader *reader) {
00186   clear();
00187 
00188   if (reader == NULL) {
00189     return false;
00190   }
00191 
00192   if (!reader->is_valid()) {
00193     delete reader;
00194     return false;
00195   }
00196 
00197   copy_header_from(*reader);
00198   _type = reader->get_type();
00199 
00200   // We reassign y_size after reading because we might have read a
00201   // truncated file.
00202   _y_size = reader->read_data(_array, _alpha);
00203   delete reader;
00204 
00205   if (_y_size == 0) {
00206     clear();
00207     return false;
00208   } else {
00209     setup_rc();
00210     return true;
00211   }
00212 }
00213 
00214 ////////////////////////////////////////////////////////////////////
00215 //     Function: PNMImage::write
00216 //       Access: Public
00217 //  Description: Writes the image to the indicated filename.  If type
00218 //               is non-NULL, it is a suggestion for the type of image
00219 //               file to write.
00220 ////////////////////////////////////////////////////////////////////
00221 bool PNMImage::
00222 write(const Filename &filename, PNMFileType *type) const {
00223   if (!is_valid()) {
00224     return false;
00225   }
00226 
00227   PNMWriter *writer = PNMImageHeader::make_writer(filename, type);
00228   if (writer == (PNMWriter *)NULL) {
00229     return false;
00230   }
00231 
00232   return write(writer);
00233 }
00234 
00235 ////////////////////////////////////////////////////////////////////
00236 //     Function: PNMImage::write
00237 //       Access: Public
00238 //  Description: This flavor of write() uses an already-existing
00239 //               PNMWriter to write the image file.  You can get a
00240 //               writer via the PNMImageHeader::make_writer() methods.
00241 //
00242 //               The PNMWriter is always deleted upon completion,
00243 //               whether succesful or not.
00244 ////////////////////////////////////////////////////////////////////
00245 bool PNMImage::
00246 write(PNMWriter *writer) const {
00247   if (writer == NULL) {
00248     return false;
00249   }
00250 
00251   if (!is_valid()) {
00252     delete writer;
00253     return false;
00254   }
00255 
00256   writer->copy_header_from(*this);
00257   int result = writer->write_data(_array, _alpha);
00258   delete writer;
00259 
00260   return (result == _y_size);
00261 }
00262 
00263 
00264 
00265 ////////////////////////////////////////////////////////////////////
00266 //     Function: PNMImage::set_color_type
00267 //       Access: Public
00268 //  Description: Translates the image to or from grayscale, color, or
00269 //               four-color mode.  Grayscale images are converted to
00270 //               full-color images with R, G, B set to the original
00271 //               gray level; color images are converted to grayscale
00272 //               according to the value of Bright().  The alpha
00273 //               channel, if added, is initialized to zero.
00274 ////////////////////////////////////////////////////////////////////
00275 void PNMImage::
00276 set_color_type(PNMImage::ColorType color_type) {
00277   nassertv((int)color_type >= 1 && (int)color_type <= 4);
00278   if (color_type == get_color_type()) {
00279     return;
00280   }
00281 
00282   if (!is_grayscale() && is_grayscale(color_type)) {
00283     // convert to grayscale from color
00284     for (int y = 0; y < get_y_size(); y++) {
00285       for (int x = 0; x < get_x_size(); x++) {
00286         set_gray(x, y, get_bright(x, y));
00287       }
00288     }
00289 
00290   } else if (is_grayscale() && !is_grayscale(color_type)) {
00291     // convert to color from grayscale
00292     for (int y = 0; y < get_y_size(); y++) {
00293       for (int x = 0; x<get_x_size(); x++) {
00294         set_xel_val(x, y, get_gray_val(x, y));
00295       }
00296     }
00297   }
00298 
00299   if (has_alpha() && !has_alpha(color_type)) {
00300     // discard the alpha channel
00301     if (_alpha!=NULL) {
00302       delete[] _alpha;
00303       _alpha = NULL;
00304     }
00305 
00306   } else if (!has_alpha() && has_alpha(color_type)) {
00307     // create a new alpha channel
00308     allocate_alpha();
00309     memset(_alpha, 0, sizeof(xelval) * (_x_size * _y_size));
00310   }
00311 
00312   _num_channels = (int)color_type;
00313   setup_rc();
00314 }
00315 
00316 ////////////////////////////////////////////////////////////////////
00317 //     Function: PNMImage::make_grayscale
00318 //       Access: Public
00319 //  Description: Converts the image from RGB to grayscale.  Any alpha
00320 //               channel, if present, is left undisturbed.  The
00321 //               optional rc, gc, bc values represent the relative
00322 //               weights to apply to each channel to convert it to
00323 //               grayscale.
00324 ////////////////////////////////////////////////////////////////////
00325 void PNMImage::
00326 make_grayscale(double rc, double gc, double bc) {
00327   if (is_grayscale()) {
00328     return;
00329   }
00330 
00331   for (int y = 0; y < get_y_size(); y++) {
00332     for (int x = 0; x < get_x_size(); x++) {
00333       set_gray(x, y, min(get_bright(x, y, rc, gc, bc), 1.0));
00334     }
00335   }
00336 
00337   _num_channels = has_alpha() ? 2 : 1;
00338   setup_rc();
00339 }
00340 
00341 ////////////////////////////////////////////////////////////////////
00342 //     Function: PNMImage::set_maxval
00343 //       Access: Public
00344 //  Description: Rescales the image to the indicated maxval.
00345 ////////////////////////////////////////////////////////////////////
00346 void PNMImage::
00347 set_maxval(xelval maxval) {
00348   nassertv(maxval > 0.0);
00349 
00350   if (maxval != _maxval) {
00351     double ratio = maxval / _maxval;
00352 
00353     if (is_grayscale()) {
00354       for (int y = 0; y < get_y_size(); y++) {
00355         for (int x = 0; x < get_x_size(); x++) {
00356           set_gray_val(x, y, (xelval)((long)get_gray_val(x, y) * ratio));
00357         }
00358       }
00359     } else {
00360       for (int y = 0; y < get_y_size(); y++) {
00361         for (int x = 0; x < get_x_size(); x++) {
00362           set_red_val(x, y, (xelval)((long)get_red_val(x, y) * ratio));
00363           set_green_val(x, y, (xelval)((long)get_green_val(x, y) * ratio));
00364           set_blue_val(x, y, (xelval)((long)get_blue_val(x, y) * ratio));
00365         }
00366       }
00367     }
00368 
00369     if (has_alpha()) {
00370       for (int y = 0; y < get_y_size(); y++) {
00371         for (int x = 0; x < get_x_size(); x++) {
00372           set_alpha_val(x, y,
00373                         (xelval)((long)get_alpha_val(x, y) * ratio));
00374         }
00375       }
00376     }
00377     _maxval = maxval;
00378   }
00379 }
00380 
00381 ////////////////////////////////////////////////////////////////////
00382 //     Function: PNMImage::get_channel_val
00383 //       Access: Public
00384 //  Description: Returns the nth component color at the indicated
00385 //               pixel.  The channel index should be in the range
00386 //               0..(get_num_channels()-1).  The channels are ordered B,
00387 //               G, R, A.  This is slightly less optimal than
00388 //               accessing the component values directly by named
00389 //               methods.  The value returned is in the range
00390 //               0..maxval.
00391 ////////////////////////////////////////////////////////////////////
00392 xelval PNMImage::
00393 get_channel_val(int x, int y, int channel) const {
00394   switch (channel) {
00395   case 0:
00396     return get_blue_val(x, y);
00397 
00398   case 1:
00399     return (_num_channels == 2) ? get_alpha_val(x, y) : get_green_val(x, y);
00400 
00401   case 2:
00402     return get_red_val(x, y);
00403 
00404   case 3:
00405     return get_alpha_val(x, y);
00406 
00407   default:
00408     pnmimage_cat.error()
00409       << "Invalid request for channel " << channel << " in "
00410       << get_num_channels() << "-channel image.\n";
00411     nassertr(false, 0);
00412     return 0;
00413   }
00414 }
00415 
00416 ////////////////////////////////////////////////////////////////////
00417 //     Function: PNMImage::set_channel_val
00418 //       Access: Public
00419 //  Description: Sets the nth component color at the indicated
00420 //               pixel.  The channel index should be in the range
00421 //               0..(get_num_channels()-1).  The channels are ordered B,
00422 //               G, R, A.  This is slightly less optimal than
00423 //               setting the component values directly by named
00424 //               methods.  The value given should be in the range
00425 //               0..maxval.
00426 ////////////////////////////////////////////////////////////////////
00427 void PNMImage::
00428 set_channel_val(int x, int y, int channel, xelval value) {
00429   switch (channel) {
00430   case 0:
00431     set_blue_val(x, y, value);
00432     break;
00433 
00434   case 1:
00435     if (_num_channels == 2) {
00436       set_alpha_val(x, y, value);
00437     } else {
00438       set_green_val(x, y, value);
00439     }
00440     break;
00441 
00442   case 2:
00443     set_red_val(x, y, value);
00444     break;
00445 
00446   case 3:
00447     set_alpha_val(x, y, value);
00448     break;
00449 
00450   default:
00451     nassertv(false);
00452   }
00453 }
00454 
00455 ////////////////////////////////////////////////////////////////////
00456 //     Function: PNMImage::blend
00457 //       Access: Public
00458 //  Description: Smoothly blends the indicated pixel value in with
00459 //               whatever was already in the image, based on the given
00460 //               alpha value.  An alpha of 1.0 is fully opaque and
00461 //               completely replaces whatever was there previously;
00462 //               alpha of 0.0 is fully transparent and does nothing.
00463 ////////////////////////////////////////////////////////////////////
00464 void PNMImage::
00465 blend(int x, int y, double r, double g, double b, double alpha) {
00466   if (alpha >= 1.0) {
00467     // Completely replace the previous color.
00468     if (has_alpha()) {
00469       set_alpha(x, y, 1.0);
00470     }
00471     set_xel(x, y, r, g, b);
00472 
00473   } else if (alpha > 0.0) {
00474     // Blend with the previous color.
00475     double prev_alpha = has_alpha() ? get_alpha(x, y) : 1.0;
00476 
00477     if (prev_alpha == 0.0) {
00478       // Nothing there previously; replace with this new color.
00479       set_alpha(x, y, alpha);
00480       set_xel(x, y, r, g, b);
00481 
00482     } else {
00483       // Blend the color with the previous color.
00484       RGBColord prev_rgb = get_xel(x, y);
00485       r = r + (1.0 - alpha) * (get_red(x, y) - r);
00486       g = g + (1.0 - alpha) * (get_green(x, y) - g);
00487       b = b + (1.0 - alpha) * (get_blue(x, y) - b);
00488       alpha = prev_alpha + alpha * (1.0 - prev_alpha);
00489 
00490       if (has_alpha()) {
00491         set_alpha(x, y, alpha);
00492       }
00493       set_xel(x, y, r, g, b);
00494     }
00495   }
00496 }
00497 
00498 ////////////////////////////////////////////////////////////////////
00499 //     Function: PNMImage::copy_sub_image
00500 //       Access: Public
00501 //  Description: Copies a rectangular area of another image into a
00502 //               rectangular area of this image.  Both images must
00503 //               already have been initialized.  The upper-left corner
00504 //               of the region in both images is specified, and the
00505 //               size of the area; if the size is omitted, it defaults
00506 //               to the entire other image, or the largest piece that
00507 //               will fit.
00508 ////////////////////////////////////////////////////////////////////
00509 void PNMImage::
00510 copy_sub_image(const PNMImage &copy, int xto, int yto,
00511                int xfrom, int yfrom, int x_size, int y_size) {
00512   if (xfrom < 0) {
00513     xto += -xfrom;
00514     xfrom = 0;
00515   }
00516   if (yfrom < 0) {
00517     yto += -yfrom;
00518     yfrom = 0;
00519   }
00520 
00521   x_size = (x_size < 0) ?
00522     copy.get_x_size() :
00523     min(x_size, copy.get_x_size() - xfrom);
00524   y_size = (y_size < 0) ?
00525     copy.get_y_size() :
00526     min(y_size, copy.get_y_size() - yfrom);
00527 
00528   int xmin = max(0, xto);
00529   int ymin = max(0, yto);
00530 
00531   int xmax = min(xmin + x_size, get_x_size());
00532   int ymax = min(ymin + y_size, get_y_size());
00533 
00534   int x, y;
00535   for (y = ymin; y < ymax; y++) {
00536     for (x = xmin; x < xmax; x++) {
00537       set_xel(x, y, copy.get_xel(x - xmin + xfrom, y - ymin + yfrom));
00538     }
00539   }
00540 
00541   if (has_alpha() && copy.has_alpha()) {
00542     for (y = ymin; y < ymax; y++) {
00543       for (x = xmin; x < xmax; x++) {
00544         set_alpha(x, y, copy.get_alpha(x - xmin + xfrom, y - ymin + yfrom));
00545       }
00546     }
00547   }
00548 }
00549 
00550 
00551 ////////////////////////////////////////////////////////////////////
00552 //     Function: PNMImage::setup_rc
00553 //       Access: Public
00554 //  Description: Sets the _default_rc,bc,gc values appropriately
00555 //               according to the color type of the image, so that
00556 //               get_bright() will return a meaningful value for both
00557 //               color and grayscale images.
00558 ////////////////////////////////////////////////////////////////////
00559 void PNMImage::
00560 setup_rc() {
00561   if (is_grayscale()) {
00562     _default_rc = 0.0;
00563     _default_gc = 0.0;
00564     _default_bc = 1.0;
00565   } else {
00566     _default_rc = lumin_red;
00567     _default_gc = lumin_grn;
00568     _default_bc = lumin_blu;
00569   }
00570 }

Generated on Fri May 2 00:43:08 2003 for Panda by doxygen1.3