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