00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00060 #include <stdlib.h>
00061 #include <stdio.h>
00062 #include <math.h>
00063 #include <assert.h>
00064
00065
00066 #ifdef _LOCAL_LIBS
00067 #include "png.h"
00068 #else
00069 #include <png.h>
00070 #endif
00071
00072
00073 #include "io_png.h"
00074
00075 #define PNG_SIG_LEN 4
00076
00077
00078 #define IO_PNG_U8 0x0001
00079 #define IO_PNG_F32 0x0002
00080
00081
00082
00083
00084
00094 static void *read_png_abort(FILE * fp,
00095 png_structp * png_ptr_p, png_infop * info_ptr_p)
00096 {
00097 png_destroy_read_struct(png_ptr_p, info_ptr_p, NULL);
00098 if (NULL != fp && stdin != fp)
00099 (void) fclose(fp);
00100 return NULL;
00101 }
00102
00116 static void *read_png_raw(const char *fname,
00117 size_t * nx, size_t * ny, size_t * nc,
00118 int transform, int dtype)
00119 {
00120 png_byte png_sig[PNG_SIG_LEN];
00121 png_structp png_ptr;
00122 png_infop info_ptr;
00123 png_bytepp row_pointers;
00124 png_bytep row_ptr;
00125
00126 FILE *volatile fp = NULL;
00127 void *data = NULL;
00128 unsigned char *data_u8 = NULL;
00129 unsigned char *data_u8_ptr = NULL;
00130 float *data_f32 = NULL;
00131 float *data_f32_ptr = NULL;
00132 size_t size;
00133 size_t i, j, k;
00134
00135
00136 if (NULL == fname || NULL == nx || NULL == ny || NULL == nc)
00137 return NULL;
00138 if (IO_PNG_U8 != dtype && IO_PNG_F32 != dtype)
00139 return NULL;
00140
00141
00142 if (0 == strcmp(fname, "-"))
00143 fp = stdin;
00144 else if (NULL == (fp = fopen(fname, "rb")))
00145 return NULL;
00146
00147
00148 if ((PNG_SIG_LEN != fread(png_sig, 1, PNG_SIG_LEN, fp))
00149 || 0 != png_sig_cmp(png_sig, (png_size_t) 0, PNG_SIG_LEN))
00150 return read_png_abort(fp, NULL, NULL);
00151
00152
00153
00154
00155
00156 if (NULL == (png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
00157 NULL, NULL, NULL)))
00158 return read_png_abort(fp, NULL, NULL);
00159
00160
00161 if (NULL == (info_ptr = png_create_info_struct(png_ptr)))
00162 return read_png_abort(fp, &png_ptr, NULL);
00163
00164
00165 if (0 != setjmp(png_jmpbuf(png_ptr)))
00166
00167
00168 return read_png_abort(fp, &png_ptr, &info_ptr);
00169
00170
00171 png_init_io(png_ptr, fp);
00172
00173
00174 png_set_sig_bytes(png_ptr, PNG_SIG_LEN);
00175
00176
00177
00178
00179
00180
00181
00182
00183 transform |= (PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING);
00184
00185
00186 png_read_png(png_ptr, info_ptr, transform, NULL);
00187
00188
00189 *nx = (size_t) png_get_image_width(png_ptr, info_ptr);
00190 *ny = (size_t) png_get_image_height(png_ptr, info_ptr);
00191 *nc = (size_t) png_get_channels(png_ptr, info_ptr);
00192 row_pointers = png_get_rows(png_ptr, info_ptr);
00193
00194
00195
00196
00197
00198
00199
00200 size = *nx * *ny * *nc;
00201 switch (dtype)
00202 {
00203 case IO_PNG_U8:
00204 if (NULL == (data_u8 =
00205 (unsigned char *) malloc(size * sizeof(unsigned char))))
00206 return read_png_abort(fp, &png_ptr, &info_ptr);
00207 data = (void *) data_u8;
00208 for (k = 0; k < *nc; k++)
00209 {
00210
00211 data_u8_ptr = data_u8 + (size_t) (*nx * *ny * k);
00212 for (j = 0; j < *ny; j++)
00213 {
00214
00215 row_ptr = row_pointers[j] + k;
00216 for (i = 0; i < *nx; i++)
00217 {
00218
00219 *data_u8_ptr++ = (unsigned char) *row_ptr;
00220 row_ptr += *nc;
00221 }
00222 }
00223 }
00224 break;
00225 case IO_PNG_F32:
00226 if (NULL == (data_f32 = (float *) malloc(size * sizeof(float))))
00227 return read_png_abort(fp, &png_ptr, &info_ptr);
00228 data = (void *) data_f32;
00229 for (k = 0; k < *nc; k++)
00230 {
00231
00232 data_f32_ptr = data_f32 + (size_t) (*nx * *ny * k);
00233 for (j = 0; j < *ny; j++)
00234 {
00235
00236 row_ptr = row_pointers[j] + k;
00237 for (i = 0; i < *nx; i++)
00238 {
00239
00240 *data_f32_ptr++ = (float) *row_ptr;
00241 row_ptr += *nc;
00242 }
00243 }
00244 }
00245 break;
00246 }
00247
00248
00249 (void) read_png_abort(fp, &png_ptr, &info_ptr);
00250
00251 return data;
00252 }
00253
00269 unsigned char *read_png_u8(const char *fname,
00270 size_t * nx, size_t * ny, size_t * nc)
00271 {
00272
00273 return (unsigned char *) read_png_raw(fname, nx, ny, nc,
00274 PNG_TRANSFORM_IDENTITY, IO_PNG_U8);
00275 }
00276
00282 unsigned char *read_png_u8_rgb(const char *fname, size_t * nx, size_t * ny)
00283 {
00284 size_t nc;
00285 unsigned char *img;
00286
00287
00288 img = (unsigned char *) read_png_raw(fname, nx, ny, &nc,
00289 PNG_TRANSFORM_STRIP_ALPHA,
00290 IO_PNG_U8);
00291 if (NULL == img)
00292
00293 return NULL;
00294 if (3 == nc)
00295
00296 return img;
00297 else
00298 {
00299
00300 unsigned char *ptr_r, *ptr_g, *ptr_b, *ptr_end;
00301
00302
00303 img = realloc(img, 3 * *nx * *ny * sizeof(unsigned char));
00304
00305
00306 ptr_r = img;
00307 ptr_end = ptr_r + *nx * *ny;
00308 ptr_g = img + *nx * *ny;
00309 ptr_b = img + 2 * *nx * *ny;
00310 while (ptr_r < ptr_end)
00311 {
00312 *ptr_g++ = *ptr_r;
00313 *ptr_b++ = *ptr_r++;
00314 }
00315 return img;
00316 }
00317 }
00318
00324 unsigned char *read_png_u8_gray(const char *fname, size_t * nx, size_t * ny)
00325 {
00326 size_t nc;
00327 unsigned char *img;
00328
00329
00330 img = (unsigned char *) read_png_raw(fname, nx, ny, &nc,
00331 PNG_TRANSFORM_STRIP_ALPHA,
00332 IO_PNG_U8);
00333 if (NULL == img)
00334
00335 return NULL;
00336 if (1 == nc)
00337
00338 return img;
00339 else
00340 {
00341
00342 unsigned char *ptr_r, *ptr_g, *ptr_b, *ptr_gray, *ptr_end;
00343
00344
00345
00346
00347
00348
00349
00350 ptr_r = img;
00351 ptr_g = img + *nx * *ny;
00352 ptr_b = img + 2 * *nx * *ny;
00353 ptr_gray = img;
00354 ptr_end = ptr_gray + *nx * *ny;
00355 while (ptr_gray < ptr_end)
00356 *ptr_gray++ = (unsigned char) (6969 * *ptr_r++
00357 + 23434 * *ptr_g++
00358 + 2365 * *ptr_b++) / 32768;
00359
00360 img = realloc(img, *nx * *ny * sizeof(unsigned char));
00361 return img;
00362 }
00363 }
00364
00379 float *read_png_f32(const char *fname, size_t * nx, size_t * ny, size_t * nc)
00380 {
00381
00382 return (float *) read_png_raw(fname, nx, ny, nc,
00383 PNG_TRANSFORM_IDENTITY, IO_PNG_F32);
00384 }
00385
00391 float *read_png_f32_rgb(const char *fname, size_t * nx, size_t * ny)
00392 {
00393 size_t nc;
00394 float *img;
00395
00396
00397 img = (float *) read_png_raw(fname, nx, ny, &nc,
00398 PNG_TRANSFORM_STRIP_ALPHA, IO_PNG_F32);
00399 if (NULL == img)
00400
00401 return NULL;
00402 if (3 == nc)
00403
00404 return img;
00405 else
00406 {
00407
00408 float *ptr_r, *ptr_g, *ptr_b, *ptr_end;
00409
00410
00411 img = realloc(img, 3 * *nx * *ny * sizeof(float));
00412
00413
00414 ptr_r = img;
00415 ptr_end = ptr_r + *nx * *ny;
00416 ptr_g = img + *nx * *ny;
00417 ptr_b = img + 2 * *nx * *ny;
00418 while (ptr_r < ptr_end)
00419 {
00420 *ptr_g++ = *ptr_r;
00421 *ptr_b++ = *ptr_r++;
00422 }
00423 return img;
00424 }
00425 }
00426
00432 float *read_png_f32_gray(const char *fname, size_t * nx, size_t * ny)
00433 {
00434 size_t nc;
00435 float *img;
00436
00437
00438 img = (float *) read_png_raw(fname, nx, ny, &nc,
00439 PNG_TRANSFORM_STRIP_ALPHA, IO_PNG_F32);
00440 if (NULL == img)
00441
00442 return NULL;
00443 if (1 == nc)
00444
00445 return img;
00446 else
00447 {
00448
00449 float *ptr_r, *ptr_g, *ptr_b, *ptr_gray, *ptr_end;
00450
00451
00452
00453
00454
00455
00456
00457 ptr_r = img;
00458 ptr_g = img + *nx * *ny;
00459 ptr_b = img + 2 * *nx * *ny;
00460 ptr_gray = img;
00461 ptr_end = ptr_gray + *nx * *ny;
00462 while (ptr_gray < ptr_end)
00463 *ptr_gray++ = (float) (6969 * *ptr_r++
00464 + 23434 * *ptr_g++
00465 + 2365 * *ptr_b++) / 32768;
00466
00467 img = realloc(img, *nx * *ny * sizeof(float));
00468 return img;
00469 }
00470 }
00471
00472
00473
00474
00475
00486 static int write_png_abort(FILE * fp,
00487 png_byte * idata, png_bytep * row_pointers,
00488 png_structp * png_ptr_p, png_infop * info_ptr_p)
00489 {
00490 png_destroy_write_struct(png_ptr_p, info_ptr_p);
00491 if (NULL != row_pointers)
00492 free(row_pointers);
00493 if (NULL != idata)
00494 free(idata);
00495 if (NULL != fp && stdout != fp)
00496 (void) fclose(fp);
00497 return -1;
00498 }
00499
00515 static int write_png_raw(const char *fname, const void *data,
00516 size_t nx, size_t ny, size_t nc, int dtype)
00517 {
00518 png_structp png_ptr;
00519 png_infop info_ptr;
00520 png_byte *idata = NULL, *idata_ptr = NULL;
00521 png_bytep *row_pointers = NULL;
00522 png_byte bit_depth;
00523
00524 FILE *volatile fp;
00525 const unsigned char *data_u8 = NULL;
00526 const unsigned char *data_u8_ptr = NULL;
00527 const float *data_f32 = NULL;
00528 const float *data_f32_ptr = NULL;
00529 float tmp;
00530 int color_type, interlace, compression, filter;
00531 size_t size;
00532 size_t i, j, k;
00533
00534
00535 if (0 >= nx || 0 >= ny || 0 >= nc)
00536 return -1;
00537 if (NULL == fname || NULL == data)
00538 return -1;
00539 if (IO_PNG_U8 != dtype && IO_PNG_F32 != dtype)
00540 return -1;
00541
00542
00543 if (0 == strcmp(fname, "-"))
00544 fp = stdout;
00545 else if (NULL == (fp = fopen(fname, "wb")))
00546 return -1;
00547
00548
00549 size = nx * ny * nc;
00550 if (NULL == (idata = (png_byte *) malloc(size * sizeof(png_byte))))
00551 return write_png_abort(fp, NULL, NULL, NULL, NULL);
00552
00553 if (NULL == (row_pointers = (png_bytep *) malloc(ny * sizeof(png_bytep))))
00554 return write_png_abort(fp, idata, NULL, NULL, NULL);
00555
00556
00557
00558
00559
00560 if (NULL == (png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
00561 NULL, NULL, NULL)))
00562 return write_png_abort(fp, idata, row_pointers, NULL, NULL);
00563
00564
00565 if (NULL == (info_ptr = png_create_info_struct(png_ptr)))
00566 return write_png_abort(fp, idata, row_pointers, &png_ptr, NULL);
00567
00568
00569 if (0 != setjmp(png_jmpbuf(png_ptr)))
00570
00571 return write_png_abort(fp, idata, row_pointers, &png_ptr, &info_ptr);
00572
00573
00574 png_init_io(png_ptr, fp);
00575
00576
00577 bit_depth = 8;
00578 switch (nc)
00579 {
00580 case 1:
00581 color_type = PNG_COLOR_TYPE_GRAY;
00582 break;
00583 case 2:
00584 color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
00585 break;
00586 case 3:
00587 color_type = PNG_COLOR_TYPE_RGB;
00588 break;
00589 case 4:
00590 color_type = PNG_COLOR_TYPE_RGB_ALPHA;
00591 break;
00592 default:
00593 png_destroy_read_struct(&png_ptr, NULL, NULL);
00594 free(row_pointers);
00595 free(idata);
00596 (void) fclose(fp);
00597 return -1;
00598 }
00599 interlace = PNG_INTERLACE_ADAM7;
00600 compression = PNG_COMPRESSION_TYPE_BASE;
00601 filter = PNG_FILTER_TYPE_BASE;
00602
00603
00604 png_set_IHDR(png_ptr, info_ptr, (png_uint_32) nx, (png_uint_32) ny,
00605 bit_depth, color_type, interlace, compression, filter);
00606
00607 png_write_info(png_ptr, info_ptr);
00608
00609
00610
00611
00612
00613
00614 switch (dtype)
00615 {
00616 case IO_PNG_U8:
00617 data_u8 = (unsigned char *) data;
00618 for (k = 0; k < nc; k++)
00619 {
00620
00621 data_u8_ptr = data_u8 + (size_t) (nx * ny * k);
00622 idata_ptr = idata + (size_t) k;
00623 for (j = 0; j < ny; j++)
00624 {
00625
00626 for (i = 0; i < nx; i++)
00627 {
00628
00629 *idata_ptr = (png_byte) * data_u8_ptr++;
00630 idata_ptr += nc;
00631 }
00632 }
00633 }
00634 break;
00635 case IO_PNG_F32:
00636 data_f32 = (float *) data;
00637 for (k = 0; k < nc; k++)
00638 {
00639
00640 data_f32_ptr = data_f32 + (size_t) (nx * ny * k);
00641 idata_ptr = idata + (size_t) k;
00642 for (j = 0; j < ny; j++)
00643 {
00644
00645 for (i = 0; i < nx; i++)
00646 {
00647
00648 tmp = floor(*data_f32_ptr++ + .5);
00649 *idata_ptr = (png_byte) (tmp < 0. ? 0. :
00650 (tmp > 255. ? 255. : tmp));
00651 idata_ptr += nc;
00652 }
00653 }
00654 }
00655 break;
00656 }
00657
00658
00659 for (j = 0; j < ny; j++)
00660 row_pointers[j] = idata + (size_t) (nc * nx * j);
00661
00662
00663 png_write_image(png_ptr, row_pointers);
00664 png_write_end(png_ptr, info_ptr);
00665
00666
00667 (void) write_png_abort(fp, idata, row_pointers, &png_ptr, &info_ptr);
00668
00669 return 0;
00670 }
00671
00680 int write_png_u8(const char *fname, const unsigned char *data,
00681 size_t nx, size_t ny, size_t nc)
00682 {
00683 return write_png_raw(fname, (void *) data,
00684 (png_uint_32) nx, (png_uint_32) ny, (png_byte) nc,
00685 IO_PNG_U8);
00686 }
00687
00700 int write_png_f32(const char *fname, const float *data,
00701 size_t nx, size_t ny, size_t nc)
00702 {
00703 return write_png_raw(fname, (void *) data,
00704 (png_uint_32) nx, (png_uint_32) ny, (png_byte) nc,
00705 IO_PNG_F32);
00706 }