00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00026
00027
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
00044
00045
00046
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
00069
00070
00071
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
00100
00101
00102
00103 void PNMImage::
00104 copy_from(const PNMImage ©) {
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
00118
00119
00120
00121
00122 void PNMImage::
00123 copy_channel(const PNMImage ©, int src_channel, int dest_channel) {
00124
00125 nassertv(src_channel >= 0 && src_channel <= 3);
00126 nassertv(dest_channel >= 0 && dest_channel <= 3);
00127
00128 if (!copy.is_valid() || !is_valid()) {
00129 pnmimage_cat.error() << "One of the images is invalid!\n";
00130 return;
00131 }
00132
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
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
00151
00152
00153
00154
00155
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
00172
00173
00174
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
00194
00195
00196
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
00211
00212
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
00231
00232
00233
00234
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
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
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
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
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
00311
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
00324
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
00336
00337
00338
00339
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
00357
00358
00359
00360
00361
00362
00363
00364
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
00383
00384
00385
00386
00387
00388
00389
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
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
00422
00423
00424
00425
00426
00427
00428
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
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
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
00456 if (_alpha!=NULL) {
00457 PANDA_FREE_ARRAY(_alpha);
00458 _alpha = NULL;
00459 }
00460
00461 } else if (!has_alpha() && has_alpha(color_type)) {
00462
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
00473
00474
00475
00476
00477
00478
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
00498
00499
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
00526
00527
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
00566
00567
00568
00569
00570
00571
00572
00573
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
00601
00602
00603
00604
00605
00606
00607
00608
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
00640
00641
00642
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
00662
00663
00664
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
00678
00679
00680
00681
00682
00683
00684
00685 void PNMImage::
00686 blend(int x, int y, double r, double g, double b, double alpha) {
00687 if (alpha >= 1.0) {
00688
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
00696 double prev_alpha = has_alpha() ? get_alpha(x, y) : 1.0;
00697
00698 if (prev_alpha == 0.0) {
00699
00700 set_alpha(x, y, alpha);
00701 set_xel(x, y, r, g, b);
00702
00703 } else {
00704
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
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730 void PNMImage::
00731 copy_sub_image(const PNMImage ©, 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
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
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
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788 void PNMImage::
00789 blend_sub_image(const PNMImage ©, 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
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833 void PNMImage::
00834 darken_sub_image(const PNMImage ©, 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
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
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
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903 void PNMImage::
00904 lighten_sub_image(const PNMImage ©, 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
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
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
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982 void PNMImage::
00983 threshold(const PNMImage &select_image, int channel, double threshold,
00984 const PNMImage <, 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
00994 int x, y;
00995
00996 if (channel == 3) {
00997
00998 if (has_alpha() && lt.has_alpha() && ge.has_alpha()) {
00999
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
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
01026 if (has_alpha() && lt.has_alpha() && ge.has_alpha()) {
01027
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
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
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
01086
01087
01088
01089
01090
01091 void PNMImage::
01092 copy_channel(const PNMImage ©, 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
01101 int x, y;
01102 for (y = ymin; y < ymax; y++) {
01103 if (cto == 3 && cfrom == 3) {
01104
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
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
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
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
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
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
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
01162
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
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
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
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
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
01225
01226
01227
01228
01229
01230
01231
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
01250
01251
01252
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
01277
01278
01279
01280
01281
01282
01283
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
01300
01301
01302
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
01318
01319
01320
01321
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
01338
01339
01340
01341
01342
01343
01344
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
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
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
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
01434
01435
01436
01437
01438
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
01455
01456
01457
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
01479
01480
01481
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
01503
01504
01505
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
01527
01528
01529
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
01559
01560
01561
01562
01563
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
01593
01594
01595
01596
01597 void PNMImage::
01598 operator += (const LColord &other) {
01599 size_t array_size = _x_size * _y_size;
01600
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
01628
01629
01630
01631
01632
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
01662
01663
01664
01665
01666 void PNMImage::
01667 operator -= (const LColord &other) {
01668 (*this) += (-other);
01669 }
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679
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
01708
01709
01710
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