~ubuntu-branches/ubuntu/wily/ntop/wily-proposed

« back to all changes in this revision

Viewing changes to gdchart0.94c/gd-1.8.3/gd_png.c

  • Committer: Bazaar Package Importer
  • Author(s): Dennis Schoen
  • Date: 2002-04-12 11:38:47 UTC
  • Revision ID: james.westby@ubuntu.com-20020412113847-4k4yydw0pzybc6g8
Tags: upstream-2.0.0
ImportĀ upstreamĀ versionĀ 2.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <stdio.h>
 
2
#include <math.h>
 
3
#include <string.h>
 
4
#include <stdlib.h>
 
5
#include "gd.h"
 
6
#include "png.h"    /* includes zlib.h and setjmp.h */
 
7
 
 
8
#define TRUE 1
 
9
#define FALSE 0
 
10
 
 
11
/*---------------------------------------------------------------------------
 
12
 
 
13
    gd_png.c                 Copyright 1999 Greg Roelofs and Thomas Boutell
 
14
 
 
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).
 
19
 
 
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.
 
26
 
 
27
    Last updated:  19 July 1999
 
28
 
 
29
  ---------------------------------------------------------------------------*/
 
30
 
 
31
typedef struct _jmpbuf_wrapper {
 
32
  jmp_buf jmpbuf;
 
33
} jmpbuf_wrapper;
 
34
 
 
35
static jmpbuf_wrapper gdPngJmpbufStruct;
 
36
 
 
37
static void gdPngErrorHandler(png_structp png_ptr, png_const_charp msg)
 
38
{
 
39
  jmpbuf_wrapper  *jmpbuf_ptr;
 
40
 
 
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)
 
48
   * been defined. */
 
49
 
 
50
  fprintf(stderr, "gd-png:  fatal libpng error: %s\n", msg);
 
51
  fflush(stderr);
 
52
 
 
53
  jmpbuf_ptr = png_get_error_ptr(png_ptr);
 
54
  if (jmpbuf_ptr == NULL) {         /* we are completely hosed now */
 
55
    fprintf(stderr,
 
56
      "gd-png:  EXTREMELY fatal error: jmpbuf unrecoverable; terminating.\n");
 
57
    fflush(stderr);
 
58
    exit(99);
 
59
  }
 
60
 
 
61
  longjmp(jmpbuf_ptr->jmpbuf, 1);
 
62
}
 
63
 
 
64
 
 
65
static void gdPngReadData(png_structp png_ptr,
 
66
        png_bytep data, png_size_t length)
 
67
{
 
68
        gdGetBuf(data, length, (gdIOCtx *)
 
69
                png_get_io_ptr(png_ptr));
 
70
}
 
71
 
 
72
static void gdPngWriteData(png_structp png_ptr,
 
73
        png_bytep data, png_size_t length)
 
74
{
 
75
        gdPutBuf(data, length, (gdIOCtx *)
 
76
                png_get_io_ptr(png_ptr));
 
77
}
 
78
 
 
79
static void gdPngFlushData(png_structp png_ptr)
 
80
{
 
81
}
 
82
 
 
83
gdImagePtr gdImageCreateFromPng(FILE *inFile)
 
84
{
 
85
        gdImagePtr im;
 
86
        gdIOCtx *in = gdNewFileCtx(inFile);
 
87
        im = gdImageCreateFromPngCtx(in);
 
88
        in->free(in);
 
89
        return im;
 
90
}
 
91
 
 
92
 
 
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).
 
95
 */
 
96
gdImagePtr gdImageCreateFromPngCtx(gdIOCtx *infile)
 
97
{
 
98
    png_byte sig[8];
 
99
    png_structp png_ptr;
 
100
    png_infop info_ptr;
 
101
    png_uint_32 width, height, rowbytes;
 
102
    int bit_depth, color_type, interlace_type;
 
103
    int num_palette, num_trans;
 
104
    png_colorp palette;
 
105
    png_color_16p trans_gray_rgb;
 
106
    png_bytep trans;
 
107
    png_bytep image_data = NULL;
 
108
    png_bytepp row_pointers = NULL;
 
109
    gdImagePtr im = NULL;
 
110
    int i, j, *open;
 
111
    volatile int transparent = -1;
 
112
    volatile int palette_allocated = FALSE;
 
113
 
 
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));
 
117
 
 
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 */
 
123
 
 
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");
 
128
        return NULL;
 
129
    }
 
130
 
 
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);
 
135
        return NULL;
 
136
    }
 
137
 
 
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) */
 
141
 
 
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);
 
147
        return NULL;
 
148
    }
 
149
 
 
150
    png_set_sig_bytes(png_ptr, 8);  /* we already read the 8 signature bytes */
 
151
 
 
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 */
 
154
 
 
155
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
 
156
      &interlace_type, NULL, NULL);
 
157
 
 
158
    if (bit_depth == 16)
 
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 */
 
162
 
 
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);
 
166
    }
 
