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
00035 }
00036
00038
00039 void PNG_error_function(png_structp png_ptr, png_const_charp warning) {
00040
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
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
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
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
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
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
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
00133 png_set_error_fn(png_ptr, 0, PNG_error_function, PNG_warning_function);
00134
00135
00136 png_set_read_fn(png_ptr, file, PNG_read_function);
00137 png_set_sig_bytes(png_ptr, 8);
00138
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;
00152 PixelFormat format;
00153 byte* palette = 0;
00154 PixelFormat palette_format;
00155
00156
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
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
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
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++;
00201 }
00202 }
00203
00204 } else {
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
00214 png_bytep trans;
00215 int num_trans = 0;
00216 png_color_16p trans_values;
00217 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values);
00218
00219
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
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 {
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 }