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 IO_PNG_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
00058
00059
00060
00061 static char io_png_tag[] = "using io_png " IO_PNG_VERSION;
00070 char *io_png_info(void)
00071 {
00072 return io_png_tag;
00073 }
00074
00075
00076
00077
00078
00088 static void *io_png_read_abort(FILE * fp,
00089 png_structp * png_ptr_p,
00090 png_infop * info_ptr_p)
00091 {
00092 png_destroy_read_struct(png_ptr_p, info_ptr_p, NULL);
00093 if (NULL != fp && stdin != fp)
00094 (void) fclose(fp);
00095 return NULL;
00096 }
00097
00112 static void *io_png_read_raw(const char *fname,
00113 size_t * nxp, size_t * nyp, size_t * ncp,
00114 int png_transform, int dtype)
00115 {
00116 png_byte png_sig[PNG_SIG_LEN];
00117 png_structp png_ptr;
00118 png_infop info_ptr;
00119 png_bytepp row_pointers;
00120 png_bytep row_ptr;
00121
00122 FILE *volatile fp = NULL;
00123 void *data = NULL;
00124 unsigned char *data_u8 = NULL;
00125 unsigned char *data_u8_ptr = NULL;
00126 float *data_f32 = NULL;
00127 float *data_f32_ptr = NULL;
00128 size_t size;
00129 size_t i, j, k;
00130
00131
00132 if (NULL == fname || NULL == nxp || NULL == nyp || NULL == ncp)
00133 return NULL;
00134 if (IO_PNG_U8 != dtype && IO_PNG_F32 != dtype)
00135 return NULL;
00136
00137
00138 if (0 == strcmp(fname, "-"))
00139 fp = stdin;
00140 else if (NULL == (fp = fopen(fname, "rb")))
00141 return NULL;
00142
00143
00144 if ((PNG_SIG_LEN != fread(png_sig, 1, PNG_SIG_LEN, fp))
00145 || 0 != png_sig_cmp(png_sig, (png_size_t) 0, PNG_SIG_LEN))
00146 return io_png_read_abort(fp, NULL, NULL);
00147
00148
00149
00150
00151
00152 if (NULL == (png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
00153 NULL, NULL, NULL)))
00154 return io_png_read_abort(fp, NULL, NULL);
00155
00156
00157 if (NULL == (info_ptr = png_create_info_struct(png_ptr)))
00158 return io_png_read_abort(fp, &png_ptr, NULL);
00159
00160
00161 if (0 != setjmp(png_jmpbuf(png_ptr)))
00162
00163
00164 return io_png_read_abort(fp, &png_ptr, &info_ptr);
00165
00166
00167 png_init_io(png_ptr, fp);
00168
00169
00170 png_set_sig_bytes(png_ptr, PNG_SIG_LEN);
00171
00172
00173
00174
00175
00176
00177
00178
00179 png_transform |= (PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING);
00180
00181
00182 png_read_png(png_ptr, info_ptr, png_transform, NULL);
00183
00184
00185 *nxp = (size_t) png_get_image_width(png_ptr, info_ptr);
00186 *nyp = (size_t) png_get_image_height(png_ptr, info_ptr);
00187 *ncp = (size_t) png_get_channels(png_ptr, info_ptr);
00188 row_pointers = png_get_rows(png_ptr, info_ptr);
00189
00190
00191
00192
00193
00194
00195
00196 size = *nxp * *nyp * *ncp;
00197 switch (dtype) {
00198 case IO_PNG_U8:
00199 if (NULL == (data_u8 =
00200 (unsigned char *) malloc(size * sizeof(unsigned char))))
00201 return io_png_read_abort(fp, &png_ptr, &info_ptr);
00202 data = (void *) data_u8;
00203 for (k = 0; k < *ncp; k++) {
00204
00205 data_u8_ptr = data_u8 + (size_t) (*nxp * *nyp * k);
00206 for (j = 0; j < *nyp; j++) {
00207
00208 row_ptr = row_pointers[j] + k;
00209 for (i = 0; i < *nxp; i++) {
00210
00211 *data_u8_ptr++ = (unsigned char) *row_ptr;
00212 row_ptr += *ncp;
00213 }
00214 }
00215 }
00216 break;
00217 case IO_PNG_F32:
00218 if (NULL == (data_f32 = (float *) malloc(size * sizeof(float))))
00219 return io_png_read_abort(fp, &png_ptr, &info_ptr);
00220 data = (void *) data_f32;
00221 for (k = 0; k < *ncp; k++) {
00222
00223 data_f32_ptr = data_f32 + (size_t) (*nxp * *nyp * k);
00224 for (j = 0; j < *nyp; j++) {
00225
00226 row_ptr = row_pointers[j] + k;
00227 for (i = 0; i < *nxp; i++) {
00228
00229 *data_f32_ptr++ = (float) *row_ptr;
00230 row_ptr += *ncp;
00231 }
00232 }
00233 }
00234 break;
00235 }
00236
00237
00238 (void) io_png_read_abort(fp, &png_ptr, &info_ptr);
00239
00240 return data;
00241 }
00242
00258 unsigned char *io_png_read_u8(const char *fname,
00259 size_t * nxp, size_t * nyp, size_t * ncp)
00260 {
00261
00262 return (unsigned char *) io_png_read_raw(fname, nxp, nyp, ncp,
00263 PNG_TRANSFORM_IDENTITY,
00264 IO_PNG_U8);
00265 }
00266
00272 unsigned char *io_png_read_u8_rgb(const char *fname, size_t * nxp,
00273 size_t * nyp)
00274 {
00275 size_t nc;
00276 unsigned char *img;
00277
00278
00279 img = (unsigned char *) io_png_read_raw(fname, nxp, nyp, &nc,
00280 PNG_TRANSFORM_STRIP_ALPHA,
00281 IO_PNG_U8);
00282 if (NULL == img)
00283
00284 return NULL;
00285 if (3 == nc)
00286
00287 return img;
00288 else {
00289
00290 size_t i, size;
00291 unsigned char *img_r, *img_g, *img_b;
00292
00293
00294 size = *nxp * *nyp;
00295 img = (unsigned char *)
00296 realloc(img, 3 * size * sizeof(unsigned char));
00297 img_r = img;
00298 img_g = img + size;
00299 img_b = img + 2 * size;
00300
00301
00302 for (i = 0; i < size; i++) {
00303 img_g[i] = img_r[i];
00304 img_b[i] = img_r[i];
00305 }
00306 return img;
00307 }
00308 }
00309
00315 unsigned char *io_png_read_u8_gray(const char *fname,
00316 size_t * nxp, size_t * nyp)
00317 {
00318 size_t nc;
00319 unsigned char *img;
00320
00321
00322 img = (unsigned char *) io_png_read_raw(fname, nxp, nyp, &nc,
00323 PNG_TRANSFORM_STRIP_ALPHA,
00324 IO_PNG_U8);
00325 if (NULL == img)
00326
00327 return NULL;
00328 if (1 == nc)
00329
00330 return img;
00331 else {
00332
00333 size_t i, size;
00334 unsigned char *img_r, *img_g, *img_b;
00335
00336
00337
00338
00339
00340
00341
00342 size = *nxp * *nyp;
00343 img_r = img;
00344 img_g = img + size;
00345 img_b = img + 2 * size;
00346 for (i = 0; i < size; i++)
00347 img[i] = (unsigned char) ((6969 * img_r[i]
00348 + 23434 * img_g[i]
00349 + 2365 * img_b[i]) / 32768);
00350
00351 img = (unsigned char *) realloc(img, size * sizeof(unsigned char));
00352 return img;
00353 }
00354 }
00355
00370 float *io_png_read_f32(const char *fname,
00371 size_t * nxp, size_t * nyp, size_t * ncp)
00372 {
00373
00374 return (float *) io_png_read_raw(fname, nxp, nyp, ncp,
00375 PNG_TRANSFORM_IDENTITY, IO_PNG_F32);
00376 }
00377
00383 float *io_png_read_f32_rgb(const char *fname, size_t * nxp, size_t * nyp)
00384 {
00385 size_t nc;
00386 float *img;
00387
00388
00389 img = (float *) io_png_read_raw(fname, nxp, nyp, &nc,
00390 PNG_TRANSFORM_STRIP_ALPHA, IO_PNG_F32);
00391 if (NULL == img)
00392
00393 return NULL;
00394 if (3 == nc)
00395
00396 return img;
00397 else {
00398
00399 size_t i, size;
00400 float *img_r, *img_g, *img_b;
00401
00402
00403 size = *nxp * *nyp;
00404 img = (float *) realloc(img, 3 * size * sizeof(float));
00405 img_r = img;
00406 img_g = img + size;
00407 img_b = img + 2 * size;
00408
00409
00410 for (i = 0; i < size; i++) {
00411 img_g[i] = img_r[i];
00412 img_b[i] = img_r[i];
00413 }
00414 return img;
00415 }
00416 }
00417
00423 float *io_png_read_f32_gray(const char *fname, size_t * nxp, size_t * nyp)
00424 {
00425 size_t nc;
00426 float *img;
00427
00428
00429 img = (float *) io_png_read_raw(fname, nxp, nyp, &nc,
00430 PNG_TRANSFORM_STRIP_ALPHA, IO_PNG_F32);
00431 if (NULL == img)
00432
00433 return NULL;
00434 if (1 == nc)
00435
00436 return img;
00437 else {
00438
00439 size_t i, size;
00440 float *img_r, *img_g, *img_b;
00441
00442
00443
00444
00445
00446 size = *nxp * *nyp;
00447 img_r = img;
00448 img_g = img + size;
00449 img_b = img + 2 * size;
00450 for (i = 0; i < size; i++)
00451 img[i] = (float) (0.212671 * img_r[i]
00452 + 0.715160 * img_g[i]
00453 + 0.072169 * img_b[i]);
00454
00455 img = (float *) realloc(img, size * sizeof(float));
00456 return img;
00457 }
00458 }
00459
00460
00461
00462
00463
00474 static int io_png_write_abort(FILE * fp,
00475 png_byte * idata, png_bytep * row_pointers,
00476 png_structp * png_ptr_p, png_infop * info_ptr_p)
00477 {
00478 png_destroy_write_struct(png_ptr_p, info_ptr_p);
00479 if (NULL != row_pointers)
00480 free(row_pointers);
00481 if (NULL != idata)
00482 free(idata);
00483 if (NULL != fp && stdout != fp)
00484 (void) fclose(fp);
00485 return -1;
00486 }
00487
00503 static int io_png_write_raw(const char *fname, const void *data,
00504 size_t nx, size_t ny, size_t nc, int dtype)
00505 {
00506 png_structp png_ptr;
00507 png_infop info_ptr;
00508 png_byte *idata = NULL, *idata_ptr = NULL;
00509 png_bytep *row_pointers = NULL;
00510 png_byte bit_depth;
00511
00512 FILE *volatile fp;
00513 const unsigned char *data_u8 = NULL;
00514 const unsigned char *data_u8_ptr = NULL;
00515 const float *data_f32 = NULL;
00516 const float *data_f32_ptr = NULL;
00517 float tmp;
00518 int color_type, interlace, compression, filter;
00519 size_t size;
00520 size_t i, j, k;
00521
00522
00523 if (0 >= nx || 0 >= ny || 0 >= nc)
00524 return -1;
00525 if (NULL == fname || NULL == data)
00526 return -1;
00527 if (IO_PNG_U8 != dtype && IO_PNG_F32 != dtype)
00528 return -1;
00529
00530
00531 if (0 == strcmp(fname, "-"))
00532 fp = stdout;
00533 else if (NULL == (fp = fopen(fname, "wb")))
00534 return -1;
00535
00536
00537 size = nx * ny * nc;
00538 if (NULL == (idata = (png_byte *) malloc(size * sizeof(png_byte))))
00539 return io_png_write_abort(fp, NULL, NULL, NULL, NULL);
00540
00541 if (NULL == (row_pointers = (png_bytep *) malloc(ny * sizeof(png_bytep))))
00542 return io_png_write_abort(fp, idata, NULL, NULL, NULL);
00543
00544
00545
00546
00547
00548 if (NULL == (png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
00549 NULL, NULL, NULL)))
00550 return io_png_write_abort(fp, idata, row_pointers, NULL, NULL);
00551
00552
00553 if (NULL == (info_ptr = png_create_info_struct(png_ptr)))
00554 return io_png_write_abort(fp, idata, row_pointers, &png_ptr, NULL);
00555
00556
00557 if (0 != setjmp(png_jmpbuf(png_ptr)))
00558
00559 return io_png_write_abort(fp, idata, row_pointers, &png_ptr,
00560 &info_ptr);
00561
00562
00563 png_init_io(png_ptr, fp);
00564
00565
00566 bit_depth = 8;
00567 switch (nc) {
00568 case 1:
00569 color_type = PNG_COLOR_TYPE_GRAY;
00570 break;
00571 case 2:
00572 color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
00573 break;
00574 case 3:
00575 color_type = PNG_COLOR_TYPE_RGB;
00576 break;
00577 case 4:
00578 color_type = PNG_COLOR_TYPE_RGB_ALPHA;
00579 break;
00580 default:
00581 png_destroy_read_struct(&png_ptr, NULL, NULL);
00582 free(row_pointers);
00583 free(idata);
00584 (void) fclose(fp);
00585 return -1;
00586 }
00587 interlace = PNG_INTERLACE_ADAM7;
00588 compression = PNG_COMPRESSION_TYPE_BASE;
00589 filter = PNG_FILTER_TYPE_BASE;
00590
00591
00592 png_set_IHDR(png_ptr, info_ptr, (png_uint_32) nx, (png_uint_32) ny,
00593 bit_depth, color_type, interlace, compression, filter);
00594
00595 png_write_info(png_ptr, info_ptr);
00596
00597
00598
00599
00600
00601
00602 switch (dtype) {
00603 case IO_PNG_U8:
00604 data_u8 = (unsigned char *) data;
00605 for (k = 0; k < nc; k++) {
00606
00607 data_u8_ptr = data_u8 + (size_t) (nx * ny * k);
00608 idata_ptr = idata + (size_t) k;
00609 for (j = 0; j < ny; j++) {
00610
00611 for (i = 0; i < nx; i++) {
00612
00613 *idata_ptr = (png_byte) * data_u8_ptr++;
00614 idata_ptr += nc;
00615 }
00616 }
00617 }
00618 break;
00619 case IO_PNG_F32:
00620 data_f32 = (float *) data;
00621 for (k = 0; k < nc; k++) {
00622
00623 data_f32_ptr = data_f32 + (size_t) (nx * ny * k);
00624 idata_ptr = idata + (size_t) k;
00625 for (j = 0; j < ny; j++) {
00626
00627 for (i = 0; i < nx; i++) {
00628
00629 tmp = floor(*data_f32_ptr++ + .5);
00630 *idata_ptr = (png_byte) (tmp < 0. ? 0. :
00631 (tmp > 255. ? 255. : tmp));
00632 idata_ptr += nc;
00633 }
00634 }
00635 }
00636 break;
00637 }
00638
00639
00640 for (j = 0; j < ny; j++)
00641 row_pointers[j] = idata + (size_t) (nc * nx * j);
00642
00643
00644 png_write_image(png_ptr, row_pointers);
00645 png_write_end(png_ptr, info_ptr);
00646
00647
00648 (void) io_png_write_abort(fp, idata, row_pointers, &png_ptr, &info_ptr);
00649
00650 return 0;
00651 }
00652
00661 int io_png_write_u8(const char *fname, const unsigned char *data,
00662 size_t nx, size_t ny, size_t nc)
00663 {
00664 return io_png_write_raw(fname, (void *) data,
00665 (png_uint_32) nx, (png_uint_32) ny, (png_byte) nc,
00666 IO_PNG_U8);
00667 }
00668
00681 int io_png_write_f32(const char *fname, const float *data,
00682 size_t nx, size_t ny, size_t nc)
00683 {
00684 return io_png_write_raw(fname, (void *) data,
00685 (png_uint_32) nx, (png_uint_32) ny, (png_byte) nc,
00686 IO_PNG_F32);
00687 }