src/pngHelper.h

Go to the documentation of this file.
00001 
00008 #ifndef __LIBPNG_HELPERS__
00009 #define __LIBPNG_HELPERS__
00010 
00011 // prevent c-style cast warnings in png.h
00012 #define PNG_NO_TYPECAST_NULL
00013 
00014 #include <png.h>
00015 #include <cstdio>
00016 #include <iostream>
00017 
00018 static unsigned const int   PNG_BYTES_TO_CHECK = 8;
00019 
00020 // TODO make a OO class out of this crap
00021 
00022 using namespace std;
00023 
00024 
00025 int check_if_png(const char *file_name, FILE **fp)
00026 {
00027     png_byte buf[PNG_BYTES_TO_CHECK];
00028 
00029     /* Open the prospective PNG file. */
00030     if ((*fp = fopen(file_name, "rb")) == NULL)
00031         return 0;
00032 
00033     /* Read in some of the signature bytes */
00034     if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK)
00035         return 0;
00036 
00037     /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature.
00038        Return nonzero (true) if they match */
00039 
00040     bool res = (!png_sig_cmp(buf, static_cast<png_size_t>(0), PNG_BYTES_TO_CHECK));
00041     fclose(*fp);
00042     return res;
00043 }
00044 
00045 
00046 void read_png(  const char *        file_name,
00047                 unsigned char *&    buffer,
00048                 int &               width,
00049                 int &               height,
00050                 int &               channels,
00051                 int &               bit_depth,
00052                 int &               color_type,
00053                 bool                flip_vert )
00054 {
00055     png_structp png_ptr;
00056     png_infop   info_ptr;
00057     FILE *      fp;
00058     bool        check = check_if_png(file_name, &fp);
00059 
00060     if (!check)
00061     {
00062         std::cerr << "This is not a PNG file !!" << endl;
00063         exit(1);
00064     }
00065 
00066     fp = fopen(file_name, "rb");
00067 
00068     /* Create and initialize the png_struct with the desired error handler
00069      * functions.  If you want to use the default stderr and longjump method,
00070      * you can supply NULL for the last three parameters.  We also supply the
00071      * the compiler header file version, so that we know if the application
00072      * was compiled with a compatible version of the library.  REQUIRED
00073      */
00074     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00075 
00076     if (png_ptr == NULL)
00077     {
00078         fclose(fp);
00079         std::cerr << "Error initializing png_ptr !" << endl;
00080         exit(1);
00081     }
00082 
00083     /* Allocate/initialize the memory for image information.  REQUIRED. */
00084     info_ptr = png_create_info_struct(png_ptr);
00085     if (info_ptr == NULL)
00086     {
00087         fclose(fp);
00088         png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
00089         std::cerr << "Error initializing info_ptr !" << endl;
00090         exit(1);
00091     }
00092 
00093     /* Set error handling if you are using the setjmp/longjmp method (this is
00094      * the normal method of doing things with libpng).  REQUIRED unless you
00095      * set up your own error handlers in the png_create_read_struct() earlier.
00096      */
00097     if (setjmp(png_jmpbuf(png_ptr)))
00098     {
00099         /* Free all of the memory associated with the png_ptr and info_ptr */
00100         png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
00101         fclose(fp);
00102         /* If we get here, we had a problem reading the file */
00103         std::cerr << "Error initializing png_ptr !" << endl;
00104         exit(1);
00105     }
00106 
00107     png_init_io(png_ptr, fp);
00108 
00109     /* If we have already read some of the signature */
00110     png_set_sig_bytes(png_ptr, 0);
00111 
00112     /* If you have enough memory to read in the entire image at once,
00113      * and you need to specify only transforms that can be controlled
00114      * with one of the PNG_TRANSFORM_* bits (this presently excludes
00115      * dithering, filling, setting background, and doing gamma
00116      * adjustment), then you can read the entire image (including
00117      * pixels) into the info structure with this call:
00118      */
00119     png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, png_voidp_NULL);
00120 
00121     width       = png_get_image_width(png_ptr, info_ptr);
00122     height      = png_get_image_height(png_ptr, info_ptr);
00123     channels    = png_get_channels(png_ptr, info_ptr);
00124     bit_depth   = png_get_bit_depth(png_ptr, info_ptr);
00125     color_type  = png_get_color_type(png_ptr, info_ptr);
00126 
00127     png_uint_32 valid = 0;
00128     png_get_valid(png_ptr, info_ptr, valid);
00129 
00130     png_bytep* row_pointers = png_get_rows(png_ptr, info_ptr);
00131 
00132     // allocate buffer
00133     const int c = width*channels*bit_depth/8;
00134     buffer = new unsigned char[channels * width * height * bit_depth / 8];
00135 
00136     if (!flip_vert)
00137     {
00138         for (int y = 0;y<height;++y)
00139         {
00140             memcpy(static_cast<void*>(&(buffer[y*c])), static_cast<void*>(row_pointers[y]), c);
00141         }
00142     }
00143     else
00144     {
00145         for (int y = 0;y<height;++y)
00146         {
00147             memcpy(static_cast<void*>(&(buffer[(height-1-y)*c])), static_cast<void*>(row_pointers[y]), c);
00148         }
00149     }
00150 
00151     png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
00152     fclose(fp);
00153  }
00154 
00155 
00156 /* write a png file */
00157 
00168 void write_png( const char *    file_name,
00169                 unsigned char * buffer,
00170                 int             width,
00171                 int             height,
00172                 int             channels,
00173                 int             bit_depth,
00174                 png_uint_32     color_type,
00175                 bool            flip_vert)
00176 {
00177     FILE *      fp;
00178     png_structp png_ptr;
00179     png_infop   info_ptr;
00180     //   png_colorp palette;
00181 
00182     /* open the file */
00183     fp = fopen(file_name, "wb");
00184     if (fp == NULL)
00185     {
00186         std::cerr << "Error opening file " << endl;
00187     }
00188 
00189     /* Create and initialize the png_struct with the desired error handler
00190      * functions.  If you want to use the default stderr and longjump method,
00191      * you can supply NULL for the last three parameters.  We also check that
00192      * the library version is compatible with the one used at compile time,
00193      * in case we are using dynamically linked libraries.  REQUIRED.
00194      */
00195     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00196 
00197     if (png_ptr == NULL)
00198     {
00199         fclose(fp);
00200         std::cerr << "Error allocating png_ptr !!" << endl;
00201         exit(1);
00202     }
00203 
00204     /* Allocate/initialize the image information data.  REQUIRED */
00205     info_ptr = png_create_info_struct(png_ptr);
00206     if (info_ptr == NULL)
00207     {
00208         fclose(fp);
00209         png_destroy_write_struct(&png_ptr, png_infopp_NULL);
00210         std::cerr << "Error allocating info ptr !!" << endl;
00211         exit(1);
00212     }
00213 
00214     /* Set error handling.  REQUIRED if you aren't supplying your own
00215      * error handling functions in the png_create_write_struct() call.
00216      */
00217     if (setjmp(png_jmpbuf(png_ptr)))
00218     {
00219         /* If we get here, we had a problem reading the file */
00220         fclose(fp);
00221         png_destroy_write_struct(&png_ptr, &info_ptr);
00222         exit(1);
00223     }
00224 
00225     png_init_io(png_ptr, fp);
00226 
00227     png_set_IHDR(   png_ptr, info_ptr,
00228                     static_cast<png_uint_32>(width), static_cast<png_uint_32>(height),
00229                     static_cast<png_byte>(bit_depth), static_cast<png_byte>(color_type),
00230                     PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT );
00231 
00232     // setup row data structure from buffer
00233 
00234     png_bytep * row_pointers = new png_bytep[height];
00235     const int c = width * channels * bit_depth / 8;
00236     if (!flip_vert)
00237     {
00238         for (int y = 0;y<height;++y)
00239         {
00240             row_pointers[y] = static_cast<png_bytep>(&(buffer[y*c]));
00241         }
00242     }
00243     else
00244     {
00245         for (int y = 0;y<height;++y)
00246         {
00247             row_pointers[height-1-y] = static_cast<png_bytep>(&(buffer[y*c]));
00248         }
00249     }
00250     //raise(5);
00251 
00252     png_set_rows(png_ptr, info_ptr, row_pointers);
00253     png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, png_voidp_NULL);
00254 
00255     png_destroy_write_struct(&png_ptr, &info_ptr);
00256     delete [] row_pointers;
00257     fclose(fp);
00258 }
00259 
00260 #endif
00261 

Generated on Fri Feb 1 00:01:42 2008 for Grayfall by  doxygen 1.5.1