|
Packit |
ed3af9 |
/* $Id$ */
|
|
Packit |
ed3af9 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
ed3af9 |
#include "config.h"
|
|
Packit |
ed3af9 |
#endif
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
#include <stdio.h>
|
|
Packit |
ed3af9 |
#include <math.h>
|
|
Packit |
ed3af9 |
#include <string.h>
|
|
Packit |
ed3af9 |
#include <stdlib.h>
|
|
Packit |
ed3af9 |
#include "gd.h"
|
|
Packit |
ed3af9 |
#include "gd_errors.h"
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* JCE: Arrange HAVE_LIBPNG so that it can be set in gd.h */
|
|
Packit |
ed3af9 |
#ifdef HAVE_LIBPNG
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
#include "gdhelpers.h"
|
|
Packit |
ed3af9 |
#include "png.h" /* includes zlib.h and setjmp.h */
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
#define TRUE 1
|
|
Packit |
ed3af9 |
#define FALSE 0
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/*---------------------------------------------------------------------------
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
gd_png.c Copyright 1999 Greg Roelofs and Thomas Boutell
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
The routines in this file, gdImagePng*() and gdImageCreateFromPng*(),
|
|
Packit |
ed3af9 |
are drop-in replacements for gdImageGif*() and gdImageCreateFromGif*(),
|
|
Packit |
ed3af9 |
except that these functions are noisier in the case of errors (comment
|
|
Packit |
ed3af9 |
out all fprintf() statements to disable that).
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
GD 2.0 supports RGBA truecolor and will read and write truecolor PNGs.
|
|
Packit |
ed3af9 |
GD 2.0 supports 8 bits of color resolution per channel and
|
|
Packit |
ed3af9 |
7 bits of alpha channel resolution. Images with more than 8 bits
|
|
Packit |
ed3af9 |
per channel are reduced to 8 bits. Images with an alpha channel are
|
|
Packit |
ed3af9 |
only able to resolve down to '1/128th opaque' instead of '1/256th',
|
|
Packit |
ed3af9 |
and this conversion is also automatic. I very much doubt you can see it.
|
|
Packit |
ed3af9 |
Both tRNS and true alpha are supported.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Gamma is ignored, and there is no support for text annotations.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Last updated: 9 February 2001
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
---------------------------------------------------------------------------*/
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/**
|
|
Packit |
ed3af9 |
* File: PNG IO
|
|
Packit |
ed3af9 |
*
|
|
Packit |
ed3af9 |
* Read and write PNG images.
|
|
Packit |
ed3af9 |
*/
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
#ifdef PNG_SETJMP_SUPPORTED
|
|
Packit |
ed3af9 |
typedef struct _jmpbuf_wrapper {
|
|
Packit |
ed3af9 |
jmp_buf jmpbuf;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
jmpbuf_wrapper;
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
static void
|
|
Packit |
ed3af9 |
gdPngErrorHandler (png_structp png_ptr, png_const_charp msg)
|
|
Packit |
ed3af9 |
{
|
|
Packit |
ed3af9 |
jmpbuf_wrapper *jmpbuf_ptr;
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* This function, aside from the extra step of retrieving the "error
|
|
Packit |
ed3af9 |
* pointer" (below) and the fact that it exists within the application
|
|
Packit |
ed3af9 |
* rather than within libpng, is essentially identical to libpng's
|
|
Packit |
ed3af9 |
* default error handler. The second point is critical: since both
|
|
Packit |
ed3af9 |
* setjmp() and longjmp() are called from the same code, they are
|
|
Packit |
ed3af9 |
* guaranteed to have compatible notions of how big a jmp_buf is,
|
|
Packit |
ed3af9 |
* regardless of whether _BSD_SOURCE or anything else has (or has not)
|
|
Packit |
ed3af9 |
* been defined. */
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
gd_error_ex(GD_WARNING, "gd-png: fatal libpng error: %s\n", msg);
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
jmpbuf_ptr = png_get_error_ptr (png_ptr);
|
|
Packit |
ed3af9 |
if (jmpbuf_ptr == NULL) { /* we are completely hosed now */
|
|
Packit |
ed3af9 |
gd_error_ex(GD_ERROR, "gd-png: EXTREMELY fatal error: jmpbuf unrecoverable; terminating.\n");
|
|
Packit |
ed3af9 |
exit (99);
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
longjmp (jmpbuf_ptr->jmpbuf, 1);
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
#endif
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
static void
|
|
Packit |
ed3af9 |
gdPngReadData (png_structp png_ptr, png_bytep data, png_size_t length)
|
|
Packit |
ed3af9 |
{
|
|
Packit |
ed3af9 |
int check;
|
|
Packit |
ed3af9 |
check = gdGetBuf (data, length, (gdIOCtx *) png_get_io_ptr (png_ptr));
|
|
Packit |
ed3af9 |
if (check != (int)length) {
|
|
Packit |
ed3af9 |
png_error(png_ptr, "Read Error: truncated data");
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
static void
|
|
Packit |
ed3af9 |
gdPngWriteData (png_structp png_ptr, png_bytep data, png_size_t length)
|
|
Packit |
ed3af9 |
{
|
|
Packit |
ed3af9 |
gdPutBuf (data, length, (gdIOCtx *) png_get_io_ptr (png_ptr));
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
static void
|
|
Packit |
ed3af9 |
gdPngFlushData (png_structp png_ptr)
|
|
Packit |
ed3af9 |
{
|
|
Packit |
ed3af9 |
(void)png_ptr;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/*
|
|
Packit |
ed3af9 |
Function: gdImageCreateFromPng
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
<gdImageCreateFromPng> is called to load images from PNG format
|
|
Packit |
ed3af9 |
files. Invoke <gdImageCreateFromPng> with an already opened
|
|
Packit |
ed3af9 |
pointer to a FILE containing the desired
|
|
Packit |
ed3af9 |
image. <gdImageCreateFromPng> returns a <gdImagePtr> to the new
|
|
Packit |
ed3af9 |
image, or NULL if unable to load the image (most often because the
|
|
Packit |
ed3af9 |
file is corrupt or does not contain a PNG
|
|
Packit |
ed3af9 |
image). <gdImageCreateFromPng> does not close the file. You can
|
|
Packit |
ed3af9 |
inspect the sx and sy members of the image to determine its
|
|
Packit |
ed3af9 |
size. The image must eventually be destroyed using
|
|
Packit |
ed3af9 |
gdImageDestroy().
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
If the PNG image being loaded is a truecolor image, the resulting
|
|
Packit |
ed3af9 |
gdImagePtr will refer to a truecolor image. If the PNG image being
|
|
Packit |
ed3af9 |
loaded is a palette or grayscale image, the resulting gdImagePtr
|
|
Packit |
ed3af9 |
will refer to a palette image. gd retains only 8 bits of
|
|
Packit |
ed3af9 |
resolution for each of the red, green and blue channels, and only
|
|
Packit |
ed3af9 |
7 bits of resolution for the alpha channel. The former restriction
|
|
Packit |
ed3af9 |
affects only a handful of very rare 48-bit color and 16-bit
|
|
Packit |
ed3af9 |
grayscale PNG images. The second restriction affects all
|
|
Packit |
ed3af9 |
semitransparent PNG images, but the difference is essentially
|
|
Packit |
ed3af9 |
invisible to the eye. 7 bits of alpha channel resolution is, in
|
|
Packit |
ed3af9 |
practice, quite a lot.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Variants:
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
<gdImageCreateFromPngPtr> creates an image from PNG data (i.e. the
|
|
Packit |
ed3af9 |
contents of a PNG file) already in memory.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
<gdImageCreateFromPngCtx> reads in an image using the functions in
|
|
Packit |
ed3af9 |
a <gdIOCtx> struct.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
<gdImageCreateFromPngSource> is similar to
|
|
Packit |
ed3af9 |
<gdImageCreateFromPngCtx> but uses the old <gdSource> interface.
|
|
Packit |
ed3af9 |
It is *obsolete*.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Parameters:
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
infile - The input FILE pointer.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Returns:
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
A pointer to the new image or NULL if an error occurred.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Example:
|
|
Packit |
ed3af9 |
(start code)
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
gdImagePtr im;
|
|
Packit |
ed3af9 |
... inside a function ...
|
|
Packit |
ed3af9 |
FILE *in;
|
|
Packit |
ed3af9 |
in = fopen("mypng.png", "rb");
|
|
Packit |
ed3af9 |
im = gdImageCreateFromPng(in);
|
|
Packit |
ed3af9 |
fclose(in);
|
|
Packit |
ed3af9 |
// ... Use the image ...
|
|
Packit |
ed3af9 |
gdImageDestroy(im);
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
(end code)
|
|
Packit |
ed3af9 |
*/
|
|
Packit |
ed3af9 |
BGD_DECLARE(gdImagePtr) gdImageCreateFromPng (FILE * inFile)
|
|
Packit |
ed3af9 |
{
|
|
Packit |
ed3af9 |
gdImagePtr im;
|
|
Packit |
ed3af9 |
gdIOCtx *in = gdNewFileCtx (inFile);
|
|
Packit |
ed3af9 |
if (in == NULL) return NULL;
|
|
Packit |
ed3af9 |
im = gdImageCreateFromPngCtx (in);
|
|
Packit |
ed3af9 |
in->gd_free (in);
|
|
Packit |
ed3af9 |
return im;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/*
|
|
Packit |
ed3af9 |
Function: gdImageCreateFromPngPtr
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
See <gdImageCreateFromPng>.
|
|
Packit |
ed3af9 |
*/
|
|
Packit |
ed3af9 |
BGD_DECLARE(gdImagePtr) gdImageCreateFromPngPtr (int size, void *data)
|
|
Packit |
ed3af9 |
{
|
|
Packit |
ed3af9 |
gdImagePtr im;
|
|
Packit |
ed3af9 |
gdIOCtx *in = gdNewDynamicCtxEx (size, data, 0);
|
|
Packit |
ed3af9 |
if(!in)
|
|
Packit |
ed3af9 |
return 0;
|
|
Packit |
ed3af9 |
im = gdImageCreateFromPngCtx (in);
|
|
Packit |
ed3af9 |
in->gd_free (in);
|
|
Packit |
ed3af9 |
return im;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* This routine is based in part on the Chapter 13 demo code in
|
|
Packit |
ed3af9 |
* "PNG: The Definitive Guide" (http://www.libpng.org/pub/png/book/).
|
|
Packit |
ed3af9 |
*/
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/*
|
|
Packit |
ed3af9 |
Function: gdImageCreateFromPngCtx
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
See <gdImageCreateFromPng>.
|
|
Packit |
ed3af9 |
*/
|
|
Packit |
ed3af9 |
BGD_DECLARE(gdImagePtr) gdImageCreateFromPngCtx (gdIOCtx * infile)
|
|
Packit |
ed3af9 |
{
|
|
Packit |
ed3af9 |
png_byte sig[8];
|
|
Packit |
ed3af9 |
#ifdef PNG_SETJMP_SUPPORTED
|
|
Packit |
ed3af9 |
jmpbuf_wrapper jbw;
|
|
Packit |
ed3af9 |
#endif
|
|
Packit |
ed3af9 |
png_structp png_ptr;
|
|
Packit |
ed3af9 |
png_infop info_ptr;
|
|
Packit |
ed3af9 |
png_uint_32 width, height, rowbytes, w, h, res_x, res_y;
|
|
Packit |
ed3af9 |
int bit_depth, color_type, interlace_type, unit_type;
|
|
Packit |
ed3af9 |
int num_palette = 0, num_trans;
|
|
Packit |
ed3af9 |
png_colorp palette;
|
|
Packit |
ed3af9 |
png_color_16p trans_gray_rgb;
|
|
Packit |
ed3af9 |
png_color_16p trans_color_rgb;
|
|
Packit |
ed3af9 |
png_bytep trans;
|
|
Packit |
ed3af9 |
png_bytep image_data = NULL;
|
|
Packit |
ed3af9 |
png_bytepp row_pointers = NULL;
|
|
Packit |
ed3af9 |
gdImagePtr im = NULL;
|
|
Packit |
ed3af9 |
int i, j, *open = NULL;
|
|
Packit |
ed3af9 |
volatile int transparent = -1;
|
|
Packit |
ed3af9 |
volatile int palette_allocated = FALSE;
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* Make sure the signature can't match by dumb luck -- TBB */
|
|
Packit |
ed3af9 |
/* GRR: isn't sizeof(infile) equal to the size of the pointer? */
|
|
Packit |
ed3af9 |
memset (sig, 0, sizeof (sig));
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* first do a quick check that the file really is a PNG image; could
|
|
Packit |
ed3af9 |
* have used slightly more general png_sig_cmp() function instead */
|
|
Packit |
ed3af9 |
if (gdGetBuf (sig, 8, infile) < 8) {
|
|
Packit |
ed3af9 |
return NULL;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
if (png_sig_cmp(sig, 0, 8) != 0) { /* bad signature */
|
|
Packit |
ed3af9 |
return NULL; /* bad signature */
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
#ifdef PNG_SETJMP_SUPPORTED
|
|
Packit |
ed3af9 |
png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, &jbw, gdPngErrorHandler, NULL);
|
|
Packit |
ed3af9 |
#else
|
|
Packit |
ed3af9 |
png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
|
Packit |
ed3af9 |
#endif
|
|
Packit |
ed3af9 |
if (png_ptr == NULL) {
|
|
Packit |
ed3af9 |
gd_error("gd-png error: cannot allocate libpng main struct\n");
|
|
Packit |
ed3af9 |
return NULL;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
info_ptr = png_create_info_struct (png_ptr);
|
|
Packit |
ed3af9 |
if (info_ptr == NULL) {
|
|
Packit |
ed3af9 |
gd_error("gd-png error: cannot allocate libpng info struct\n");
|
|
Packit |
ed3af9 |
png_destroy_read_struct (&png_ptr, NULL, NULL);
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
return NULL;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* we could create a second info struct here (end_info), but it's only
|
|
Packit |
ed3af9 |
* useful if we want to keep pre- and post-IDAT chunk info separated
|
|
Packit |
ed3af9 |
* (mainly for PNG-aware image editors and converters)
|
|
Packit |
ed3af9 |
*/
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* setjmp() must be called in every non-callback function that calls a
|
|
Packit |
ed3af9 |
* PNG-reading libpng function. We must reset it everytime we get a
|
|
Packit |
ed3af9 |
* new allocation that we save in a stack variable.
|
|
Packit |
ed3af9 |
*/
|
|
Packit |
ed3af9 |
#ifdef PNG_SETJMP_SUPPORTED
|
|
Packit |
ed3af9 |
if (setjmp(jbw.jmpbuf)) {
|
|
Packit |
ed3af9 |
gd_error("gd-png error: setjmp returns error condition 1\n");
|
|
Packit |
ed3af9 |
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
return NULL;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
#endif
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
png_set_sig_bytes (png_ptr, 8); /* we already read the 8 signature bytes */
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
png_set_read_fn (png_ptr, (void *) infile, gdPngReadData);
|
|
Packit |
ed3af9 |
png_read_info (png_ptr, info_ptr); /* read all PNG info up to image data */
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
|
|
Packit |
ed3af9 |
if ((color_type == PNG_COLOR_TYPE_RGB) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
|
|
Packit |
ed3af9 |
|| color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
|
|
Packit |
ed3af9 |
im = gdImageCreateTrueColor ((int) width, (int) height);
|
|
Packit |
ed3af9 |
} else {
|
|
Packit |
ed3af9 |
im = gdImageCreate ((int) width, (int) height);
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
if (im == NULL) {
|
|
Packit |
ed3af9 |
gd_error("gd-png error: cannot allocate gdImage struct\n");
|
|
Packit |
ed3af9 |
goto error;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
if (bit_depth == 16) {
|
|
Packit |
ed3af9 |
png_set_strip_16 (png_ptr);
|
|
Packit |
ed3af9 |
} else if (bit_depth < 8) {
|
|
Packit |
ed3af9 |
png_set_packing (png_ptr); /* expand to 1 byte per pixel */
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* setjmp() must be called in every non-callback function that calls a
|
|
Packit |
ed3af9 |
* PNG-reading libpng function. We must reset it everytime we get a
|
|
Packit |
ed3af9 |
* new allocation that we save in a stack variable.
|
|
Packit |
ed3af9 |
*/
|
|
Packit |
ed3af9 |
#ifdef PNG_SETJMP_SUPPORTED
|
|
Packit |
ed3af9 |
if (setjmp(jbw.jmpbuf)) {
|
|
Packit |
ed3af9 |
gd_error("gd-png error: setjmp returns error condition 2\n");
|
|
Packit |
ed3af9 |
goto error;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
#endif
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
#ifdef PNG_pHYs_SUPPORTED
|
|
Packit |
ed3af9 |
/* check if the resolution is specified */
|
|
Packit |
ed3af9 |
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) {
|
|
Packit |
ed3af9 |
if (png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type)) {
|
|
Packit |
ed3af9 |
switch (unit_type) {
|
|
Packit |
ed3af9 |
case PNG_RESOLUTION_METER:
|
|
Packit |
ed3af9 |
im->res_x = DPM2DPI(res_x);
|
|
Packit |
ed3af9 |
im->res_y = DPM2DPI(res_y);
|
|
Packit |
ed3af9 |
break;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
#endif
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
switch (color_type) {
|
|
Packit |
ed3af9 |
case PNG_COLOR_TYPE_PALETTE:
|
|
Packit |
ed3af9 |
png_get_PLTE (png_ptr, info_ptr, &palette, &num_palette);
|
|
Packit |
ed3af9 |
#ifdef DEBUG
|
|
Packit |
ed3af9 |
gd_error("gd-png color_type is palette, colors: %d\n", num_palette);
|
|
Packit |
ed3af9 |
#endif /* DEBUG */
|
|
Packit |
ed3af9 |
if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) {
|
|
Packit |
ed3af9 |
/* gd 2.0: we support this rather thoroughly now. Grab the
|
|
Packit |
ed3af9 |
* first fully transparent entry, if any, as the value of
|
|
Packit |
ed3af9 |
* the simple-transparency index, mostly for backwards
|
|
Packit |
ed3af9 |
* binary compatibility. The alpha channel is where it's
|
|
Packit |
ed3af9 |
* really at these days.
|
|
Packit |
ed3af9 |
*/
|
|
Packit |
ed3af9 |
int firstZero = 1;
|
|
Packit |
ed3af9 |
png_get_tRNS (png_ptr, info_ptr, &trans, &num_trans, NULL);
|
|
Packit |
ed3af9 |
for (i = 0; i < num_trans; ++i) {
|
|
Packit |
ed3af9 |
im->alpha[i] = gdAlphaMax - (trans[i] >> 1);
|
|
Packit |
ed3af9 |
if ((trans[i] == 0) && (firstZero)) {
|
|
Packit |
ed3af9 |
/* 2.0.5: long-forgotten patch from Wez Furlong */
|
|
Packit |
ed3af9 |
transparent = i;
|
|
Packit |
ed3af9 |
firstZero = 0;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
break;
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
case PNG_COLOR_TYPE_GRAY:
|
|
Packit |
ed3af9 |
/* create a fake palette and check for single-shade transparency */
|
|
Packit |
ed3af9 |
if ((palette = (png_colorp) gdMalloc (256 * sizeof (png_color))) == NULL) {
|
|
Packit |
ed3af9 |
gd_error("gd-png error: cannot allocate gray palette\n");
|
|
Packit |
ed3af9 |
goto error;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
palette_allocated = TRUE;
|
|
Packit |
ed3af9 |
if (bit_depth < 8) {
|
|
Packit |
ed3af9 |
num_palette = 1 << bit_depth;
|
|
Packit |
ed3af9 |
for (i = 0; i < 256; ++i) {
|
|
Packit |
ed3af9 |
j = (255 * i) / (num_palette - 1);
|
|
Packit |
ed3af9 |
palette[i].red = palette[i].green = palette[i].blue = j;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
} else {
|
|
Packit |
ed3af9 |
num_palette = 256;
|
|
Packit |
ed3af9 |
for (i = 0; i < 256; ++i) {
|
|
Packit |
ed3af9 |
palette[i].red = palette[i].green = palette[i].blue = i;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) {
|
|
Packit |
ed3af9 |
png_get_tRNS (png_ptr, info_ptr, NULL, NULL, &trans_gray_rgb);
|
|
Packit |
ed3af9 |
if (bit_depth == 16) { /* png_set_strip_16() not yet in effect */
|
|
Packit |
ed3af9 |
transparent = trans_gray_rgb->gray >> 8;
|
|
Packit |
ed3af9 |
} else {
|
|
Packit |
ed3af9 |
transparent = trans_gray_rgb->gray;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
/* Note slight error in 16-bit case: up to 256 16-bit shades
|
|
Packit |
ed3af9 |
* may get mapped to a single 8-bit shade, and only one of them
|
|
Packit |
ed3af9 |
* is supposed to be transparent. IOW, both opaque pixels and
|
|
Packit |
ed3af9 |
* transparent pixels will be mapped into the transparent entry.
|
|
Packit |
ed3af9 |
* There is no particularly good way around this in the case
|
|
Packit |
ed3af9 |
* that all 256 8-bit shades are used, but one could write some
|
|
Packit |
ed3af9 |
* custom 16-bit code to handle the case where there are gdFree
|
|
Packit |
ed3af9 |
* palette entries. This error will be extremely rare in
|
|
Packit |
ed3af9 |
* general, though. (Quite possibly there is only one such
|
|
Packit |
ed3af9 |
* image in existence.) */
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
break;
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
case PNG_COLOR_TYPE_GRAY_ALPHA:
|
|
Packit |
ed3af9 |
png_set_gray_to_rgb(png_ptr);
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
case PNG_COLOR_TYPE_RGB:
|
|
Packit |
ed3af9 |
case PNG_COLOR_TYPE_RGB_ALPHA:
|
|
Packit |
ed3af9 |
/* gd 2.0: we now support truecolor. See the comment above
|
|
Packit |
ed3af9 |
for a rare situation in which the transparent pixel may not
|
|
Packit |
ed3af9 |
work properly with 16-bit channels. */
|
|
Packit |
ed3af9 |
if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) {
|
|
Packit |
ed3af9 |
png_get_tRNS (png_ptr, info_ptr, NULL, NULL, &trans_color_rgb);
|
|
Packit |
ed3af9 |
if (bit_depth == 16) { /* png_set_strip_16() not yet in effect */
|
|
Packit |
ed3af9 |
transparent = gdTrueColor (trans_color_rgb->red >> 8,
|
|
Packit |
ed3af9 |
trans_color_rgb->green >> 8,
|
|
Packit |
ed3af9 |
trans_color_rgb->blue >> 8);
|
|
Packit |
ed3af9 |
} else {
|
|
Packit |
ed3af9 |
transparent = gdTrueColor (trans_color_rgb->red,
|
|
Packit |
ed3af9 |
trans_color_rgb->green,
|
|
Packit |
ed3af9 |
trans_color_rgb->blue);
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
break;
|
|
Packit |
ed3af9 |
default:
|
|
Packit |
ed3af9 |
gd_error("gd-png color_type is unknown: %d\n", color_type);
|
|
Packit |
ed3af9 |
goto error;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
png_read_update_info (png_ptr, info_ptr);
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* allocate space for the PNG image data */
|
|
Packit |
ed3af9 |
rowbytes = png_get_rowbytes (png_ptr, info_ptr);
|
|
Packit |
ed3af9 |
if (overflow2(rowbytes, height))
|
|
Packit |
ed3af9 |
goto error;
|
|
Packit |
ed3af9 |
image_data = (png_bytep) gdMalloc (rowbytes * height);
|
|
Packit |
ed3af9 |
if (!image_data) {
|
|
Packit |
ed3af9 |
gd_error("gd-png error: cannot allocate image data\n");
|
|
Packit |
ed3af9 |
goto error;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
if (overflow2(height, sizeof (png_bytep)))
|
|
Packit |
ed3af9 |
goto error;
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
row_pointers = (png_bytepp) gdMalloc (height * sizeof (png_bytep));
|
|
Packit |
ed3af9 |
if (!row_pointers) {
|
|
Packit |
ed3af9 |
gd_error("gd-png error: cannot allocate row pointers\n");
|
|
Packit |
ed3af9 |
goto error;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* setjmp() must be called in every non-callback function that calls a
|
|
Packit |
ed3af9 |
* PNG-reading libpng function. We must reset it everytime we get a
|
|
Packit |
ed3af9 |
* new allocation that we save in a stack variable.
|
|
Packit |
ed3af9 |
*/
|
|
Packit |
ed3af9 |
#ifdef PNG_SETJMP_SUPPORTED
|
|
Packit |
ed3af9 |
if (setjmp(jbw.jmpbuf)) {
|
|
Packit |
ed3af9 |
gd_error("gd-png error: setjmp returns error condition 3\n");
|
|
Packit |
ed3af9 |
goto error;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
#endif
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* set the individual row_pointers to point at the correct offsets */
|
|
Packit |
ed3af9 |
for (h = 0; h < height; ++h) {
|
|
Packit |
ed3af9 |
row_pointers[h] = image_data + h * rowbytes;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
png_read_image (png_ptr, row_pointers); /* read whole image... */
|
|
Packit |
ed3af9 |
png_read_end (png_ptr, NULL); /* ...done! */
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
if (!im->trueColor) {
|
|
Packit |
ed3af9 |
im->colorsTotal = num_palette;
|
|
Packit |
ed3af9 |
/* load the palette and mark all entries "open" (unused) for now */
|
|
Packit |
ed3af9 |
open = im->open;
|
|
Packit |
ed3af9 |
for (i = 0; i < num_palette; ++i) {
|
|
Packit |
ed3af9 |
im->red[i] = palette[i].red;
|
|
Packit |
ed3af9 |
im->green[i] = palette[i].green;
|
|
Packit |
ed3af9 |
im->blue[i] = palette[i].blue;
|
|
Packit |
ed3af9 |
open[i] = 1;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
for (i = num_palette; i < gdMaxColors; ++i) {
|
|
Packit |
ed3af9 |
open[i] = 1;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
/* 2.0.12: Slaven Rezic: palette images are not the only images
|
|
Packit |
ed3af9 |
with a simple transparent color setting */
|
|
Packit |
ed3af9 |
im->transparent = transparent;
|
|
Packit |
ed3af9 |
im->interlace = (interlace_type == PNG_INTERLACE_ADAM7);
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* can't nuke structs until done with palette */
|
|
Packit |
ed3af9 |
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
|
|
Packit |
ed3af9 |
switch (color_type) {
|
|
Packit |
ed3af9 |
case PNG_COLOR_TYPE_RGB:
|
|
Packit |
ed3af9 |
for (h = 0; h < height; h++) {
|
|
Packit |
ed3af9 |
int boffset = 0;
|
|
Packit |
ed3af9 |
for (w = 0; w < width; w++) {
|
|
Packit |
ed3af9 |
register png_byte r = row_pointers[h][boffset++];
|
|
Packit |
ed3af9 |
register png_byte g = row_pointers[h][boffset++];
|
|
Packit |
ed3af9 |
register png_byte b = row_pointers[h][boffset++];
|
|
Packit |
ed3af9 |
im->tpixels[h][w] = gdTrueColor (r, g, b);
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
break;
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
case PNG_COLOR_TYPE_GRAY_ALPHA:
|
|
Packit |
ed3af9 |
case PNG_COLOR_TYPE_RGB_ALPHA:
|
|
Packit |
ed3af9 |
for (h = 0; h < height; h++) {
|
|
Packit |
ed3af9 |
int boffset = 0;
|
|
Packit |
ed3af9 |
for (w = 0; w < width; w++) {
|
|
Packit |
ed3af9 |
register png_byte r = row_pointers[h][boffset++];
|
|
Packit |
ed3af9 |
register png_byte g = row_pointers[h][boffset++];
|
|
Packit |
ed3af9 |
register png_byte b = row_pointers[h][boffset++];
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* gd has only 7 bits of alpha channel resolution, and
|
|
Packit |
ed3af9 |
* 127 is transparent, 0 opaque. A moment of convenience,
|
|
Packit |
ed3af9 |
* a lifetime of compatibility.
|
|
Packit |
ed3af9 |
*/
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
register png_byte a = gdAlphaMax - (row_pointers[h][boffset++] >> 1);
|
|
Packit |
ed3af9 |
im->tpixels[h][w] = gdTrueColorAlpha(r, g, b, a);
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
break;
|
|
Packit |
ed3af9 |
default:
|
|
Packit |
ed3af9 |
if (!im->trueColor) {
|
|
Packit |
ed3af9 |
/* Palette image, or something coerced to be one */
|
|
Packit |
ed3af9 |
for (h = 0; h < height; ++h) {
|
|
Packit |
ed3af9 |
for (w = 0; w < width; ++w) {
|
|
Packit |
ed3af9 |
register png_byte idx = row_pointers[h][w];
|
|
Packit |
ed3af9 |
im->pixels[h][w] = idx;
|
|
Packit |
ed3af9 |
open[idx] = 0;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
#ifdef DEBUG
|
|
Packit |
ed3af9 |
if (!im->trueColor) {
|
|
Packit |
ed3af9 |
for (i = num_palette; i < gdMaxColors; ++i) {
|
|
Packit |
ed3af9 |
if (!open[i]) {
|
|
Packit |
ed3af9 |
fprintf (stderr,
|
|
Packit |
ed3af9 |
"gd-png warning: image data references out-of-range"
|
|
Packit |
ed3af9 |
" color index (%d)\n", i);
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
#endif
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
done:
|
|
Packit |
ed3af9 |
if (palette_allocated) {
|
|
Packit |
ed3af9 |
gdFree (palette);
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
if (image_data)
|
|
Packit |
ed3af9 |
gdFree(image_data);
|
|
Packit |
ed3af9 |
if (row_pointers)
|
|
Packit |
ed3af9 |
gdFree(row_pointers);
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
return im;
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
error:
|
|
Packit |
ed3af9 |
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
|
Packit |
ed3af9 |
if (im) {
|
|
Packit |
ed3af9 |
gdImageDestroy(im);
|
|
Packit |
ed3af9 |
im = NULL;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
goto done;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/*
|
|
Packit |
ed3af9 |
Function: gdImagePngEx
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
<gdImagePngEx> outputs the specified image to the specified file in
|
|
Packit |
ed3af9 |
PNG format. The file must be open for writing. Under MSDOS and all
|
|
Packit |
ed3af9 |
versions of Windows, it is important to use "wb" as opposed to
|
|
Packit |
ed3af9 |
simply "w" as the mode when opening the file, and under Unix there
|
|
Packit |
ed3af9 |
is no penalty for doing so. <gdImagePngEx> does not close the file;
|
|
Packit |
ed3af9 |
your code must do so.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
In addition, <gdImagePngEx> allows the level of compression to be
|
|
Packit |
ed3af9 |
specified. A compression level of 0 means "no compression." A
|
|
Packit |
ed3af9 |
compression level of 1 means "compressed, but as quickly as
|
|
Packit |
ed3af9 |
possible." A compression level of 9 means "compressed as much as
|
|
Packit |
ed3af9 |
possible to produce the smallest possible file." A compression level
|
|
Packit |
ed3af9 |
of -1 will use the default compression level at the time zlib was
|
|
Packit |
ed3af9 |
compiled on your system.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Variants:
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
<gdImagePng> is equivalent to calling <gdImagePngEx> with
|
|
Packit |
ed3af9 |
compression of -1.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
<gdImagePngCtx> and <gdImagePngCtxEx> write via a <gdIOCtx>
|
|
Packit |
ed3af9 |
instead of a file handle.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
<gdImagePngPtr> and <gdImagePngPtrEx> store the image file to
|
|
Packit |
ed3af9 |
memory.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Parameters:
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
im - the image to write
|
|
Packit |
ed3af9 |
outFile - the output FILE* object.
|
|
Packit |
ed3af9 |
level - compression level: 0 -> none, 1-9 -> level, -1 -> default
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Returns:
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Nothing.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Example:
|
|
Packit |
ed3af9 |
(start code)
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
gdImagePtr im;
|
|
Packit |
ed3af9 |
int black, white;
|
|
Packit |
ed3af9 |
FILE *out;
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
im = gdImageCreate(100, 100); // Create the image
|
|
Packit |
ed3af9 |
white = gdImageColorAllocate(im, 255, 255, 255); // Alloc background
|
|
Packit |
ed3af9 |
black = gdImageColorAllocate(im, 0, 0, 0); // Allocate drawing color
|
|
Packit |
ed3af9 |
gdImageRectangle(im, 0, 0, 99, 99, black); // Draw rectangle
|
|
Packit |
ed3af9 |
out = fopen("rect.png", "wb"); // Open output file (binary)
|
|
Packit |
ed3af9 |
gdImagePngEx(im, out, 9); // Write PNG, max compression
|
|
Packit |
ed3af9 |
fclose(out); // Close file
|
|
Packit |
ed3af9 |
gdImageDestroy(im); // Destroy image
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
(end code)
|
|
Packit |
ed3af9 |
*/
|
|
Packit |
ed3af9 |
BGD_DECLARE(void) gdImagePngEx (gdImagePtr im, FILE * outFile, int level)
|
|
Packit |
ed3af9 |
{
|
|
Packit |
ed3af9 |
gdIOCtx *out = gdNewFileCtx (outFile);
|
|
Packit |
ed3af9 |
if (out == NULL) return;
|
|
Packit |
ed3af9 |
gdImagePngCtxEx (im, out, level);
|
|
Packit |
ed3af9 |
out->gd_free (out);
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/*
|
|
Packit |
ed3af9 |
Function: gdImagePng
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Equivalent to calling <gdImagePngEx> with compression of -1.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Parameters:
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
im - the image to save.
|
|
Packit |
ed3af9 |
outFile - the output FILE*.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Returns:
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Nothing.
|
|
Packit |
ed3af9 |
*/
|
|
Packit |
ed3af9 |
BGD_DECLARE(void) gdImagePng (gdImagePtr im, FILE * outFile)
|
|
Packit |
ed3af9 |
{
|
|
Packit |
ed3af9 |
gdIOCtx *out = gdNewFileCtx (outFile);
|
|
Packit |
ed3af9 |
if (out == NULL) return;
|
|
Packit |
ed3af9 |
gdImagePngCtxEx (im, out, -1);
|
|
Packit |
ed3af9 |
out->gd_free (out);
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
static int _gdImagePngCtxEx(gdImagePtr im, gdIOCtx * outfile, int level);
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/*
|
|
Packit |
ed3af9 |
Function: gdImagePngPtr
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Equivalent to calling <gdImagePngPtrEx> with compression of -1.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
See <gdImagePngEx> for more information.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Parameters:
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
im - the image to save.
|
|
Packit |
ed3af9 |
size - Output: size in bytes of the result.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Returns:
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
A pointer to memory containing the image data or NULL on error.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
*/
|
|
Packit |
ed3af9 |
BGD_DECLARE(void *) gdImagePngPtr (gdImagePtr im, int *size)
|
|
Packit |
ed3af9 |
{
|
|
Packit |
ed3af9 |
void *rv;
|
|
Packit |
ed3af9 |
gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
|
|
Packit |
ed3af9 |
if (out == NULL) return NULL;
|
|
Packit |
ed3af9 |
if (!_gdImagePngCtxEx (im, out, -1)) {
|
|
Packit |
ed3af9 |
rv = gdDPExtractData (out, size);
|
|
Packit |
ed3af9 |
} else {
|
|
Packit |
ed3af9 |
rv = NULL;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
out->gd_free (out);
|
|
Packit |
ed3af9 |
return rv;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/*
|
|
Packit |
ed3af9 |
Function: gdImagePngPtrEx
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Identical to <gdImagePngEx> except that it returns a pointer to a
|
|
Packit |
ed3af9 |
memory area with the PNG data. This memory must be freed by the
|
|
Packit |
ed3af9 |
caller when it is no longer needed. **The caller must invoke
|
|
Packit |
ed3af9 |
gdFree(), not free()**
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
The 'size' parameter receives the total size of the block of
|
|
Packit |
ed3af9 |
memory.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
See <gdImagePngEx> for more information.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Parameters:
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
im - the image to save.
|
|
Packit |
ed3af9 |
size - Output: size in bytes of the result.
|
|
Packit |
ed3af9 |
level - compression level: 0 -> none, 1-9 -> level, -1 -> default
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Returns:
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
A pointer to memory containing the image data or NULL on error.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
*/
|
|
Packit |
ed3af9 |
BGD_DECLARE(void *) gdImagePngPtrEx (gdImagePtr im, int *size, int level)
|
|
Packit |
ed3af9 |
{
|
|
Packit |
ed3af9 |
void *rv;
|
|
Packit |
ed3af9 |
gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
|
|
Packit |
ed3af9 |
if (out == NULL) return NULL;
|
|
Packit |
ed3af9 |
if (!_gdImagePngCtxEx (im, out, level)) {
|
|
Packit |
ed3af9 |
rv = gdDPExtractData (out, size);
|
|
Packit |
ed3af9 |
} else {
|
|
Packit |
ed3af9 |
rv = NULL;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
out->gd_free (out);
|
|
Packit |
ed3af9 |
return rv;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/*
|
|
Packit |
ed3af9 |
Function: gdImagePngCtx
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Equivalent to calling <gdImagePngCtxEx> with compression of -1.
|
|
Packit |
ed3af9 |
See <gdImagePngEx> for more information.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Parameters:
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
im - the image to save.
|
|
Packit |
ed3af9 |
outfile - the <gdIOCtx> to write to.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Returns:
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Nothing.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
*/
|
|
Packit |
ed3af9 |
BGD_DECLARE(void) gdImagePngCtx (gdImagePtr im, gdIOCtx * outfile)
|
|
Packit |
ed3af9 |
{
|
|
Packit |
ed3af9 |
/* 2.0.13: 'return' here was an error, thanks to Kevin Smith */
|
|
Packit |
ed3af9 |
gdImagePngCtxEx (im, outfile, -1);
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/*
|
|
Packit |
ed3af9 |
Function: gdImagePngCtxEx
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Outputs the given image as PNG data, but using a <gdIOCtx> instead
|
|
Packit |
ed3af9 |
of a file. See <gdIamgePnEx>.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Parameters:
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
im - the image to save.
|
|
Packit |
ed3af9 |
outfile - the <gdIOCtx> to write to.
|
|
Packit |
ed3af9 |
level - compression level: 0 -> none, 1-9 -> level, -1 -> default
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Returns:
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
Nothing.
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
*/
|
|
Packit |
ed3af9 |
BGD_DECLARE(void) gdImagePngCtxEx (gdImagePtr im, gdIOCtx * outfile, int level)
|
|
Packit |
ed3af9 |
{
|
|
Packit |
ed3af9 |
_gdImagePngCtxEx(im, outfile, level);
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* This routine is based in part on code from Dale Lutz (Safe Software Inc.)
|
|
Packit |
ed3af9 |
* and in part on demo code from Chapter 15 of "PNG: The Definitive Guide"
|
|
Packit |
ed3af9 |
* (http://www.libpng.org/pub/png/book/).
|
|
Packit |
ed3af9 |
*/
|
|
Packit |
ed3af9 |
/* returns 0 on success, 1 on failure */
|
|
Packit |
ed3af9 |
static int _gdImagePngCtxEx(gdImagePtr im, gdIOCtx * outfile, int level)
|
|
Packit |
ed3af9 |
{
|
|
Packit |
ed3af9 |
int i, j, bit_depth = 0, interlace_type;
|
|
Packit |
ed3af9 |
int width = im->sx;
|
|
Packit |
ed3af9 |
int height = im->sy;
|
|
Packit |
ed3af9 |
int colors = im->colorsTotal;
|
|
Packit |
ed3af9 |
int *open = im->open;
|
|
Packit |
ed3af9 |
int mapping[gdMaxColors]; /* mapping[gd_index] == png_index */
|
|
Packit |
ed3af9 |
png_byte trans_values[256];
|
|
Packit |
ed3af9 |
png_color_16 trans_rgb_value;
|
|
Packit |
ed3af9 |
png_color palette[gdMaxColors];
|
|
Packit |
ed3af9 |
png_structp png_ptr;
|
|
Packit |
ed3af9 |
png_infop info_ptr;
|
|
Packit |
ed3af9 |
volatile int transparent = im->transparent;
|
|
Packit |
ed3af9 |
volatile int remap = FALSE;
|
|
Packit |
ed3af9 |
#ifdef PNG_SETJMP_SUPPORTED
|
|
Packit |
ed3af9 |
jmpbuf_wrapper jbw;
|
|
Packit |
ed3af9 |
#endif
|
|
Packit |
ed3af9 |
int ret = 0;
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* width or height of value 0 is invalid in IHDR;
|
|
Packit |
ed3af9 |
see http://www.w3.org/TR/PNG-Chunks.html */
|
|
Packit |
ed3af9 |
if (width == 0 || height ==0) return 1;
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
#ifdef PNG_SETJMP_SUPPORTED
|
|
Packit |
ed3af9 |
png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
|
|
Packit |
ed3af9 |
&jbw, gdPngErrorHandler,
|
|
Packit |
ed3af9 |
NULL);
|
|
Packit |
ed3af9 |
#else
|
|
Packit |
ed3af9 |
png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
|
Packit |
ed3af9 |
#endif
|
|
Packit |
ed3af9 |
if (png_ptr == NULL) {
|
|
Packit |
ed3af9 |
gd_error("gd-png error: cannot allocate libpng main struct\n");
|
|
Packit |
ed3af9 |
return 1;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
info_ptr = png_create_info_struct (png_ptr);
|
|
Packit |
ed3af9 |
if (info_ptr == NULL) {
|
|
Packit |
ed3af9 |
gd_error("gd-png error: cannot allocate libpng info struct\n");
|
|
Packit |
ed3af9 |
png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
|
|
Packit |
ed3af9 |
return 1;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
#ifdef PNG_SETJMP_SUPPORTED
|
|
Packit |
ed3af9 |
if (setjmp(jbw.jmpbuf)) {
|
|
Packit |
ed3af9 |
gd_error("gd-png error: setjmp returns error condition\n");
|
|
Packit |
ed3af9 |
png_destroy_write_struct (&png_ptr, &info_ptr);
|
|
Packit |
ed3af9 |
return 1;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
#endif
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
png_set_write_fn (png_ptr, (void *) outfile, gdPngWriteData,
|
|
Packit |
ed3af9 |
gdPngFlushData);
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* This is best for palette images, and libpng defaults to it for
|
|
Packit |
ed3af9 |
palette images anyway, so we don't need to do it explicitly.
|
|
Packit |
ed3af9 |
What to ideally do for truecolor images depends, alas, on the image.
|
|
Packit |
ed3af9 |
gd is intentionally imperfect and doesn't spend a lot of time
|
|
Packit |
ed3af9 |
fussing with such things. */
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* Faster if this is uncommented, but may produce larger truecolor files.
|
|
Packit |
ed3af9 |
Wait for gdImagePngCtxEx. */
|
|
Packit |
ed3af9 |
#if 0
|
|
Packit |
ed3af9 |
png_set_filter (png_ptr, 0, PNG_FILTER_NONE);
|
|
Packit |
ed3af9 |
#endif
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* 2.0.12: this is finally a parameter */
|
|
Packit |
ed3af9 |
png_set_compression_level (png_ptr, level);
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
#ifdef PNG_pHYs_SUPPORTED
|
|
Packit |
ed3af9 |
/* 2.1.0: specify the resolution */
|
|
Packit |
ed3af9 |
png_set_pHYs(png_ptr, info_ptr, DPI2DPM(im->res_x), DPI2DPM(im->res_y),
|
|
Packit |
ed3af9 |
PNG_RESOLUTION_METER);
|
|
Packit |
ed3af9 |
#endif
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* can set this to a smaller value without compromising compression if all
|
|
Packit |
ed3af9 |
* image data is 16K or less; will save some decoder memory [min == 8] */
|
|
Packit |
ed3af9 |
/* png_set_compression_window_bits(png_ptr, 15); */
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
if (!im->trueColor) {
|
|
Packit |
ed3af9 |
if (transparent >= im->colorsTotal ||
|
|
Packit |
ed3af9 |
(transparent >= 0 && open[transparent]))
|
|
Packit |
ed3af9 |
transparent = -1;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
if (!im->trueColor) {
|
|
Packit |
ed3af9 |
for (i = 0; i < gdMaxColors; ++i)
|
|
Packit |
ed3af9 |
mapping[i] = -1;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
if (!im->trueColor) {
|
|
Packit |
ed3af9 |
/* count actual number of colors used (colorsTotal == high-water mark) */
|
|
Packit |
ed3af9 |
colors = 0;
|
|
Packit |
ed3af9 |
for (i = 0; i < im->colorsTotal; ++i) {
|
|
Packit |
ed3af9 |
if (!open[i]) {
|
|
Packit |
ed3af9 |
mapping[i] = colors;
|
|
Packit |
ed3af9 |
++colors;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
if (colors == 0) {
|
|
Packit |
ed3af9 |
gd_error("gd-png error: no colors in palette\n");
|
|
Packit |
ed3af9 |
ret = 1;
|
|
Packit |
ed3af9 |
goto bail;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
if (colors < im->colorsTotal) {
|
|
Packit |
ed3af9 |
remap = TRUE;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
if (colors <= 2)
|
|
Packit |
ed3af9 |
bit_depth = 1;
|
|
Packit |
ed3af9 |
else if (colors <= 4)
|
|
Packit |
ed3af9 |
bit_depth = 2;
|
|
Packit |
ed3af9 |
else if (colors <= 16)
|
|
Packit |
ed3af9 |
bit_depth = 4;
|
|
Packit |
ed3af9 |
else
|
|
Packit |
ed3af9 |
bit_depth = 8;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
interlace_type = im->interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
if (im->trueColor) {
|
|
Packit |
ed3af9 |
if (im->saveAlphaFlag) {
|
|
Packit |
ed3af9 |
png_set_IHDR (png_ptr, info_ptr, width, height, 8,
|
|
Packit |
ed3af9 |
PNG_COLOR_TYPE_RGB_ALPHA, interlace_type,
|
|
Packit |
ed3af9 |
PNG_COMPRESSION_TYPE_DEFAULT,
|
|
Packit |
ed3af9 |
PNG_FILTER_TYPE_DEFAULT);
|
|
Packit |
ed3af9 |
} else {
|
|
Packit |
ed3af9 |
png_set_IHDR (png_ptr, info_ptr, width, height, 8,
|
|
Packit |
ed3af9 |
PNG_COLOR_TYPE_RGB, interlace_type,
|
|
Packit |
ed3af9 |
PNG_COMPRESSION_TYPE_DEFAULT,
|
|
Packit |
ed3af9 |
PNG_FILTER_TYPE_DEFAULT);
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
} else {
|
|
Packit |
ed3af9 |
png_set_IHDR (png_ptr, info_ptr, width, height, bit_depth,
|
|
Packit |
ed3af9 |
PNG_COLOR_TYPE_PALETTE, interlace_type,
|
|
Packit |
ed3af9 |
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
if (im->trueColor && (!im->saveAlphaFlag) && (transparent >= 0)) {
|
|
Packit |
ed3af9 |
/* 2.0.9: fixed by Thomas Winzig */
|
|
Packit |
ed3af9 |
trans_rgb_value.red = gdTrueColorGetRed (im->transparent);
|
|
Packit |
ed3af9 |
trans_rgb_value.green = gdTrueColorGetGreen (im->transparent);
|
|
Packit |
ed3af9 |
trans_rgb_value.blue = gdTrueColorGetBlue (im->transparent);
|
|
Packit |
ed3af9 |
png_set_tRNS (png_ptr, info_ptr, 0, 0, &trans_rgb_value);
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
if (!im->trueColor) {
|
|
Packit |
ed3af9 |
/* Oy veh. Remap the PNG palette to put the
|
|
Packit |
ed3af9 |
entries with interesting alpha channel
|
|
Packit |
ed3af9 |
values first. This minimizes the size
|
|
Packit |
ed3af9 |
of the tRNS chunk and thus the size
|
|
Packit |
ed3af9 |
of the PNG file as a whole. */
|
|
Packit |
ed3af9 |
int tc = 0;
|
|
Packit |
ed3af9 |
int i;
|
|
Packit |
ed3af9 |
int j;
|
|
Packit |
ed3af9 |
int k;
|
|
Packit |
ed3af9 |
for (i = 0; (i < im->colorsTotal); i++) {
|
|
Packit |
ed3af9 |
if ((!im->open[i]) && (im->alpha[i] != gdAlphaOpaque)) {
|
|
Packit |
ed3af9 |
tc++;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
if (tc) {
|
|
Packit |
ed3af9 |
#if 0
|
|
Packit |
ed3af9 |
for (i = 0; (i < im->colorsTotal); i++) {
|
|
Packit |
ed3af9 |
trans_values[i] = 255 -
|
|
Packit |
ed3af9 |
((im->alpha[i] << 1) + (im->alpha[i] >> 6));
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
png_set_tRNS (png_ptr, info_ptr, trans_values, 256, NULL);
|
|
Packit |
ed3af9 |
#endif
|
|
Packit |
ed3af9 |
if (!remap) {
|
|
Packit |
ed3af9 |
remap = TRUE;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
/* (Semi-)transparent indexes come up from the bottom
|
|
Packit |
ed3af9 |
of the list of real colors; opaque
|
|
Packit |
ed3af9 |
indexes come down from the top */
|
|
Packit |
ed3af9 |
j = 0;
|
|
Packit |
ed3af9 |
k = colors - 1;
|
|
Packit |
ed3af9 |
for (i = 0; (i < im->colorsTotal); i++) {
|
|
Packit |
ed3af9 |
if (!im->open[i]) {
|
|
Packit |
ed3af9 |
if (im->alpha[i] != gdAlphaOpaque) {
|
|
Packit |
ed3af9 |
/* Andrew Hull: >> 6, not >> 7! (gd 2.0.5) */
|
|
Packit |
ed3af9 |
trans_values[j] = 255 -
|
|
Packit |
ed3af9 |
((im->alpha[i] << 1) + (im->alpha[i] >> 6));
|
|
Packit |
ed3af9 |
mapping[i] = j++;
|
|
Packit |
ed3af9 |
} else {
|
|
Packit |
ed3af9 |
mapping[i] = k--;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
png_set_tRNS (png_ptr, info_ptr, trans_values, tc, NULL);
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* convert palette to libpng layout */
|
|
Packit |
ed3af9 |
if (!im->trueColor) {
|
|
Packit |
ed3af9 |
if (remap)
|
|
Packit |
ed3af9 |
for (i = 0; i < im->colorsTotal; ++i) {
|
|
Packit |
ed3af9 |
if (mapping[i] < 0)
|
|
Packit |
ed3af9 |
continue;
|
|
Packit |
ed3af9 |
palette[mapping[i]].red = im->red[i];
|
|
Packit |
ed3af9 |
palette[mapping[i]].green = im->green[i];
|
|
Packit |
ed3af9 |
palette[mapping[i]].blue = im->blue[i];
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
else
|
|
Packit |
ed3af9 |
for (i = 0; i < colors; ++i) {
|
|
Packit |
ed3af9 |
palette[i].red = im->red[i];
|
|
Packit |
ed3af9 |
palette[i].green = im->green[i];
|
|
Packit |
ed3af9 |
palette[i].blue = im->blue[i];
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
png_set_PLTE (png_ptr, info_ptr, palette, colors);
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* write out the PNG header info (everything up to first IDAT) */
|
|
Packit |
ed3af9 |
png_write_info (png_ptr, info_ptr);
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* make sure < 8-bit images are packed into pixels as tightly as possible */
|
|
Packit |
ed3af9 |
png_set_packing (png_ptr);
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
/* This code allocates a set of row buffers and copies the gd image data
|
|
Packit |
ed3af9 |
* into them only in the case that remapping is necessary; in gd 1.3 and
|
|
Packit |
ed3af9 |
* later, the im->pixels array is laid out identically to libpng's row
|
|
Packit |
ed3af9 |
* pointers and can be passed to png_write_image() function directly.
|
|
Packit |
ed3af9 |
* The remapping case could be accomplished with less memory for non-
|
|
Packit |
ed3af9 |
* interlaced images, but interlacing causes some serious complications. */
|
|
Packit |
ed3af9 |
if (im->trueColor) {
|
|
Packit |
ed3af9 |
/* performance optimizations by Phong Tran */
|
|
Packit |
ed3af9 |
int channels = im->saveAlphaFlag ? 4 : 3;
|
|
Packit |
ed3af9 |
/* Our little 7-bit alpha channel trick costs us a bit here. */
|
|
Packit |
ed3af9 |
png_bytep *row_pointers;
|
|
Packit |
ed3af9 |
unsigned char *pOutputRow;
|
|
Packit |
ed3af9 |
int **ptpixels = im->tpixels;
|
|
Packit |
ed3af9 |
int *pThisRow;
|
|
Packit |
ed3af9 |
unsigned char a;
|
|
Packit |
ed3af9 |
int thisPixel;
|
|
Packit |
ed3af9 |
png_bytep *prow_pointers;
|
|
Packit |
ed3af9 |
int saveAlphaFlag = im->saveAlphaFlag;
|
|
Packit |
ed3af9 |
if (overflow2(sizeof (png_bytep), height)) {
|
|
Packit |
ed3af9 |
ret = 1;
|
|
Packit |
ed3af9 |
goto bail;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
row_pointers = gdMalloc (sizeof (png_bytep) * height);
|
|
Packit |
ed3af9 |
if (row_pointers == NULL) {
|
|
Packit |
ed3af9 |
gd_error("gd-png error: unable to allocate row_pointers\n");
|
|
Packit |
ed3af9 |
ret = 1;
|
|
Packit |
ed3af9 |
goto bail;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
prow_pointers = row_pointers;
|
|
Packit |
ed3af9 |
for (j = 0; j < height; ++j) {
|
|
Packit |
ed3af9 |
if (overflow2(width, channels) || ((*prow_pointers =
|
|
Packit |
ed3af9 |
(png_bytep) gdMalloc (width * channels)) == NULL)) {
|
|
Packit |
ed3af9 |
gd_error("gd-png error: unable to allocate rows\n");
|
|
Packit |
ed3af9 |
for (i = 0; i < j; ++i)
|
|
Packit |
ed3af9 |
gdFree (row_pointers[i]);
|
|
Packit |
ed3af9 |
/* 2.0.29: memory leak TBB */
|
|
Packit |
ed3af9 |
gdFree(row_pointers);
|
|
Packit |
ed3af9 |
ret = 1;
|
|
Packit |
ed3af9 |
goto bail;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
pOutputRow = *prow_pointers++;
|
|
Packit |
ed3af9 |
pThisRow = *ptpixels++;
|
|
Packit |
ed3af9 |
for (i = 0; i < width; ++i) {
|
|
Packit |
ed3af9 |
thisPixel = *pThisRow++;
|
|
Packit |
ed3af9 |
*pOutputRow++ = gdTrueColorGetRed (thisPixel);
|
|
Packit |
ed3af9 |
*pOutputRow++ = gdTrueColorGetGreen (thisPixel);
|
|
Packit |
ed3af9 |
*pOutputRow++ = gdTrueColorGetBlue (thisPixel);
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
if (saveAlphaFlag) {
|
|
Packit |
ed3af9 |
/* convert the 7-bit alpha channel to an 8-bit alpha channel.
|
|
Packit |
ed3af9 |
We do a little bit-flipping magic, repeating the MSB
|
|
Packit |
ed3af9 |
as the LSB, to ensure that 0 maps to 0 and
|
|
Packit |
ed3af9 |
127 maps to 255. We also have to invert to match
|
|
Packit |
ed3af9 |
PNG's convention in which 255 is opaque. */
|
|
Packit |
ed3af9 |
a = gdTrueColorGetAlpha (thisPixel);
|
|
Packit |
ed3af9 |
/* Andrew Hull: >> 6, not >> 7! (gd 2.0.5) */
|
|
Packit |
ed3af9 |
*pOutputRow++ = 255 - ((a << 1) + (a >> 6));
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
png_write_image (png_ptr, row_pointers);
|
|
Packit |
ed3af9 |
png_write_end (png_ptr, info_ptr);
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
for (j = 0; j < height; ++j)
|
|
Packit |
ed3af9 |
gdFree (row_pointers[j]);
|
|
Packit |
ed3af9 |
gdFree (row_pointers);
|
|
Packit |
ed3af9 |
} else {
|
|
Packit |
ed3af9 |
if (remap) {
|
|
Packit |
ed3af9 |
png_bytep *row_pointers;
|
|
Packit |
ed3af9 |
if (overflow2(sizeof (png_bytep), height)) {
|
|
Packit |
ed3af9 |
ret = 1;
|
|
Packit |
ed3af9 |
goto bail;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
row_pointers = gdMalloc (sizeof (png_bytep) * height);
|
|
Packit |
ed3af9 |
if (row_pointers == NULL) {
|
|
Packit |
ed3af9 |
gd_error("gd-png error: unable to allocate row_pointers\n");
|
|
Packit |
ed3af9 |
ret = 1;
|
|
Packit |
ed3af9 |
goto bail;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
for (j = 0; j < height; ++j) {
|
|
Packit |
ed3af9 |
if ((row_pointers[j] = (png_bytep) gdMalloc (width)) == NULL) {
|
|
Packit |
ed3af9 |
gd_error("gd-png error: unable to allocate rows\n");
|
|
Packit |
ed3af9 |
for (i = 0; i < j; ++i)
|
|
Packit |
ed3af9 |
gdFree (row_pointers[i]);
|
|
Packit |
ed3af9 |
/* TBB: memory leak */
|
|
Packit |
ed3af9 |
gdFree (row_pointers);
|
|
Packit |
ed3af9 |
ret = 1;
|
|
Packit |
ed3af9 |
goto bail;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
for (i = 0; i < width; ++i)
|
|
Packit |
ed3af9 |
row_pointers[j][i] = mapping[im->pixels[j][i]];
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
png_write_image (png_ptr, row_pointers);
|
|
Packit |
ed3af9 |
png_write_end (png_ptr, info_ptr);
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
for (j = 0; j < height; ++j)
|
|
Packit |
ed3af9 |
gdFree (row_pointers[j]);
|
|
Packit |
ed3af9 |
gdFree (row_pointers);
|
|
Packit |
ed3af9 |
} else {
|
|
Packit |
ed3af9 |
png_write_image (png_ptr, im->pixels);
|
|
Packit |
ed3af9 |
png_write_end (png_ptr, info_ptr);
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
/* 1.6.3: maybe we should give that memory BACK! TBB */
|
|
Packit |
ed3af9 |
bail:
|
|
Packit |
ed3af9 |
png_destroy_write_struct (&png_ptr, &info_ptr);
|
|
Packit |
ed3af9 |
return ret;
|
|
Packit |
ed3af9 |
}
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
|
|
Packit |
ed3af9 |
#endif /* HAVE_LIBPNG */
|