Blame src/gd_gd.c

Packit ed3af9
/**
Packit ed3af9
 * File: GD IO
Packit ed3af9
 *
Packit ed3af9
 * Read and write GD images.
Packit ed3af9
 *
Packit ed3af9
 * The GD image format is a proprietary image format of libgd. *It has to be*
Packit ed3af9
 * *regarded as being obsolete, and should only be used for development and*
Packit ed3af9
 * *testing purposes.*
Packit ed3af9
 *
Packit ed3af9
 * Structure of a GD image file:
Packit ed3af9
 *  - file header
Packit ed3af9
 *  - color header (either truecolor or palette)
Packit ed3af9
 *  - image data
Packit ed3af9
 *
Packit ed3af9
 * All numbers are stored in big-endian format.
Packit ed3af9
 *
Packit ed3af9
 * File header structure:
Packit ed3af9
 *  signature     - 1 word ("\xFF\xFE" for truecolor, "\xFF\xFF" for palette)
Packit ed3af9
 *  width         - 1 word
Packit ed3af9
 *  height        - 1 word
Packit ed3af9
 *
Packit ed3af9
 * Truecolor image color header:
Packit ed3af9
 *  truecolor   - 1 byte (always "\001")
Packit ed3af9
 *  transparent - 1 dword (ARGB color)
Packit ed3af9
 *
Packit ed3af9
 * Palette image color header:
Packit ed3af9
 *  truecolor   - 1 byte (always "\0")
Packit ed3af9
 *  count       - 1 word (the number of used palette colors)
Packit ed3af9
 *  transparent - 1 dword (ARGB color)
Packit ed3af9
 *  palette     - 256 dwords (RGBA colors)
Packit ed3af9
 *
Packit ed3af9
 * Image data:
Packit ed3af9
 *  Sequential pixel data; row-major from top to bottom, left to right:
Packit ed3af9
 *   - 1 byte per pixel for palette images
Packit ed3af9
 *   - 1 dword (ARGB) per pixel for truecolor images
Packit ed3af9
 */
