Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OpenPNG.cpp

Go to the documentation of this file.
00001 
00008 #include <png.h>
00009 #include "Debug.h"
00010 #include "Open.h"
00011 #include "SimpleImage.h"
00012 #include "Utility.h"
00013 
00014 
00015 namespace corona {
00016 
00017   typedef unsigned char byte;
00018 
00019 
00021 
00022   void PNG_read_function(png_structp png_ptr,
00023                          png_bytep data,
00024                          png_size_t length) {
00025     File* file = (File*)png_get_io_ptr(png_ptr);
00026     if (file->read(data, length) != int(length)) {
00027       png_error(png_ptr, "Read error");
00028     }
00029   }
00030 
00032 
00033   void PNG_warning_function(png_structp png_ptr, png_const_charp error) {
00034     // no warnings
00035   }
00036 
00038 
00039   void PNG_error_function(png_structp png_ptr, png_const_charp warning) {
00040     // copied from libpng's pngerror.cpp, but without the fprintf
00041     jmp_buf jmpbuf;
00042     memcpy(jmpbuf, png_ptr->jmpbuf, sizeof(jmp_buf));
00043     longjmp(jmpbuf, 1);
00044   }
00045 
00047 
00048   void fill_palette(png_structp png, png_infop info, png_color palette[256]) {
00049 
00050    COR_GUARD("fill_palette");
00051 
00052     // by default, the palette is greyscale
00053     for (int i = 0; i < 256; ++i) {
00054       palette[i].red   = i;
00055       palette[i].green = i;
00056       palette[i].blue  = i;
00057     }
00058 
00059     // do we have a palette and is it big enough?
00060     png_colorp png_palette;
00061     int num_palette = 0;
00062     png_get_PLTE(png, info, &png_palette, &num_palette);
00063 
00064     COR_IF_DEBUG {
00065       char str[80];
00066       sprintf(str, "palette size: %d", num_palette);
00067       COR_LOG(str);
00068     }
00069 
00070     if (num_palette >= 256) {
00071 
00072 #if 0
00073       COR_IF_DEBUG {
00074         for (int i = 0; i < 256; ++i) {
00075           char str[80];
00076           sprintf(str, "r(%d) g(%d) b(%d)",
00077             int(palette[i].red),
00078             int(palette[i].green),
00079             int(palette[i].blue));
00080           COR_LOG(str);
00081         }
00082       }
00083 #endif
00084 
00085       memcpy(palette, png_palette, 256 * sizeof(png_color));
00086     }
00087   }
00088 
00090 
00091   Image* OpenPNG(File* file) {
00092 
00093     COR_GUARD("OpenPNG");
00094 
00095     // verify PNG signature
00096     byte sig[8];
00097     file->read(sig, 8);
00098     if (png_sig_cmp(sig, 0, 8)) {
00099       return 0;
00100     }
00101 
00102     COR_LOG("Signature verified");
00103 
00104     // read struct
00105     png_structp png_ptr = png_create_read_struct(
00106       PNG_LIBPNG_VER_STRING,
00107       NULL, NULL, NULL);
00108     if (!png_ptr) {
00109       return 0;
00110     }
00111 
00112     COR_LOG("png struct created");
00113 
00114     // info struct
00115     png_infop info_ptr = png_create_info_struct(png_ptr);
00116     if (!info_ptr) {
00117       png_destroy_read_struct(&png_ptr, NULL, NULL);
00118       return 0;
00119     }
00120 
00121     COR_LOG("info struct created");
00122 
00123     // the PNG error function calls longjmp(png_ptr->jmpbuf)
00124     if (setjmp(png_jmpbuf(png_ptr))) {
00125       COR_LOG("Error loading PNG");
00126       png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
00127       return 0;
00128     }
00129 
00130     COR_LOG("setjmp() succeeded");
00131 
00132     // set the error function
00133     png_set_error_fn(png_ptr, 0, PNG_error_function, PNG_warning_function);
00134 
00135     // read the image
00136     png_set_read_fn(png_ptr, file, PNG_read_function);
00137     png_set_sig_bytes(png_ptr, 8);  // we already read 8 bytes for the sig
00138     // always give us 8-bit samples (strip 16-bit and expand <8-bit)
00139     int png_transform = PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_EXPAND;
00140     png_read_png(png_ptr, info_ptr, png_transform, NULL);
00141 
00142     COR_LOG("PNG read");
00143 
00144     if (!png_get_rows(png_ptr, info_ptr)) {
00145       png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
00146       return 0;
00147     }
00148 
00149     int width  = png_get_image_width(png_ptr, info_ptr);
00150     int height = png_get_image_height(png_ptr, info_ptr);
00151     byte* pixels = 0;  // allocate when we know the format
00152     PixelFormat format;
00153     byte* palette = 0;
00154     PixelFormat palette_format;
00155 
00156     // decode based on pixel format
00157     int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
00158     int num_channels = png_get_channels(png_ptr, info_ptr);
00159     png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr);
00160 
00161     // 32-bit RGBA
00162     if (bit_depth == 8 && num_channels == 4) {
00163       COR_LOG("32-bit RGBA: bit_depth = 8 && num_channels = 4");
00164 
00165       format = PF_R8G8B8A8;
00166       pixels = new byte[width * height * 4];
00167       for (int i = 0; i < height; ++i) {
00168         memcpy(pixels + i * width * 4, row_pointers[i], width * 4);
00169       }
00170 
00171     // 24-bit RGB
00172     } else if (bit_depth == 8 && num_channels == 3) {
00173       COR_LOG("24-bit RGB: bit_depth = 8 && num_channels = 3");
00174 
00175       format = PF_R8G8B8;
00176       pixels = new byte[width * height * 3];
00177       for (int i = 0; i < height; ++i) {
00178         memcpy(pixels + i * width * 3, row_pointers[i], width * 3);
00179       }
00180 
00181     // palettized or greyscale with alpha
00182     } else if (bit_depth == 8 && (num_channels == 2 || num_channels == 1)) {
00183       png_color png_palette[256];
00184       fill_palette(png_ptr, info_ptr, png_palette);
00185 
00186       if (num_channels == 2) {
00187         COR_LOG("bit_depth = 8 && num_channels = 2");
00188 
00189         format = PF_R8G8B8A8;
00190         pixels = new byte[width * height * 4];
00191         byte* out = pixels;
00192 
00193         for (int i = 0; i < height; ++i) {
00194           byte* in = row_pointers[i];
00195           for (int j = 0; j < width; ++j) {
00196             byte c = *in++;
00197             *out++ = png_palette[c].red;
00198             *out++ = png_palette[c].green;
00199             *out++ = png_palette[c].blue;
00200             *out++ = *in++;  // alpha
00201           }
00202         }
00203 
00204       } else { // (num_channels == 1)
00205         COR_LOG("bit_depth = 8 && num_channels = 1");
00206 
00207         pixels = new byte[width * height];
00208         format = PF_I8;
00209         palette = new byte[256 * 4];
00210         palette_format = PF_R8G8B8A8;
00211 
00212 
00213         // get the transparent palette flags
00214         png_bytep trans;
00215         int num_trans = 0;
00216         png_color_16p trans_values; // XXX not used - should be?
00217         png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values);
00218 
00219         // copy the palette from the PNG
00220         for (int i = 0; i < 256; ++i) {
00221           palette[i * 4 + 0] = png_palette[i].red;
00222           palette[i * 4 + 1] = png_palette[i].green;
00223           palette[i * 4 + 2] = png_palette[i].blue;
00224           palette[i * 4 + 3] = 255;
00225         }
00226         // apply transparency to palette entries
00227         for (int i = 0; i < num_trans; ++i) {
00228           palette[trans[i] * 4 + 3] = 0;
00229         }
00230 
00231         byte* out = pixels;
00232         for (int i = 0; i < height; ++i) {
00233           memcpy(out, row_pointers[i], width);
00234           out += width;
00235         }
00236       }
00237 
00238     } else {  // unknown format
00239       png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
00240       return 0;
00241     }
00242 
00243     png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
00244 
00245     if (palette) {
00246       return new SimpleImage(width, height, format, pixels,
00247                              palette, 256, palette_format);
00248     } else {
00249       return new SimpleImage(width, height, format, pixels);
00250     }
00251   }
00252 
00254 
00255 }

Generated on Thu Oct 2 12:59:31 2003 for corona by doxygen1.3-rc1