• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
loadpng(const char * fn,unsigned * _width,unsigned * _height)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
png_reader_read_data(png_structp png_ptr,png_bytep data,png_size_t length)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 
readpng(const unsigned char * base,size_t size,unsigned * _width,unsigned * _height)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