loadpng.cc (3038B)
1 /* Copyright 2013 Brian Swetland <swetland@frotz.net> 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 20 #include <png.h> 21 22 #include "util.h" 23 #include "io.h" 24 25 void *_load_png(const char *fn, unsigned *_width, unsigned *_height, int options) { 26 png_structp png; 27 png_infop info; 28 png_uint_32 w, h; 29 int depth, ctype, itype, ch, i; 30 png_byte *data = 0; 31 FILE *fp; 32 33 ch = (options & OPT_PNG_GRAY) ? 1 : 4; 34 35 if ((fp = io_fopen_asset(fn, "image")) == NULL) 36 goto exit; 37 38 if (!(png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) 39 goto close_and_exit; 40 41 if (!(info = png_create_info_struct(png))) { 42 png_destroy_read_struct(&png, NULL, NULL); 43 goto destroy_and_exit; 44 } 45 46 if (setjmp(png->jmpbuf)) { 47 if (data) { 48 free(data); 49 data = 0; 50 } 51 goto destroy_and_exit; 52 } 53 54 png_init_io(png, fp); 55 56 png_read_info(png, info); 57 58 png_get_IHDR(png, info, &w, &h, &depth, &ctype, &itype, NULL, NULL); 59 60 if (depth < 8) 61 png_set_packing(png); 62 63 if (depth > 8) 64 png_set_strip_16(png); 65 66 if (ctype == PNG_COLOR_TYPE_PALETTE) 67 png_set_expand(png); 68 69 if ((ctype == PNG_COLOR_TYPE_GRAY) && (depth < 8)) 70 png_set_expand(png); 71 72 if (png_get_valid(png, info, PNG_INFO_tRNS)) 73 png_set_expand(png); 74 75 if (ch == 4) { 76 if ((ctype == PNG_COLOR_TYPE_RGB) || 77 (ctype == PNG_COLOR_TYPE_GRAY)) 78 png_set_add_alpha(png, 0xFF, PNG_FILLER_AFTER); 79 80 if ((ctype == PNG_COLOR_TYPE_GRAY) || 81 (ctype == PNG_COLOR_TYPE_GRAY_ALPHA)) 82 png_set_gray_to_rgb(png); 83 } else if (ch == 1) { 84 if ((ctype == PNG_COLOR_TYPE_RGB) || 85 (ctype == PNG_COLOR_TYPE_RGB_ALPHA)) 86 png_set_rgb_to_gray_fixed(png, 1, -1, -1); 87 88 png_set_strip_alpha(png); 89 } else { 90 png_error(png, "unsupported channel count"); 91 } 92 93 if (!(data = (png_byte*) malloc(w * h * ch))) 94 png_error(png, "cannot allocate image buffer"); 95 96 if (options & OPT_PNG_INVERTY) 97 for (i = h-1; i >= 0; i--) 98 png_read_row(png, data + (i * w * ch), NULL); 99 else 100 for (i = 0; i < h; i++) 101 png_read_row(png, data + (i * w * ch), NULL); 102 103 *_width = w; 104 *_height = h; 105 106 destroy_and_exit: 107 png_destroy_read_struct(&png, &info, NULL); 108 109 close_and_exit: 110 fclose(fp); 111 exit: 112 if (!data) 113 error("Failed to load '%s'", fn); 114 return data; 115 } 116 117 void *load_png_rgba(const char *fn, unsigned *_width, unsigned *_height, int options) { 118 return _load_png(fn, _width, _height, options); 119 } 120 121 void *load_png_gray(const char *fn, unsigned *_width, unsigned *_height, int options) { 122 return _load_png(fn, _width, _height, options | OPT_PNG_GRAY); 123 } 124