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 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 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 png_byte png_sig[PNG_SIG_LEN];
00114 png_structp png_ptr;
00115 png_infop info_ptr;
00116 png_bytepp row_pointers;
00117 png_bytep row_ptr;
00118
00119 FILE *volatile fp = NULL;
00120 void *data = NULL;
00121 unsigned char *data_u8 = NULL;
00122 unsigned char *data_u8_ptr = NULL;
00123 float *data_f32 = NULL;
00124 float *data_f32_ptr = NULL;
00125 size_t size;
00126 size_t i, j, k;
00127
00128
00129 if (NULL == fname || NULL == nxp || NULL == nyp || NULL == ncp)
00130 return NULL;
00131 if (IO_PNG_U8 != dtype && IO_PNG_F32 != dtype)
00132 return NULL;
00133
00134
00135 if (0 == strcmp(fname, "-"))
00136 fp = stdin;
00137 else if (NULL == (fp = fopen(fname, "rb")))
00138 return NULL;
00139
00140
00141 if ((PNG_SIG_LEN != fread(png_sig, 1, PNG_SIG_LEN, fp))
00142 || 0 != png_sig_cmp(png_sig, (png_size_t) 0, PNG_SIG_LEN))
00143 return io_png_read_abort(fp, NULL, NULL);
00144
00145
00146
00147
00148
00149 if (NULL == (png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
00150 NULL, NULL, NULL)))
00151 return io_png_read_abort(fp, NULL, NULL);
00152
00153
00154 if (NULL == (info_ptr = png_create_info_struct(png_ptr)))
00155 return io_png_read_abort(fp, &png_ptr, NULL);
00156
00157
00158 if (0 != setjmp(png_jmpbuf(png_ptr)))
00159
00160
00161 return io_png_read_abort(fp, &png_ptr, &info_ptr);
00162
00163
00164 png_init_io(png_ptr, fp);
00165
00166
00167 png_set_sig_bytes(png_ptr, PNG_SIG_LEN);
00168
00169
00170
00171
00172
00173
00174
00175
00176 png_transform |= (PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING);
00177
00178
00179 png_read_png(png_ptr, info_ptr, png_transform, NULL);
00180
00181
00182 *nxp = (size_t) png_get_image_width(png_ptr, info_ptr);
00183 *nyp = (size_t) png_get_image_height(png_ptr, info_ptr);
00184 *ncp = (size_t) png_get_channels(png_ptr, info_ptr);
00185 row_pointers = png_get_rows(png_ptr, info_ptr);
00186
00187
00188
00189
00190
00191
00192
00193 size = *nxp * *nyp * *ncp;
00194 switch (dtype) {
00195 case IO_PNG_U8:
00196 if (NULL == (data_u8 =
00197 (unsigned char *) malloc(size * sizeof(unsigned char))))
00198 return io_png_read_abort(fp, &png_ptr, &info_ptr);
00199 data = (void *) data_u8;
00200 for (k = 0; k < *ncp; k++) {
00201
00202 data_u8_ptr = data_u8 + (size_t) (*nxp * *nyp * k);
00203 for (j = 0; j < *nyp; j++) {
00204
00205 row_ptr = row_pointers[j] + k;
00206 for (i = 0; i < *nxp; i++) {
00207
00208 *data_u8_ptr++ = (unsigned char) *row_ptr;
00209 row_ptr += *ncp;
00210 }
00211 }
00212 }
00213 break;
00214 case IO_PNG_F32:
00215 if (NULL == (data_f32 = (float *) malloc(size * sizeof(float))))
00216 return io_png_read_abort(fp, &png_ptr, &info_ptr);
00217 data = (void *) data_f32;
00218 for (k = 0; k < *ncp; k++) {
00219
00220 data_f32_ptr = data_f32 + (size_t) (*nxp * *nyp * k);
00221 for (j = 0; j < *nyp; j++) {
00222
00223 row_ptr = row_pointers[j] + k;
00224 for (i = 0; i < *nxp; i++) {
00225
00226 *data_f32_ptr++ = (float) *row_ptr;
00227 row_ptr += *ncp;
00228 }
00229 }
00230 }
00231 break;
00232 }
00233
00234
00235 (void) io_png_read_abort(fp, &png_ptr, &info_ptr);
00236
00237 return data;
00238 }
00239
00255 unsigned char *io_png_read_u8(const char *fname,
00256 size_t * nxp, size_t * nyp, size_t * ncp) {
00257
00258 return (unsigned char *) io_png_read_raw(fname, nxp, nyp, ncp,
00259 PNG_TRANSFORM_IDENTITY,
00260 IO_PNG_U8);
00261 }
00262
00268 unsigned char *io_png_read_u8_rgb(const char *fname, size_t * nxp,
00269 size_t * nyp) {
00270 size_t nc;
00271 unsigned char *img;
00272
00273
00274 img = (unsigned char *) io_png_read_raw(fname, nxp, nyp, &nc,
00275 PNG_TRANSFORM_STRIP_ALPHA,
00276 IO_PNG_U8);
00277 if (NULL == img)
00278
00279 return NULL;
00280 if (3 == nc)
00281
00282 return img;
00283 else {
00284
00285 size_t i, size;
00286 unsigned char *img_r, *img_g, *img_b;
00287
00288
00289 size = *nxp * *nyp;
00290 img = (unsigned char *)
00291 realloc(img, 3 * size * sizeof(unsigned char));
00292 img_r = img;
00293 img_g = img + size;
00294 img_b = img + 2 * size;
00295
00296
00297 for (i = 0; i < size; i++) {
00298 img_g[i] = img_r[i];
00299 img_b[i] = img_r[i];
00300 }
00301 return img;
00302 }
00303 }
00304
00310 unsigned char *io_png_read_u8_gray(const char *fname,
00311 size_t * nxp, size_t * nyp) {
00312 size_t nc;
00313 unsigned char *img;
00314
00315
00316 img = (unsigned char *) io_png_read_raw(fname, nxp, nyp, &nc,
00317 PNG_TRANSFORM_STRIP_ALPHA,
00318 IO_PNG_U8);
00319 if (NULL == img)
00320
00321 return NULL;
00322 if (1 == nc)
00323
00324 return img;
00325 else {
00326
00327 size_t i, size;
00328 unsigned char *img_r, *img_g, *img_b;
00329
00330
00331
00332
00333
00334
00335
00336 size = *nxp * *nyp;
00337 img_r = img;
00338 img_g = img + size;
00339 img_b = img + 2 * size;
00340 for (i = 0; i < size; i++)
00341 img[i] = (unsigned char) ((6969 * img_r[i]
00342 + 23434 * img_g[i]
00343 + 2365 * img_b[i]) / 32768);
00344
00345 img = (unsigned char *) realloc(img, size * sizeof(unsigned char));
00346 return img;
00347 }
00348 }
00349
00364 float *io_png_read_f32(const char *fname,
00365 size_t * nxp, size_t * nyp, size_t * ncp) {
00366
00367 return (float *) io_png_read_raw(fname, nxp, nyp, ncp,
00368 PNG_TRANSFORM_IDENTITY, IO_PNG_F32);
00369 }
00370
00376 float *io_png_read_f32_rgb(const char *fname, size_t * nxp, size_t * nyp) {
00377 size_t nc;
00378 float *img;
00379
00380
00381 img = (float *) io_png_read_raw(fname, nxp, nyp, &nc,
00382 PNG_TRANSFORM_STRIP_ALPHA, IO_PNG_F32);
00383 if (NULL == img)
00384
00385 return NULL;
00386 if (3 == nc)
00387
00388 return img;
00389 else {
00390
00391 size_t i, size;
00392 float *img_r, *img_g, *img_b;
00393
00394
00395 size = *nxp * *nyp;
00396 img = (float *) realloc(img, 3 * size * sizeof(float));
00397 img_r = img;
00398 img_g = img + size;
00399 img_b = img + 2 * size;
00400
00401
00402 for (i = 0; i < size; i++) {
00403 img_g[i] = img_r[i];
00404 img_b[i] = img_r[i];
00405 }
00406 return img;
00407 }
00408 }
00409
00415 float *io_png_read_f32_gray(const char *fname, size_t * nxp, size_t * nyp) {
00416 size_t nc;
00417 float *img;
00418
00419
00420 img = (float *) io_png_read_raw(fname, nxp, nyp, &nc,
00421 PNG_TRANSFORM_STRIP_ALPHA, IO_PNG_F32);
00422 if (NULL == img)
00423
00424 return NULL;
00425 if (1 == nc)
00426
00427 return img;
00428 else {
00429
00430 size_t i, size;
00431 float *img_r, *img_g, *img_b;
00432
00433
00434
00435
00436
00437 size = *nxp * *nyp;
00438 img_r = img;
00439 img_g = img + size;
00440 img_b = img + 2 * size;
00441 for (i = 0; i < size; i++)
00442 img[i] = (float) (0.212671 * img_r[i]
00443 + 0.715160 * img_g[i]
00444 + 0.072169 * img_b[i]);
00445
00446 img = (float *) realloc(img, size * sizeof(float));
00447 return img;
00448 }
00449 }
00450
00451
00452
00453
00454
00465 static int io_png_write_abort(FILE * fp,
00466 png_byte * idata, png_bytep * row_pointers,
00467 png_structp * png_ptr_p, png_infop * info_ptr_p) {
00468 png_destroy_write_struct(png_ptr_p, info_ptr_p);
00469 if (NULL != row_pointers)
00470 free(row_pointers);
00471 if (NULL != idata)
00472 free(idata);
00473 if (NULL != fp && stdout != fp)
00474 (void) fclose(fp);
00475 return -1;
00476 }
00477
00493 static int io_png_write_raw(const char *fname, const void *data,
00494 size_t nx, size_t ny, size_t nc, int dtype) {
00495 png_structp png_ptr;
00496 png_infop info_ptr;
00497 png_byte *idata = NULL, *idata_ptr = NULL;
00498 png_bytep *row_pointers = NULL;
00499 png_byte bit_depth;
00500
00501 FILE *volatile fp;
00502 const unsigned char *data_u8 = NULL;
00503 const unsigned char *data_u8_ptr = NULL;
00504 const float *data_f32 = NULL;
00505 const float *data_f32_ptr = NULL;
00506 float tmp;
00507 int color_type, interlace, compression, filter;
00508 size_t size;
00509 size_t i, j, k;
00510
00511
00512 if (0 >= nx || 0 >= ny || 0 >= nc)
00513 return -1;
00514 if (NULL == fname || NULL == data)
00515 return -1;
00516 if (IO_PNG_U8 != dtype && IO_PNG_F32 != dtype)
00517 return -1;
00518
00519
00520 if (0 == strcmp(fname, "-"))
00521 fp = stdout;
00522 else if (NULL == (fp = fopen(fname, "wb")))
00523 return -1;
00524
00525
00526 size = nx * ny * nc;
00527 if (NULL == (idata = (png_byte *) malloc(size * sizeof(png_byte))))
00528 return io_png_write_abort(fp, NULL, NULL, NULL, NULL);
00529
00530 if (NULL == (row_pointers = (png_bytep *) malloc(ny * sizeof(png_bytep))))
00531 return io_png_write_abort(fp, idata, NULL, NULL, NULL);
00532
00533
00534
00535
00536
00537 if (NULL == (png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
00538 NULL, NULL, NULL)))
00539 return io_png_write_abort(fp, idata, row_pointers, NULL, NULL);
00540
00541
00542 if (NULL == (info_ptr = png_create_info_struct(png_ptr)))
00543 return io_png_write_abort(fp, idata, row_pointers, &png_ptr, NULL);
00544
00545
00546 if (0 != setjmp(png_jmpbuf(png_ptr)))
00547
00548 return io_png_write_abort(fp, idata, row_pointers, &png_ptr,
00549 &info_ptr);
00550
00551
00552 png_init_io(png_ptr, fp);
00553
00554
00555 bit_depth = 8;
00556 switch (nc) {
00557 case 1:
00558 color_type = PNG_COLOR_TYPE_GRAY;
00559 break;
00560 case 2:
00561 color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
00562 break;
00563 case 3:
00564 color_type = PNG_COLOR_TYPE_RGB;
00565 break;
00566 case 4:
00567 color_type = PNG_COLOR_TYPE_RGB_ALPHA;
00568 break;
00569 default:
00570 png_destroy_read_struct(&png_ptr, NULL, NULL);
00571 free(row_pointers);
00572 free(idata);
00573 (void) fclose(fp);
00574 return -1;
00575 }
00576 interlace = PNG_INTERLACE_ADAM7;
00577 compression = PNG_COMPRESSION_TYPE_BASE;
00578 filter = PNG_FILTER_TYPE_BASE;
00579
00580
00581 png_set_IHDR(png_ptr, info_ptr, (png_uint_32) nx, (png_uint_32) ny,
00582 bit_depth, color_type, interlace, compression, filter);
00583
00584 png_write_info(png_ptr, info_ptr);
00585
00586
00587
00588
00589
00590
00591 switch (dtype) {
00592 case IO_PNG_U8:
00593 data_u8 = (unsigned char *) data;
00594 for (k = 0; k < nc; k++) {
00595
00596 data_u8_ptr = data_u8 + (size_t) (nx * ny * k);
00597 idata_ptr = idata + (size_t) k;
00598 for (j = 0; j < ny; j++) {
00599
00600 for (i = 0; i < nx; i++) {
00601
00602 *idata_ptr = (png_byte) * data_u8_ptr++;
00603 idata_ptr += nc;
00604 }
00605 }
00606 }
00607 break;
00608 case IO_PNG_F32:
00609 data_f32 = (float *) data;
00610 for (k = 0; k < nc; k++) {
00611
00612 data_f32_ptr = data_f32 + (size_t) (nx * ny * k);
00613 idata_ptr = idata + (size_t) k;
00614 for (j = 0; j < ny; j++) {
00615
00616 for (i = 0; i < nx; i++) {
00617
00618 tmp = floor(*data_f32_ptr++ + .5);
00619 *idata_ptr = (png_byte) (tmp < 0. ? 0. :
00620 (tmp > 255. ? 255. : tmp));
00621 idata_ptr += nc;
00622 }
00623 }
00624 }
00625 break;
00626 }
00627
00628
00629 for (j = 0; j < ny; j++)
00630 row_pointers[j] = idata + (size_t) (nc * nx * j);
00631
00632
00633 png_write_image(png_ptr, row_pointers);
00634 png_write_end(png_ptr, info_ptr);
00635
00636
00637 (void) io_png_write_abort(fp, idata, row_pointers, &png_ptr, &info_ptr);
00638
00639 return 0;
00640 }
00641
00650 int io_png_write_u8(const char *fname, const unsigned char *data,
00651 size_t nx, size_t ny, size_t nc) {
00652 return io_png_write_raw(fname, (void *) data,
00653 (png_uint_32) nx, (png_uint_32) ny, (png_byte) nc,
00654 IO_PNG_U8);
00655 }
00656
00669 int io_png_write_f32(const char *fname, const float *data,
00670 size_t nx, size_t ny, size_t nc) {
00671 return io_png_write_raw(fname, (void *) data,
00672 (png_uint_32) nx, (png_uint_32) ny, (png_byte) nc,
00673 IO_PNG_F32);
00674 }