Packit ed3af9
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
Packit ed3af9
#define TRUE 1
Packit ed3af9
#define FALSE 0
Packit ed3af9
Packit ed3af9
/* Use this for commenting out debug-print statements. */
Packit ed3af9
/* Just use the first '#define' to allow all the prints... */
Packit ed3af9
/*#define GD2_DBG(s) (s) */
Packit ed3af9
#define GD2_DBG(s)
Packit ed3af9
Packit ed3af9
/* */
Packit ed3af9
/* Shared code to read color tables from gd file. */
Packit ed3af9
/* */
Packit ed3af9
int
Packit ed3af9
_gdGetColors (gdIOCtx * in, gdImagePtr im, int gd2xFlag)
Packit ed3af9
{
Packit ed3af9
	int i;
Packit ed3af9
	if (gd2xFlag) {
Packit ed3af9
		int trueColorFlag;
Packit ed3af9
		if (!gdGetByte (&trueColorFlag, in)) {
Packit ed3af9
			goto fail1;
Packit ed3af9
		}
Packit ed3af9
		/* 2.0.12: detect bad truecolor .gd files created by pre-2.0.12.
Packit ed3af9
		   Beginning in 2.0.12 truecolor is indicated by the initial 2-byte
Packit ed3af9
		   signature. */
Packit ed3af9
		if (trueColorFlag != im->trueColor) {
Packit ed3af9
			goto fail1;
Packit ed3af9
		}
Packit ed3af9
		/* This should have been a word all along */
Packit ed3af9
		if (!im->trueColor) {
Packit ed3af9
			if (!gdGetWord (&im->colorsTotal, in)) {
Packit ed3af9
				goto fail1;
Packit ed3af9
			}
Packit ed3af9
			if (im->colorsTotal > gdMaxColors) {
Packit ed3af9
				goto fail1;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
		/* Int to accommodate truecolor single-color transparency */
Packit ed3af9
		if (!gdGetInt (&im->transparent, in)) {
Packit ed3af9
			goto fail1;
Packit ed3af9
		}
Packit ed3af9
	} else {
Packit ed3af9
		if (!gdGetByte (&im->colorsTotal, in)) {
Packit ed3af9
			goto fail1;
Packit ed3af9
		}
Packit ed3af9
		if (!gdGetWord (&im->transparent, in)) {
Packit ed3af9
			goto fail1;
Packit ed3af9
		}
Packit ed3af9
		if (im->transparent == 257) {
Packit ed3af9
			im->transparent = (-1);
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
	GD2_DBG (printf
Packit ed3af9
	         ("Palette had %d colours (T=%d)\n", im->colorsTotal,
Packit ed3af9
	          im->transparent));
Packit ed3af9
	if (im->trueColor) {
Packit ed3af9
		return TRUE;
Packit ed3af9
	}
Packit ed3af9
	for (i = 0; (i < gdMaxColors); i++) {
Packit ed3af9
		if (!gdGetByte (&im->red[i], in)) {
Packit ed3af9
			goto fail1;
Packit ed3af9
		}
Packit ed3af9
		if (!gdGetByte (&im->green[i], in)) {
Packit ed3af9
			goto fail1;
Packit ed3af9
		}
Packit ed3af9
		if (!gdGetByte (&im->blue[i], in)) {
Packit ed3af9
			goto fail1;
Packit ed3af9
		}
Packit ed3af9
		if (gd2xFlag) {
Packit ed3af9
			if (!gdGetByte (&im->alpha[i], in)) {
Packit ed3af9
				goto fail1;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	for (i = 0; (i < im->colorsTotal); i++) {
Packit ed3af9
		im->open[i] = 0;
Packit ed3af9
	};
Packit ed3af9
Packit ed3af9
	return TRUE;
Packit ed3af9
fail1:
Packit ed3af9
	return FALSE;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/* */
Packit ed3af9
/* Use the common basic header info to make the image object. */
Packit ed3af9
/* */
Packit ed3af9
static gdImagePtr
Packit ed3af9
_gdCreateFromFile (gdIOCtx * in, int *sx, int *sy)
Packit ed3af9
{
Packit ed3af9
	gdImagePtr im;
Packit ed3af9
	int gd2xFlag = 0;
Packit ed3af9
	int trueColorFlag = 0;
Packit ed3af9
	if (!gdGetWord (sx, in)) {
Packit ed3af9
		goto fail1;
Packit ed3af9
	}
Packit ed3af9
	if ((*sx == 65535) || (*sx == 65534)) {
Packit ed3af9
		/* This is a gd 2.0 .gd file */
Packit ed3af9
		gd2xFlag = 1;
Packit ed3af9
		/* 2.0.12: 65534 signals a truecolor .gd file.
Packit ed3af9
		   There is a slight redundancy here but we can
Packit ed3af9
		   live with it. */
Packit ed3af9
		if (*sx == 65534) {
Packit ed3af9
			trueColorFlag = 1;
Packit ed3af9
		}
Packit ed3af9
		if (!gdGetWord (sx, in)) {
Packit ed3af9
			goto fail1;
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
	if (!gdGetWord (sy, in)) {
Packit ed3af9
		goto fail1;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	GD2_DBG (printf ("Image is %dx%d\n", *sx, *sy));
Packit ed3af9
	if (trueColorFlag) {
Packit ed3af9
		im = gdImageCreateTrueColor (*sx, *sy);
Packit ed3af9
	} else {
Packit ed3af9
		im = gdImageCreate (*sx, *sy);
Packit ed3af9
	}
Packit ed3af9
	if (!im) {
Packit ed3af9
		goto fail1;
Packit ed3af9
	}
Packit ed3af9
	if (!_gdGetColors (in, im, gd2xFlag)) {
Packit ed3af9
		goto fail2;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	return im;
Packit ed3af9
fail2:
Packit ed3af9
	gdImageDestroy (im);
Packit ed3af9
fail1:
Packit ed3af9
	return 0;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
  Function: gdImageCreateFromGd
Packit ed3af9
Packit ed3af9
    <gdImageCreateFromGd> is called to load images from gd format
Packit ed3af9
    files. Invoke <gdImageCreateFromGd> with an already opened pointer
Packit ed3af9
    to a file containing the desired image in the gd file format,
Packit ed3af9
    which is specific to gd and intended for very fast loading. (It is
Packit ed3af9
    not intended for compression; for compression, use PNG or JPEG.)
Packit ed3af9
Packit ed3af9
    <gdImageCreateFromGd> returns a <gdImagePtr> to the new image, or
Packit ed3af9
    NULL if unable to load the image (most often because the file is
Packit ed3af9
    corrupt or does not contain a gd format
Packit ed3af9
    image). <gdImageCreateFromGd> 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
  Variants:
Packit ed3af9
Packit ed3af9
    <gdImageCreateFromGdPtr> creates an image from GD data (i.e. the
Packit ed3af9
    contents of a GD file) already in memory.
Packit ed3af9
Packit ed3af9
    <gdImageCreateFromGdCtx> reads in an image using the functions in
Packit ed3af9
    a <gdIOCtx> struct.
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
Packit ed3af9
    > gdImagePtr im;
Packit ed3af9
    > FILE *in;
Packit ed3af9
    > in = fopen("mygd.gd", "rb");
Packit ed3af9
    > im = gdImageCreateFromGd(in);
Packit ed3af9
    > fclose(in);
Packit ed3af9
    > // ... Use the image ... 
Packit ed3af9
    > gdImageDestroy(im);
Packit ed3af9
*/
Packit ed3af9
BGD_DECLARE(gdImagePtr) gdImageCreateFromGd (FILE * inFile)
Packit ed3af9
{
Packit ed3af9
	gdImagePtr im;
Packit ed3af9
	gdIOCtx *in;
Packit ed3af9
Packit ed3af9
	in = gdNewFileCtx (inFile);
Packit ed3af9
	if (in == NULL) return NULL;
Packit ed3af9
	im = gdImageCreateFromGdCtx (in);
Packit ed3af9
Packit ed3af9
	in->gd_free (in);
Packit ed3af9
Packit ed3af9
	return im;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
  Function: gdImageCreateFromGdPtr
Packit ed3af9
Packit ed3af9
  Parameters:
Packit ed3af9
Packit ed3af9
    size - size of GD data in bytes.
Packit ed3af9
    data - GD data (i.e. contents of a GIF file).
Packit ed3af9
Packit ed3af9
  Reads in GD data from memory. See <gdImageCreateFromGd>.
Packit ed3af9
*/
Packit ed3af9
BGD_DECLARE(gdImagePtr) gdImageCreateFromGdPtr (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 = gdImageCreateFromGdCtx (in);
Packit ed3af9
	in->gd_free (in);
Packit ed3af9
	return im;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
  Function: gdImageCreateFromGdCtx
Packit ed3af9
Packit ed3af9
  Reads in a GD image via a <gdIOCtx> struct.  See
Packit ed3af9
  <gdImageCreateFromGd>.
Packit ed3af9
*/
Packit ed3af9
BGD_DECLARE(gdImagePtr) gdImageCreateFromGdCtx (gdIOCtxPtr in)
Packit ed3af9
{
Packit ed3af9
	int sx, sy;
Packit ed3af9
	int x, y;
Packit ed3af9
	gdImagePtr im;
Packit ed3af9
Packit ed3af9
	/* Read the header */
Packit ed3af9
	im = _gdCreateFromFile (in, &sx, &sy;;
Packit ed3af9
Packit ed3af9
	if (im == NULL) {
Packit ed3af9
		goto fail1;
Packit ed3af9
	};
Packit ed3af9
Packit ed3af9
	/* Then the data... */
Packit ed3af9
	/* 2.0.12: support truecolor properly in .gd as well as in .gd2.
Packit ed3af9
	   Problem reported by Andreas Pfaller. */
Packit ed3af9
	if (im->trueColor) {
Packit ed3af9
		for (y = 0; (y < sy); y++) {
Packit ed3af9
			for (x = 0; (x < sx); x++) {
Packit ed3af9
				int pix;
Packit ed3af9
				if (!gdGetInt (&pix, in)) {
Packit ed3af9
					goto fail2;
Packit ed3af9
				}
Packit ed3af9
				im->tpixels[y][x] = pix;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
	} else {
Packit ed3af9
		for (y = 0; (y < sy); y++) {
Packit ed3af9
			for (x = 0; (x < sx); x++) {
Packit ed3af9
				int ch;
Packit ed3af9
				ch = gdGetC (in);
Packit ed3af9
				if (ch == EOF) {
Packit ed3af9
					goto fail2;
Packit ed3af9
				}
Packit ed3af9
				/* ROW-MAJOR IN GD 1.3 */
Packit ed3af9
				im->pixels[y][x] = ch;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
	return im;
Packit ed3af9
Packit ed3af9
fail2:
Packit ed3af9
	gdImageDestroy (im);
Packit ed3af9
fail1:
Packit ed3af9
	return 0;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
void
Packit ed3af9
_gdPutColors (gdImagePtr im, gdIOCtx * out)
Packit ed3af9
{
Packit ed3af9
	int i;
Packit ed3af9
Packit ed3af9
	gdPutC (im->trueColor, out);
Packit ed3af9
	if (!im->trueColor) {
Packit ed3af9
		gdPutWord (im->colorsTotal, out);
Packit ed3af9
	}
Packit ed3af9
	gdPutInt (im->transparent, out);
Packit ed3af9
	if (!im->trueColor) {
Packit ed3af9
		for (i = 0; (i < gdMaxColors); i++) {
Packit ed3af9
			gdPutC ((unsigned char) im->red[i], out);
Packit ed3af9
			gdPutC ((unsigned char) im->green[i], out);
Packit ed3af9
			gdPutC ((unsigned char) im->blue[i], out);
Packit ed3af9
			gdPutC ((unsigned char) im->alpha[i], out);
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static void
Packit ed3af9
_gdPutHeader (gdImagePtr im, gdIOCtx * out)
Packit ed3af9
{
Packit ed3af9
	/* 65535 indicates this is a gd 2.x .gd file.
Packit ed3af9
	   2.0.12: 65534 indicates truecolor. */
Packit ed3af9
	if (im->trueColor) {
Packit ed3af9
		gdPutWord (65534, out);
Packit ed3af9
	} else {
Packit ed3af9
		gdPutWord (65535, out);
Packit ed3af9
	}
Packit ed3af9
	gdPutWord (im->sx, out);
Packit ed3af9
	gdPutWord (im->sy, out);
Packit ed3af9
Packit ed3af9
	_gdPutColors (im, out);
Packit ed3af9
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static void
Packit ed3af9
_gdImageGd (gdImagePtr im, gdIOCtx * out)
Packit ed3af9
{
Packit ed3af9
	int x, y;
Packit ed3af9
Packit ed3af9
	_gdPutHeader (im, out);
Packit ed3af9
Packit ed3af9
	for (y = 0; (y < im->sy); y++) {
Packit ed3af9
		for (x = 0; (x < im->sx); x++) {
Packit ed3af9
			/* ROW-MAJOR IN GD 1.3 */
Packit ed3af9
			if (im->trueColor) {
Packit ed3af9
				gdPutInt (im->tpixels[y][x], out);
Packit ed3af9
			} else {
Packit ed3af9
				gdPutC ((unsigned char) im->pixels[y][x], out);
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
	Function: gdImageGd
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(void) gdImageGd (gdImagePtr im, FILE * outFile)
Packit ed3af9
{
Packit ed3af9
	gdIOCtx *out = gdNewFileCtx (outFile);
Packit ed3af9
	if (out == NULL) return;
Packit ed3af9
	_gdImageGd (im, out);
Packit ed3af9
	out->gd_free (out);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
	Function: gdImageGdPtr
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(void *) gdImageGdPtr (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
	_gdImageGd (im, out);
Packit ed3af9
	rv = gdDPExtractData (out, size);
Packit ed3af9
	out->gd_free (out);
Packit ed3af9
	return rv;
Packit ed3af9
}