00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "pnmImage.h"
00020 #include "pnmReader.h"
00021 #include "pnmWriter.h"
00022 #include "config_pnmimage.h"
00023
00024
00025
00026
00027
00028
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
00049
00050
00051
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
00078
00079
00080
00081 void PNMImage::
00082 copy_from(const PNMImage ©) {
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
00097
00098
00099
00100
00101
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
00118
00119
00120
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
00135
00136
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
00155
00156
00157
00158
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
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
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
00201
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
00216
00217
00218
00219
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
00237
00238
00239
00240
00241
00242
00243
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
00267
00268
00269
00270
00271
00272
00273
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
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
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
00301 if (_alpha!=NULL) {
00302 delete[] _alpha;
00303 _alpha = NULL;
00304 }
00305
00306 } else if (!has_alpha() && has_alpha(color_type)) {
00307
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
00318
00319
00320
00321
00322
00323
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
00343
00344
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
00383
00384
00385
00386
00387
00388
00389
00390
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
00418
00419
00420
00421
00422
00423
00424
00425
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
00457
00458
00459
00460
00461
00462
00463
00464 void PNMImage::
00465 blend(int x, int y, double r, double g, double b, double alpha) {
00466 if (alpha >= 1.0) {
00467
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
00475 double prev_alpha = has_alpha() ? get_alpha(x, y) : 1.0;
00476
00477 if (prev_alpha == 0.0) {
00478
00479 set_alpha(x, y, alpha);
00480 set_xel(x, y, r, g, b);
00481
00482 } else {
00483
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
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509 void PNMImage::
00510 copy_sub_image(const PNMImage ©, 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
00553
00554
00555
00556
00557
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 }