blob: 5abbd7d39b5c2037382ee3e751a8a2164bc1c49a [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001#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
12void *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;
David 'Digit' Turnerc0052462014-02-25 18:39:29 +010020
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080021 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 }
David 'Digit' Turnerc0052462014-02-25 18:39:29 +010035
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080036 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 }
David 'Digit' Turnerc0052462014-02-25 18:39:29 +010046
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080047 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;
David 'Digit' Turnerc0052462014-02-25 18:39:29 +010084
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080085 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 }
David 'Digit' Turnerc0052462014-02-25 18:39:29 +010092
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080093 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 }
David 'Digit' Turnerc0052462014-02-25 18:39:29 +0100113
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800114 png_read_image(p, rowptrs);
David 'Digit' Turnerc0052462014-02-25 18:39:29 +0100115
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800116 png_destroy_read_struct(&p, &pi, 0);
117 fclose(fp);
118 if(rowptrs != 0) free(rowptrs);
119
120 *_width = width;
121 *_height = height;
David 'Digit' Turnerc0052462014-02-25 18:39:29 +0100122
123 return (void*) data;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800124}
125
126
127typedef struct
128{
129 const unsigned char* base;
130 const unsigned char* end;
131 const unsigned char* cursor;
132
133} PngReader;
134
135static void
136png_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
151void *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
David 'Digit' Turnerc0052462014-02-25 18:39:29 +0100254 return (void*) data;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800255}
256
257
258#if 0
259int main(int argc, char **argv)
260{
261 unsigned w,h;
262 unsigned char *data;
David 'Digit' Turnerc0052462014-02-25 18:39:29 +0100263
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800264 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