1 #include <stdio.h> 2 #include <stdlib.h> 3 4 #include <png.h> 5 6 #if 0 7 #define LOG(x...) fprintf(stderr,"error: " x) 8 #else 9 #define LOG(x...) do {} while (0) 10 #endif 11 12 void *loadpng(const char *fn, unsigned *_width, unsigned *_height) 13 { 14 FILE *fp = 0; 15 unsigned char header[8]; 16 unsigned char *data = 0; 17 unsigned char **rowptrs = 0; 18 png_structp p = 0; 19 png_infop pi = 0; 20 21 png_uint_32 width, height; 22 int bitdepth, colortype, imethod, cmethod, fmethod, i; 23 24 p = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); 25 if(p == 0) { 26 LOG("%s: failed to allocate png read struct\n", fn); 27 return 0; 28 } 29 30 pi = png_create_info_struct(p); 31 if(pi == 0) { 32 LOG("%s: failed to allocate png info struct\n", fn); 33 goto oops; 34 } 35 36 fp = fopen(fn, "rb"); 37 if(fp == 0) { 38 LOG("%s: failed to open file\n", fn); 39 return 0; 40 } 41 42 if(fread(header, 8, 1, fp) != 1) { 43 LOG("%s: failed to read header\n", fn); 44 goto oops; 45 } 46 47 if(png_sig_cmp(header, 0, 8)) { 48 LOG("%s: header is not a PNG header\n", fn); 49 goto oops; 50 } 51 52 if(setjmp(png_jmpbuf(p))) { 53 LOG("%s: png library error\n", fn); 54 oops: 55 png_destroy_read_struct(&p, &pi, 0); 56 if(fp != 0) fclose(fp); 57 if(data != 0) free(data); 58 if(rowptrs != 0) free(rowptrs); 59 return 0; 60 } 61 62 png_init_io(p, fp); 63 png_set_sig_bytes(p, 8); 64 65 png_read_info(p, pi); 66 67 png_get_IHDR(p, pi, &width, &height, &bitdepth, &colortype, 68 &imethod, &cmethod, &fmethod); 69 // printf("PNG: %d x %d (d=%d, c=%d)\n", 70 // width, height, bitdepth, colortype); 71 72 switch(colortype){ 73 case PNG_COLOR_TYPE_PALETTE: 74 png_set_palette_to_rgb(p); 75 break; 76 77 case PNG_COLOR_TYPE_RGB: 78 if(png_get_valid(p, pi, PNG_INFO_tRNS)) { 79 png_set_tRNS_to_alpha(p); 80 } else { 81 png_set_filler(p, 0xff, PNG_FILLER_AFTER); 82 } 83 break; 84 85 case PNG_COLOR_TYPE_RGB_ALPHA: 86 break; 87 88 case PNG_COLOR_TYPE_GRAY: 89 if(bitdepth < 8) { 90 png_set_gray_1_2_4_to_8(p); 91 } 92 93 default: 94 LOG("%s: unsupported (grayscale?) color type\n"); 95 goto oops; 96 } 97 98 if(bitdepth == 16) { 99 png_set_strip_16(p); 100 } 101 102 data = (unsigned char*) malloc((width * 4) * height); 103 rowptrs = (unsigned char **) malloc(sizeof(unsigned char*) * height); 104 105 if((data == 0) || (rowptrs == 0)){ 106 LOG("could not allocate data buffer\n"); 107 goto oops; 108 } 109 110 for(i = 0; i < height; i++) { 111 rowptrs[i] = data + ((width * 4) * i); 112 } 113 114 png_read_image(p, rowptrs); 115 116 png_destroy_read_struct(&p, &pi, 0); 117 fclose(fp); 118 if(rowptrs != 0) free(rowptrs); 119 120 *_width = width; 121 *_height = height; 122 123 return (void*) data; 124 } 125 126 127 typedef struct 128 { 129 const unsigned char* base; 130 const unsigned char* end; 131 const unsigned char* cursor; 132 133 } PngReader; 134 135 static void 136 png_reader_read_data( png_structp png_ptr, 137 png_bytep data, 138 png_size_t length ) 139 { 140 PngReader* reader = png_get_io_ptr(png_ptr); 141 png_size_t avail = (png_size_t)(reader->end - reader->cursor); 142 143 if (avail > length) 144 avail = length; 145 146 memcpy( data, reader->cursor, avail ); 147 reader->cursor += avail; 148 } 149 150 151 void *readpng(const unsigned char *base, size_t size, unsigned *_width, unsigned *_height) 152 { 153 PngReader reader; 154 unsigned char *data = 0; 155 unsigned char **rowptrs = 0; 156 png_structp p = 0; 157 png_infop pi = 0; 158 159 png_uint_32 width, height; 160 int bitdepth, colortype, imethod, cmethod, fmethod, i; 161 162 p = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); 163 if(p == 0) { 164 LOG("%s: failed to allocate png read struct\n", fn); 165 return 0; 166 } 167 168 pi = png_create_info_struct(p); 169 if(pi == 0) { 170 LOG("%s: failed to allocate png info struct\n", fn); 171 goto oops; 172 } 173 174 reader.base = base; 175 reader.end = base + size; 176 reader.cursor = base; 177 178 if(size < 8 || png_sig_cmp((unsigned char*)base, 0, 8)) { 179 LOG("%s: header is not a PNG header\n", fn); 180 goto oops; 181 } 182 183 reader.cursor += 8; 184 185 if(setjmp(png_jmpbuf(p))) { 186 LOG("%s: png library error\n", fn); 187 oops: 188 png_destroy_read_struct(&p, &pi, 0); 189 if(data != 0) free(data); 190 if(rowptrs != 0) free(rowptrs); 191 return 0; 192 } 193 194 png_set_read_fn (p, &reader, png_reader_read_data); 195 png_set_sig_bytes(p, 8); 196 197 png_read_info(p, pi); 198 199 png_get_IHDR(p, pi, &width, &height, &bitdepth, &colortype, 200 &imethod, &cmethod, &fmethod); 201 // printf("PNG: %d x %d (d=%d, c=%d)\n", 202 // width, height, bitdepth, colortype); 203 204 switch(colortype){ 205 case PNG_COLOR_TYPE_PALETTE: 206 png_set_palette_to_rgb(p); 207 break; 208 209 case PNG_COLOR_TYPE_RGB: 210 if(png_get_valid(p, pi, PNG_INFO_tRNS)) { 211 png_set_tRNS_to_alpha(p); 212 } else { 213 png_set_filler(p, 0xff, PNG_FILLER_AFTER); 214 } 215 break; 216 217 case PNG_COLOR_TYPE_RGB_ALPHA: 218 break; 219 220 case PNG_COLOR_TYPE_GRAY: 221 if(bitdepth < 8) { 222 png_set_gray_1_2_4_to_8(p); 223 } 224 225 default: 226 LOG("%s: unsupported (grayscale?) color type\n"); 227 goto oops; 228 } 229 230 if(bitdepth == 16) { 231 png_set_strip_16(p); 232 } 233 234 data = (unsigned char*) malloc((width * 4) * height); 235 rowptrs = (unsigned char **) malloc(sizeof(unsigned char*) * height); 236 237 if((data == 0) || (rowptrs == 0)){ 238 LOG("could not allocate data buffer\n"); 239 goto oops; 240 } 241 242 for(i = 0; i < height; i++) { 243 rowptrs[i] = data + ((width * 4) * i); 244 } 245 246 png_read_image(p, rowptrs); 247 248 png_destroy_read_struct(&p, &pi, 0); 249 if(rowptrs != 0) free(rowptrs); 250 251 *_width = width; 252 *_height = height; 253 254 return (void*) data; 255 } 256 257 258 #if 0 259 int main(int argc, char **argv) 260 { 261 unsigned w,h; 262 unsigned char *data; 263 264 if(argc < 2) return 0; 265 266 267 data = loadpng(argv[1], &w, &h); 268 269 if(data != 0) { 270 printf("w: %d h: %d\n", w, h); 271 } 272 273 return 0; 274 } 275 #endif 276