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