167
 
 
168
    switch (color_type) {
 
169
        case PNG_COLOR_TYPE_PALETTE:
 
170
            png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
 
171
#ifdef DEBUG
 
172
            fprintf(stderr, "gd-png color_type is palette, colors: %d\n",
 
173
                num_palette);
 
174
#endif /* DEBUG */
 
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;
 
178
 
 
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) {
 
182
                        ++real_num_trans;
 
183
                        if (idx_first_trans < 0)
 
184
                            idx_first_trans = i;
 
185
                        if (trans[i] < min_trans) {
 
186
                            min_trans = trans[i];
 
187
                            idx_min_trans = i;
 
188
                        }
 
189
                    }
 
190
                }
 
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;
 
196
                    } else {
 
197
                        transparent = idx_first_trans;
 
198
                    }
 
199
                }
 
200
            }
 
201
            break;
 
202
 
 
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);
 
209
                return NULL;
 
210
            }
 
211
            palette_allocated = TRUE;
 
212
            if (bit_depth < 8)
 
213
            {
 
214
              num_palette = 1<<bit_depth;
 
215
              for (i = 0;  i < 256;  ++i)
 
216
              {
 
217
                j = (255*i)/(num_palette-1);
 
218
                palette[i].red = palette[i].green = palette[i].blue = j;
 
219
              }
 
220
            }
 
221
            else
 
222
            {
 
223
            num_palette = 256;
 
224
              for (i = 0;  i < 256;  ++i)
 
225
              {
 
226
                palette[i].red = palette[i].green = palette[i].blue = i;
 
227
              }
 
228
            }
 
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;
 
233
                else
 
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.) */
 
245
            }
 
246
            break;
 
247
 
 
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);
 
254
                return NULL;
 
255
            }
 
256
            palette_allocated = TRUE;
 
257
            num_palette = 256;
 
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;
 
264
                } else {
 
265
                    palette[0].red   = trans_gray_rgb->red;
 
266
                    palette[0].green = trans_gray_rgb->green;
 
267
                    palette[0].blue  = trans_gray_rgb->blue;
 
268
                }
 
269
                transparent = 0;
 
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... */
 
276
            } else {
 
277
                palette[0].red = palette[0].green = palette[0].blue = 224;
 
278
            }
 
279
 
 
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;
 
283
 
 
284
                png_get_hIST(png_ptr, info_ptr, &histogram);
 
285
                png_set_dither(png_ptr, palette, num_palette,
 
286
                  max_screen_colors, histogram, 1);
 
287
            } else
 
288
#endif
 
289
            {
 
290
                int idx, red, green, blue;
 
291
 
 
292
#ifdef PALETTE_6x7x6
 
293
                /* allocate a 6x7x6 color cube, starting at index 4 */
 
294
                idx = 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;
 
302
                            ++idx;
 
303
                        }
 
304
                    }
 
305
                }
 
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);
 
312
#else
 
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;
 
321
                            ++idx;
 
322
                        }
 
323
                    }
 
324
                }
 
325
                png_set_dither(png_ptr, palette, idx, idx, NULL, 1);
 
326
#endif
 
327
            }
 
328
            break;
 
329
    }
 
330
 
 
331
    png_read_update_info(png_ptr, info_ptr);
 
332
 
 
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);
 
338
        return NULL;
 
339
    }
 
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);
 
343
        free(image_data);
 
344
        return NULL;
 
345
    }
 
346
 
 
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;
 
350
    }
 
351
 
 
352
    png_read_image(png_ptr, row_pointers);   /* read whole image... */
 
353
    png_read_end(png_ptr, NULL);             /* ...done! */
 
354
 
 
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);
 
358
        free(image_data);
 
359
        free(row_pointers);
 
360
        return NULL;
 
361
    }
 
362
 
 
363
    im->colorsTotal = num_palette;
 
364
    im->transparent = transparent;
 
365
    im->interlace = (interlace_type == PNG_INTERLACE_ADAM7);
 
366
 
 
367
    /* load the palette and mark all entries "open" (unused) for now */
 
368
    open = im->open;
 
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;
 
373
        open[i] = 1;
 
374
    }
 
375
    for (i = num_palette;  i < gdMaxColors;  ++i) {
 
376
        open[i] = 1;
 
377
    }
 
378
 
 
379
    /* can't nuke structs until done with palette */
 
380
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
 
381
 
 
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];
 
386
 
 
387
            im->pixels[j][i] = idx;
 
388
            open[idx] = 0;
 
389
        }
 
390
    }
 
391
 
 
392
#ifdef DEBUG
 
393
    for (i = num_palette;  i < gdMaxColors;  ++i) {
 
394
        if (!open[i]) {
 
395
            fprintf(stderr, "gd-png warning: image data references out-of-range"
 
396
              " color index (%d)\n", i);
 
397
        }
 
398
    }
 
399
#endif
 
400
 
 
401
    if (palette_allocated)
 
402
        free(palette);
 
403
    free(image_data);
 
404
    free(row_pointers);
 
405
 
 
406
    return im;
 
407
}
 
