6
#include "png.h" /* includes zlib.h and setjmp.h */
11
/*---------------------------------------------------------------------------
13
gd_png.c Copyright 1999 Greg Roelofs and Thomas Boutell
15
The routines in this file, gdImagePng*() and gdImageCreateFromPng*(),
16
are drop-in replacements for gdImageGif*() and gdImageCreateFromGif*(),
17
except that these functions are noisier in the case of errors (comment
18
out all fprintf() statements to disable that).
20
Only GIF-like PNG features are currently supported; that is, images must
21
either be indexed-color to begin with or they will be converted to it,
22
and they can have, at most, a single, fully transparent palette entry or
23
color. (Alpha channels are ignored.) Since gd images are artificially
24
generated, gamma is also ignored, and there is currently no support for
25
embedded text annotations (a la GIF comments) in gd.
27
Last updated: 19 July 1999
29
---------------------------------------------------------------------------*/
31
typedef struct _jmpbuf_wrapper {
35
static jmpbuf_wrapper gdPngJmpbufStruct;
37
static void gdPngErrorHandler(png_structp png_ptr, png_const_charp msg)
39
jmpbuf_wrapper *jmpbuf_ptr;
41
/* This function, aside from the extra step of retrieving the "error
42
* pointer" (below) and the fact that it exists within the application
43
* rather than within libpng, is essentially identical to libpng's
44
* default error handler. The second point is critical: since both
45
* setjmp() and longjmp() are called from the same code, they are
46
* guaranteed to have compatible notions of how big a jmp_buf is,
47
* regardless of whether _BSD_SOURCE or anything else has (or has not)
50
fprintf(stderr, "gd-png: fatal libpng error: %s\n", msg);
53
jmpbuf_ptr = png_get_error_ptr(png_ptr);
54
if (jmpbuf_ptr == NULL) { /* we are completely hosed now */
56
"gd-png: EXTREMELY fatal error: jmpbuf unrecoverable; terminating.\n");
61
longjmp(jmpbuf_ptr->jmpbuf, 1);
65
static void gdPngReadData(png_structp png_ptr,
66
png_bytep data, png_size_t length)
68
gdGetBuf(data, length, (gdIOCtx *)
69
png_get_io_ptr(png_ptr));
72
static void gdPngWriteData(png_structp png_ptr,
73
png_bytep data, png_size_t length)
75
gdPutBuf(data, length, (gdIOCtx *)
76
png_get_io_ptr(png_ptr));
79
static void gdPngFlushData(png_structp png_ptr)
83
gdImagePtr gdImageCreateFromPng(FILE *inFile)
86
gdIOCtx *in = gdNewFileCtx(inFile);
87
im = gdImageCreateFromPngCtx(in);
93
/* This routine is based in part on the Chapter 13 demo code in "PNG: The
94
* Definitive Guide" (http://www.cdrom.com/pub/png/pngbook.html).
96
gdImagePtr gdImageCreateFromPngCtx(gdIOCtx *infile)
101
png_uint_32 width, height, rowbytes;
102
int bit_depth, color_type, interlace_type;
103
int num_palette, num_trans;
105
png_color_16p trans_gray_rgb;
107
png_bytep image_data = NULL;
108
png_bytepp row_pointers = NULL;
109
gdImagePtr im = NULL;
111
volatile int transparent = -1;
112
volatile int palette_allocated = FALSE;
114
/* Make sure the signature can't match by dumb luck -- TBB */
115
/* GRR: isn't sizeof(infile) equal to the size of the pointer? */
116
memset(infile, 0, sizeof(infile));
118
/* first do a quick check that the file really is a PNG image; could
119
* have used slightly more general png_sig_cmp() function instead */
120
gdGetBuf(sig, 8, infile);
121
if (!png_check_sig(sig, 8))
122
return NULL; /* bad signature */
124
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, &gdPngJmpbufStruct,
125
gdPngErrorHandler, NULL);
126
if (png_ptr == NULL) {
127
fprintf(stderr, "gd-png error: cannot allocate libpng main struct\n");
131
info_ptr = png_create_info_struct(png_ptr);
132
if (info_ptr == NULL) {
133
fprintf(stderr, "gd-png error: cannot allocate libpng info struct\n");
134
png_destroy_read_struct(&png_ptr, NULL, NULL);
138
/* we could create a second info struct here (end_info), but it's only
139
* useful if we want to keep pre- and post-IDAT chunk info separated
140
* (mainly for PNG-aware image editors and converters) */
142
/* setjmp() must be called in every non-callback function that calls a
143
* PNG-reading libpng function */
144
if (setjmp(gdPngJmpbufStruct.jmpbuf)) {
145
fprintf(stderr, "gd-png error: setjmp returns error condition\n");
146
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
150
png_set_sig_bytes(png_ptr, 8); /* we already read the 8 signature bytes */
152
png_set_read_fn(png_ptr, (void *)infile, gdPngReadData);
153
png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */
155
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
156
&interlace_type, NULL, NULL);
159
png_set_strip_16(png_ptr);
160
else if (bit_depth < 8)
161
png_set_packing(png_ptr); /* expand to 1 byte per pixel */
163
if (color_type & PNG_COLOR_MASK_ALPHA) {
164
fprintf(stderr, "gd-png warning: alpha channel not supported\n");
165
png_set_strip_alpha(png_ptr);
168
switch (color_type) {
169
case PNG_COLOR_TYPE_PALETTE:
170
png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
172
fprintf(stderr, "gd-png color_type is palette, colors: %d\n",
175
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
176
int real_num_trans = 0, idx_first_trans = -1;
177
int min_trans = 256, idx_min_trans = -1;
179
png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
180
for (i = 0; i < num_trans; ++i) {
181
if (trans[i] < 255) {
183
if (idx_first_trans < 0)
185
if (trans[i] < min_trans) {
186
min_trans = trans[i];
191
if (real_num_trans > 0) {
192
if (real_num_trans > 1 || trans[idx_first_trans] != 0) {
193
fprintf(stderr, "gd-png warning: only single-color, "
194
"100%% transparency supported\n");
195
transparent = idx_min_trans;
197
transparent = idx_first_trans;
203
case PNG_COLOR_TYPE_GRAY:
204
case PNG_COLOR_TYPE_GRAY_ALPHA:
205
/* create a fake palette and check for single-shade transparency */
206
if ((palette = (png_colorp)malloc(256*sizeof(png_color))) == NULL) {
207
fprintf(stderr, "gd-png error: cannot allocate gray palette\n");
208
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
211
palette_allocated = TRUE;
214
num_palette = 1<<bit_depth;
215
for (i = 0; i < 256; ++i)
217
j = (255*i)/(num_palette-1);
218
palette[i].red = palette[i].green = palette[i].blue = j;
224
for (i = 0; i < 256; ++i)
226
palette[i].red = palette[i].green = palette[i].blue = i;
229
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
230
png_get_tRNS(png_ptr, info_ptr, NULL, NULL, &trans_gray_rgb);
231
if (bit_depth == 16) /* png_set_strip_16() not yet in effect */
232
transparent = trans_gray_rgb->gray >> 8;
234
transparent = trans_gray_rgb->gray;
235
/* Note slight error in 16-bit case: up to 256 16-bit shades
236
* may get mapped to a single 8-bit shade, and only one of them
237
* is supposed to be transparent. IOW, both opaque pixels and
238
* transparent pixels will be mapped into the transparent entry.
239
* There is no particularly good way around this in the case
240
* that all 256 8-bit shades are used, but one could write some
241
* custom 16-bit code to handle the case where there are free
242
* palette entries. This error will be extremely rare in
243
* general, though. (Quite possibly there is only one such
244
* image in existence.) */
248
case PNG_COLOR_TYPE_RGB:
249
case PNG_COLOR_TYPE_RGB_ALPHA:
250
/* allocate a palette and check for single-shade transparency */
251
if ((palette = (png_colorp)malloc(256*sizeof(png_color))) == NULL) {
252
fprintf(stderr, "gd-png error: cannot allocate RGB palette\n");
253
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
256
palette_allocated = TRUE;
258
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
259
png_get_tRNS(png_ptr, info_ptr, NULL, NULL, &trans_gray_rgb);
260
if (bit_depth == 16) { /* png_set_strip_16() not yet active */
261
palette[0].red = trans_gray_rgb->red >> 8;
262
palette[0].green = trans_gray_rgb->green >> 8;
263
palette[0].blue = trans_gray_rgb->blue >> 8;
265
palette[0].red = trans_gray_rgb->red;
266
palette[0].green = trans_gray_rgb->green;
267
palette[0].blue = trans_gray_rgb->blue;
270
/* Note that the same error exists in the 16-bit RGB case as in
271
* the grayscale case, except that the degeneracy is now 16.8
272
* million to 1 (at a minimum--actually more than that due to
273
* quantization). Again, this is an extremely rare problem.
274
* Unfortunately, it also affects 8-bit-per-sample RGB images
275
* (quantization), unless libpng is doing something sneaky... */
277
palette[0].red = palette[0].green = palette[0].blue = 224;
280
#if 0 /* libpng.txt demo code looks broken--need to check both PLTE and hIST */
281
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) {
282
png_color_16p histogram;
284
png_get_hIST(png_ptr, info_ptr, &histogram);
285
png_set_dither(png_ptr, palette, num_palette,
286
max_screen_colors, histogram, 1);
290
int idx, red, green, blue;
293
/* allocate a 6x7x6 color cube, starting at index 4 */
295
for (red = 0; red < 256; red += 51) {
296
for (i = 0; i < 7; ++i) {
297
green = (i * 425) / 10; /* i.e., 42.5 */
298
for (blue = 0; blue < 256; blue += 51) {
299
palette[idx].red = red;
300
palette[idx].green = green;
301
palette[idx].blue = blue;
306
/* fill in remaining entries (1-3) with common gray values */
307
palette[1].red = palette[1].green = palette[1].blue = 192;
308
palette[2].red = palette[2].green = palette[2].blue = 128;
309
palette[3].red = palette[3].green = palette[3].blue = 64;
310
/* final argument (full_dither) *must* be 1: */
311
png_set_dither(png_ptr, palette, 256, 256, NULL, 1);
313
/* allocate a 6x6x6 color cube, starting at index 0 or 1 */
314
idx = (transparent < 0)? 0 : 1;
315
for (red = 0; red < 256; red += 51) {
316
for (green = 0; green < 256; green += 51) {
317
for (blue = 0; blue < 256; blue += 51) {
318
palette[idx].red = red;
319
palette[idx].green = green;
320
palette[idx].blue = blue;
325
png_set_dither(png_ptr, palette, idx, idx, NULL, 1);
331
png_read_update_info(png_ptr, info_ptr);
333
/* allocate space for the PNG image data */
334
rowbytes = png_get_rowbytes(png_ptr, info_ptr);
335
if ((image_data = (png_bytep)malloc(rowbytes*height)) == NULL) {
336
fprintf(stderr, "gd-png error: cannot allocate image data\n");
337
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
340
if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) {
341
fprintf(stderr, "gd-png error: cannot allocate row pointers\n");
342
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
347
/* set the individual row_pointers to point at the correct offsets */
348
for (j = 0; j < height; ++j) {
349
row_pointers[j] = image_data + j*rowbytes;
352
png_read_image(png_ptr, row_pointers); /* read whole image... */
353
png_read_end(png_ptr, NULL); /* ...done! */
355
if ((im = gdImageCreate((int)width, (int)height)) == NULL) {
356
fprintf(stderr, "gd-png error: cannot allocate gdImage struct\n");
357
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
363
im->colorsTotal = num_palette;
364
im->transparent = transparent;
365
im->interlace = (interlace_type == PNG_INTERLACE_ADAM7);
367
/* load the palette and mark all entries "open" (unused) for now */
369
for (i = 0; i < num_palette; ++i) {
370
im->red[i] = palette[i].red;
371
im->green[i] = palette[i].green;
372
im->blue[i] = palette[i].blue;
375
for (i = num_palette; i < gdMaxColors; ++i) {
379
/* can't nuke structs until done with palette */
380
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
382
/* could copy data with memcpy(), but also want to check colormap entries */
383
for (j = 0; j < height; ++j) {
384
for (i = 0; i < width; ++i) {
385
register png_byte idx = row_pointers[j][i];
387
im->pixels[j][i] = idx;
393
for (i = num_palette; i < gdMaxColors; ++i) {
395
fprintf(stderr, "gd-png warning: image data references out-of-range"
396
" color index (%d)\n", i);
401
if (palette_allocated)
410
void gdImagePng(gdImagePtr im, FILE *outFile)
412
gdIOCtx *out = gdNewFileCtx(outFile);
413
gdImagePngCtx(im, out);
417
void* gdImagePngPtr(gdImagePtr im, int *size)
420
gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
421
gdImagePngCtx(im, out);
422
rv = gdDPExtractData(out, size);
427
/* This routine is based in part on code from Dale Lutz (Safe Software Inc.)
428
* and in part on demo code from Chapter 15 of "PNG: The Definitive Guide"
429
* (http://www.cdrom.com/pub/png/pngbook.html).
431
void gdImagePngCtx(gdImagePtr im, gdIOCtx *outfile)
433
int i, j, bit_depth, interlace_type;
436
int colors = im->colorsTotal;
437
int *open = im->open;
438
int mapping[gdMaxColors]; /* mapping[gif_index] == png_index */
439
png_byte trans_value = 0;
440
png_color palette[gdMaxColors];
443
volatile int transparent = im->transparent;
444
volatile int remap = FALSE;
447
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
448
&gdPngJmpbufStruct, gdPngErrorHandler, NULL);
449
if (png_ptr == NULL) {
450
fprintf(stderr, "gd-png error: cannot allocate libpng main struct\n");
454
info_ptr = png_create_info_struct (png_ptr);
455
if (info_ptr == NULL) {
456
fprintf(stderr, "gd-png error: cannot allocate libpng info struct\n");
457
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
461
if (setjmp(gdPngJmpbufStruct.jmpbuf)) {
462
fprintf(stderr, "gd-png error: setjmp returns error condition\n");
463
png_destroy_write_struct(&png_ptr, &info_ptr);
467
png_set_write_fn(png_ptr, (void *)outfile, gdPngWriteData, gdPngFlushData);
469
/* For now gd only supports palette images, for which filter type NONE is
470
* almost guaranteed to be the best. But that's what libpng defaults to
471
* for palette images anyway, so no need to set this explicitly. */
472
/* png_set_filter(png_ptr, 0, PNG_FILTER_NONE); */
474
/* may want to force maximum compression, but time penalty is large */
475
/* png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); */
477
/* can set this to a smaller value without compromising compression if all
478
* image data is 16K or less; will save some decoder memory [min == 8] */
479
/* png_set_compression_window_bits(png_ptr, 15); */
481
if (transparent >= im->colorsTotal ||
482
(transparent >= 0 && open[transparent]))
485
for (i = 0; i < gdMaxColors; ++i)
488
/* count actual number of colors used (colorsTotal == high-water mark) */
490
for (i = 0; i < im->colorsTotal; ++i) {
496
if (colors < im->colorsTotal) {
498
if (transparent >= 0)
499
transparent = mapping[transparent];
504
else if (colors <= 4)
506
else if (colors <= 16)
511
interlace_type = im->interlace? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
513
png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
514
PNG_COLOR_TYPE_PALETTE, interlace_type,
515
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
517
if (transparent >= 0) {
518
/* always write PNG files with the transparent palette entry first to
519
* minimize size of the tRNS chunk; swap if necessary */
520
if (transparent != 0) {
521
if (!remap) { /* so colors == im->colorsTotal */
523
for (i = 0; i < colors; ++i)
526
mapping[transparent] = 0;
527
mapping[0] = transparent;
529
png_set_tRNS(png_ptr, info_ptr, &trans_value, 1, NULL);
532
/* convert GIF palette to libpng layout */
534
for (i = 0; i < im->colorsTotal; ++i) {
537
palette[mapping[i]].red = im->red[i];
538
palette[mapping[i]].green = im->green[i];
539
palette[mapping[i]].blue = im->blue[i];
542
for (i = 0; i < colors; ++i) {
543
palette[i].red = im->red[i];
544
palette[i].green = im->green[i];
545
palette[i].blue = im->blue[i];
547
png_set_PLTE(png_ptr, info_ptr, palette, colors);
550
/* write out the PNG header info (everything up to first IDAT) */
551
png_write_info(png_ptr, info_ptr);
553
/* make sure < 8-bit images are packed into pixels as tightly as possible */
554
png_set_packing(png_ptr);
556
/* This code allocates a set of row buffers and copies the gd image data
557
* into them only in the case that remapping is necessary; in gd 1.3 and
558
* later, the im->pixels array is laid out identically to libpng's row
559
* pointers and can be passed to png_write_image() function directly.
560
* The remapping case could be accomplished with less memory for non-
561
* interlaced images, but interlacing causes some serious complications. */
563
png_bytep *row_pointers;
564
row_pointers = malloc(sizeof(png_bytep) * height);
565
if (row_pointers == NULL) {
566
fprintf(stderr, "gd-png error: unable to allocate row_pointers\n");
568
for (j = 0; j < height; ++j) {
569
if ((row_pointers[j] = (png_bytep)malloc(width)) == NULL) {
570
fprintf(stderr, "gd-png error: unable to allocate rows\n");
571
for (i = 0; i < j; ++i)
572
free(row_pointers[i]);
575
for (i = 0; i < width; ++i)
576
row_pointers[j][i] = mapping[im->pixels[j][i]];
579
png_write_image(png_ptr, row_pointers);
580
png_write_end(png_ptr, info_ptr);
582
for (j = 0; j < height; ++j)
583
free(row_pointers[j]);
586
png_write_image(png_ptr, im->pixels);
587
png_write_end(png_ptr, info_ptr);
589
/* 1.6.3: maybe we should give that memory BACK! TBB */
590
png_destroy_write_struct(&png_ptr, &info_ptr);