]> git.imager.perl.org - imager.git/blame - png.c
check the ft2 library too
[imager.git] / png.c
CommitLineData
790923a4 1#include "iolayer.h"
02d1d628
AMH
2#include "image.h"
3#include "png.h"
4
5/* Check to see if a file is a PNG file using png_sig_cmp(). png_sig_cmp()
6 * returns zero if the image is a PNG and nonzero if it isn't a PNG.
7 *
8 * The function check_if_png() shown here, but not used, returns nonzero (true)
9 * if the file can be opened and is a PNG, 0 (false) otherwise.
10 *
11 * If this call is successful, and you are going to keep the file open,
12 * you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once
13 * you have created the png_ptr, so that libpng knows your application
14 * has read that many bytes from the start of the file. Make sure you
15 * don't call png_set_sig_bytes() with more than 8 bytes read or give it
16 * an incorrect number of bytes read, or you will either have read too
17 * many bytes (your fault), or you are telling libpng to read the wrong
18 * number of magic bytes (also your fault).
19 *
20 * Many applications already read the first 2 or 4 bytes from the start
21 * of the image to determine the file type, so it would be easiest just
22 * to pass the bytes to png_sig_cmp() or even skip that if you know
23 * you have a PNG file, and call png_set_sig_bytes().
24 */
25
26/* this is a way to get number of channels from color space
27 * Color code to channel number */
28
29int CC2C[PNG_COLOR_MASK_PALETTE|PNG_COLOR_MASK_COLOR|PNG_COLOR_MASK_ALPHA];
30
31#define PNG_BYTES_TO_CHECK 4
32
33
34
35
36
37
38
39
40
41/*
6829f5f6
AMH
42 png_set_read_fn(png_structp read_ptr, voidp read_io_ptr, png_rw_ptr read_data_fn)
43 png_set_write_fn(png_structp write_ptr, voidp write_io_ptr, png_rw_ptr write_data_fn,
44 png_flush_ptr output_flush_fn);
45 voidp read_io_ptr = png_get_io_ptr(read_ptr);
46 voidp write_io_ptr = png_get_io_ptr(write_ptr);
02d1d628
AMH
47*/
48
02d1d628
AMH
49
50
02d1d628
AMH
51
52static void
790923a4
AMH
53wiol_read_data(png_structp png_ptr, png_bytep data, png_size_t length) {
54 io_glue *ig = (io_glue *)png_ptr->io_ptr;
55 int rc = ig->readcb(ig, data, length);
56 if (rc != length) png_error(png_ptr, "Read overflow error on an iolayer source.");
02d1d628
AMH
57}
58
02d1d628 59static void
790923a4
AMH
60wiol_write_data(png_structp png_ptr, png_bytep data, png_size_t length) {
61 int rc;
62 io_glue *ig = (io_glue *)png_ptr->io_ptr;
63 rc = ig->writecb(ig, data, length);
64 if (rc != length) png_error(png_ptr, "Write error on an iolayer source.");
02d1d628
AMH
65}
66
67static void
790923a4
AMH
68wiol_flush_data(png_structp png_ptr) {
69 /* XXX : This needs to be added to the io layer */
02d1d628 70}
02d1d628
AMH
71
72
73int
74check_if_png(char *file_name, FILE **fp) {
790923a4 75 char buf[PNG_BYTES_TO_CHECK];
02d1d628 76
790923a4
AMH
77 /* Open the prospective PNG file. */
78 if ((*fp = fopen(file_name, "rb")) != NULL) return 0;
02d1d628 79
790923a4
AMH
80 /* Read in some of the signature bytes */
81 if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK) return 0;
02d1d628 82
790923a4
AMH
83 /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature.
84 Return nonzero (true) if they match */
02d1d628 85
790923a4 86 return(!png_sig_cmp((png_bytep)buf, (png_size_t)0, PNG_BYTES_TO_CHECK));
02d1d628
AMH
87}
88
02d1d628 89
790923a4
AMH
90
91undef_int
92i_writepng(i_img *im, int fd) {
93 FILE *fp;
02d1d628
AMH
94 png_structp png_ptr;
95 png_infop info_ptr;
790923a4
AMH
96 int width,height,y;
97 volatile int cspace,channels;
faa9b3e7
TC
98 double xres, yres;
99 int aspect_only, have_res;
100 double offx, offy;
101 char offunit[20] = "pixel";
02d1d628 102
790923a4
AMH
103 mm_log((1,"i_writepng(0x%x,fd %d)\n",im,fd));
104
105 if ((fp = fdopen(fd,"w")) == NULL) {
02d1d628
AMH
106 mm_log((1,"can't fdopen.\n"));
107 exit(1);
108 }
109
790923a4
AMH
110 height=im->ysize;
111 width=im->xsize;
02d1d628 112
790923a4
AMH
113 channels=im->channels;
114
115 if (channels>2) { cspace=PNG_COLOR_TYPE_RGB; channels-=3; }
116 else { cspace=PNG_COLOR_TYPE_GRAY; channels--; }
117
118 if (channels) cspace|=PNG_COLOR_MASK_ALPHA;
119 mm_log((1,"cspace=%d\n",cspace));
120
121 channels=im->channels;
122
123 /* Create and initialize the png_struct with the desired error handler
124 * functions. If you want to use the default stderr and longjump method,
125 * you can supply NULL for the last three parameters. We also check that
126 * the library version is compatible with the one used at compile time,
127 * in case we are using dynamically linked libraries. REQUIRED.
128 */
129
130 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
02d1d628
AMH
131
132 if (png_ptr == NULL) {
133 fclose(fp);
134 return 0;
135 }
136
790923a4 137 /* Allocate/initialize the image information data. REQUIRED */
02d1d628 138 info_ptr = png_create_info_struct(png_ptr);
790923a4 139
02d1d628
AMH
140 if (info_ptr == NULL) {
141 fclose(fp);
790923a4
AMH
142 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
143 return(0);
02d1d628
AMH
144 }
145
790923a4
AMH
146 /* Set error handling. REQUIRED if you aren't supplying your own
147 * error hadnling functions in the png_create_write_struct() call.
02d1d628 148 */
02d1d628 149 if (setjmp(png_ptr->jmpbuf)) {
02d1d628 150 /* If we get here, we had a problem reading the file */
790923a4
AMH
151 fclose(fp);
152 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
153 return(0);
02d1d628
AMH
154 }
155
02d1d628 156 png_init_io(png_ptr, fp);
02d1d628 157
790923a4
AMH
158 /* Set the image information here. Width and height are up to 2^31,
159 * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
160 * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
161 * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
162 * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
163 * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
164 * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
29a70e5d 165 */
02d1d628 166
790923a4
AMH
167 png_set_IHDR(png_ptr, info_ptr, width, height, 8, cspace,
168 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
29a70e5d 169
faa9b3e7
TC
170 have_res = 1;
171 if (i_tags_get_float(&im->tags, "i_xres", 0, &xres)) {
172 if (i_tags_get_float(&im->tags, "i_yres", 0, &yres))
173 ; /* nothing to do */
174 else
175 yres = xres;
176 }
177 else {
178 if (i_tags_get_float(&im->tags, "i_yres", 0, &yres))
179 xres = yres;
180 else
181 have_res = 0;
182 }
183 if (have_res) {
184 aspect_only = 0;
185 i_tags_get_int(&im->tags, "i_aspect_only", 0, &aspect_only);
186 xres /= 0.0254;
187 yres /= 0.0254;
188 png_set_pHYs(png_ptr, info_ptr, xres + 0.5, yres + 0.5,
189 aspect_only ? PNG_RESOLUTION_UNKNOWN : PNG_RESOLUTION_METER);
190 }
191
790923a4 192 png_write_info(png_ptr, info_ptr);
faa9b3e7
TC
193 if (!im->virtual && im->type == i_direct_type && im->bits == i_8_bits) {
194 for (y = 0; y < height; y++)
195 png_write_row(png_ptr, (png_bytep) &(im->idata[channels*width*y]));
196 }
197 else {
198 unsigned char *data = mymalloc(im->xsize * im->channels);
199 if (data) {
200 for (y = 0; y < height; y++) {
201 i_gsamp(im, 0, im->xsize, y, data, NULL, im->channels);
202 png_write_row(png_ptr, (png_bytep)data);
203 }
204 myfree(data);
205 }
206 else {
207 fclose(fp);
208 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
209 return 0;
210 }
211 }
790923a4
AMH
212 png_write_end(png_ptr, info_ptr);
213 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
02d1d628
AMH
214
215 fclose(fp);
790923a4 216 return(1);
02d1d628
AMH
217}
218
02d1d628
AMH
219
220
221undef_int
790923a4 222i_writepng_wiol(i_img *im, io_glue *ig) {
02d1d628
AMH
223 FILE *fp;
224 png_structp png_ptr;
225 png_infop info_ptr;
226 int width,height,y;
227 volatile int cspace,channels;
faa9b3e7
TC
228 double xres, yres;
229 int aspect_only, have_res;
230 double offx, offy;
231 char offunit[20] = "pixel";
02d1d628 232
790923a4
AMH
233 io_glue_commit_types(ig);
234 mm_log((1,"i_writepng(im %p ,ig %p)\n", im, ig));
02d1d628 235
790923a4
AMH
236 height = im->ysize;
237 width = im->xsize;
02d1d628
AMH
238
239 channels=im->channels;
240
790923a4 241 if (channels > 2) { cspace = PNG_COLOR_TYPE_RGB; channels-=3; }
02d1d628
AMH
242 else { cspace=PNG_COLOR_TYPE_GRAY; channels--; }
243
244 if (channels) cspace|=PNG_COLOR_MASK_ALPHA;
245 mm_log((1,"cspace=%d\n",cspace));
246
790923a4 247 channels = im->channels;
02d1d628
AMH
248
249 /* Create and initialize the png_struct with the desired error handler
250 * functions. If you want to use the default stderr and longjump method,
251 * you can supply NULL for the last three parameters. We also check that
252 * the library version is compatible with the one used at compile time,
253 * in case we are using dynamically linked libraries. REQUIRED.
254 */
255
256 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
257
790923a4
AMH
258 if (png_ptr == NULL) return 0;
259
02d1d628
AMH
260
261 /* Allocate/initialize the image information data. REQUIRED */
262 info_ptr = png_create_info_struct(png_ptr);
263
264 if (info_ptr == NULL) {
02d1d628 265 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
790923a4 266 return 0;
02d1d628
AMH
267 }
268
269 /* Set error handling. REQUIRED if you aren't supplying your own
270 * error hadnling functions in the png_create_write_struct() call.
271 */
272 if (setjmp(png_ptr->jmpbuf)) {
02d1d628
AMH
273 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
274 return(0);
275 }
276
790923a4
AMH
277 png_set_write_fn(png_ptr, (png_voidp) (ig), wiol_write_data, wiol_flush_data);
278 png_ptr->io_ptr = (png_voidp) ig;
02d1d628
AMH
279
280 /* Set the image information here. Width and height are up to 2^31,
281 * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
282 * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
283 * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
284 * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
285 * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
286 * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
287 */
288
289 png_set_IHDR(png_ptr, info_ptr, width, height, 8, cspace,
290 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
291
faa9b3e7
TC
292 have_res = 1;
293 if (i_tags_get_float(&im->tags, "i_xres", 0, &xres)) {
294 if (i_tags_get_float(&im->tags, "i_yres", 0, &yres))
295 ; /* nothing to do */
296 else
297 yres = xres;
298 }
299 else {
300 if (i_tags_get_float(&im->tags, "i_yres", 0, &yres))
301 xres = yres;
302 else
303 have_res = 0;
304 }
305 if (have_res) {
306 aspect_only = 0;
307 i_tags_get_int(&im->tags, "i_aspect_only", 0, &aspect_only);
308 xres /= 0.0254;
309 yres /= 0.0254;
310 png_set_pHYs(png_ptr, info_ptr, xres + 0.5, yres + 0.5,
311 aspect_only ? PNG_RESOLUTION_UNKNOWN : PNG_RESOLUTION_METER);
312 }
313
02d1d628 314 png_write_info(png_ptr, info_ptr);
790923a4 315
faa9b3e7
TC
316 if (!im->virtual && im->type == i_direct_type && im->bits == i_8_bits) {
317 for (y = 0; y < height; y++)
318 png_write_row(png_ptr, (png_bytep) &(im->idata[channels*width*y]));
319 }
320 else {
321 unsigned char *data = mymalloc(im->xsize * im->channels);
322 if (data) {
323 for (y = 0; y < height; y++) {
324 i_gsamp(im, 0, im->xsize, y, data, NULL, im->channels);
325 png_write_row(png_ptr, (png_bytep)data);
326 }
327 myfree(data);
328 }
329 else {
330 fclose(fp);
331 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
332 return 0;
333 }
334 }
790923a4 335
02d1d628 336 png_write_end(png_ptr, info_ptr);
790923a4 337
02d1d628
AMH
338 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
339
02d1d628
AMH
340 return(1);
341}
342
343
344
faa9b3e7 345static void get_png_tags(i_img *im, png_structp png_ptr, png_infop info_ptr);
02d1d628
AMH
346
347i_img*
790923a4 348i_readpng_wiol(io_glue *ig, int length) {
02d1d628
AMH
349 i_img *im;
350 png_structp png_ptr;
351 png_infop info_ptr;
790923a4 352 png_uint_32 width, height;
02d1d628 353 int bit_depth, color_type, interlace_type;
790923a4
AMH
354 int number_passes,y;
355 int channels,pass;
02d1d628
AMH
356 unsigned int sig_read;
357
790923a4 358 sig_read = 0;
02d1d628 359
790923a4
AMH
360 io_glue_commit_types(ig);
361 mm_log((1,"i_readpng_wiol(ig %p, length %d)\n", ig, length));
02d1d628
AMH
362
363 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
790923a4 364 png_set_read_fn(png_ptr, (png_voidp) (ig), wiol_read_data);
02d1d628
AMH
365
366 info_ptr = png_create_info_struct(png_ptr);
367 if (info_ptr == NULL) {
368 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
369 return NULL;
370 }
371
372 if (setjmp(png_ptr->jmpbuf)) {
790923a4 373 mm_log((1,"i_readpng_wiol: error.\n"));
02d1d628
AMH
374 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
375 return NULL;
376 }
790923a4
AMH
377
378 png_ptr->io_ptr = (png_voidp) ig;
02d1d628
AMH
379 png_set_sig_bytes(png_ptr, sig_read);
380 png_read_info(png_ptr, info_ptr);
381 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
382
383 mm_log((1,
790923a4 384 "png_get_IHDR results: width %d, height %d, bit_depth %d, color_type %d, interlace_type %d\n",
02d1d628
AMH
385 width,height,bit_depth,color_type,interlace_type));
386
387 CC2C[PNG_COLOR_TYPE_GRAY]=1;
388 CC2C[PNG_COLOR_TYPE_PALETTE]=3;
389 CC2C[PNG_COLOR_TYPE_RGB]=3;
390 CC2C[PNG_COLOR_TYPE_RGB_ALPHA]=4;
391 CC2C[PNG_COLOR_TYPE_GRAY_ALPHA]=2;
790923a4
AMH
392 channels = CC2C[color_type];
393
394 mm_log((1,"i_readpng_wiol: channels %d\n",channels));
395
02d1d628
AMH
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);
6829f5f6
AMH
400
401 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
402 channels++;
403 mm_log((1, "image has transparency, adding alpha: channels = %d\n", channels));
404 png_set_expand(png_ptr);
405 }
790923a4 406
02d1d628
AMH
407 number_passes = png_set_interlace_handling(png_ptr);
408 mm_log((1,"number of passes=%d\n",number_passes));
409 png_read_update_info(png_ptr, info_ptr);
790923a4
AMH
410
411 im = i_img_empty_ch(NULL,width,height,channels);
412
02d1d628 413 for (pass = 0; pass < number_passes; pass++)
faa9b3e7 414 for (y = 0; y < height; y++) { png_read_row(png_ptr,(png_bytep) &(im->idata[channels*width*y]), NULL); }
02d1d628 415
790923a4 416 png_read_end(png_ptr, info_ptr);
02d1d628 417
faa9b3e7
TC
418 get_png_tags(im, png_ptr, info_ptr);
419
790923a4 420 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
02d1d628 421
790923a4 422 mm_log((1,"(0x%08X) <- i_readpng_scalar\n", im));
02d1d628 423
790923a4
AMH
424 return im;
425}
faa9b3e7
TC
426
427static void get_png_tags(i_img *im, png_structp png_ptr, png_infop info_ptr) {
428 png_uint_32 xres, yres;
429 int unit_type;
430 if (png_get_pHYs(png_ptr, info_ptr, &xres, &yres, &unit_type)) {
431 mm_log((1,"pHYs (%d, %d) %d\n", xres, yres, unit_type));
432 if (unit_type == PNG_RESOLUTION_METER) {
433 i_tags_set_float(&im->tags, "i_xres", 0, xres * 0.0254);
434 i_tags_set_float(&im->tags, "i_yres", 0, xres * 0.0254);
435 }
436 else {
437 i_tags_addn(&im->tags, "i_xres", 0, xres);
438 i_tags_addn(&im->tags, "i_yres", 0, yres);
439 i_tags_addn(&im->tags, "i_aspect_only", 0, 1);
440 }
441 }
442}