Just code layout changes and logging.
[imager.git] / png.c
CommitLineData
02d1d628
AMH
1#include "image.h"
2#include "png.h"
3
4/* Check to see if a file is a PNG file using png_sig_cmp(). png_sig_cmp()
5 * returns zero if the image is a PNG and nonzero if it isn't a PNG.
6 *
7 * The function check_if_png() shown here, but not used, returns nonzero (true)
8 * if the file can be opened and is a PNG, 0 (false) otherwise.
9 *
10 * If this call is successful, and you are going to keep the file open,
11 * you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once
12 * you have created the png_ptr, so that libpng knows your application
13 * has read that many bytes from the start of the file. Make sure you
14 * don't call png_set_sig_bytes() with more than 8 bytes read or give it
15 * an incorrect number of bytes read, or you will either have read too
16 * many bytes (your fault), or you are telling libpng to read the wrong
17 * number of magic bytes (also your fault).
18 *
19 * Many applications already read the first 2 or 4 bytes from the start
20 * of the image to determine the file type, so it would be easiest just
21 * to pass the bytes to png_sig_cmp() or even skip that if you know
22 * you have a PNG file, and call png_set_sig_bytes().
23 */
24
25/* this is a way to get number of channels from color space
26 * Color code to channel number */
27
28int CC2C[PNG_COLOR_MASK_PALETTE|PNG_COLOR_MASK_COLOR|PNG_COLOR_MASK_ALPHA];
29
30#define PNG_BYTES_TO_CHECK 4
31
32
33
34
35
36
37
38
39
40/*
41png_set_read_fn(png_structp read_ptr, voidp read_io_ptr, png_rw_ptr read_data_fn)
42png_set_write_fn(png_structp write_ptr, voidp write_io_ptr, png_rw_ptr write_data_fn,
43png_flush_ptr output_flush_fn);
44voidp read_io_ptr = png_get_io_ptr(read_ptr);
45voidp write_io_ptr = png_get_io_ptr(write_ptr);
46*/
47
48struct png_scalar_info {
49 char *data;
50 int length;
51 int cpos;
52};
53
54
55struct png_wiol_info {
56 io_glue *cp;
57 int length;
58 int cpos;
59};
60
61static void
62user_read_data(png_structp png_ptr,png_bytep data, png_size_t length) {
63 struct png_scalar_info *sci=(struct png_scalar_info *)png_ptr->io_ptr;
64
65 /* fprintf(stderr,"user_read_data: cpos %d/%d (%d)\n",sci->cpos,sci->length,length); */
66
67 if (sci->cpos+(ssize_t)length > sci->length ) { png_error(png_ptr, "Read overflow error on a scalar."); }
68
69 memcpy(data, sci->data+sci->cpos , length);
70 sci->cpos+=length;
71}
72
73/*
74static void
75user_write_data(png_structp png_ptr, png_bytep data, png_uint_32 length) {
76 FIXME: implement these
77}
78
79static void
80user_flush_data(png_structp png_ptr) {
81 FIXME: implement these
82}
83*/
84
85
86void
87scalar_png_init_io(png_structp png_ptr,struct png_scalar_info *sci) {
88 png_ptr->io_ptr = (png_voidp)sci;
89}
90
91
92
93
94
95
96int
97check_if_png(char *file_name, FILE **fp) {
98 char buf[PNG_BYTES_TO_CHECK];
99
100 /* Open the prospective PNG file. */
101 if ((*fp = fopen(file_name, "rb")) != NULL) return 0;
102
103 /* Read in some of the signature bytes */
104 if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK) return 0;
105
106 /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature.
107 Return nonzero (true) if they match */
108
109 return(!png_sig_cmp((png_bytep)buf, (png_size_t)0, PNG_BYTES_TO_CHECK));
110}
111
112/* Read a PNG file. You may want to return an error code if the read
113 * fails (depending upon the failure). There are two "prototypes" given
114 * here - one where we are given the filename, and we need to open the
115 * file, and the other where we are given an open file (possibly with
116 * some or all of the magic bytes read - see comments above).
117 */
118
119i_img *
120i_readpng(int fd) {
121 i_img *im;
122 png_structp png_ptr;
123 png_infop info_ptr;
124 png_uint_32 width, height, y;
125 int bit_depth, color_type, interlace_type;
126 int number_passes;
127 int channels, pass;
128
129 FILE *fp;
130 unsigned int sig_read;
131
29a70e5d 132 sig_read = 0;
02d1d628
AMH
133
134 if ((fp = fdopen(fd,"r")) == NULL) {
135 mm_log((1,"can't fdopen.\n"));
136 exit(1);
137 }
138
139 mm_log((1,"i_readpng(fd %d)\n",fd));
140
141 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
142
143 if (png_ptr == NULL) {
144 fclose(fp);
145 return 0;
146 }
147
148 /* Allocate/initialize the memory for image information. REQUIRED. */
149 info_ptr = png_create_info_struct(png_ptr);
150 if (info_ptr == NULL) {
151 fclose(fp);
152 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
153 return 0;
154 }
155
156 /* Set error handling if you are using the setjmp/longjmp method (this is
157 * the normal method of doing things with libpng). REQUIRED unless you
158 * set up your own error handlers in the png_create_read_struct() earlier.
159 */
160
161 if (setjmp(png_ptr->jmpbuf)) {
162 /* Free all of the memory associated with the png_ptr and info_ptr */
163 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
164 fclose(fp);
165 /* If we get here, we had a problem reading the file */
166 return NULL;
167 }
168
169 /* Set up the input control if you are using standard C streams */
170 png_init_io(png_ptr, fp);
171 /* If we have already read some of the signature */
172 png_set_sig_bytes(png_ptr, sig_read);
173
174 /* The call to png_read_info() gives us all of the information from the
175 * PNG file before the first IDAT (image data chunk). REQUIRED
176 */
177
178 png_read_info(png_ptr, info_ptr);
179 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
180 &interlace_type, NULL, NULL);
181
182 mm_log((1,
183 "png_get_IHDR results: width %d, height %d, bit_depth %d,color_type %d,interlace_type %d\n",
29a70e5d 184 width, height, bit_depth, color_type, interlace_type));
02d1d628
AMH
185
186 CC2C[PNG_COLOR_TYPE_GRAY]=1;
187 CC2C[PNG_COLOR_TYPE_PALETTE]=3;
188 CC2C[PNG_COLOR_TYPE_RGB]=3;
189 CC2C[PNG_COLOR_TYPE_RGB_ALPHA]=4;
190 CC2C[PNG_COLOR_TYPE_GRAY_ALPHA]=2;
191
192 channels=CC2C[color_type];
193
29a70e5d 194 mm_log((1,"channels %d\n", channels));
02d1d628 195
29a70e5d 196 im = i_img_empty_ch(NULL, width, height, channels);
02d1d628
AMH
197
198 /**** Set up the data transformations you want. Note that these are all
199 **** optional. Only call them if you want/need them. Many of the
200 **** transformations only work on specific types of images, and many
201 **** are mutually exclusive.
202 ****/
203
204 /* tell libpng to strip 16 bit/color files down to 8 bits/color */
205 png_set_strip_16(png_ptr);
206
29a70e5d 207
02d1d628
AMH
208 /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
209 * byte into separate bytes (useful for paletted and grayscale images).
210 */
211
212 png_set_packing(png_ptr);
213
214 /* Expand paletted colors into true RGB triplets */
215 if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr);
216
217 /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
218 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(png_ptr);
219
220 /* Expand paletted or RGB images with transparency to full alpha channels
221 * so the data will be available as RGBA quartets.
29a70e5d
AMH
222 *
223 * if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr);
224 *
02d1d628 225 */
02d1d628 226
29a70e5d
AMH
227 /* Strip alpha bytes from the input data without combining with the
228 * background (not recommended).
229 */
230 if (color_type != PNG_COLOR_TYPE_RGB_ALPHA || color_type != PNG_COLOR_TYPE_GRAY_ALPHA)
231 png_set_strip_alpha(png_ptr);
232
233
02d1d628
AMH
234 number_passes = png_set_interlace_handling(png_ptr);
235
236 mm_log((1,"number of passes=%d\n",number_passes));
237
238 png_read_update_info(png_ptr, info_ptr);
29a70e5d 239
02d1d628 240 for (pass = 0; pass < number_passes; pass++)
29a70e5d
AMH
241 for (y = 0; y < height; y++) {
242 png_read_row(png_ptr,(png_bytep) &(im->data[channels*width*y]), NULL);
29a70e5d 243 }
02d1d628
AMH
244 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
245
246 png_read_end(png_ptr, info_ptr);
247 /* clean up after the read, and free any memory allocated - REQUIRED */
248 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
249
250 fclose(fp);
251 return im;
252}
253
254
255
256
257undef_int
258i_writepng(i_img *im,int fd) {
259 FILE *fp;
260 png_structp png_ptr;
261 png_infop info_ptr;
262 int width,height,y;
263 volatile int cspace,channels;
264
265 mm_log((1,"i_writepng(0x%x,fd %d)\n",im,fd));
266
267 if ((fp = fdopen(fd,"w")) == NULL) {
268 mm_log((1,"can't fdopen.\n"));
269 exit(1);
270 }
271
272 height=im->ysize;
273 width=im->xsize;
274
275 channels=im->channels;
276
277 if (channels>2) { cspace=PNG_COLOR_TYPE_RGB; channels-=3; }
278 else { cspace=PNG_COLOR_TYPE_GRAY; channels--; }
279
280 if (channels) cspace|=PNG_COLOR_MASK_ALPHA;
281 mm_log((1,"cspace=%d\n",cspace));
282
283 channels=im->channels;
284
285 /* Create and initialize the png_struct with the desired error handler
286 * functions. If you want to use the default stderr and longjump method,
287 * you can supply NULL for the last three parameters. We also check that
288 * the library version is compatible with the one used at compile time,
289 * in case we are using dynamically linked libraries. REQUIRED.
290 */
291
292 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
293
294 if (png_ptr == NULL) {
295 fclose(fp);
296 return 0;
297 }
298
299 /* Allocate/initialize the image information data. REQUIRED */
300 info_ptr = png_create_info_struct(png_ptr);
301
302 if (info_ptr == NULL) {
303 fclose(fp);
304 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
305 return(0);
306 }
307
308 /* Set error handling. REQUIRED if you aren't supplying your own
309 * error hadnling functions in the png_create_write_struct() call.
310 */
311 if (setjmp(png_ptr->jmpbuf)) {
312 /* If we get here, we had a problem reading the file */
313 fclose(fp);
314 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
315 return(0);
316 }
317
318 png_init_io(png_ptr, fp);
319
320 /* Set the image information here. Width and height are up to 2^31,
321 * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
322 * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
323 * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
324 * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
325 * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
326 * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
327 */
328
329 png_set_IHDR(png_ptr, info_ptr, width, height, 8, cspace,
330 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
331
332 png_write_info(png_ptr, info_ptr);
333 for (y = 0; y < height; y++) png_write_row(png_ptr, (png_bytep) &(im->data[channels*width*y]));
334 png_write_end(png_ptr, info_ptr);
335 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
336
337 fclose(fp);
338 return(1);
339}
340
341
342
343
344i_img*
345i_readpng_scalar(char *data, int length) {
346 i_img *im;
347 png_structp png_ptr;
348 png_infop info_ptr;
349 png_uint_32 width, height, y;
350 int bit_depth, color_type, interlace_type;
351 int number_passes;
352 int channels, pass;
353 unsigned int sig_read;
354
355 struct png_scalar_info sci;
356
357 sci.data=data;
358 sci.length=length;
359 sci.cpos=0;
360
361 sig_read=0;
362 mm_log((1,"i_readpng_scalar(char 0x%08X, length %d)\n",data,length));
363
364 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
365 png_set_read_fn(png_ptr, (void*) (&sci), user_read_data);
366
367 info_ptr = png_create_info_struct(png_ptr);
368 if (info_ptr == NULL) {
369 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
370 return NULL;
371 }
372
373 if (setjmp(png_ptr->jmpbuf)) {
374 mm_log((1,"i_readpng_scalar: error.\n"));
375 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
376 return NULL;
377 }
378
379 scalar_png_init_io(png_ptr, &sci);
380 png_set_sig_bytes(png_ptr, sig_read);
381 png_read_info(png_ptr, info_ptr);
382 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
383
384 mm_log((1,
385 "png_get_IHDR results: width %d, height %d, bit_depth %d,color_type %d,interlace_type %d\n",
386 width,height,bit_depth,color_type,interlace_type));
387
388 CC2C[PNG_COLOR_TYPE_GRAY]=1;
389 CC2C[PNG_COLOR_TYPE_PALETTE]=3;
390 CC2C[PNG_COLOR_TYPE_RGB]=3;
391 CC2C[PNG_COLOR_TYPE_RGB_ALPHA]=4;
392 CC2C[PNG_COLOR_TYPE_GRAY_ALPHA]=2;
393 channels=CC2C[color_type];
394 mm_log((1,"channels %d\n",channels));
395 im=i_img_empty_ch(NULL,width,height,channels);
396 png_set_strip_16(png_ptr);
397 png_set_packing(png_ptr);
398 if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr);
399 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(png_ptr);
400 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr);
401 number_passes = png_set_interlace_handling(png_ptr);
402 mm_log((1,"number of passes=%d\n",number_passes));
403 png_read_update_info(png_ptr, info_ptr);
404 mm_log((1,"made it to here 1\n"));
405 for (pass = 0; pass < number_passes; pass++)
406 for (y = 0; y < height; y++) { png_read_row(png_ptr,(png_bytep) &(im->data[channels*width*y]), NULL); }
407 mm_log((1,"made it to here 2\n"));
408 png_read_end(png_ptr, info_ptr);
409 mm_log((1,"made it to here 3\n"));
410 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
411 mm_log((1,"made it to here 4\n"));
412 mm_log((1,"(0x%08X) <- i_readpng_scalar\n",im));
413 return im;
414}
415
416
417
418
419/* i_img* */
420/* i_readpng_wiol(io_glue *ig, int length) { */
421/* i_img *im; */
422/* png_structp png_ptr; */
423/* png_infop info_ptr; */
424/* png_uint_32 width, height; */
425/* int bit_depth, color_type, interlace_type; */
426/* int number_passes,y; */
427/* int channels,pass; */
428/* unsigned int sig_read; */
429
430/* struct png_wiol_info wi; */
431
432/* wi.data = ig; */
433/* wi.length = length; */
434/* wi.cpos = 0; */
435
436/* sig_read=0; */
437/* mm_log((1,"i_readpng_wiol(char 0x%p, length %d)\n", data, length)); */
438
439/* png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); */
440/* png_set_read_fn(png_ptr, (void*) (&wi), user_read_data); */
441
442/* info_ptr = png_create_info_struct(png_ptr); */
443/* if (info_ptr == NULL) { */
444/* png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); */
445/* return NULL; */
446/* } */
447
448/* if (setjmp(png_ptr->jmpbuf)) { */
449/* mm_log((1,"i_readpng_wiol: error.\n")); */
450/* png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); */
451/* return NULL; */
452/* } */
453
454/* scalar_png_init_io(png_ptr, &sci); */
455/* png_set_sig_bytes(png_ptr, sig_read); */
456/* png_read_info(png_ptr, info_ptr); */
457/* png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); */
458
459/* mm_log((1, */
460/* "png_get_IHDR results: width %d, height %d, bit_depth %d,color_type %d,interlace_type %d\n", */
461/* width,height,bit_depth,color_type,interlace_type)); */
462
463/* CC2C[PNG_COLOR_TYPE_GRAY]=1; */
464/* CC2C[PNG_COLOR_TYPE_PALETTE]=3; */
465/* CC2C[PNG_COLOR_TYPE_RGB]=3; */
466/* CC2C[PNG_COLOR_TYPE_RGB_ALPHA]=4; */
467/* CC2C[PNG_COLOR_TYPE_GRAY_ALPHA]=2; */
468/* channels = CC2C[color_type]; */
469
470/* mm_log((1,"i_readpng_wiol: channels %d\n",channels)); */
471
472/* im = i_img_empty_ch(NULL,width,height,channels); */
473/* png_set_strip_16(png_ptr); */
474/* png_set_packing(png_ptr); */
475/* if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); */
476/* if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(png_ptr); */
477/* if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); */
478/* number_passes = png_set_interlace_handling(png_ptr); */
479/* mm_log((1,"number of passes=%d\n",number_passes)); */
480/* png_read_update_info(png_ptr, info_ptr); */
481/* mm_log((1,"made it to here 1\n")); */
482/* for (pass = 0; pass < number_passes; pass++) */
483/* for (y = 0; y < height; y++) { png_read_row(png_ptr,(png_bytep) &(im->data[channels*width*y]), NULL); } */
484/* mm_log((1,"made it to here 2\n")); */
485/* png_read_end(png_ptr, info_ptr); */
486/* mm_log((1,"made it to here 3\n")); */
487/* png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); */
488/* mm_log((1,"made it to here 4\n")); */
489/* mm_log((1,"(0x%08X) <- i_readpng_scalar\n",im)); */
490
491/* return im; */
492/* } */