408
 
 
409
 
 
410
void gdImagePng(gdImagePtr im, FILE *outFile)
 
411
{
 
412
        gdIOCtx *out = gdNewFileCtx(outFile);
 
413
        gdImagePngCtx(im, out);
 
414
        out->free(out);
 
415
}
 
416
 
 
417
void* gdImagePngPtr(gdImagePtr im, int *size)
 
418
{
 
419
        void *rv;
 
420
        gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
 
421
        gdImagePngCtx(im, out);
 
422
        rv = gdDPExtractData(out, size);
 
423
        out->free(out);
 
424
        return rv;
 
425
}
 
426
 
 
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).
 
430
 */
 
431
void gdImagePngCtx(gdImagePtr im, gdIOCtx *outfile)
 
432
{
 
433
    int i, j, bit_depth, interlace_type;
 
434
    int width = im->sx;
 
435
    int height = im->sy;
 
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];
 
441
    png_structp png_ptr;
 
442
    png_infop info_ptr;
 
443
    volatile int transparent = im->transparent;
 
444
    volatile int remap = FALSE;
 
445
 
 
446
 
 
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");
 
451
        return;
 
452
    }
 
453
 
 
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);
 
458
        return;
 
459
    }
 
460
 
 
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);
 
464
        return;
 
465
    }
 
466
 
 
467
    png_set_write_fn(png_ptr, (void *)outfile, gdPngWriteData, gdPngFlushData);
 
468
 
 
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);  */
 
473
 
 
474
    /* may want to force maximum compression, but time penalty is large */
 
475
/*  png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);  */
 
476
 
 
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);  */
 
480
 
 
481
    if (transparent >= im->colorsTotal ||
 
482
       (transparent >= 0 && open[transparent])) 
 
483
        transparent = -1;
 
484
 
 
485
    for (i = 0;  i < gdMaxColors;  ++i)
 
486
        mapping[i] = -1;
 
487
 
 
488
    /* count actual number of colors used (colorsTotal == high-water mark) */
 
489
    colors = 0;
 
490
    for (i = 0;  i < im->colorsTotal;  ++i) {
 
491
        if (!open[i]) {
 
492
            mapping[i] = colors;
 
493
            ++colors;
 
494
        }
 
495
    }
 
496
    if (colors < im->colorsTotal) {
 
497
        remap = TRUE;
 
498
        if (transparent >= 0)
 
499
            transparent = mapping[transparent];
 
500
    }
 
501
 
 
502
    if (colors <= 2)
 
503
        bit_depth = 1;
 
504
    else if (colors <= 4)
 
505
        bit_depth = 2;
 
506
    else if (colors <= 16)
 
507
        bit_depth = 4;
 
508
    else
 
509
        bit_depth = 8;
 
510
 
 
511
    interlace_type = im->interlace? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
 
512
 
 
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);
 
516
 
 
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 */
 
522
                remap = TRUE;
 
523
                for (i = 0;  i < colors;  ++i)
 
524
                    mapping[i] = i;
 
525
            }
 
526
            mapping[transparent] = 0;
 
527
            mapping[0] = transparent;
 
528
        }
 
529
        png_set_tRNS(png_ptr, info_ptr, &trans_value, 1, NULL);
 
530
    }
 
531
 
 
532
    /* convert GIF palette to libpng layout */
 
533
    if (remap)
 
534
        for (i = 0;  i < im->colorsTotal;  ++i) {
 
535
            if (mapping[i] < 0)
 
536
                continue;
 
537
            palette[mapping[i]].red   = im->red[i];
 
538
            palette[mapping[i]].green = im->green[i];
 
539
            palette[mapping[i]].blue  = im->blue[i];
 
540
        }
 
541
    else
 
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];
 
546
        }
 
547
    png_set_PLTE(png_ptr, info_ptr, palette, colors);
 
548
 
 
549
 
 
550
    /* write out the PNG header info (everything up to first IDAT) */
 
551
    png_write_info(png_ptr, info_ptr);
 
552
 
 
553
    /* make sure < 8-bit images are packed into pixels as tightly as possible */
 
554
    png_set_packing(png_ptr);
 
555
 
 
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. */
 
562
    if (remap) {
 
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");
 
567
        }
 
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]);
 
573
                return;
 
574
            }
 
575
            for (i = 0;  i < width;  ++i)
 
576
                row_pointers[j][i] = mapping[im->pixels[j][i]];
 
577
        }
 
578
 
 
579
        png_write_image(png_ptr, row_pointers);
 
580
        png_write_end(png_ptr, info_ptr);
 
581
 
 
582
        for (j = 0;  j < height;  ++j)
 
583
            free(row_pointers[j]);
 
584
        free(row_pointers);
 
585
    } else {
 
586
        png_write_image(png_ptr, im->pixels);
 
587
        png_write_end(png_ptr, info_ptr);
 
588
    }
 
589
    /* 1.6.3: maybe we should give that memory BACK! TBB */
 
590
        png_destroy_write_struct(&png_ptr, &info_ptr);
 
591
}
 
592
 
 
593