00001
00002
00003
00004
00005 #include "std/config.H"
00006 #include "geom/image.H"
00007 #include "geom/rgba.H"
00008 static
00009 inline
00010 void
00011 eat_whitespace(istream& in)
00012 {
00013 while (isspace(in.peek())) {
00014 in.get();
00015 }
00016 }
00017
00018
00019
00020
00021
00022
00023
00024 uchar*
00025 Image::copy()
00026 {
00027 if (empty())
00028 return 0;
00029
00030 uchar* ret = new uchar [ size() ];
00031
00032 if (ret) memcpy(ret, _data, size());
00033 else err_ret("Image::copy: can't allocate data");
00034
00035 return ret;
00036 }
00037
00038 int
00039 Image::resize_rows_mult_4()
00040 {
00041 if (empty() || (row_size()%4) == 0)
00042 return 1;
00043
00044 uint new_w = _width + 4 - _width%4;
00045 uchar* new_d = 0;
00046 if ((new_d = new uchar [ new_w * _height * _bpp ]) == 0) {
00047 err_ret("Image::resize_rows_mult_4: can't allocate data");
00048 return 0;
00049 }
00050 int new_row_size = new_w*_bpp;
00051 for (uint r=0; r<_height; r++)
00052 memcpy(new_d + new_row_size*r, row(r), row_size());
00053
00054 set(new_w, _height, _bpp, new_d, 0);
00055
00056 return 1;
00057 }
00058
00059 int
00060 Image::copy_tile(const Image& tile, uint i, uint j)
00061 {
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078 if (tile._width*(i+1) > _width ||
00079 tile._height*(j+1) > _height ||
00080 tile._bpp != _bpp) {
00081 err_msg("Image::copy_tile: bad size in tiled image");
00082 return 0;
00083 }
00084
00085
00086 int row_offset = tile.row_size()*i;
00087 for (uint r=0; r<tile._height; r++) {
00088 memcpy(row(tile._height*j + r) + row_offset,
00089 tile.row(r),
00090 tile.row_size());
00091 }
00092
00093 return 1;
00094 }
00095
00096
00097
00098
00099
00100
00101
00102 int
00103 Image::load_file(char *file)
00104 {
00105 if (!file || *file == '\0')
00106 return 0;
00107
00108
00109 {
00110 #if (defined (WIN32) && defined(_MSC_VER) && (_MSC_VER <=1300))
00111 ifstream in(file, ios::in | ios::nocreate );
00112 #else
00113 ifstream in(file);
00114 #endif
00115 if (!in.good())
00116 {
00117 err_mesg(ERR_LEV_INFO | ERR_INCL_ERRNO, "Image::load_file() - ERROR! Can't open file %s", file);
00118 return 0;
00119 }
00120 }
00121
00122
00123 if (read_png(file))
00124 return 1;
00125
00126
00127 if (read_pnm(file))
00128 return 1;
00129
00130
00131 return 0;
00132 }
00133
00134 int
00135 Image::read_pnm(char* file)
00136 {
00137 #if (defined (WIN32) && defined(_MSC_VER) && (_MSC_VER <=1200))
00138 ifstream in(file, ios::in | ios::binary | ios::nocreate );
00139 #else
00140 ifstream in(file);
00141 #endif
00142
00143 if (!in.good())
00144 {
00145 err_ret("Image::read_pnm() - ERROR! Can't open file %s", file);
00146 return 0;
00147 }
00148
00149 char head[128];
00150 in >> head;
00151
00152 if (!strcmp(head, "P2")) return read_pgm(in, 1);
00153 else if (!strcmp(head, "P5")) return read_pgm(in, 0);
00154 else if (!strcmp(head, "P3")) return read_ppm(in, 1);
00155 else if (!strcmp(head, "P6")) return read_ppm(in, 0);
00156 else return 0;
00157 }
00158
00159 inline int
00160 pnm_read_int(istream& in, uint* d)
00161 {
00162 while (!in.eof() && !in.bad()) {
00163 char buf[128];
00164 in >> buf;
00165 if (buf[0] == '#')
00166 in.getline(buf, 128);
00167 else if (sscanf(buf, "%d", d) == 1)
00168 return 1;
00169 }
00170 return 0;
00171 }
00172
00173
00174 int
00175 Image::read_pgm(istream& in, bool ascii)
00176 {
00177
00178 clear();
00179
00180
00181 pnm_read_int(in, &_width);
00182 pnm_read_int(in, &_height);
00183 uint max_val;
00184 pnm_read_int(in, &max_val);
00185 if (!ascii) eat_whitespace(in);
00186
00187
00188
00189 _bpp = 3;
00190
00191 if (in.bad() || in.eof()) {
00192 err_ret("Image::read_pgm: error reading stream");
00193 clear();
00194 return 0;
00195 } else if ((_data = new uchar [ _width*_height*_bpp ]) == 0) {
00196 err_ret("Image::read_pgm: can't allocate data");
00197 clear();
00198 return 0;
00199 }
00200 _no_delete = 0;
00201
00202
00203 int row_bytes = _width*_bpp, val;
00204 for (int y=_height-1; y>=0; y--) {
00205 uchar* row = _data + y*row_bytes;
00206 for (unsigned int x=0; x<_width; x++) {
00207
00208 if (in.bad() || in.eof()) {
00209 err_ret("Image::read_pgm: error reading stream");
00210 clear();
00211 return 0;
00212 }
00213
00214 if (ascii) in >> val;
00215 else val = in.get();
00216
00217 *row++ = val;
00218 *row++ = val;
00219 *row++ = val;
00220 }
00221 }
00222
00223 return 1;
00224 }
00225
00226
00227
00228
00229
00230
00231
00232 int
00233 Image::read_ppm(istream& in, bool ascii)
00234 {
00235
00236 clear();
00237
00238
00239 pnm_read_int(in, &_width);
00240 pnm_read_int(in, &_height);
00241 uint max_val;
00242 pnm_read_int(in, &max_val);
00243 if (!ascii) eat_whitespace(in);
00244
00245 _bpp = 3;
00246
00247 if (in.bad() || in.eof()) {
00248 err_ret("Image::read_ppm: error reading from stream");
00249 clear();
00250 return 0;
00251 } else if ((_data = new uchar [ _width*_height*_bpp ]) == 0) {
00252 err_ret("Image::read_ppm: can't allocate data");
00253 clear();
00254 return 0;
00255 }
00256 _no_delete = 0;
00257
00258
00259 int row_bytes = _width*_bpp, val;
00260 for (int y=_height-1; y>=0; y--) {
00261 uchar* row = _data + y*row_bytes;
00262
00263 if (in.bad() || in.eof()) {
00264 err_ret("Image::read_ppm: error reading from stream");
00265 clear();
00266 return 0;
00267 }
00268
00269 if (!ascii) {
00270 in.read((char *) row, _width*3);
00271 } else {
00272 for (unsigned int x=0; x<_width; x++) {
00273 in >> val; *row++ = val;
00274 in >> val; *row++ = val;
00275 in >> val; *row++ = val;
00276 }
00277 }
00278 }
00279
00280 return 1;
00281 }
00282
00283
00284
00285
00286
00287
00288
00289 int
00290 Image::write_pnm(char*file) const
00291 {
00292 if (_bpp != 3) {
00293 err_msg("Image::write_pnm: writing files w/o 3 BPP is unimplemented");
00294 return 0;
00295 }
00296
00297 cerr << "WARNING: writing ppm file, but these colors appear to be off from" << endl;
00298 cerr << " the ones shown in the JOT window. Somehow there's error" << endl;
00299 cerr << " being introduced, it appears. This needs debugging." << endl;
00300
00301 FILE* fp;
00302 fp = fopen(file, "wb");
00303
00304
00305 fprintf(fp, "P6\n");
00306
00307
00308 fprintf(fp, "%d %d\n", _width, _height);
00309 fprintf(fp, "255\n");
00310
00311
00312 int row_bytes = _width*_bpp;
00313 for(int y=_height-1;y>=0;y--)
00314 fwrite(_data + y * row_bytes, _bpp, _width, fp);
00315
00316 fclose(fp);
00317
00318 return 1;
00319 }
00320
00321
00322
00323
00324
00325
00326
00327
00328 bool
00329 Image::expand_power2()
00330 {
00331 if (empty())
00332 return false;
00333
00334 unsigned int w = getPower2Size(_width);
00335 unsigned int h = getPower2Size(_height);
00336 if (w == _width && h == _height)
00337 return false;
00338
00339 uchar *data;
00340 if ((data = new uchar [ (w*h*_bpp) ]) == 0) {
00341 err_ret("Image::expand_power2: can't allocate data");
00342 return false;
00343 }
00344 memset(data, 0, w*h*_bpp);
00345 int old_row_size = _width * _bpp;
00346 int new_row_size = w * _bpp;
00347 for (uint y=0; y<_height; y++)
00348 memcpy(data + y*new_row_size,
00349 _data + y*old_row_size,
00350 old_row_size);
00351 set(w,h,_bpp,data,0);
00352 return true;
00353 }
00354
00355 #include "libpng/png.h"
00356
00357
00358
00359
00360
00361
00362
00363 FILE*
00364 Image::open_png(char *file_name)
00365 {
00366
00367
00368
00369 FILE* fp = fopen(file_name, "rb");
00370 if (!fp) {
00371 err_ret("Image::open_png() - ERROR! Can't open file %s", file_name);
00372 return 0;
00373 }
00374
00375
00376 unsigned char buf[PNG_BYTES_TO_CHECK];
00377 if (fread(buf, 1, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK) {
00378 err_ret("Image::open_png: can't read file %s", file_name);
00379 return 0;
00380 }
00381
00382
00383 if (!png_sig_cmp(buf, 0, PNG_BYTES_TO_CHECK)) {
00384
00385 return fp;
00386 } else {
00387
00388
00389 fclose(fp);
00390 return 0;
00391 }
00392 }
00393
00394
00395
00396
00397
00398
00399
00400 int
00401 Image::read_png(char *file)
00402 {
00403 FILE *fp = open_png(file);
00404 if (!fp)
00405 return 0;
00406
00407 int success = read_png(fp);
00408
00409 fclose(fp);
00410
00411 if (success)
00412 return 1;
00413
00414 err_msg("Image::read_png: error reading file: %s", file);
00415 return 0;
00416 }
00417
00418 int
00419 Image::read_png(FILE* fp)
00420 {
00421
00422 clear();
00423
00424 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0);
00425 if (!png_ptr) {
00426 err_msg("Image::read_png: png_create_read_struct() failed");
00427 return 0;
00428 }
00429
00430
00431 png_infop info_ptr = png_create_info_struct(png_ptr);
00432 if (!info_ptr) {
00433 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
00434 err_msg("Image::read_png: png_create_info_struct() failed");
00435 return 0;
00436 }
00437
00438
00439 if (setjmp(png_ptr->jmpbuf)) {
00440
00441
00442 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
00443 return 0;
00444 }
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455 png_init_io(png_ptr, fp);
00456
00457
00458 png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
00459
00460
00461 png_read_info(png_ptr, info_ptr);
00462
00463
00464 int bit_depth, color_type, interlace_type;
00465 png_get_IHDR(png_ptr, info_ptr,
00466 (png_uint_32*)&_width,
00467 (png_uint_32*)&_height,
00468 &bit_depth,
00469 &color_type,
00470 &interlace_type,
00471 NULL, NULL);
00472
00473
00474 png_set_strip_16(png_ptr);
00475
00476
00477
00478 png_set_packing(png_ptr);
00479
00480
00481 if (color_type == PNG_COLOR_TYPE_PALETTE)
00482 png_set_expand(png_ptr);
00483
00484
00485 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
00486 png_set_expand(png_ptr);
00487
00488
00489
00490 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
00491 png_set_expand(png_ptr);
00492
00493
00494 png_read_update_info(png_ptr, info_ptr);
00495
00496
00497 unsigned long row_bytes = png_get_rowbytes(png_ptr, info_ptr);
00498 _bpp = row_bytes / _width;
00499
00500
00501 if (_bpp < 1 || _bpp > 4) {
00502 err_msg("Image::read_png: %d bytes/pixel not supported", _bpp);
00503 } else if (interlace_type != PNG_INTERLACE_NONE) {
00504 err_msg("Image::read_png: unsupported interlace type (%d)",
00505 interlace_type);
00506 } else if ((_data = new uchar [ size() ]) == 0) {
00507 err_ret("Image::read_png: can't allocate data");
00508 } else {
00509 _no_delete = 0;
00510
00511
00512 for (int y=_height-1; y>=0; y--)
00513 png_read_row(png_ptr, _data + y*row_bytes, 0);
00514
00515
00516
00517 png_read_end(png_ptr, info_ptr);
00518 }
00519
00520
00521 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
00522
00523
00524 if (_data)
00525 return 1;
00526 else {
00527 clear();
00528 return 0;
00529 }
00530 }
00531
00532
00533
00534
00535
00536
00537
00538 int
00539 Image::write_png(char *file) const
00540 {
00541
00542 if (_width == 0 || _height == 0 || _data == 0) {
00543 err_msg("Image::write_png: image has no data");
00544 return 0;
00545 } else if (_bpp < 1 || _bpp > 4) {
00546 err_msg("Image::write_png: unsupported number of bytes/pixel (%d)",
00547 _bpp);
00548 return 0;
00549 }
00550
00551 FILE* fp;
00552 if ((fp = fopen(file, "wb")) == 0) {
00553 err_ret("Image::write_png: can't open file %s", file);
00554 return 0;
00555 }
00556
00557
00558
00559
00560
00561
00562 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,0,0,0);
00563 if (!png_ptr) {
00564 fclose(fp);
00565 err_msg("Image::write_png: png_create_write_struct() failed");
00566 return 0;
00567 }
00568
00569
00570 png_infop info_ptr = png_create_info_struct(png_ptr);
00571 if (!info_ptr) {
00572 fclose(fp);
00573 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
00574 err_msg("Image::write_png: png_create_info_struct() failed");
00575 return 0;
00576 }
00577
00578
00579 if (setjmp(png_ptr->jmpbuf)) {
00580
00581
00582 fclose(fp);
00583 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
00584 err_msg("Image::write_png: error writing file %s", file);
00585 return 0;
00586 }
00587
00588
00589
00590
00591
00592 png_init_io(png_ptr, fp);
00593
00594
00595 png_set_IHDR(png_ptr,
00596 info_ptr,
00597 _width,
00598 _height,
00599 8,
00600 ((_bpp==4) ? PNG_COLOR_TYPE_RGB_ALPHA :
00601 (_bpp==3) ? PNG_COLOR_TYPE_RGB :
00602 (_bpp==2) ? PNG_COLOR_TYPE_GRAY_ALPHA :
00603 PNG_COLOR_TYPE_GRAY),
00604 PNG_INTERLACE_NONE,
00605 PNG_COMPRESSION_TYPE_BASE,
00606 PNG_FILTER_TYPE_BASE);
00607
00608
00609 double gamma = Config::get_var_dbl("JOT_GAMMA",0.45,true);
00610 png_set_gAMA(png_ptr, info_ptr, gamma);
00611
00612
00613 png_write_info(png_ptr, info_ptr);
00614
00615
00616 for (int y=_height-1; y>=0; y--)
00617 png_write_row(png_ptr, row(y));
00618
00619
00620 png_write_end(png_ptr, info_ptr);
00621
00622
00623 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
00624
00625
00626 fclose(fp);
00627
00628 return 1;
00629 }
00630
00631 uint
00632 Image::pixel_rgba(uint x, uint y) const
00633 {
00634 if (x >= _width || y >= _height)
00635 return 0;
00636 uchar* val = row(y);
00637 uint ret=0;
00638 switch(_bpp) {
00639 case 4:
00640
00641 ret = build_rgba(val[x*_bpp], val[x*_bpp+1], val[x*_bpp+2], val[x*_bpp+3]);
00642 break;
00643 case 3:
00644
00645 ret = build_rgba(val[x*_bpp], val[x*_bpp+1], val[x*_bpp+2]);
00646 break;
00647 case 2:
00648
00649 ret = build_rgba(val[x*_bpp], val[x*_bpp], val[x*_bpp], val[x*_bpp+1]);
00650 break;
00651 case 1:
00652
00653 ret = build_rgba(val[x*_bpp], val[x*_bpp], val[x*_bpp]);
00654 break;
00655 default:
00656
00657 err_msg( "Image::pixel_rgba: unknown bits per pixel (%d) in image", _bpp);
00658 return 0;
00659 }
00660 return ret;
00661 }
00662
00663 uint
00664 Image::pixel_r(uint x, uint y) const
00665 {
00666 return rgba_to_r(pixel_rgba(x,y));
00667 }
00668
00669 uint
00670 Image::pixel_g(uint x, uint y) const
00671 {
00672 return rgba_to_g(pixel_rgba(x,y));
00673 }
00674
00675 uint
00676 Image::pixel_b(uint x, uint y) const
00677 {
00678 return rgba_to_b(pixel_rgba(x,y));
00679 }
00680
00681 uint
00682 Image::pixel_a(uint x, uint y) const
00683 {
00684 return rgba_to_a(pixel_rgba(x,y));
00685 }
00686
00687