• Main Page
  • Related Pages
  • Files
  • File List
  • Globals

io_png.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010-2011, Nicolas Limare <nicolas.limare@cmla.ens-cachan.fr>
00003  * All rights reserved.
00004  *
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under, at your option, the terms of the GNU General Public
00007  * License as published by the Free Software Foundation, either
00008  * version 3 of the License, or (at your option) any later version, or
00009  * the terms of the simplified BSD license.
00010  *
00011  * You should have received a copy of these licenses along this
00012  * program. If not, see <http://www.gnu.org/licenses/> and
00013  * <http://www.opensource.org/licenses/bsd-license.html>.
00014  */
00015 
00034 #include <stdlib.h>
00035 #include <stdio.h>
00036 #include <math.h>
00037 
00038 /* option to use a local version of the libpng */
00039 #ifdef IO_PNG_LOCAL_LIBPNG
00040 #include "png.h"
00041 #else
00042 #include <png.h>
00043 #endif
00044 
00045 /* ensure consistency */
00046 #include "io_png.h"
00047 
00048 #define PNG_SIG_LEN 4
00049 
00050 /* internal only datatype identifiers */
00051 #define IO_PNG_U8  0x0001       /*  8bit unsigned integer */
00052 #define IO_PNG_F32 0x0002       /* 32bit float */
00053 
00054 /*
00055  * INFO
00056  */
00057 
00058 /* string tag inserted into the binary */
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  * READ
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     /* volatile: because of setjmp/longjmp */
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     /* parameters check */
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     /* open the PNG input file */
00136     if (0 == strcmp(fname, "-"))
00137         fp = stdin;
00138     else if (NULL == (fp = fopen(fname, "rb")))
00139         return NULL;
00140 
00141     /* read in some of the signature bytes and check this signature */
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      * create and initialize the png_struct
00148      * with the default stderr and error handling
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     /* allocate/initialize the memory for image information */
00155     if (NULL == (info_ptr = png_create_info_struct(png_ptr)))
00156         return io_png_read_abort(fp, &png_ptr, NULL);
00157 
00158     /* set error handling */
00159     if (0 != setjmp(png_jmpbuf(png_ptr)))
00160         /* if we get here, we had a problem reading the file */
00161         /* free all of the memory associated with the png_ptr and info_ptr */
00162         return io_png_read_abort(fp, &png_ptr, &info_ptr);
00163 
00164     /* set up the input control using standard C streams */
00165     png_init_io(png_ptr, fp);
00166 
00167     /* let libpng know that some bytes have been read */
00168     png_set_sig_bytes(png_ptr, PNG_SIG_LEN);
00169 
00170     /*
00171      * set the read filter transforms, to get 8bit RGB whatever the
00172      * original file may contain:
00173      * PNG_TRANSFORM_STRIP_16      strip 16-bit samples to 8 bits
00174      * PNG_TRANSFORM_PACKING       expand 1, 2 and 4-bit
00175      *                             samples to bytes
00176      */
00177     png_transform |= (PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING);
00178 
00179     /* read in the entire image at once */
00180     png_read_png(png_ptr, info_ptr, png_transform, NULL);
00181 
00182     /* get image informations */
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      * allocate the output data RGB array
00190      * deinterlace and convert png RGB RGB RGB 8bit to RRR GGG BBB
00191      * the image is deinterlaced layer after layer
00192      * this generic loop also works for one single channel
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             /* channel loop */
00203             data_u8_ptr = data_u8 + (size_t) (*nxp * *nyp * k);
00204             for (j = 0; j < *nyp; j++) {
00205                 /* row loop */
00206                 row_ptr = row_pointers[j] + k;
00207                 for (i = 0; i < *nxp; i++) {
00208                     /* pixel loop */
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             /* channel loop */
00221             data_f32_ptr = data_f32 + (size_t) (*nxp * *nyp * k);
00222             for (j = 0; j < *nyp; j++) {
00223                 /* row loop */
00224                 row_ptr = row_pointers[j] + k;
00225                 for (i = 0; i < *nxp; i++) {
00226                     /* pixel loop */
00227                     *data_f32_ptr++ = (float) *row_ptr;
00228                     row_ptr += *ncp;
00229                 }
00230             }
00231         }
00232         break;
00233     }
00234 
00235     /* clean up and free any memory allocated, close the file */
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     /* read the image as unsigned char */
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     /* read the image */
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         /* error */
00282         return NULL;
00283     if (3 == nc)
00284         /* already RGB */
00285         return img;
00286     else {
00287         /* convert to RGB */
00288         size_t i, size;
00289         unsigned char *img_r, *img_g, *img_b;
00290 
00291         /* resize the image */
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         /* gray->RGB conversion */
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     /* read the image */
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         /* error */
00325         return NULL;
00326     if (1 == nc)
00327         /* already gray */
00328         return img;
00329     else {
00330         /* convert to gray */
00331         size_t i, size;
00332         unsigned char *img_r, *img_g, *img_b;
00333 
00334         /*
00335          * RGB->gray conversion
00336          * Y = (6969 * R + 23434 * G + 2365 * B)/32768
00337          * integer approximation of
00338          * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
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         /* resize and return the image */
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     /* read the image as float */
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     /* read the image */
00387     img = (float *) io_png_read_raw(fname, nxp, nyp, &nc,
00388                                     PNG_TRANSFORM_STRIP_ALPHA, IO_PNG_F32);
00389     if (NULL == img)
00390         /* error */
00391         return NULL;
00392     if (3 == nc)
00393         /* already RGB */
00394         return img;
00395     else {
00396         /* convert to RGB */
00397         size_t i, size;
00398         float *img_r, *img_g, *img_b;
00399 
00400         /* resize the image */
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         /* gray->RGB conversion */
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     /* read the image */
00427     img = (float *) io_png_read_raw(fname, nxp, nyp, &nc,
00428                                     PNG_TRANSFORM_STRIP_ALPHA, IO_PNG_F32);
00429     if (NULL == img)
00430         /* error */
00431         return NULL;
00432     if (1 == nc)
00433         /* already gray */
00434         return img;
00435     else {
00436         /* convert to gray */
00437         size_t i, size;
00438         float *img_r, *img_g, *img_b;
00439 
00440         /*
00441          * RGB->gray conversion
00442          * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
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         /* resize and return the image */
00453         img = (float *) realloc(img, size * sizeof(float));
00454         return img;
00455     }
00456 }
00457 
00458 /*
00459  * WRITE
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     /* volatile: because of setjmp/longjmp */
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     /* parameters check */
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     /* open the PNG output file */
00529     if (0 == strcmp(fname, "-"))
00530         fp = stdout;
00531     else if (NULL == (fp = fopen(fname, "wb")))
00532         return -1;
00533 
00534     /* allocate the interlaced array and row pointers */
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      * create and initialize the png_struct
00544      * with the default stderr and error handling
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     /* allocate/initialize the memory for image information */
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     /* set error handling */
00555     if (0 != setjmp(png_jmpbuf(png_ptr)))
00556         /* if we get here, we had a problem reading the file */
00557         return io_png_write_abort(fp, idata, row_pointers, &png_ptr,
00558                                   &info_ptr);
00559 
00560     /* set up the input control using standard C streams */
00561     png_init_io(png_ptr, fp);
00562 
00563     /* set image informations */
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     /* set image header */
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     /* TODO : significant bit (sBIT), gamma (gAMA), comments (text) chunks */
00593     png_write_info(png_ptr, info_ptr);
00594 
00595     /*
00596      * interlace and convert RRR GGG BBB to RGB RGB RGB
00597      * the image is interlaced layer after layer
00598      * this involves more memory exchange, but allows a generic loop
00599      */
00600     switch (dtype) {
00601     case IO_PNG_U8:
00602         data_u8 = (unsigned char *) data;
00603         for (k = 0; k < nc; k++) {
00604             /* channel loop */
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                 /* row loop */
00609                 for (i = 0; i < nx; i++) {
00610                     /* pixel loop */
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             /* channel loop */
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                 /* row loop */
00625                 for (i = 0; i < nx; i++) {
00626                     /* pixel loop */
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     /* set row pointers */
00638     for (j = 0; j < ny; j++)
00639         row_pointers[j] = idata + (size_t) (nc * nx * j);
00640 
00641     /* write out the entire image and end it */
00642     png_write_image(png_ptr, row_pointers);
00643     png_write_end(png_ptr, info_ptr);
00644 
00645     /* clean up and free any memory allocated, close the file */
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 }

Generated on Fri Aug 19 2011 09:41:43 for random_phase_noise by  doxygen 1.7.1