00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00035 #include <stdlib.h>
00036 #include <stdio.h>
00037 #include <math.h>
00038 #include <assert.h>
00039
00040
00041 #ifdef WITH_LOCAL_LIBPNG
00042 #include "png.h"
00043 #else
00044 #include <png.h>
00045 #endif
00046
00047
00048 #include "io_png.h"
00049
00050 #define PNG_SIG_LEN 4
00051
00052
00053 #define IO_PNG_U8 0x0001
00054 #define IO_PNG_F32 0x0002
00055
00056
00057 char _io_png_tag[] = "using io_png " IO_PNG_VERSION;
00058
00059
00060
00061
00062
00072 static void *read_png_abort(FILE * fp,
00073 png_structp * png_ptr_p, png_infop * info_ptr_p)
00074 {
00075 png_destroy_read_struct(png_ptr_p, info_ptr_p, NULL);
00076 if (NULL != fp && stdin != fp)
00077 (void) fclose(fp);
00078 return NULL;
00079 }
00080
00094 static void *read_png_raw(const char *fname,
00095 size_t * nxp, size_t * nyp, size_t * ncp,
00096 int transform, int dtype)
00097 {
00098 png_byte png_sig[PNG_SIG_LEN];
00099 png_structp png_ptr;
00100 png_infop info_ptr;
00101 png_bytepp row_pointers;
00102 png_bytep row_ptr;
00103
00104 FILE *volatile fp = NULL;
00105 void *data = NULL;
00106 unsigned char *data_u8 = NULL;
00107 unsigned char *data_u8_ptr = NULL;
00108 float *data_f32 = NULL;
00109 float *data_f32_ptr = NULL;
00110 size_t size;
00111 size_t i, j, k;
00112
00113
00114 if (NULL == fname || NULL == nxp || NULL == nyp || NULL == ncp)
00115 return NULL;
00116 if (IO_PNG_U8 != dtype && IO_PNG_F32 != dtype)
00117 return NULL;
00118
00119
00120 if (0 == strcmp(fname, "-"))
00121 fp = stdin;
00122 else if (NULL == (fp = fopen(fname, "rb")))
00123 return NULL;
00124
00125
00126 if ((PNG_SIG_LEN != fread(png_sig, 1, PNG_SIG_LEN, fp))
00127 || 0 != png_sig_cmp(png_sig, (png_size_t) 0, PNG_SIG_LEN))
00128 return read_png_abort(fp, NULL, NULL);
00129
00130
00131
00132
00133
00134 if (NULL == (png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
00135 NULL, NULL, NULL)))
00136 return read_png_abort(fp, NULL, NULL);
00137
00138
00139 if (NULL == (info_ptr = png_create_info_struct(png_ptr)))
00140 return read_png_abort(fp, &png_ptr, NULL);
00141
00142
00143 if (0 != setjmp(png_jmpbuf(png_ptr)))
00144
00145
00146 return read_png_abort(fp, &png_ptr, &info_ptr);
00147
00148
00149 png_init_io(png_ptr, fp);
00150
00151
00152 png_set_sig_bytes(png_ptr, PNG_SIG_LEN);
00153
00154
00155
00156
00157
00158
00159
00160
00161 transform |= (PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING);
00162
00163
00164 png_read_png(png_ptr, info_ptr, transform, NULL);
00165
00166
00167 *nxp = (size_t) png_get_image_width(png_ptr, info_ptr);
00168 *nyp = (size_t) png_get_image_height(png_ptr, info_ptr);
00169 *ncp = (size_t) png_get_channels(png_ptr, info_ptr);
00170 row_pointers = png_get_rows(png_ptr, info_ptr);
00171
00172
00173
00174
00175
00176
00177
00178 size = *nxp * *nyp * *ncp;
00179 switch (dtype)
00180 {
00181 case IO_PNG_U8:
00182 if (NULL == (data_u8 =
00183 (unsigned char *) malloc(size * sizeof(unsigned char))))
00184 return read_png_abort(fp, &png_ptr, &info_ptr);
00185 data = (void *) data_u8;
00186 for (k = 0; k < *ncp; k++)
00187 {
00188
00189 data_u8_ptr = data_u8 + (size_t) (*nxp * *nyp * k);
00190 for (j = 0; j < *nyp; j++)
00191 {
00192
00193 row_ptr = row_pointers[j] + k;
00194 for (i = 0; i < *nxp; i++)
00195 {
00196
00197 *data_u8_ptr++ = (unsigned char) *row_ptr;
00198 row_ptr += *ncp;
00199 }
00200 }
00201 }
00202 break;
00203 case IO_PNG_F32:
00204 if (NULL == (data_f32 = (float *) malloc(size * sizeof(float))))
00205 return read_png_abort(fp, &png_ptr, &info_ptr);
00206 data = (void *) data_f32;
00207 for (k = 0; k < *ncp; k++)
00208 {
00209
00210 data_f32_ptr = data_f32 + (size_t) (*nxp * *nyp * k);
00211 for (j = 0; j < *nyp; j++)
00212 {
00213
00214 row_ptr = row_pointers[j] + k;
00215 for (i = 0; i < *nxp; i++)
00216 {
00217
00218 *data_f32_ptr++ = (float) *row_ptr;
00219 row_ptr += *ncp;
00220 }
00221 }
00222 }
00223 break;
00224 }
00225
00226
00227 (void) read_png_abort(fp, &png_ptr, &info_ptr);
00228
00229 return data;
00230 }
00231
00247 unsigned char *read_png_u8(const char *fname,
00248 size_t * nxp, size_t * nyp, size_t * ncp)
00249 {
00250
00251 return (unsigned char *) read_png_raw(fname, nxp, nyp, ncp,
00252 PNG_TRANSFORM_IDENTITY, IO_PNG_U8);
00253 }
00254
00260 unsigned char *read_png_u8_rgb(const char *fname, size_t * nxp, size_t * nyp)
00261 {
00262 size_t nc;
00263 unsigned char *img;
00264
00265
00266 img = (unsigned char *) read_png_raw(fname, nxp, nyp, &nc,
00267 PNG_TRANSFORM_STRIP_ALPHA,
00268 IO_PNG_U8);
00269 if (NULL == img)
00270
00271 return NULL;
00272 if (3 == nc)
00273
00274 return img;
00275 else
00276 {
00277
00278 unsigned char *ptr_r, *ptr_g, *ptr_b, *ptr_end;
00279
00280
00281 img = realloc(img, 3 * *nxp * *nyp * sizeof(unsigned char));
00282
00283
00284 ptr_r = img;
00285 ptr_end = ptr_r + *nxp * *nyp;
00286 ptr_g = img + *nxp * *nyp;
00287 ptr_b = img + 2 * *nxp * *nyp;
00288 while (ptr_r < ptr_end)
00289 {
00290 *ptr_g++ = *ptr_r;
00291 *ptr_b++ = *ptr_r++;
00292 }
00293 return img;
00294 }
00295 }
00296
00302 unsigned char *read_png_u8_gray(const char *fname, size_t * nxp, size_t * nyp)
00303 {
00304 size_t nc;
00305 unsigned char *img;
00306
00307
00308 img = (unsigned char *) read_png_raw(fname, nxp, nyp, &nc,
00309 PNG_TRANSFORM_STRIP_ALPHA,
00310 IO_PNG_U8);
00311 if (NULL == img)
00312
00313 return NULL;
00314 if (1 == nc)
00315
00316 return img;
00317 else
00318 {
00319
00320 unsigned char *ptr_r, *ptr_g, *ptr_b, *ptr_gray, *ptr_end;
00321
00322
00323
00324
00325
00326
00327
00328 ptr_r = img;
00329 ptr_g = img + *nxp * *nyp;
00330 ptr_b = img + 2 * *nxp * *nyp;
00331 ptr_gray = img;
00332 ptr_end = ptr_gray + *nxp * *nyp;
00333 while (ptr_gray < ptr_end)
00334 *ptr_gray++ = (unsigned char) (6969 * *ptr_r++
00335 + 23434 * *ptr_g++
00336 + 2365 * *ptr_b++) / 32768;
00337
00338 img = realloc(img, *nxp * *nyp * sizeof(unsigned char));
00339 return img;
00340 }
00341 }
00342
00357 float *read_png_f32(const char *fname, size_t * nxp, size_t * nyp,
00358 size_t * ncp)
00359 {
00360
00361 return (float *) read_png_raw(fname, nxp, nyp, ncp,
00362 PNG_TRANSFORM_IDENTITY, IO_PNG_F32);
00363 }
00364
00370 float *read_png_f32_rgb(const char *fname, size_t * nxp, size_t * nyp)
00371 {
00372 size_t nc;
00373 float *img;
00374
00375
00376 img = (float *) read_png_raw(fname, nxp, nyp, &nc,
00377 PNG_TRANSFORM_STRIP_ALPHA, IO_PNG_F32);
00378 if (NULL == img)
00379
00380 return NULL;
00381 if (3 == nc)
00382
00383 return img;
00384 else
00385 {
00386
00387 float *ptr_r, *ptr_g, *ptr_b, *ptr_end;
00388
00389
00390 img = realloc(img, 3 * *nxp * *nyp * sizeof(float));
00391
00392
00393 ptr_r = img;
00394 ptr_end = ptr_r + *nxp * *nyp;
00395 ptr_g = img + *nxp * *nyp;
00396 ptr_b = img + 2 * *nxp * *nyp;
00397 while (ptr_r < ptr_end)
00398 {
00399 *ptr_g++ = *ptr_r;
00400 *ptr_b++ = *ptr_r++;
00401 }
00402 return img;
00403 }
00404 }
00405
00411 float *read_png_f32_gray(const char *fname, size_t * nxp, size_t * nyp)
00412 {
00413 size_t nc;
00414 float *img;
00415
00416
00417 img = (float *) read_png_raw(fname, nxp, nyp, &nc,
00418 PNG_TRANSFORM_STRIP_ALPHA, IO_PNG_F32);
00419 if (NULL == img)
00420
00421 return NULL;
00422 if (1 == nc)
00423
00424 return img;
00425 else
00426 {
00427
00428 float *ptr_r, *ptr_g, *ptr_b, *ptr_gray, *ptr_end;
00429
00430
00431
00432
00433
00434
00435
00436 ptr_r = img;
00437 ptr_g = img + *nxp * *nyp;
00438 ptr_b = img + 2 * *nxp * *nyp;
00439 ptr_gray = img;
00440 ptr_end = ptr_gray + *nxp * *nyp;
00441 while (ptr_gray < ptr_end)
00442 *ptr_gray++ = (float) (6969 * *ptr_r++
00443 + 23434 * *ptr_g++
00444 + 2365 * *ptr_b++) / 32768;
00445
00446 img = realloc(img, *nxp * *nyp * sizeof(float));
00447 return img;
00448 }
00449 }
00450
00451
00452
00453
00454
00465 static int write_png_abort(FILE * fp,
00466 png_byte * idata, png_bytep * row_pointers,
00467 png_structp * png_ptr_p, png_infop * info_ptr_p)
00468 {
00469 png_destroy_write_struct(png_ptr_p, info_ptr_p);
00470 if (NULL != row_pointers)
00471 free(row_pointers);
00472 if (NULL != idata)
00473 free(idata);
00474 if (NULL != fp && stdout != fp)
00475 (void) fclose(fp);
00476 return -1;
00477 }
00478
00494 static int write_png_raw(const char *fname, const void *data,
00495 size_t nx, size_t ny, size_t nc, int dtype)
00496 {
00497 png_structp png_ptr;
00498 png_infop info_ptr;
00499 png_byte *idata = NULL, *idata_ptr = NULL;
00500 png_bytep *row_pointers = NULL;
00501 png_byte bit_depth;
00502
00503 FILE *volatile fp;
00504 const unsigned char *data_u8 = NULL;
00505 const unsigned char *data_u8_ptr = NULL;
00506 const float *data_f32 = NULL;
00507 const float *data_f32_ptr = NULL;
00508 float tmp;
00509 int color_type, interlace, compression, filter;
00510 size_t size;
00511 size_t i, j, k;
00512
00513
00514 if (0 >= nx || 0 >= ny || 0 >= nc)
00515 return -1;
00516 if (NULL == fname || NULL == data)
00517 return -1;
00518 if (IO_PNG_U8 != dtype && IO_PNG_F32 != dtype)
00519 return -1;
00520
00521
00522 if (0 == strcmp(fname, "-"))
00523 fp = stdout;
00524 else if (NULL == (fp = fopen(fname, "wb")))
00525 return -1;
00526
00527
00528 size = nx * ny * nc;
00529 if (NULL == (idata = (png_byte *) malloc(size * sizeof(png_byte))))
00530 return write_png_abort(fp, NULL, NULL, NULL, NULL);
00531
00532 if (NULL == (row_pointers = (png_bytep *) malloc(ny * sizeof(png_bytep))))
00533 return write_png_abort(fp, idata, NULL, NULL, NULL);
00534
00535
00536
00537
00538
00539 if (NULL == (png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
00540 NULL, NULL, NULL)))
00541 return write_png_abort(fp, idata, row_pointers, NULL, NULL);
00542
00543
00544 if (NULL == (info_ptr = png_create_info_struct(png_ptr)))
00545 return write_png_abort(fp, idata, row_pointers, &png_ptr, NULL);
00546
00547
00548 if (0 != setjmp(png_jmpbuf(png_ptr)))
00549
00550 return write_png_abort(fp, idata, row_pointers, &png_ptr, &info_ptr);
00551
00552
00553 png_init_io(png_ptr, fp);
00554
00555
00556 bit_depth = 8;
00557 switch (nc)
00558 {
00559 case 1:
00560 color_type = PNG_COLOR_TYPE_GRAY;
00561 break;
00562 case 2:
00563 color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
00564 break;
00565 case 3:
00566 color_type = PNG_COLOR_TYPE_RGB;
00567 break;
00568 case 4:
00569 color_type = PNG_COLOR_TYPE_RGB_ALPHA;
00570 break;
00571 default:
00572 png_destroy_read_struct(&png_ptr, NULL, NULL);
00573 free(row_pointers);
00574 free(idata);
00575 (void) fclose(fp);
00576 return -1;
00577 }
00578 interlace = PNG_INTERLACE_ADAM7;
00579 compression = PNG_COMPRESSION_TYPE_BASE;
00580 filter = PNG_FILTER_TYPE_BASE;
00581
00582
00583 png_set_IHDR(png_ptr, info_ptr, (png_uint_32) nx, (png_uint_32) ny,
00584 bit_depth, color_type, interlace, compression, filter);
00585
00586 png_write_info(png_ptr, info_ptr);
00587
00588
00589
00590
00591
00592
00593 switch (dtype)
00594 {
00595 case IO_PNG_U8:
00596 data_u8 = (unsigned char *) data;
00597 for (k = 0; k < nc; k++)
00598 {
00599
00600 data_u8_ptr = data_u8 + (size_t) (nx * ny * k);
00601 idata_ptr = idata + (size_t) k;
00602 for (j = 0; j < ny; j++)
00603 {
00604
00605 for (i = 0; i < nx; i++)
00606 {
00607
00608 *idata_ptr = (png_byte) * data_u8_ptr++;
00609 idata_ptr += nc;
00610 }
00611 }
00612 }
00613 break;
00614 case IO_PNG_F32:
00615 data_f32 = (float *) data;
00616 for (k = 0; k < nc; k++)
00617 {
00618
00619 data_f32_ptr = data_f32 + (size_t) (nx * ny * k);
00620 idata_ptr = idata + (size_t) k;
00621 for (j = 0; j < ny; j++)
00622 {
00623
00624 for (i = 0; i < nx; i++)
00625 {
00626
00627 tmp = floor(*data_f32_ptr++ + .5);
00628 *idata_ptr = (png_byte) (tmp < 0. ? 0. :
00629 (tmp > 255. ? 255. : tmp));
00630 idata_ptr += nc;
00631 }
00632 }
00633 }
00634 break;
00635 }
00636
00637
00638 for (j = 0; j < ny; j++)
00639 row_pointers[j] = idata + (size_t) (nc * nx * j);
00640
00641
00642 png_write_image(png_ptr, row_pointers);
00643 png_write_end(png_ptr, info_ptr);
00644
00645
00646 (void) write_png_abort(fp, idata, row_pointers, &png_ptr, &info_ptr);
00647
00648 return 0;
00649 }
00650
00659 int write_png_u8(const char *fname, const unsigned char *data,
00660 size_t nx, size_t ny, size_t nc)
00661 {
00662 return write_png_raw(fname, (void *) data,
00663 (png_uint_32) nx, (png_uint_32) ny, (png_byte) nc,
00664 IO_PNG_U8);
00665 }
00666
00679 int write_png_f32(const char *fname, const float *data,
00680 size_t nx, size_t ny, size_t nc)
00681 {
00682 return write_png_raw(fname, (void *) data,
00683 (png_uint_32) nx, (png_uint_32) ny, (png_byte) nc,
00684 IO_PNG_F32);
00685 }