readpng.C

Go to the documentation of this file.
00001 
00002 /* ignore tag evaluated by for docuscangxsmplugins.pl -- this is no main plugin file
00003 % PlugInModuleIgnore
00004 */
00005 
00006 
00007 /*---------------------------------------------------------------------------
00008 
00009    rpng - simple PNG display program                              readpng.c
00010 
00011   ---------------------------------------------------------------------------
00012 
00013       Copyright (c) 1998-2000 Greg Roelofs.  All rights reserved.
00014 
00015       This software is provided "as is," without warranty of any kind,
00016       express or implied.  In no event shall the author or contributors
00017       be held liable for any damages arising in any way from the use of
00018       this software.
00019 
00020       Permission is granted to anyone to use this software for any purpose,
00021       including commercial applications, and to alter it and redistribute
00022       it freely, subject to the following restrictions:
00023 
00024       1. Redistributions of source code must retain the above copyright
00025          notice, disclaimer, and this list of conditions.
00026       2. Redistributions in binary form must reproduce the above copyright
00027          notice, disclaimer, and this list of conditions in the documenta-
00028          tion and/or other materials provided with the distribution.
00029       3. All advertising materials mentioning features or use of this
00030          software must display the following acknowledgment:
00031 
00032             This product includes software developed by Greg Roelofs
00033             and contributors for the book, "PNG: The Definitive Guide,"
00034             published by O'Reilly and Associates.
00035 
00036   ---------------------------------------------------------------------------*/
00037 
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 
00041 #include "png.h"        /* libpng header; includes zlib.h */
00042 #include "readpng.h"    /* typedefs, common macros, public prototypes */
00043 
00044 /* future versions of libpng will provide this macro: */
00045 #ifndef png_jmpbuf
00046 #  define png_jmpbuf(png_ptr)   ((png_ptr)->jmpbuf)
00047 #endif
00048 
00049 
00050 static png_structp png_ptr = NULL;
00051 static png_infop info_ptr = NULL;
00052 
00053 png_uint_32  width, height;
00054 int  bit_depth, color_type;
00055 uch  *image_data = NULL;
00056 
00057 /* return value = 0 for success, 1 for bad sig, 2 for bad IHDR, 4 for no mem */
00058 
00059 int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight)
00060 {
00061     uch sig[8];
00062 
00063 
00064     /* first do a quick check that the file really is a PNG image; could
00065      * have used slightly more general png_sig_cmp() function instead */
00066 
00067     fread(sig, 1, 8, infile);
00068     if (!png_check_sig(sig, 8))
00069         return 1;   /* bad signature */
00070 
00071 
00072     /* could pass pointers to user-defined error handlers instead of NULLs: */
00073 
00074     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00075     if (!png_ptr)
00076         return 4;   /* out of memory */
00077 
00078     info_ptr = png_create_info_struct(png_ptr);
00079     if (!info_ptr) {
00080         png_destroy_read_struct(&png_ptr, NULL, NULL);
00081         return 4;   /* out of memory */
00082     }
00083 
00084 
00085     /* we could create a second info struct here (end_info), but it's only
00086      * useful if we want to keep pre- and post-IDAT chunk info separated
00087      * (mainly for PNG-aware image editors and converters) */
00088 
00089 
00090     /* setjmp() must be called in every function that calls a PNG-reading
00091      * libpng function */
00092 
00093     if (setjmp(png_jmpbuf(png_ptr))) {
00094         png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
00095         return 2;
00096     }
00097 
00098 
00099     png_init_io(png_ptr, infile);
00100     png_set_sig_bytes(png_ptr, 8);  /* we already read the 8 signature bytes */
00101 
00102     png_read_info(png_ptr, info_ptr);  /* read all PNG info up to image data */
00103 
00104 
00105     /* alternatively, could make separate calls to png_get_image_width(),
00106      * etc., but want bit_depth and color_type for later [don't care about
00107      * compression_type and filter_type => NULLs] */
00108 
00109     png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
00110       NULL, NULL, NULL);
00111     *pWidth = width;
00112     *pHeight = height;
00113 
00114 
00115     /* OK, that's all we need for now; return happy */
00116 
00117     return 0;
00118 }
00119 
00120 
00121 
00122 
00123 /* returns 0 if succeeds, 1 if fails due to no bKGD chunk, 2 if libpng error;
00124  * scales values to 8-bit if necessary */
00125 
00126 int readpng_get_bgcolor(uch *red, uch *green, uch *blue)
00127 {
00128     png_color_16p pBackground;
00129 
00130 
00131     /* setjmp() must be called in every function that calls a PNG-reading
00132      * libpng function */
00133 
00134     if (setjmp(png_jmpbuf(png_ptr))) {
00135         png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
00136         return 2;
00137     }
00138 
00139 
00140     if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD))
00141         return 1;
00142 
00143     /* it is not obvious from the libpng documentation, but this function
00144      * takes a pointer to a pointer, and it always returns valid red, green
00145      * and blue values, regardless of color_type: */
00146 
00147     png_get_bKGD(png_ptr, info_ptr, &pBackground);
00148 
00149 
00150     /* however, it always returns the raw bKGD data, regardless of any
00151      * bit-depth transformations, so check depth and adjust if necessary */
00152 
00153     if (bit_depth == 16) {
00154         *red   = pBackground->red   >> 8;
00155         *green = pBackground->green >> 8;
00156         *blue  = pBackground->blue  >> 8;
00157     } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
00158         if (bit_depth == 1)
00159             *red = *green = *blue = pBackground->gray? 255 : 0;
00160         else if (bit_depth == 2)
00161             *red = *green = *blue = (255/3) * pBackground->gray;
00162         else /* bit_depth == 4 */
00163             *red = *green = *blue = (255/15) * pBackground->gray;
00164     } else {
00165         *red   = (uch)pBackground->red;
00166         *green = (uch)pBackground->green;
00167         *blue  = (uch)pBackground->blue;
00168     }
00169 
00170     return 0;
00171 }
00172 
00173 
00174 
00175 
00176 /* display_exponent == LUT_exponent * CRT_exponent */
00177 
00178 uch *readpng_get_image(double display_exponent, int *pChannels, ulg *pRowbytes)
00179 {
00180     double  gamma;
00181     png_uint_32  i, rowbytes;
00182     png_bytepp  row_pointers = NULL;
00183 
00184 
00185     /* setjmp() must be called in every function that calls a PNG-reading
00186      * libpng function */
00187 
00188     if (setjmp(png_jmpbuf(png_ptr))) {
00189         png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
00190         return NULL;
00191     }
00192 
00193 
00194     /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits,
00195      * transparency chunks to full alpha channel; strip 16-bit-per-sample
00196      * images to 8 bits per sample; and convert grayscale to RGB[A] */
00197 
00198     if (color_type == PNG_COLOR_TYPE_PALETTE)
00199         png_set_expand(png_ptr);
00200     if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
00201         png_set_expand(png_ptr);
00202     if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
00203         png_set_expand(png_ptr);
00204     if (bit_depth == 16)
00205         png_set_strip_16(png_ptr);
00206     if (color_type == PNG_COLOR_TYPE_GRAY ||
00207         color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
00208         png_set_gray_to_rgb(png_ptr);
00209 
00210 
00211     /* unlike the example in the libpng documentation, we have *no* idea where
00212      * this file may have come from--so if it doesn't have a file gamma, don't
00213      * do any correction ("do no harm") */
00214 
00215     if (png_get_gAMA(png_ptr, info_ptr, &gamma))
00216         png_set_gamma(png_ptr, display_exponent, gamma);
00217 
00218 
00219     /* all transformations have been registered; now update info_ptr data,
00220      * get rowbytes and channels, and allocate image memory */
00221 
00222     png_read_update_info(png_ptr, info_ptr);
00223 
00224     *pRowbytes = rowbytes = png_get_rowbytes(png_ptr, info_ptr);
00225     *pChannels = (int)png_get_channels(png_ptr, info_ptr);
00226 
00227     if ((image_data = (uch *)malloc(rowbytes*height)) == NULL) {
00228         png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
00229         return NULL;
00230     }
00231     if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) {
00232         png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
00233         free(image_data);
00234         image_data = NULL;
00235         return NULL;
00236     }
00237 
00238     Trace((stderr, "readpng_get_image:  channels = %d, rowbytes = %ld, height = %ld\n", *pChannels, rowbytes, height));
00239 
00240 
00241     /* set the individual row_pointers to point at the correct offsets */
00242 
00243     for (i = 0;  i < height;  ++i)
00244         row_pointers[i] = image_data + i*rowbytes;
00245 
00246 
00247     /* now we can go ahead and just read the whole image */
00248 
00249     png_read_image(png_ptr, row_pointers);
00250 
00251 
00252     /* and we're done!  (png_read_end() can be omitted if no processing of
00253      * post-IDAT text/time/etc. is desired) */
00254 
00255     free(row_pointers);
00256     row_pointers = NULL;
00257 
00258     png_read_end(png_ptr, NULL);
00259 
00260     return image_data;
00261 }
00262 
00263 
00264 void readpng_cleanup(int free_image_data)
00265 {
00266     if (free_image_data && image_data) {
00267         free(image_data);
00268         image_data = NULL;
00269     }
00270 
00271     if (png_ptr && info_ptr) {
00272         png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
00273         png_ptr = NULL;
00274         info_ptr = NULL;
00275     }
00276 }

Generated on Sat Apr 1 09:04:26 2006 for GXSM by  doxygen 1.4.6