summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/gd.c2710
-rw-r--r--src/gd.h54
-rw-r--r--src/gd2copypal.c2
-rw-r--r--src/gd2time.c2
-rw-r--r--src/gd2topng.c38
-rw-r--r--src/gd_gd.c401
-rw-r--r--src/gd_gd2.c1455
-rw-r--r--src/gd_io.c157
-rw-r--r--src/gd_io.h39
-rw-r--r--src/gd_io_dp.c375
-rw-r--r--src/gd_io_file.c127
-rw-r--r--src/gd_io_ss.c147
-rw-r--r--src/gd_png.c227
-rw-r--r--src/gd_ss.c38
-rw-r--r--src/gddemo.c14
-rw-r--r--src/gdparttopng.c48
-rw-r--r--src/gdtest.c136
-rw-r--r--src/gdtopng.c38
-rw-r--r--src/pngtogd.c38
-rw-r--r--src/pngtogd2.c44
-rw-r--r--src/webpng.c191
21 files changed, 3904 insertions, 2377 deletions
diff --git a/src/gd.c b/src/gd.c
index cd14564..858e865 100644
--- a/src/gd.c
+++ b/src/gd.c
@@ -1,1354 +1,1356 @@
-#include <stdio.h>
-#include <math.h>
-#include <string.h>
-#include <stdlib.h>
-#include <zlib.h>
-#include "gd.h"
-#include "mtables.c"
-
-static void gdImageBrushApply(gdImagePtr im, int x, int y);
-static void gdImageTileApply(gdImagePtr im, int x, int y);
-
-gdImagePtr gdImageCreate(int sx, int sy)
-{
- int i;
- gdImagePtr im;
- im = (gdImage *) malloc(sizeof(gdImage));
- /* NOW ROW-MAJOR IN GD 1.3 */
- im->pixels = (unsigned char **) malloc(sizeof(unsigned char *) * sy);
- im->polyInts = 0;
- im->polyAllocated = 0;
- im->brush = 0;
- im->tile = 0;
- im->style = 0;
- for (i=0; (i<sy); i++) {
- /* NOW ROW-MAJOR IN GD 1.3 */
- im->pixels[i] = (unsigned char *) calloc(
- sx, sizeof(unsigned char));
- }
- im->sx = sx;
- im->sy = sy;
- im->colorsTotal = 0;
- im->transparent = (-1);
- im->interlace = 0;
-
- for (i=0; (i < gdMaxColors); i++) {
- im->open[i] = 1;
- im->red[i] = 0;
- im->green[i] = 0;
- im->blue[i] = 0;
- };
-
- return im;
-}
-
-void gdImageDestroy(gdImagePtr im)
-{
- int i;
- for (i=0; (i<im->sy); i++) {
- free(im->pixels[i]);
- }
- free(im->pixels);
- if (im->polyInts) {
- free(im->polyInts);
- }
- if (im->style) {
- free(im->style);
- }
- free(im);
-}
-
-int gdImageColorClosest(gdImagePtr im, int r, int g, int b)
-{
- int i;
- long rd, gd, bd;
- int ct = (-1);
- long mindist = 0;
- for (i=0; (i<(im->colorsTotal)); i++) {
- long dist;
- if (im->open[i]) {
- continue;
- }
- rd = (im->red[i] - r);
- gd = (im->green[i] - g);
- bd = (im->blue[i] - b);
- dist = rd * rd + gd * gd + bd * bd;
- if ((i == 0) || (dist < mindist)) {
- mindist = dist;
- ct = i;
- }
- }
- return ct;
-}
-
-int gdImageColorExact(gdImagePtr im, int r, int g, int b)
-{
- int i;
- for (i=0; (i<(im->colorsTotal)); i++) {
- if (im->open[i]) {
- continue;
- }
- if ((im->red[i] == r) &&
- (im->green[i] == g) &&
- (im->blue[i] == b)) {
- return i;
- }
- }
- return -1;
-}
-
-int gdImageColorAllocate(gdImagePtr im, int r, int g, int b)
-{
- int i;
- int ct = (-1);
- for (i=0; (i<(im->colorsTotal)); i++) {
- if (im->open[i]) {
- ct = i;
- break;
- }
- }
- if (ct == (-1)) {
- ct = im->colorsTotal;
- if (ct == gdMaxColors) {
- return -1;
- }
- im->colorsTotal++;
- }
- im->red[ct] = r;
- im->green[ct] = g;
- im->blue[ct] = b;
- im->open[ct] = 0;
- return ct;
-}
-
-void gdImageColorDeallocate(gdImagePtr im, int color)
-{
- /* Mark it open. */
- im->open[color] = 1;
-}
-
-void gdImageColorTransparent(gdImagePtr im, int color)
-{
- im->transparent = color;
-}
-
-void gdImagePaletteCopy(gdImagePtr to, gdImagePtr from)
-{
- int i;
- int x, y, p;
- int xlate[256];
-
- for (i=0; i < 256 ; i++) {
- xlate[i] = -1;
- };
-
- for (x=0 ; x < (to->sx) ; x++) {
- for (y=0 ; y < (to->sy) ; y++) {
- p = gdImageGetPixel(to, x, y);
- if (xlate[p] == -1) {
- xlate[p] = gdImageColorClosest(from, to->red[p], to->green[p], to->blue[p]);
- /*printf("Mapping %d (%d, %d, %d) to %d (%d, %d, %d)\n", */
- /* p, to->red[p], to->green[p], to->blue[p], */
- /* xlate[p], from->red[xlate[p]], from->green[xlate[p]], from->blue[xlate[p]]); */
- };
- gdImageSetPixel(to, x, y, xlate[p]);
- };
- };
-
- for (i=0; (i < (from->colorsTotal) ) ; i++) {
- /*printf("Copying color %d (%d, %d, %d)\n", i, from->red[i], from->blue[i], from->green[i]); */
- to->red[i] = from->red[i];
- to->blue[i] = from->blue[i];
- to->green[i] = from->green[i];
- to->open[i] = 0;
- };
-
- for (i=from->colorsTotal ; (i < to->colorsTotal) ; i++) {
- to->open[i] = 1;
- };
-
- to->colorsTotal = from->colorsTotal;
-
-}
-
-void gdImageSetPixel(gdImagePtr im, int x, int y, int color)
-{
- int p;
- switch(color) {
- case gdStyled:
- if (!im->style) {
- /* Refuse to draw if no style is set. */
- return;
- } else {
- p = im->style[im->stylePos++];
- }
- if (p != (gdTransparent)) {
- gdImageSetPixel(im, x, y, p);
- }
- im->stylePos = im->stylePos % im->styleLength;
- break;
- case gdStyledBrushed:
- if (!im->style) {
- /* Refuse to draw if no style is set. */
- return;
- }
- p = im->style[im->stylePos++];
- if ((p != gdTransparent) && (p != 0)) {
- gdImageSetPixel(im, x, y, gdBrushed);
- }
- im->stylePos = im->stylePos % im->styleLength;
- break;
- case gdBrushed:
- gdImageBrushApply(im, x, y);
- break;
- case gdTiled:
- gdImageTileApply(im, x, y);
- break;
- default:
- if (gdImageBoundsSafe(im, x, y)) {
- /* NOW ROW-MAJOR IN GD 1.3 */
- im->pixels[y][x] = color;
- }
- break;
- }
-}
-
-static void gdImageBrushApply(gdImagePtr im, int x, int y)
-{
- int lx, ly;
- int hy;
- int hx;
- int x1, y1, x2, y2;
- int srcx, srcy;
- if (!im->brush) {
- return;
- }
- hy = gdImageSY(im->brush)/2;
- y1 = y - hy;
- y2 = y1 + gdImageSY(im->brush);
- hx = gdImageSX(im->brush)/2;
- x1 = x - hx;
- x2 = x1 + gdImageSX(im->brush);
- srcy = 0;
- for (ly = y1; (ly < y2); ly++) {
- srcx = 0;
- for (lx = x1; (lx < x2); lx++) {
- int p;
- p = gdImageGetPixel(im->brush, srcx, srcy);
- /* Allow for non-square brushes! */
- if (p != gdImageGetTransparent(im->brush)) {
- gdImageSetPixel(im, lx, ly,
- im->brushColorMap[p]);
- }
- srcx++;
- }
- srcy++;
- }
-}
-
-static void gdImageTileApply(gdImagePtr im, int x, int y)
-{
- int srcx, srcy;
- int p;
- if (!im->tile) {
- return;
- }
- srcx = x % gdImageSX(im->tile);
- srcy = y % gdImageSY(im->tile);
- p = gdImageGetPixel(im->tile, srcx, srcy);
- /* Allow for transparency */
- if (p != gdImageGetTransparent(im->tile)) {
- gdImageSetPixel(im, x, y,
- im->tileColorMap[p]);
- }
-}
-
-int gdImageGetPixel(gdImagePtr im, int x, int y)
-{
- if (gdImageBoundsSafe(im, x, y)) {
- /* NOW ROW-MAJOR IN GD 1.3 */
- return im->pixels[y][x];
- } else {
- return 0;
- }
-}
-
-/* Bresenham as presented in Foley & Van Dam */
-
-void gdImageLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
-{
- int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
- dx = abs(x2-x1);
- dy = abs(y2-y1);
- if (dy <= dx) {
- d = 2*dy - dx;
- incr1 = 2*dy;
- incr2 = 2 * (dy - dx);
- if (x1 > x2) {
- x = x2;
- y = y2;
- ydirflag = (-1);
- xend = x1;
- } else {
- x = x1;
- y = y1;
- ydirflag = 1;
- xend = x2;
- }
- gdImageSetPixel(im, x, y, color);
- if (((y2 - y1) * ydirflag) > 0) {
- while (x < xend) {
- x++;
- if (d <0) {
- d+=incr1;
- } else {
- y++;
- d+=incr2;
- }
- gdImageSetPixel(im, x, y, color);
- }
- } else {
- while (x < xend) {
- x++;
- if (d <0) {
- d+=incr1;
- } else {
- y--;
- d+=incr2;
- }
- gdImageSetPixel(im, x, y, color);
- }
- }
- } else {
- d = 2*dx - dy;
- incr1 = 2*dx;
- incr2 = 2 * (dx - dy);
- if (y1 > y2) {
- y = y2;
- x = x2;
- yend = y1;
- xdirflag = (-1);
- } else {
- y = y1;
- x = x1;
- yend = y2;
- xdirflag = 1;
- }
- gdImageSetPixel(im, x, y, color);
- if (((x2 - x1) * xdirflag) > 0) {
- while (y < yend) {
- y++;
- if (d <0) {
- d+=incr1;
- } else {
- x++;
- d+=incr2;
- }
- gdImageSetPixel(im, x, y, color);
- }
- } else {
- while (y < yend) {
- y++;
- if (d <0) {
- d+=incr1;
- } else {
- x--;
- d+=incr2;
- }
- gdImageSetPixel(im, x, y, color);
- }
- }
- }
-}
-
-static void dashedSet(gdImagePtr im, int x, int y, int color,
- int *onP, int *dashStepP);
-
-void gdImageDashedLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
-{
- int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
- int dashStep = 0;
- int on = 1;
- dx = abs(x2-x1);
- dy = abs(y2-y1);
- if (dy <= dx) {
- d = 2*dy - dx;
- incr1 = 2*dy;
- incr2 = 2 * (dy - dx);
- if (x1 > x2) {
- x = x2;
- y = y2;
- ydirflag = (-1);
- xend = x1;
- } else {
- x = x1;
- y = y1;
- ydirflag = 1;
- xend = x2;
- }
- dashedSet(im, x, y, color, &on, &dashStep);
- if (((y2 - y1) * ydirflag) > 0) {
- while (x < xend) {
- x++;
- if (d <0) {
- d+=incr1;
- } else {
- y++;
- d+=incr2;
- }
- dashedSet(im, x, y, color, &on, &dashStep);
- }
- } else {
- while (x < xend) {
- x++;
- if (d <0) {
- d+=incr1;
- } else {
- y--;
- d+=incr2;
- }
- dashedSet(im, x, y, color, &on, &dashStep);
- }
- }
- } else {
- d = 2*dx - dy;
- incr1 = 2*dx;
- incr2 = 2 * (dx - dy);
- if (y1 > y2) {
- y = y2;
- x = x2;
- yend = y1;
- xdirflag = (-1);
- } else {
- y = y1;
- x = x1;
- yend = y2;
- xdirflag = 1;
- }
- dashedSet(im, x, y, color, &on, &dashStep);
- if (((x2 - x1) * xdirflag) > 0) {
- while (y < yend) {
- y++;
- if (d <0) {
- d+=incr1;
- } else {
- x++;
- d+=incr2;
- }
- dashedSet(im, x, y, color, &on, &dashStep);
- }
- } else {
- while (y < yend) {
- y++;
- if (d <0) {
- d+=incr1;
- } else {
- x--;
- d+=incr2;
- }
- dashedSet(im, x, y, color, &on, &dashStep);
- }
- }
- }
-}
-
-static void dashedSet(gdImagePtr im, int x, int y, int color,
- int *onP, int *dashStepP)
-{
- int dashStep = *dashStepP;
- int on = *onP;
- dashStep++;
- if (dashStep == gdDashSize) {
- dashStep = 0;
- on = !on;
- }
- if (on) {
- gdImageSetPixel(im, x, y, color);
- }
- *dashStepP = dashStep;
- *onP = on;
-}
-
-
-int gdImageBoundsSafe(gdImagePtr im, int x, int y)
-{
- return (!(((y < 0) || (y >= im->sy)) ||
- ((x < 0) || (x >= im->sx))));
-}
-
-void gdImageChar(gdImagePtr im, gdFontPtr f, int x, int y,
- int c, int color)
-{
- int cx, cy;
- int px, py;
- int fline;
- cx = 0;
- cy = 0;
- if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
- return;
- }
- fline = (c - f->offset) * f->h * f->w;
- for (py = y; (py < (y + f->h)); py++) {
- for (px = x; (px < (x + f->w)); px++) {
- if (f->data[fline + cy * f->w + cx]) {
- gdImageSetPixel(im, px, py, color);
- }
- cx++;
- }
- cx = 0;
- cy++;
- }
-}
-
-void gdImageCharUp(gdImagePtr im, gdFontPtr f,
- int x, int y, int c, int color)
-{
- int cx, cy;
- int px, py;
- int fline;
- cx = 0;
- cy = 0;
- if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
- return;
- }
- fline = (c - f->offset) * f->h * f->w;
- for (py = y; (py > (y - f->w)); py--) {
- for (px = x; (px < (x + f->h)); px++) {
- if (f->data[fline + cy * f->w + cx]) {
- gdImageSetPixel(im, px, py, color);
- }
- cy++;
- }
- cy = 0;
- cx++;
- }
-}
-
-void gdImageString(gdImagePtr im, gdFontPtr f,
- int x, int y, unsigned char *s, int color)
-{
- int i;
- int l;
- l = strlen(s);
- for (i=0; (i<l); i++) {
- gdImageChar(im, f, x, y, s[i], color);
- x += f->w;
- }
-}
-
-void gdImageStringUp(gdImagePtr im, gdFontPtr f,
- int x, int y, unsigned char *s, int color)
-{
- int i;
- int l;
- l = strlen(s);
- for (i=0; (i<l); i++) {
- gdImageCharUp(im, f, x, y, s[i], color);
- y -= f->w;
- }
-}
-
-static int strlen16(unsigned short *s);
-
-void gdImageString16(gdImagePtr im, gdFontPtr f,
- int x, int y, unsigned short *s, int color)
-{
- int i;
- int l;
- l = strlen16(s);
- for (i=0; (i<l); i++) {
- gdImageChar(im, f, x, y, s[i], color);
- x += f->w;
- }
-}
-
-void gdImageStringUp16(gdImagePtr im, gdFontPtr f,
- int x, int y, unsigned short *s, int color)
-{
- int i;
- int l;
- l = strlen16(s);
- for (i=0; (i<l); i++) {
- gdImageCharUp(im, f, x, y, s[i], color);
- y -= f->w;
- }
-}
-
-static int strlen16(unsigned short *s)
-{
- int len = 0;
- while (*s) {
- s++;
- len++;
- }
- return len;
-}
-
-/* s and e are integers modulo 360 (degrees), with 0 degrees
- being the rightmost extreme and degrees changing clockwise.
- cx and cy are the center in pixels; w and h are the horizontal
- and vertical diameter in pixels. Nice interface, but slow, since
- I don't yet use Bresenham (I'm using an inefficient but
- simple solution with too much work going on in it; generalizing
- Bresenham to ellipses and partial arcs of ellipses is non-trivial,
- at least for me) and there are other inefficiencies (small circles
- do far too much work). */
-
-void gdImageArc(gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color)
-{
- int i;
- int lx = 0, ly = 0;
- int w2, h2;
- w2 = w/2;
- h2 = h/2;
- while (e < s) {
- e += 360;
- }
- for (i=s; (i <= e); i++) {
- int x, y;
- x = ((long)cost[i % 360] * (long)w2 / costScale) + cx;
- y = ((long)sint[i % 360] * (long)h2 / sintScale) + cy;
- if (i != s) {
- gdImageLine(im, lx, ly, x, y, color);
- }
- lx = x;
- ly = y;
- }
-}
-
-
-#if 0
- /* Bresenham octant code, which I should use eventually */
- int x, y, d;
- x = 0;
- y = w;
- d = 3-2*w;
- while (x < y) {
- gdImageSetPixel(im, cx+x, cy+y, color);
- if (d < 0) {
- d += 4 * x + 6;
- } else {
- d += 4 * (x - y) + 10;
- y--;
- }
- x++;
- }
- if (x == y) {
- gdImageSetPixel(im, cx+x, cy+y, color);
- }
-#endif
-
-void gdImageFillToBorder(gdImagePtr im, int x, int y, int border, int color)
-{
- int lastBorder;
- /* Seek left */
- int leftLimit, rightLimit;
- int i;
- leftLimit = (-1);
- if (border < 0) {
- /* Refuse to fill to a non-solid border */
- return;
- }
- for (i = x; (i >= 0); i--) {
- if (gdImageGetPixel(im, i, y) == border) {
- break;
- }
- gdImageSetPixel(im, i, y, color);
- leftLimit = i;
- }
- if (leftLimit == (-1)) {
- return;
- }
- /* Seek right */
- rightLimit = x;
- for (i = (x+1); (i < im->sx); i++) {
- if (gdImageGetPixel(im, i, y) == border) {
- break;
- }
- gdImageSetPixel(im, i, y, color);
- rightLimit = i;
- }
- /* Look at lines above and below and start paints */
- /* Above */
- if (y > 0) {
- lastBorder = 1;
- for (i = leftLimit; (i <= rightLimit); i++) {
- int c;
- c = gdImageGetPixel(im, i, y-1);
- if (lastBorder) {
- if ((c != border) && (c != color)) {
- gdImageFillToBorder(im, i, y-1,
- border, color);
- lastBorder = 0;
- }
- } else if ((c == border) || (c == color)) {
- lastBorder = 1;
- }
- }
- }
- /* Below */
- if (y < ((im->sy) - 1)) {
- lastBorder = 1;
- for (i = leftLimit; (i <= rightLimit); i++) {
- int c;
- c = gdImageGetPixel(im, i, y+1);
- if (lastBorder) {
- if ((c != border) && (c != color)) {
- gdImageFillToBorder(im, i, y+1,
- border, color);
- lastBorder = 0;
- }
- } else if ((c == border) || (c == color)) {
- lastBorder = 1;
- }
- }
- }
-}
-
-void gdImageFill(gdImagePtr im, int x, int y, int color)
-{
- int lastBorder;
- int old;
- int leftLimit, rightLimit;
- int i;
- old = gdImageGetPixel(im, x, y);
- if (color == gdTiled) {
- /* Tile fill -- got to watch out! */
- int p, tileColor;
- int srcx, srcy;
- if (!im->tile) {
- return;
- }
- /* Refuse to flood-fill with a transparent pattern --
- I can't do it without allocating another image */
- if (gdImageGetTransparent(im->tile) != (-1)) {
- return;
- }
- srcx = x % gdImageSX(im->tile);
- srcy = y % gdImageSY(im->tile);
- p = gdImageGetPixel(im->tile, srcx, srcy);
- tileColor = im->tileColorMap[p];
- if (old == tileColor) {
- /* Nothing to be done */
- return;
- }
- } else {
- if (old == color) {
- /* Nothing to be done */
- return;
- }
- }
- /* Seek left */
- leftLimit = (-1);
- for (i = x; (i >= 0); i--) {
- if (gdImageGetPixel(im, i, y) != old) {
- break;
- }
- gdImageSetPixel(im, i, y, color);
- leftLimit = i;
- }
- if (leftLimit == (-1)) {
- return;
- }
- /* Seek right */
- rightLimit = x;
- for (i = (x+1); (i < im->sx); i++) {
- if (gdImageGetPixel(im, i, y) != old) {
- break;
- }
- gdImageSetPixel(im, i, y, color);
- rightLimit = i;
- }
- /* Look at lines above and below and start paints */
- /* Above */
- if (y > 0) {
- lastBorder = 1;
- for (i = leftLimit; (i <= rightLimit); i++) {
- int c;
- c = gdImageGetPixel(im, i, y-1);
- if (lastBorder) {
- if (c == old) {
- gdImageFill(im, i, y-1, color);
- lastBorder = 0;
- }
- } else if (c != old) {
- lastBorder = 1;
- }
- }
- }
- /* Below */
- if (y < ((im->sy) - 1)) {
- lastBorder = 1;
- for (i = leftLimit; (i <= rightLimit); i++) {
- int c;
- c = gdImageGetPixel(im, i, y+1);
- if (lastBorder) {
- if (c == old) {
- gdImageFill(im, i, y+1, color);
- lastBorder = 0;
- }
- } else if (c != old) {
- lastBorder = 1;
- }
- }
- }
-}
-
-void gdImageRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
-{
- gdImageLine(im, x1, y1, x2, y1, color);
- gdImageLine(im, x1, y2, x2, y2, color);
- gdImageLine(im, x1, y1, x1, y2, color);
- gdImageLine(im, x2, y1, x2, y2, color);
-}
-
-void gdImageFilledRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
-{
- int x, y;
- for (y=y1; (y<=y2); y++) {
- for (x=x1; (x<=x2); x++) {
- gdImageSetPixel(im, x, y, color);
- }
- }
-}
-
-void gdImageCopy(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h)
-{
- int c;
- int x, y;
- int tox, toy;
- int i;
- int colorMap[gdMaxColors];
- for (i=0; (i<gdMaxColors); i++) {
- colorMap[i] = (-1);
- }
- toy = dstY;
- for (y=srcY; (y < (srcY + h)); y++) {
- tox = dstX;
- for (x=srcX; (x < (srcX + w)); x++) {
- int nc;
- c = gdImageGetPixel(src, x, y);
- /* Added 7/24/95: support transparent copies */
- if (gdImageGetTransparent(src) == c) {
- tox++;
- continue;
- }
- /* Have we established a mapping for this color? */
- if (colorMap[c] == (-1)) {
- /* If it's the same image, mapping is trivial */
- if (dst == src) {
- nc = c;
- } else {
- /* First look for an exact match */
- nc = gdImageColorExact(dst,
- src->red[c], src->green[c],
- src->blue[c]);
- }
- if (nc == (-1)) {
- /* No, so try to allocate it */
- nc = gdImageColorAllocate(dst,
- src->red[c], src->green[c],
- src->blue[c]);
- /* If we're out of colors, go for the
- closest color */
- if (nc == (-1)) {
- nc = gdImageColorClosest(dst,
- src->red[c], src->green[c],
- src->blue[c]);
- }
- }
- colorMap[c] = nc;
- }
- gdImageSetPixel(dst, tox, toy, colorMap[c]);
- tox++;
- }
- toy++;
- }
-}
-
-void gdImageCopyMerge(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
-{
-
- int c, dc;
- int x, y;
- int tox, toy;
- int i;
- int ncR, ncG, ncB;
- int colorMap[gdMaxColors];
- for (i=0; (i<gdMaxColors); i++) {
- colorMap[i] = (-1);
- }
- toy = dstY;
- for (y=srcY; (y < (srcY + h)); y++) {
- tox = dstX;
- for (x=srcX; (x < (srcX + w)); x++) {
- int nc;
- c = gdImageGetPixel(src, x, y);
- /* Added 7/24/95: support transparent copies */
- if (gdImageGetTransparent(src) == c) {
- tox++;
- continue;
- }
- /* Have we established a mapping for this color? */
- /*if (colorMap[c] == (-1)) { */
- /* If it's the same image, mapping is trivial */
- if (dst == src) {
- nc = c;
- } else {
- dc = gdImageGetPixel(dst, tox, toy);
-
- ncR = src->red[c] * (pct/100.0)
- + dst->red[dc] * ((100-pct)/100.0);
- ncG = src->green[c] * (pct/100.0)
- + dst->green[dc] * ((100-pct)/100.0);
- ncB = src->blue[c] * (pct/100.0)
- + dst->blue[dc] * ((100-pct)/100.0);
-
- /* First look for an exact match */
- nc = gdImageColorExact(dst,ncR, ncG, ncB);
- if (nc == (-1)) {
- /* No, so try to allocate it */
- nc = gdImageColorAllocate(dst, ncR, ncG, ncB);
- /* If we're out of colors, go for the
- closest color */
- if (nc == (-1)) {
- nc = gdImageColorClosest(dst, ncR, ncG, ncB);
- }
- }
- }
- /*colorMap[c] = nc; */
- /*} */
- gdImageSetPixel(dst, tox, toy, nc);
- tox++;
- }
- toy++;
- }
-}
-
-void gdImageCopyMergeGray(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
-{
-
- int c, dc;
- int x, y;
- int tox, toy;
- int i;
- int ncR, ncG, ncB;
- int colorMap[gdMaxColors];
- float g;
-
- for (i=0; (i<gdMaxColors); i++) {
- colorMap[i] = (-1);
- }
- toy = dstY;
- for (y=srcY; (y < (srcY + h)); y++) {
- tox = dstX;
- for (x=srcX; (x < (srcX + w)); x++) {
- int nc;
- c = gdImageGetPixel(src, x, y);
- /* Added 7/24/95: support transparent copies */
- if (gdImageGetTransparent(src) == c) {
- tox++;
- continue;
- }
-
-
- dc = gdImageGetPixel(dst, tox, toy);
- g = 0.29900*dst->red[dc]
- + 0.58700*dst->green[dc]
- + 0.11400*dst->blue[dc];
-
- ncR = src->red[c] * (pct/100.0)
- + g * ((100-pct)/100.0);
- ncG = src->green[c] * (pct/100.0)
- + g * ((100-pct)/100.0);
- ncB = src->blue[c] * (pct/100.0)
- + g * ((100-pct)/100.0);
-
- /* First look for an exact match */
- nc = gdImageColorExact(dst,ncR, ncG, ncB);
- if (nc == (-1)) {
- /* No, so try to allocate it */
- nc = gdImageColorAllocate(dst, ncR, ncG, ncB);
- /* If we're out of colors, go for the
- closest color */
- if (nc == (-1)) {
- nc = gdImageColorClosest(dst, ncR, ncG, ncB);
- }
- }
- gdImageSetPixel(dst, tox, toy, nc);
- tox++;
- }
- toy++;
- }
-}
-
-
-void gdImageCopyResized(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
-{
- int c;
- int x, y;
- int tox, toy;
- int ydest;
- int i;
- int colorMap[gdMaxColors];
- /* Stretch vectors */
- int *stx;
- int *sty;
- /* We only need to use floating point to determine the correct
- stretch vector for one line's worth. */
- double accum;
- stx = (int *) malloc(sizeof(int) * srcW);
- sty = (int *) malloc(sizeof(int) * srcH);
- accum = 0;
- for (i=0; (i < srcW); i++) {
- int got;
- accum += (double)dstW/(double)srcW;
- got = (int) floor(accum);
- stx[i] = got;
- accum -= got;
- }
- accum = 0;
- for (i=0; (i < srcH); i++) {
- int got;
- accum += (double)dstH/(double)srcH;
- got = (int) floor(accum);
- sty[i] = got;
- accum -= got;
- }
- for (i=0; (i<gdMaxColors); i++) {
- colorMap[i] = (-1);
- }
- toy = dstY;
- for (y=srcY; (y < (srcY + srcH)); y++) {
- for (ydest=0; (ydest < sty[y-srcY]); ydest++) {
- tox = dstX;
- for (x=srcX; (x < (srcX + srcW)); x++) {
- int nc;
- if (!stx[x - srcX]) {
- continue;
- }
- c = gdImageGetPixel(src, x, y);
- /* Added 7/24/95: support transparent copies */
- if (gdImageGetTransparent(src) == c) {
- tox += stx[x-srcX];
- continue;
- }
- /* Have we established a mapping for this color? */
- if (colorMap[c] == (-1)) {
- /* If it's the same image, mapping is trivial */
- if (dst == src) {
- nc = c;
- } else {
- /* First look for an exact match */
- nc = gdImageColorExact(dst,
- src->red[c], src->green[c],
- src->blue[c]);
- }
- if (nc == (-1)) {
- /* No, so try to allocate it */
- nc = gdImageColorAllocate(dst,
- src->red[c], src->green[c],
- src->blue[c]);
- /* If we're out of colors, go for the
- closest color */
- if (nc == (-1)) {
- nc = gdImageColorClosest(dst,
- src->red[c], src->green[c],
- src->blue[c]);
- }
- }
- colorMap[c] = nc;
- }
- for (i=0; (i < stx[x - srcX]); i++) {
- gdImageSetPixel(dst, tox, toy, colorMap[c]);
- tox++;
- }
- }
- toy++;
- }
- }
- free(stx);
- free(sty);
-}
-
-gdImagePtr
-gdImageCreateFromXbm(FILE *fd)
-{
- gdImagePtr im;
- int bit;
- int w, h;
- int bytes;
- int ch;
- int i, x, y;
- char *sp;
- char s[161];
- if (!fgets(s, 160, fd)) {
- return 0;
- }
- sp = &s[0];
- /* Skip #define */
- sp = strchr(sp, ' ');
- if (!sp) {
- return 0;
- }
- /* Skip width label */
- sp++;
- sp = strchr(sp, ' ');
- if (!sp) {
- return 0;
- }
- /* Get width */
- w = atoi(sp + 1);
- if (!w) {
- return 0;
- }
- if (!fgets(s, 160, fd)) {
- return 0;
- }
- sp = s;
- /* Skip #define */
- sp = strchr(sp, ' ');
- if (!sp) {
- return 0;
- }
- /* Skip height label */
- sp++;
- sp = strchr(sp, ' ');
- if (!sp) {
- return 0;
- }
- /* Get height */
- h = atoi(sp + 1);
- if (!h) {
- return 0;
- }
- /* Skip declaration line */
- if (!fgets(s, 160, fd)) {
- return 0;
- }
- bytes = (w * h / 8) + 1;
- im = gdImageCreate(w, h);
- gdImageColorAllocate(im, 255, 255, 255);
- gdImageColorAllocate(im, 0, 0, 0);
- x = 0;
- y = 0;
- for (i=0; (i < bytes); i++) {
- char h[3];
- int b;
- /* Skip spaces, commas, CRs, 0x */
- while(1) {
- ch = getc(fd);
- if (ch == EOF) {
- goto fail;
- }
- if (ch == 'x') {
- break;
- }
- }
- /* Get hex value */
- ch = getc(fd);
- if (ch == EOF) {
- goto fail;
- }
- h[0] = ch;
- ch = getc(fd);
- if (ch == EOF) {
- goto fail;
- }
- h[1] = ch;
- h[2] = '\0';
- sscanf(h, "%x", &b);
- for (bit = 1; (bit <= 128); (bit = bit << 1)) {
- gdImageSetPixel(im, x++, y, (b & bit) ? 1 : 0);
- if (x == im->sx) {
- x = 0;
- y++;
- if (y == im->sy) {
- return im;
- }
- /* Fix 8/8/95 */
- break;
- }
- }
- }
- /* Shouldn't happen */
- fprintf(stderr, "Error: bug in gdImageCreateFromXbm!\n");
- return 0;
-fail:
- gdImageDestroy(im);
- return 0;
-}
-
-void gdImagePolygon(gdImagePtr im, gdPointPtr p, int n, int c)
-{
- int i;
- int lx, ly;
- if (!n) {
- return;
- }
- lx = p->x;
- ly = p->y;
- gdImageLine(im, lx, ly, p[n-1].x, p[n-1].y, c);
- for (i=1; (i < n); i++) {
- p++;
- gdImageLine(im, lx, ly, p->x, p->y, c);
- lx = p->x;
- ly = p->y;
- }
-}
-
-int gdCompareInt(const void *a, const void *b);
-
-/* THANKS to Kirsten Schulz for the polygon fixes! */
-
-/* The intersection finding technique of this code could be improved */
-/* by remembering the previous intertersection, and by using the slope.*/
-/* That could help to adjust intersections to produce a nice */
-/* interior_extrema. */
-
-void gdImageFilledPolygon(gdImagePtr im, gdPointPtr p, int n, int c)
-{
- int i;
- int y;
- int miny, maxy;
- int x1, y1;
- int x2, y2;
- int ind1, ind2;
- int ints;
- if (!n) {
- return;
- }
- if (!im->polyAllocated) {
- im->polyInts = (int *) malloc(sizeof(int) * n);
- im->polyAllocated = n;
- }
- if (im->polyAllocated < n) {
- while (im->polyAllocated < n) {
- im->polyAllocated *= 2;
- }
- im->polyInts = (int *) realloc(im->polyInts,
- sizeof(int) * im->polyAllocated);
- }
- miny = p[0].y;
- maxy = p[0].y;
- for (i=1; (i < n); i++) {
- if (p[i].y < miny) {
- miny = p[i].y;
- }
- if (p[i].y > maxy) {
- maxy = p[i].y;
- }
- }
- /* Fix in 1.3: count a vertex only once */
- for (y=miny; (y < maxy); y++) {
-/*1.4 int interLast = 0; */
-/* int dirLast = 0; */
-/* int interFirst = 1; */
- ints = 0;
- for (i=0; (i < n); i++) {
- if (!i) {
- ind1 = n-1;
- ind2 = 0;
- } else {
- ind1 = i-1;
- ind2 = i;
- }
- y1 = p[ind1].y;
- y2 = p[ind2].y;
- if (y1 < y2) {
- x1 = p[ind1].x;
- x2 = p[ind2].x;
- } else if (y1 > y2) {
- y2 = p[ind1].y;
- y1 = p[ind2].y;
- x2 = p[ind1].x;
- x1 = p[ind2].x;
- } else {
- continue;
- }
- if ((y >= y1) && (y < y2)) {
- im->polyInts[ints++] = (y-y1) * (x2-x1) / (y2-y1) + x1;
- }
- }
- qsort(im->polyInts, ints, sizeof(int), gdCompareInt);
-
- for (i=0; (i < (ints)); i+=2) {
- gdImageLine(im, im->polyInts[i], y,
- im->polyInts[i+1], y, c);
- }
- }
-}
-
-int gdCompareInt(const void *a, const void *b)
-{
- return (*(const int *)a) - (*(const int *)b);
-}
-
-void gdImageSetStyle(gdImagePtr im, int *style, int noOfPixels)
-{
- if (im->style) {
- free(im->style);
- }
- im->style = (int *)
- malloc(sizeof(int) * noOfPixels);
- memcpy(im->style, style, sizeof(int) * noOfPixels);
- im->styleLength = noOfPixels;
- im->stylePos = 0;
-}
-
-void gdImageSetBrush(gdImagePtr im, gdImagePtr brush)
-{
- int i;
- im->brush = brush;
- for (i=0; (i < gdImageColorsTotal(brush)); i++) {
- int index;
- index = gdImageColorExact(im,
- gdImageRed(brush, i),
- gdImageGreen(brush, i),
- gdImageBlue(brush, i));
- if (index == (-1)) {
- index = gdImageColorAllocate(im,
- gdImageRed(brush, i),
- gdImageGreen(brush, i),
- gdImageBlue(brush, i));
- if (index == (-1)) {
- index = gdImageColorClosest(im,
- gdImageRed(brush, i),
- gdImageGreen(brush, i),
- gdImageBlue(brush, i));
- }
- }
- im->brushColorMap[i] = index;
- }
-}
-
-void gdImageSetTile(gdImagePtr im, gdImagePtr tile)
-{
- int i;
- im->tile = tile;
- for (i=0; (i < gdImageColorsTotal(tile)); i++) {
- int index;
- index = gdImageColorExact(im,
- gdImageRed(tile, i),
- gdImageGreen(tile, i),
- gdImageBlue(tile, i));
- if (index == (-1)) {
- index = gdImageColorAllocate(im,
- gdImageRed(tile, i),
- gdImageGreen(tile, i),
- gdImageBlue(tile, i));
- if (index == (-1)) {
- index = gdImageColorClosest(im,
- gdImageRed(tile, i),
- gdImageGreen(tile, i),
- gdImageBlue(tile, i));
- }
- }
- im->tileColorMap[i] = index;
- }
-}
-
-void gdImageInterlace(gdImagePtr im, int interlaceArg)
-{
- im->interlace = interlaceArg;
-}
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include <zlib.h>
+#include "gd.h"
+#include "mtables.c"
+
+static void gdImageBrushApply(gdImagePtr im, int x, int y);
+static void gdImageTileApply(gdImagePtr im, int x, int y);
+
+gdImagePtr gdImageCreate(int sx, int sy)
+{
+ int i;
+ gdImagePtr im;
+ im = (gdImage *) malloc(sizeof(gdImage));
+ /* NOW ROW-MAJOR IN GD 1.3 */
+ im->pixels = (unsigned char **) malloc(sizeof(unsigned char *) * sy);
+ im->polyInts = 0;
+ im->polyAllocated = 0;
+ im->brush = 0;
+ im->tile = 0;
+ im->style = 0;
+ for (i=0; (i<sy); i++) {
+ /* NOW ROW-MAJOR IN GD 1.3 */
+ im->pixels[i] = (unsigned char *) calloc(
+ sx, sizeof(unsigned char));
+ }
+ im->sx = sx;
+ im->sy = sy;
+ im->colorsTotal = 0;
+ im->transparent = (-1);
+ im->interlace = 0;
+
+ for (i=0; (i < gdMaxColors); i++) {
+ im->open[i] = 1;
+ im->red[i] = 0;
+ im->green[i] = 0;
+ im->blue[i] = 0;
+ };
+
+ return im;
+}
+
+void gdImageDestroy(gdImagePtr im)
+{
+ int i;
+ for (i=0; (i<im->sy); i++) {
+ free(im->pixels[i]);
+ }
+ free(im->pixels);
+ if (im->polyInts) {
+ free(im->polyInts);
+ }
+ if (im->style) {
+ free(im->style);
+ }
+ free(im);
+}
+
+int gdImageColorClosest(gdImagePtr im, int r, int g, int b)
+{
+ int i;
+ long rd, gd, bd;
+ int ct = (-1);
+ int first = 1;
+ long mindist = 0;
+ for (i=0; (i<(im->colorsTotal)); i++) {
+ long dist;
+ if (im->open[i]) {
+ continue;
+ }
+ rd = (im->red[i] - r);
+ gd = (im->green[i] - g);
+ bd = (im->blue[i] - b);
+ dist = rd * rd + gd * gd + bd * bd;
+ if (first || (dist < mindist)) {
+ mindist = dist;
+ ct = i;
+ first = 0;
+ }
+ }
+ return ct;
+}
+
+int gdImageColorExact(gdImagePtr im, int r, int g, int b)
+{
+ int i;
+ for (i=0; (i<(im->colorsTotal)); i++) {
+ if (im->open[i]) {
+ continue;
+ }
+ if ((im->red[i] == r) &&
+ (im->green[i] == g) &&
+ (im->blue[i] == b)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int gdImageColorAllocate(gdImagePtr im, int r, int g, int b)
+{
+ int i;
+ int ct = (-1);
+ for (i=0; (i<(im->colorsTotal)); i++) {
+ if (im->open[i]) {
+ ct = i;
+ break;
+ }
+ }
+ if (ct == (-1)) {
+ ct = im->colorsTotal;
+ if (ct == gdMaxColors) {
+ return -1;
+ }
+ im->colorsTotal++;
+ }
+ im->red[ct] = r;
+ im->green[ct] = g;
+ im->blue[ct] = b;
+ im->open[ct] = 0;
+ return ct;
+}
+
+void gdImageColorDeallocate(gdImagePtr im, int color)
+{
+ /* Mark it open. */
+ im->open[color] = 1;
+}
+
+void gdImageColorTransparent(gdImagePtr im, int color)
+{
+ im->transparent = color;
+}
+
+void gdImagePaletteCopy(gdImagePtr to, gdImagePtr from)
+{
+ int i;
+ int x, y, p;
+ int xlate[256];
+
+ for (i=0; i < 256 ; i++) {
+ xlate[i] = -1;
+ };
+
+ for (x=0 ; x < (to->sx) ; x++) {
+ for (y=0 ; y < (to->sy) ; y++) {
+ p = gdImageGetPixel(to, x, y);
+ if (xlate[p] == -1) {
+ xlate[p] = gdImageColorClosest(from, to->red[p], to->green[p], to->blue[p]);
+ /*printf("Mapping %d (%d, %d, %d) to %d (%d, %d, %d)\n", */
+ /* p, to->red[p], to->green[p], to->blue[p], */
+ /* xlate[p], from->red[xlate[p]], from->green[xlate[p]], from->blue[xlate[p]]); */
+ };
+ gdImageSetPixel(to, x, y, xlate[p]);
+ };
+ };
+
+ for (i=0; (i < (from->colorsTotal) ) ; i++) {
+ /*printf("Copying color %d (%d, %d, %d)\n", i, from->red[i], from->blue[i], from->green[i]); */
+ to->red[i] = from->red[i];
+ to->blue[i] = from->blue[i];
+ to->green[i] = from->green[i];
+ to->open[i] = 0;
+ };
+
+ for (i=from->colorsTotal ; (i < to->colorsTotal) ; i++) {
+ to->open[i] = 1;
+ };
+
+ to->colorsTotal = from->colorsTotal;
+
+}
+
+void gdImageSetPixel(gdImagePtr im, int x, int y, int color)
+{
+ int p;
+ switch(color) {
+ case gdStyled:
+ if (!im->style) {
+ /* Refuse to draw if no style is set. */
+ return;
+ } else {
+ p = im->style[im->stylePos++];
+ }
+ if (p != (gdTransparent)) {
+ gdImageSetPixel(im, x, y, p);
+ }
+ im->stylePos = im->stylePos % im->styleLength;
+ break;
+ case gdStyledBrushed:
+ if (!im->style) {
+ /* Refuse to draw if no style is set. */
+ return;
+ }
+ p = im->style[im->stylePos++];
+ if ((p != gdTransparent) && (p != 0)) {
+ gdImageSetPixel(im, x, y, gdBrushed);
+ }
+ im->stylePos = im->stylePos % im->styleLength;
+ break;
+ case gdBrushed:
+ gdImageBrushApply(im, x, y);
+ break;
+ case gdTiled:
+ gdImageTileApply(im, x, y);
+ break;
+ default:
+ if (gdImageBoundsSafe(im, x, y)) {
+ /* NOW ROW-MAJOR IN GD 1.3 */
+ im->pixels[y][x] = color;
+ }
+ break;
+ }
+}
+
+static void gdImageBrushApply(gdImagePtr im, int x, int y)
+{
+ int lx, ly;
+ int hy;
+ int hx;
+ int x1, y1, x2, y2;
+ int srcx, srcy;
+ if (!im->brush) {
+ return;
+ }
+ hy = gdImageSY(im->brush)/2;
+ y1 = y - hy;
+ y2 = y1 + gdImageSY(im->brush);
+ hx = gdImageSX(im->brush)/2;
+ x1 = x - hx;
+ x2 = x1 + gdImageSX(im->brush);
+ srcy = 0;
+ for (ly = y1; (ly < y2); ly++) {
+ srcx = 0;
+ for (lx = x1; (lx < x2); lx++) {
+ int p;
+ p = gdImageGetPixel(im->brush, srcx, srcy);
+ /* Allow for non-square brushes! */
+ if (p != gdImageGetTransparent(im->brush)) {
+ gdImageSetPixel(im, lx, ly,
+ im->brushColorMap[p]);
+ }
+ srcx++;
+ }
+ srcy++;
+ }
+}
+
+static void gdImageTileApply(gdImagePtr im, int x, int y)
+{
+ int srcx, srcy;
+ int p;
+ if (!im->tile) {
+ return;
+ }
+ srcx = x % gdImageSX(im->tile);
+ srcy = y % gdImageSY(im->tile);
+ p = gdImageGetPixel(im->tile, srcx, srcy);
+ /* Allow for transparency */
+ if (p != gdImageGetTransparent(im->tile)) {
+ gdImageSetPixel(im, x, y,
+ im->tileColorMap[p]);
+ }
+}
+
+int gdImageGetPixel(gdImagePtr im, int x, int y)
+{
+ if (gdImageBoundsSafe(im, x, y)) {
+ /* NOW ROW-MAJOR IN GD 1.3 */
+ return im->pixels[y][x];
+ } else {
+ return 0;
+ }
+}
+
+/* Bresenham as presented in Foley & Van Dam */
+
+void gdImageLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
+{
+ int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
+ dx = abs(x2-x1);
+ dy = abs(y2-y1);
+ if (dy <= dx) {
+ d = 2*dy - dx;
+ incr1 = 2*dy;
+ incr2 = 2 * (dy - dx);
+ if (x1 > x2) {
+ x = x2;
+ y = y2;
+ ydirflag = (-1);
+ xend = x1;
+ } else {
+ x = x1;
+ y = y1;
+ ydirflag = 1;
+ xend = x2;
+ }
+ gdImageSetPixel(im, x, y, color);
+ if (((y2 - y1) * ydirflag) > 0) {
+ while (x < xend) {
+ x++;
+ if (d <0) {
+ d+=incr1;
+ } else {
+ y++;
+ d+=incr2;
+ }
+ gdImageSetPixel(im, x, y, color);
+ }
+ } else {
+ while (x < xend) {
+ x++;
+ if (d <0) {
+ d+=incr1;
+ } else {
+ y--;
+ d+=incr2;
+ }
+ gdImageSetPixel(im, x, y, color);
+ }
+ }
+ } else {
+ d = 2*dx - dy;
+ incr1 = 2*dx;
+ incr2 = 2 * (dx - dy);
+ if (y1 > y2) {
+ y = y2;
+ x = x2;
+ yend = y1;
+ xdirflag = (-1);
+ } else {
+ y = y1;
+ x = x1;
+ yend = y2;
+ xdirflag = 1;
+ }
+ gdImageSetPixel(im, x, y, color);
+ if (((x2 - x1) * xdirflag) > 0) {
+ while (y < yend) {
+ y++;
+ if (d <0) {
+ d+=incr1;
+ } else {
+ x++;
+ d+=incr2;
+ }
+ gdImageSetPixel(im, x, y, color);
+ }
+ } else {
+ while (y < yend) {
+ y++;
+ if (d <0) {
+ d+=incr1;
+ } else {
+ x--;
+ d+=incr2;
+ }
+ gdImageSetPixel(im, x, y, color);
+ }
+ }
+ }
+}
+
+static void dashedSet(gdImagePtr im, int x, int y, int color,
+ int *onP, int *dashStepP);
+
+void gdImageDashedLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
+{
+ int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
+ int dashStep = 0;
+ int on = 1;
+ dx = abs(x2-x1);
+ dy = abs(y2-y1);
+ if (dy <= dx) {
+ d = 2*dy - dx;
+ incr1 = 2*dy;
+ incr2 = 2 * (dy - dx);
+ if (x1 > x2) {
+ x = x2;
+ y = y2;
+ ydirflag = (-1);
+ xend = x1;
+ } else {
+ x = x1;
+ y = y1;
+ ydirflag = 1;
+ xend = x2;
+ }
+ dashedSet(im, x, y, color, &on, &dashStep);
+ if (((y2 - y1) * ydirflag) > 0) {
+ while (x < xend) {
+ x++;
+ if (d <0) {
+ d+=incr1;
+ } else {
+ y++;
+ d+=incr2;
+ }
+ dashedSet(im, x, y, color, &on, &dashStep);
+ }
+ } else {
+ while (x < xend) {
+ x++;
+ if (d <0) {
+ d+=incr1;
+ } else {
+ y--;
+ d+=incr2;
+ }
+ dashedSet(im, x, y, color, &on, &dashStep);
+ }
+ }
+ } else {
+ d = 2*dx - dy;
+ incr1 = 2*dx;
+ incr2 = 2 * (dx - dy);
+ if (y1 > y2) {
+ y = y2;
+ x = x2;
+ yend = y1;
+ xdirflag = (-1);
+ } else {
+ y = y1;
+ x = x1;
+ yend = y2;
+ xdirflag = 1;
+ }
+ dashedSet(im, x, y, color, &on, &dashStep);
+ if (((x2 - x1) * xdirflag) > 0) {
+ while (y < yend) {
+ y++;
+ if (d <0) {
+ d+=incr1;
+ } else {
+ x++;
+ d+=incr2;
+ }
+ dashedSet(im, x, y, color, &on, &dashStep);
+ }
+ } else {
+ while (y < yend) {
+ y++;
+ if (d <0) {
+ d+=incr1;
+ } else {
+ x--;
+ d+=incr2;
+ }
+ dashedSet(im, x, y, color, &on, &dashStep);
+ }
+ }
+ }
+}
+
+static void dashedSet(gdImagePtr im, int x, int y, int color,
+ int *onP, int *dashStepP)
+{
+ int dashStep = *dashStepP;
+ int on = *onP;
+ dashStep++;
+ if (dashStep == gdDashSize) {
+ dashStep = 0;
+ on = !on;
+ }
+ if (on) {
+ gdImageSetPixel(im, x, y, color);
+ }
+ *dashStepP = dashStep;
+ *onP = on;
+}
+
+
+int gdImageBoundsSafe(gdImagePtr im, int x, int y)
+{
+ return (!(((y < 0) || (y >= im->sy)) ||
+ ((x < 0) || (x >= im->sx))));
+}
+
+void gdImageChar(gdImagePtr im, gdFontPtr f, int x, int y,
+ int c, int color)
+{
+ int cx, cy;
+ int px, py;
+ int fline;
+ cx = 0;
+ cy = 0;
+ if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
+ return;
+ }
+ fline = (c - f->offset) * f->h * f->w;
+ for (py = y; (py < (y + f->h)); py++) {
+ for (px = x; (px < (x + f->w)); px++) {
+ if (f->data[fline + cy * f->w + cx]) {
+ gdImageSetPixel(im, px, py, color);
+ }
+ cx++;
+ }
+ cx = 0;
+ cy++;
+ }
+}
+
+void gdImageCharUp(gdImagePtr im, gdFontPtr f,
+ int x, int y, int c, int color)
+{
+ int cx, cy;
+ int px, py;
+ int fline;
+ cx = 0;
+ cy = 0;
+ if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
+ return;
+ }
+ fline = (c - f->offset) * f->h * f->w;
+ for (py = y; (py > (y - f->w)); py--) {
+ for (px = x; (px < (x + f->h)); px++) {
+ if (f->data[fline + cy * f->w + cx]) {
+ gdImageSetPixel(im, px, py, color);
+ }
+ cy++;
+ }
+ cy = 0;
+ cx++;
+ }
+}
+
+void gdImageString(gdImagePtr im, gdFontPtr f,
+ int x, int y, unsigned char *s, int color)
+{
+ int i;
+ int l;
+ l = strlen(s);
+ for (i=0; (i<l); i++) {
+ gdImageChar(im, f, x, y, s[i], color);
+ x += f->w;
+ }
+}
+
+void gdImageStringUp(gdImagePtr im, gdFontPtr f,
+ int x, int y, unsigned char *s, int color)
+{
+ int i;
+ int l;
+ l = strlen(s);
+ for (i=0; (i<l); i++) {
+ gdImageCharUp(im, f, x, y, s[i], color);
+ y -= f->w;
+ }
+}
+
+static int strlen16(unsigned short *s);
+
+void gdImageString16(gdImagePtr im, gdFontPtr f,
+ int x, int y, unsigned short *s, int color)
+{
+ int i;
+ int l;
+ l = strlen16(s);
+ for (i=0; (i<l); i++) {
+ gdImageChar(im, f, x, y, s[i], color);
+ x += f->w;
+ }
+}
+
+void gdImageStringUp16(gdImagePtr im, gdFontPtr f,
+ int x, int y, unsigned short *s, int color)
+{
+ int i;
+ int l;
+ l = strlen16(s);
+ for (i=0; (i<l); i++) {
+ gdImageCharUp(im, f, x, y, s[i], color);
+ y -= f->w;
+ }
+}
+
+static int strlen16(unsigned short *s)
+{
+ int len = 0;
+ while (*s) {
+ s++;
+ len++;
+ }
+ return len;
+}
+
+/* s and e are integers modulo 360 (degrees), with 0 degrees
+ being the rightmost extreme and degrees changing clockwise.
+ cx and cy are the center in pixels; w and h are the horizontal
+ and vertical diameter in pixels. Nice interface, but slow, since
+ I don't yet use Bresenham (I'm using an inefficient but
+ simple solution with too much work going on in it; generalizing
+ Bresenham to ellipses and partial arcs of ellipses is non-trivial,
+ at least for me) and there are other inefficiencies (small circles
+ do far too much work). */
+
+void gdImageArc(gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color)
+{
+ int i;
+ int lx = 0, ly = 0;
+ int w2, h2;
+ w2 = w/2;
+ h2 = h/2;
+ while (e < s) {
+ e += 360;
+ }
+ for (i=s; (i <= e); i++) {
+ int x, y;
+ x = ((long)cost[i % 360] * (long)w2 / costScale) + cx;
+ y = ((long)sint[i % 360] * (long)h2 / sintScale) + cy;
+ if (i != s) {
+ gdImageLine(im, lx, ly, x, y, color);
+ }
+ lx = x;
+ ly = y;
+ }
+}
+
+
+#if 0
+ /* Bresenham octant code, which I should use eventually */
+ int x, y, d;
+ x = 0;
+ y = w;
+ d = 3-2*w;
+ while (x < y) {
+ gdImageSetPixel(im, cx+x, cy+y, color);
+ if (d < 0) {
+ d += 4 * x + 6;
+ } else {
+ d += 4 * (x - y) + 10;
+ y--;
+ }
+ x++;
+ }
+ if (x == y) {
+ gdImageSetPixel(im, cx+x, cy+y, color);
+ }
+#endif
+
+void gdImageFillToBorder(gdImagePtr im, int x, int y, int border, int color)
+{
+ int lastBorder;
+ /* Seek left */
+ int leftLimit, rightLimit;
+ int i;
+ leftLimit = (-1);
+ if (border < 0) {
+ /* Refuse to fill to a non-solid border */
+ return;
+ }
+ for (i = x; (i >= 0); i--) {
+ if (gdImageGetPixel(im, i, y) == border) {
+ break;
+ }
+ gdImageSetPixel(im, i, y, color);
+ leftLimit = i;
+ }
+ if (leftLimit == (-1)) {
+ return;
+ }
+ /* Seek right */
+ rightLimit = x;
+ for (i = (x+1); (i < im->sx); i++) {
+ if (gdImageGetPixel(im, i, y) == border) {
+ break;
+ }
+ gdImageSetPixel(im, i, y, color);
+ rightLimit = i;
+ }
+ /* Look at lines above and below and start paints */
+ /* Above */
+ if (y > 0) {
+ lastBorder = 1;
+ for (i = leftLimit; (i <= rightLimit); i++) {
+ int c;
+ c = gdImageGetPixel(im, i, y-1);
+ if (lastBorder) {
+ if ((c != border) && (c != color)) {
+ gdImageFillToBorder(im, i, y-1,
+ border, color);
+ lastBorder = 0;
+ }
+ } else if ((c == border) || (c == color)) {
+ lastBorder = 1;
+ }
+ }
+ }
+ /* Below */
+ if (y < ((im->sy) - 1)) {
+ lastBorder = 1;
+ for (i = leftLimit; (i <= rightLimit); i++) {
+ int c;
+ c = gdImageGetPixel(im, i, y+1);
+ if (lastBorder) {
+ if ((c != border) && (c != color)) {
+ gdImageFillToBorder(im, i, y+1,
+ border, color);
+ lastBorder = 0;
+ }
+ } else if ((c == border) || (c == color)) {
+ lastBorder = 1;
+ }
+ }
+ }
+}
+
+void gdImageFill(gdImagePtr im, int x, int y, int color)
+{
+ int lastBorder;
+ int old;
+ int leftLimit, rightLimit;
+ int i;
+ old = gdImageGetPixel(im, x, y);
+ if (color == gdTiled) {
+ /* Tile fill -- got to watch out! */
+ int p, tileColor;
+ int srcx, srcy;
+ if (!im->tile) {
+ return;
+ }
+ /* Refuse to flood-fill with a transparent pattern --
+ I can't do it without allocating another image */
+ if (gdImageGetTransparent(im->tile) != (-1)) {
+ return;
+ }
+ srcx = x % gdImageSX(im->tile);
+ srcy = y % gdImageSY(im->tile);
+ p = gdImageGetPixel(im->tile, srcx, srcy);
+ tileColor = im->tileColorMap[p];
+ if (old == tileColor) {
+ /* Nothing to be done */
+ return;
+ }
+ } else {
+ if (old == color) {
+ /* Nothing to be done */
+ return;
+ }
+ }
+ /* Seek left */
+ leftLimit = (-1);
+ for (i = x; (i >= 0); i--) {
+ if (gdImageGetPixel(im, i, y) != old) {
+ break;
+ }
+ gdImageSetPixel(im, i, y, color);
+ leftLimit = i;
+ }
+ if (leftLimit == (-1)) {
+ return;
+ }
+ /* Seek right */
+ rightLimit = x;
+ for (i = (x+1); (i < im->sx); i++) {
+ if (gdImageGetPixel(im, i, y) != old) {
+ break;
+ }
+ gdImageSetPixel(im, i, y, color);
+ rightLimit = i;
+ }
+ /* Look at lines above and below and start paints */
+ /* Above */
+ if (y > 0) {
+ lastBorder = 1;
+ for (i = leftLimit; (i <= rightLimit); i++) {
+ int c;
+ c = gdImageGetPixel(im, i, y-1);
+ if (lastBorder) {
+ if (c == old) {
+ gdImageFill(im, i, y-1, color);
+ lastBorder = 0;
+ }
+ } else if (c != old) {
+ lastBorder = 1;
+ }
+ }
+ }
+ /* Below */
+ if (y < ((im->sy) - 1)) {
+ lastBorder = 1;
+ for (i = leftLimit; (i <= rightLimit); i++) {
+ int c;
+ c = gdImageGetPixel(im, i, y+1);
+ if (lastBorder) {
+ if (c == old) {
+ gdImageFill(im, i, y+1, color);
+ lastBorder = 0;
+ }
+ } else if (c != old) {
+ lastBorder = 1;
+ }
+ }
+ }
+}
+
+void gdImageRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
+{
+ gdImageLine(im, x1, y1, x2, y1, color);
+ gdImageLine(im, x1, y2, x2, y2, color);
+ gdImageLine(im, x1, y1, x1, y2, color);
+ gdImageLine(im, x2, y1, x2, y2, color);
+}
+
+void gdImageFilledRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
+{
+ int x, y;
+ for (y=y1; (y<=y2); y++) {
+ for (x=x1; (x<=x2); x++) {
+ gdImageSetPixel(im, x, y, color);
+ }
+ }
+}
+
+void gdImageCopy(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h)
+{
+ int c;
+ int x, y;
+ int tox, toy;
+ int i;
+ int colorMap[gdMaxColors];
+ for (i=0; (i<gdMaxColors); i++) {
+ colorMap[i] = (-1);
+ }
+ toy = dstY;
+ for (y=srcY; (y < (srcY + h)); y++) {
+ tox = dstX;
+ for (x=srcX; (x < (srcX + w)); x++) {
+ int nc;
+ c = gdImageGetPixel(src, x, y);
+ /* Added 7/24/95: support transparent copies */
+ if (gdImageGetTransparent(src) == c) {
+ tox++;
+ continue;
+ }
+ /* Have we established a mapping for this color? */
+ if (colorMap[c] == (-1)) {
+ /* If it's the same image, mapping is trivial */
+ if (dst == src) {
+ nc = c;
+ } else {
+ /* First look for an exact match */
+ nc = gdImageColorExact(dst,
+ src->red[c], src->green[c],
+ src->blue[c]);
+ }
+ if (nc == (-1)) {
+ /* No, so try to allocate it */
+ nc = gdImageColorAllocate(dst,
+ src->red[c], src->green[c],
+ src->blue[c]);
+ /* If we're out of colors, go for the
+ closest color */
+ if (nc == (-1)) {
+ nc = gdImageColorClosest(dst,
+ src->red[c], src->green[c],
+ src->blue[c]);
+ }
+ }
+ colorMap[c] = nc;
+ }
+ gdImageSetPixel(dst, tox, toy, colorMap[c]);
+ tox++;
+ }
+ toy++;
+ }
+}
+
+void gdImageCopyMerge(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
+{
+
+ int c, dc;
+ int x, y;
+ int tox, toy;
+ int i;
+ int ncR, ncG, ncB;
+ int colorMap[gdMaxColors];
+ for (i=0; (i<gdMaxColors); i++) {
+ colorMap[i] = (-1);
+ }
+ toy = dstY;
+ for (y=srcY; (y < (srcY + h)); y++) {
+ tox = dstX;
+ for (x=srcX; (x < (srcX + w)); x++) {
+ int nc;
+ c = gdImageGetPixel(src, x, y);
+ /* Added 7/24/95: support transparent copies */
+ if (gdImageGetTransparent(src) == c) {
+ tox++;
+ continue;
+ }
+ /* Have we established a mapping for this color? */
+ /*if (colorMap[c] == (-1)) { */
+ /* If it's the same image, mapping is trivial */
+ if (dst == src) {
+ nc = c;
+ } else {
+ dc = gdImageGetPixel(dst, tox, toy);
+
+ ncR = src->red[c] * (pct/100.0)
+ + dst->red[dc] * ((100-pct)/100.0);
+ ncG = src->green[c] * (pct/100.0)
+ + dst->green[dc] * ((100-pct)/100.0);
+ ncB = src->blue[c] * (pct/100.0)
+ + dst->blue[dc] * ((100-pct)/100.0);
+
+ /* First look for an exact match */
+ nc = gdImageColorExact(dst,ncR, ncG, ncB);
+ if (nc == (-1)) {
+ /* No, so try to allocate it */
+ nc = gdImageColorAllocate(dst, ncR, ncG, ncB);
+ /* If we're out of colors, go for the
+ closest color */
+ if (nc == (-1)) {
+ nc = gdImageColorClosest(dst, ncR, ncG, ncB);
+ }
+ }
+ }
+ /*colorMap[c] = nc; */
+ /*} */
+ gdImageSetPixel(dst, tox, toy, nc);
+ tox++;
+ }
+ toy++;
+ }
+}
+
+void gdImageCopyMergeGray(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
+{
+
+ int c, dc;
+ int x, y;
+ int tox, toy;
+ int i;
+ int ncR, ncG, ncB;
+ int colorMap[gdMaxColors];
+ float g;
+
+ for (i=0; (i<gdMaxColors); i++) {
+ colorMap[i] = (-1);
+ }
+ toy = dstY;
+ for (y=srcY; (y < (srcY + h)); y++) {
+ tox = dstX;
+ for (x=srcX; (x < (srcX + w)); x++) {
+ int nc;
+ c = gdImageGetPixel(src, x, y);
+ /* Added 7/24/95: support transparent copies */
+ if (gdImageGetTransparent(src) == c) {
+ tox++;
+ continue;
+ }
+
+
+ dc = gdImageGetPixel(dst, tox, toy);
+ g = 0.29900*dst->red[dc]
+ + 0.58700*dst->green[dc]
+ + 0.11400*dst->blue[dc];
+
+ ncR = src->red[c] * (pct/100.0)
+ + g * ((100-pct)/100.0);
+ ncG = src->green[c] * (pct/100.0)
+ + g * ((100-pct)/100.0);
+ ncB = src->blue[c] * (pct/100.0)
+ + g * ((100-pct)/100.0);
+
+ /* First look for an exact match */
+ nc = gdImageColorExact(dst,ncR, ncG, ncB);
+ if (nc == (-1)) {
+ /* No, so try to allocate it */
+ nc = gdImageColorAllocate(dst, ncR, ncG, ncB);
+ /* If we're out of colors, go for the
+ closest color */
+ if (nc == (-1)) {
+ nc = gdImageColorClosest(dst, ncR, ncG, ncB);
+ }
+ }
+ gdImageSetPixel(dst, tox, toy, nc);
+ tox++;
+ }
+ toy++;
+ }
+}
+
+
+void gdImageCopyResized(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
+{
+ int c;
+ int x, y;
+ int tox, toy;
+ int ydest;
+ int i;
+ int colorMap[gdMaxColors];
+ /* Stretch vectors */
+ int *stx;
+ int *sty;
+ /* We only need to use floating point to determine the correct
+ stretch vector for one line's worth. */
+ double accum;
+ stx = (int *) malloc(sizeof(int) * srcW);
+ sty = (int *) malloc(sizeof(int) * srcH);
+ accum = 0;
+ for (i=0; (i < srcW); i++) {
+ int got;
+ accum += (double)dstW/(double)srcW;
+ got = (int) floor(accum);
+ stx[i] = got;
+ accum -= got;
+ }
+ accum = 0;
+ for (i=0; (i < srcH); i++) {
+ int got;
+ accum += (double)dstH/(double)srcH;
+ got = (int) floor(accum);
+ sty[i] = got;
+ accum -= got;
+ }
+ for (i=0; (i<gdMaxColors); i++) {
+ colorMap[i] = (-1);
+ }
+ toy = dstY;
+ for (y=srcY; (y < (srcY + srcH)); y++) {
+ for (ydest=0; (ydest < sty[y-srcY]); ydest++) {
+ tox = dstX;
+ for (x=srcX; (x < (srcX + srcW)); x++) {
+ int nc;
+ if (!stx[x - srcX]) {
+ continue;
+ }
+ c = gdImageGetPixel(src, x, y);
+ /* Added 7/24/95: support transparent copies */
+ if (gdImageGetTransparent(src) == c) {
+ tox += stx[x-srcX];
+ continue;
+ }
+ /* Have we established a mapping for this color? */
+ if (colorMap[c] == (-1)) {
+ /* If it's the same image, mapping is trivial */
+ if (dst == src) {
+ nc = c;
+ } else {
+ /* First look for an exact match */
+ nc = gdImageColorExact(dst,
+ src->red[c], src->green[c],
+ src->blue[c]);
+ }
+ if (nc == (-1)) {
+ /* No, so try to allocate it */
+ nc = gdImageColorAllocate(dst,
+ src->red[c], src->green[c],
+ src->blue[c]);
+ /* If we're out of colors, go for the
+ closest color */
+ if (nc == (-1)) {
+ nc = gdImageColorClosest(dst,
+ src->red[c], src->green[c],
+ src->blue[c]);
+ }
+ }
+ colorMap[c] = nc;
+ }
+ for (i=0; (i < stx[x - srcX]); i++) {
+ gdImageSetPixel(dst, tox, toy, colorMap[c]);
+ tox++;
+ }
+ }
+ toy++;
+ }
+ }
+ free(stx);
+ free(sty);
+}
+
+gdImagePtr
+gdImageCreateFromXbm(FILE *fd)
+{
+ gdImagePtr im;
+ int bit;
+ int w, h;
+ int bytes;
+ int ch;
+ int i, x, y;
+ char *sp;
+ char s[161];
+ if (!fgets(s, 160, fd)) {
+ return 0;
+ }
+ sp = &s[0];
+ /* Skip #define */
+ sp = strchr(sp, ' ');
+ if (!sp) {
+ return 0;
+ }
+ /* Skip width label */
+ sp++;
+ sp = strchr(sp, ' ');
+ if (!sp) {
+ return 0;
+ }
+ /* Get width */
+ w = atoi(sp + 1);
+ if (!w) {
+ return 0;
+ }
+ if (!fgets(s, 160, fd)) {
+ return 0;
+ }
+ sp = s;
+ /* Skip #define */
+ sp = strchr(sp, ' ');
+ if (!sp) {
+ return 0;
+ }
+ /* Skip height label */
+ sp++;
+ sp = strchr(sp, ' ');
+ if (!sp) {
+ return 0;
+ }
+ /* Get height */
+ h = atoi(sp + 1);
+ if (!h) {
+ return 0;
+ }
+ /* Skip declaration line */
+ if (!fgets(s, 160, fd)) {
+ return 0;
+ }
+ bytes = (w * h / 8) + 1;
+ im = gdImageCreate(w, h);
+ gdImageColorAllocate(im, 255, 255, 255);
+ gdImageColorAllocate(im, 0, 0, 0);
+ x = 0;
+ y = 0;
+ for (i=0; (i < bytes); i++) {
+ char h[3];
+ int b;
+ /* Skip spaces, commas, CRs, 0x */
+ while(1) {
+ ch = getc(fd);
+ if (ch == EOF) {
+ goto fail;
+ }
+ if (ch == 'x') {
+ break;
+ }
+ }
+ /* Get hex value */
+ ch = getc(fd);
+ if (ch == EOF) {
+ goto fail;
+ }
+ h[0] = ch;
+ ch = getc(fd);
+ if (ch == EOF) {
+ goto fail;
+ }
+ h[1] = ch;
+ h[2] = '\0';
+ sscanf(h, "%x", &b);
+ for (bit = 1; (bit <= 128); (bit = bit << 1)) {
+ gdImageSetPixel(im, x++, y, (b & bit) ? 1 : 0);
+ if (x == im->sx) {
+ x = 0;
+ y++;
+ if (y == im->sy) {
+ return im;
+ }
+ /* Fix 8/8/95 */
+ break;
+ }
+ }
+ }
+ /* Shouldn't happen */
+ fprintf(stderr, "Error: bug in gdImageCreateFromXbm!\n");
+ return 0;
+fail:
+ gdImageDestroy(im);
+ return 0;
+}
+
+void gdImagePolygon(gdImagePtr im, gdPointPtr p, int n, int c)
+{
+ int i;
+ int lx, ly;
+ if (!n) {
+ return;
+ }
+ lx = p->x;
+ ly = p->y;
+ gdImageLine(im, lx, ly, p[n-1].x, p[n-1].y, c);
+ for (i=1; (i < n); i++) {
+ p++;
+ gdImageLine(im, lx, ly, p->x, p->y, c);
+ lx = p->x;
+ ly = p->y;
+ }
+}
+
+int gdCompareInt(const void *a, const void *b);
+
+/* THANKS to Kirsten Schulz for the polygon fixes! */
+
+/* The intersection finding technique of this code could be improved */
+/* by remembering the previous intertersection, and by using the slope.*/
+/* That could help to adjust intersections to produce a nice */
+/* interior_extrema. */
+
+void gdImageFilledPolygon(gdImagePtr im, gdPointPtr p, int n, int c)
+{
+ int i;
+ int y;
+ int miny, maxy;
+ int x1, y1;
+ int x2, y2;
+ int ind1, ind2;
+ int ints;
+ if (!n) {
+ return;
+ }
+ if (!im->polyAllocated) {
+ im->polyInts = (int *) malloc(sizeof(int) * n);
+ im->polyAllocated = n;
+ }
+ if (im->polyAllocated < n) {
+ while (im->polyAllocated < n) {
+ im->polyAllocated *= 2;
+ }
+ im->polyInts = (int *) realloc(im->polyInts,
+ sizeof(int) * im->polyAllocated);
+ }
+ miny = p[0].y;
+ maxy = p[0].y;
+ for (i=1; (i < n); i++) {
+ if (p[i].y < miny) {
+ miny = p[i].y;
+ }
+ if (p[i].y > maxy) {
+ maxy = p[i].y;
+ }
+ }
+ /* Fix in 1.3: count a vertex only once */
+ for (y=miny; (y < maxy); y++) {
+/*1.4 int interLast = 0; */
+/* int dirLast = 0; */
+/* int interFirst = 1; */
+ ints = 0;
+ for (i=0; (i < n); i++) {
+ if (!i) {
+ ind1 = n-1;
+ ind2 = 0;
+ } else {
+ ind1 = i-1;
+ ind2 = i;
+ }
+ y1 = p[ind1].y;
+ y2 = p[ind2].y;
+ if (y1 < y2) {
+ x1 = p[ind1].x;
+ x2 = p[ind2].x;
+ } else if (y1 > y2) {
+ y2 = p[ind1].y;
+ y1 = p[ind2].y;
+ x2 = p[ind1].x;
+ x1 = p[ind2].x;
+ } else {
+ continue;
+ }
+ if ((y >= y1) && (y < y2)) {
+ im->polyInts[ints++] = (y-y1) * (x2-x1) / (y2-y1) + x1;
+ }
+ }
+ qsort(im->polyInts, ints, sizeof(int), gdCompareInt);
+
+ for (i=0; (i < (ints)); i+=2) {
+ gdImageLine(im, im->polyInts[i], y,
+ im->polyInts[i+1], y, c);
+ }
+ }
+}
+
+int gdCompareInt(const void *a, const void *b)
+{
+ return (*(const int *)a) - (*(const int *)b);
+}
+
+void gdImageSetStyle(gdImagePtr im, int *style, int noOfPixels)
+{
+ if (im->style) {
+ free(im->style);
+ }
+ im->style = (int *)
+ malloc(sizeof(int) * noOfPixels);
+ memcpy(im->style, style, sizeof(int) * noOfPixels);
+ im->styleLength = noOfPixels;
+ im->stylePos = 0;
+}
+
+void gdImageSetBrush(gdImagePtr im, gdImagePtr brush)
+{
+ int i;
+ im->brush = brush;
+ for (i=0; (i < gdImageColorsTotal(brush)); i++) {
+ int index;
+ index = gdImageColorExact(im,
+ gdImageRed(brush, i),
+ gdImageGreen(brush, i),
+ gdImageBlue(brush, i));
+ if (index == (-1)) {
+ index = gdImageColorAllocate(im,
+ gdImageRed(brush, i),
+ gdImageGreen(brush, i),
+ gdImageBlue(brush, i));
+ if (index == (-1)) {
+ index = gdImageColorClosest(im,
+ gdImageRed(brush, i),
+ gdImageGreen(brush, i),
+ gdImageBlue(brush, i));
+ }
+ }
+ im->brushColorMap[i] = index;
+ }
+}
+
+void gdImageSetTile(gdImagePtr im, gdImagePtr tile)
+{
+ int i;
+ im->tile = tile;
+ for (i=0; (i < gdImageColorsTotal(tile)); i++) {
+ int index;
+ index = gdImageColorExact(im,
+ gdImageRed(tile, i),
+ gdImageGreen(tile, i),
+ gdImageBlue(tile, i));
+ if (index == (-1)) {
+ index = gdImageColorAllocate(im,
+ gdImageRed(tile, i),
+ gdImageGreen(tile, i),
+ gdImageBlue(tile, i));
+ if (index == (-1)) {
+ index = gdImageColorClosest(im,
+ gdImageRed(tile, i),
+ gdImageGreen(tile, i),
+ gdImageBlue(tile, i));
+ }
+ }
+ im->tileColorMap[i] = index;
+ }
+}
+
+void gdImageInterlace(gdImagePtr im, int interlaceArg)
+{
+ im->interlace = interlaceArg;
+}
diff --git a/src/gd.h b/src/gd.h
index e86fb93..7d0f3e5 100644
--- a/src/gd.h
+++ b/src/gd.h
@@ -1,30 +1,22 @@
#ifndef GD_H
#define GD_H 1
-/* gd.h: declarations file for the gifdraw module.
-
- Written by Tom Boutell, 5/94.
- Copyright 1994, Cold Spring Harbor Labs.
- Permission granted to use this code in any fashion provided
- that this notice is retained and any alterations are
- labeled as such. It is requested, but not required, that
- you share extensions to this module with us so that we
- can incorporate them into new versions. */
+/* gd.h: declarations file for the graphic-draw module.
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. This software is provided "AS IS." Thomas Boutell and
+ * Boutell.Com, Inc. disclaim all warranties, either express or implied,
+ * including but not limited to implied warranties of merchantability and
+ * fitness for a particular purpose, with respect to this code and accompanying
+ * documentation. */
/* stdio is needed for file I/O. */
#include <stdio.h>
-#include "io.h"
-
-/* Uncomment this line if you are licensed to use LZW compression.
- Licensing LZW is strictly between you and the Unisys corporation.
- The authors of GD can provide NO INFORMATION WHATSOEVER
- regarding licensing of LZW compression.
-*/
-
-/* #define LZW_LICENCED */
-
+#include "gd_io.h"
-/* This can't be changed, it's part of the GIF specification. */
+/* This can't be changed in the current palette-only version of gd. */
#define gdMaxColors 256
@@ -93,8 +85,8 @@ typedef gdFont *gdFontPtr;
/* Functions to manipulate images. */
gdImagePtr gdImageCreate(int sx, int sy);
-gdImagePtr gdImageCreateFromGif(FILE *fd);
-gdImagePtr gdImageCreateFromGifCtx(gdIOCtxPtr in);
+gdImagePtr gdImageCreateFromPng(FILE *fd);
+gdImagePtr gdImageCreateFromPngCtx(gdIOCtxPtr in);
/* A custom data source. */
/* The source function must return -1 on error, otherwise the number
@@ -106,7 +98,7 @@ typedef struct {
void *context;
} gdSource, *gdSourcePtr;
-gdImagePtr gdImageCreateFromGifSource(gdSourcePtr in);
+gdImagePtr gdImageCreateFromPngSource(gdSourcePtr in);
gdImagePtr gdImageCreateFromGd(FILE *in);
gdImagePtr gdImageCreateFromGdCtx(gdIOCtxPtr in);
@@ -154,7 +146,7 @@ int gdImageColorExact(gdImagePtr im, int r, int g, int b);
void gdImageColorDeallocate(gdImagePtr im, int color);
void gdImageColorTransparent(gdImagePtr im, int color);
void gdImagePaletteCopy(gdImagePtr dst, gdImagePtr src);
-void gdImageGif(gdImagePtr im, FILE *out);
+void gdImagePng(gdImagePtr im, FILE *out);
/* A custom data sink. */
/* The sink function must return -1 on error, otherwise the number
@@ -165,13 +157,11 @@ typedef struct {
void *context;
} gdSink, *gdSinkPtr;
-void gdImageGifToSink(gdImagePtr im, gdSinkPtr out);
+void gdImagePngToSink(gdImagePtr im, gdSinkPtr out);
void gdImageGd(gdImagePtr im, FILE *out);
void gdImageGd2(gdImagePtr im, FILE *out, int cs, int fmt);
-void* gdImageGifPtr(gdImagePtr im, int *size);
-void gdImageLzw(gdImagePtr im, FILE *out);
-void* gdImageLzwPtr(gdImagePtr im, int *size);
+void* gdImagePngPtr(gdImagePtr im, int *size);
void* gdImageGdPtr(gdImagePtr im, int *size);
void* gdImageGd2Ptr(gdImagePtr im, int cs, int fmt, int *size);
void gdImageArc(gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color);
@@ -202,6 +192,14 @@ void gdImageInterlace(gdImagePtr im, int interlaceArg);
#define gdImageGetTransparent(im) ((im)->transparent)
#define gdImageGetInterlaced(im) ((im)->interlace)
+/* I/O Support routines. */
+
+gdIOCtx* gdNewFileCtx(FILE*);
+gdIOCtx* gdNewDynamicCtx(int, void*);
+gdIOCtx* gdNewSSCtx(gdSourcePtr in, gdSinkPtr out);
+void* gdDPExtractData(struct gdIOCtx* ctx, int *size);
+
+
#define GD2_CHUNKSIZE 128
#define GD2_CHUNKSIZE_MIN 64
#define GD2_CHUNKSIZE_MAX 4096
diff --git a/src/gd2copypal.c b/src/gd2copypal.c
index 54521ed..abdb0d8 100644
--- a/src/gd2copypal.c
+++ b/src/gd2copypal.c
@@ -1,7 +1,7 @@
#include <stdio.h>
#include "gd.h"
-/* A short program which converts a .gif file into a .gd file, for
+/* A short program which converts a .png file into a .gd file, for
your convenience in creating images on the fly from a
basis image that must be loaded quickly. The .gd format
is not intended to be a general-purpose format. */
diff --git a/src/gd2time.c b/src/gd2time.c
index 082f2a1..74a1095 100644
--- a/src/gd2time.c
+++ b/src/gd2time.c
@@ -1,7 +1,7 @@
#include <stdio.h>
#include "gd.h"
-/* A short program which converts a .gif file into a .gd file, for
+/* A short program which converts a .png file into a .gd file, for
your convenience in creating images on the fly from a
basis image that must be loaded quickly. The .gd format
is not intended to be a general-purpose format. */
diff --git a/src/gd2topng.c b/src/gd2topng.c
new file mode 100644
index 0000000..6d513cc
--- /dev/null
+++ b/src/gd2topng.c
@@ -0,0 +1,38 @@
+#include <stdio.h>
+#include "gd.h"
+
+/* A short program which converts a .png file into a .gd file, for
+ your convenience in creating images on the fly from a
+ basis image that must be loaded quickly. The .gd format
+ is not intended to be a general-purpose format. */
+
+int main(int argc, char **argv)
+{
+ gdImagePtr im;
+ FILE *in, *out;
+ if (argc != 3) {
+ fprintf(stderr, "Usage: gd2topng filename.gd2 filename.png\n");
+ exit(1);
+ }
+ in = fopen(argv[1], "rb");
+ if (!in) {
+ fprintf(stderr, "Input file does not exist!\n");
+ exit(1);
+ }
+ im = gdImageCreateFromGd2(in);
+ fclose(in);
+ if (!im) {
+ fprintf(stderr, "Input is not in GD2 format!\n");
+ exit(1);
+ }
+ out = fopen(argv[2], "wb");
+ if (!out) {
+ fprintf(stderr, "Output file cannot be written to!\n");
+ gdImageDestroy(im);
+ exit(1);
+ }
+ gdImagePng(im, out);
+ fclose(out);
+ gdImageDestroy(im);
+}
+
diff --git a/src/gd_gd.c b/src/gd_gd.c
index 8fcf14e..174e2ee 100644
--- a/src/gd_gd.c
+++ b/src/gd_gd.c
@@ -1,201 +1,200 @@
-#include <stdio.h>
-#include <math.h>
-#include <string.h>
-#include <stdlib.h>
-#include "gd.h"
-#include "io.h"
-
-#define TRUE 1
-#define FALSE 0
-
-/* Exported functions: */
-extern void gdImageGd(gdImagePtr im, FILE *out);
-
-
-/* Use this for commenting out debug-print statements. */
-/* Just use the first '#define' to allow all the prints... */
-/*#define GD2_DBG(s) (s) */
-#define GD2_DBG(s)
-
-/* */
-/* Shared code to read color tables from gd file. */
-/* */
-int _gdGetColors(gdIOCtx *in, gdImagePtr im)
-{
- int i;
-
- if (!gdGetByte(&im->colorsTotal, in)) {
- goto fail1;
- }
- if (!gdGetWord(&im->transparent, in)) {
- goto fail1;
- }
- if (im->transparent == 257) {
- im->transparent = (-1);
- }
-
- GD2_DBG(printf("Pallette had %d colours (T=%d)\n",im->colorsTotal, im->transparent));
-
- for (i=0; (i<gdMaxColors); i++) {
- if (!gdGetByte(&im->red[i], in)) {
- goto fail1;
- }
- if (!gdGetByte(&im->green[i], in)) {
- goto fail1;
- }
- if (!gdGetByte(&im->blue[i], in)) {
- goto fail1;
- }
- }
-
- for (i=0; (i < im->colorsTotal); i++) {
- im->open[i] = 0;
- };
-
- return TRUE;
-fail1:
- return FALSE;
-}
-
-/* */
-/* Use the common basic header info to make the image object. */
-/* This is also called from _gd2CreateFromFile */
-/* */
-static
-gdImagePtr _gdCreateFromFile(gdIOCtx *in, int *sx, int *sy)
-{
- int x, y;
- int i;
- gdImagePtr im;
-
- if (!gdGetWord(sx, in)) {
- goto fail1;
- }
- if (!gdGetWord(sy, in)) {
- goto fail1;
- }
-
- GD2_DBG(printf("Image is %dx%d\n", *sx, *sy));
-
- im = gdImageCreate(*sx, *sy);
-
- if (!_gdGetColors(in, im)) {
- goto fail2;
- }
-
- return im;
-fail2:
- gdImageDestroy(im);
-fail1:
- return 0;
-}
-
-gdImagePtr gdImageCreateFromGd(FILE *inFile)
-{
- gdImagePtr im;
- gdIOCtx *in;
-
- in = gdNewFileCtx(inFile);
- im = gdImageCreateFromGdCtx(in);
-
- in->free(in);
-
- return im;
-}
-
-gdImagePtr gdImageCreateFromGdCtx(gdIOCtxPtr in)
-{
- int sx, sy;
- int x, y;
- int i;
- gdImagePtr im;
-
- /* Read the header */
- im = _gdCreateFromFile(in, &sx, &sy);
-
- if (im == NULL) {
- goto fail1;
- };
-
- /* Then the data... */
- for (y=0; (y<sy); y++) {
- for (x=0; (x<sx); x++) {
- int ch;
- ch = gdGetC(in);
- if (ch == EOF) {
- goto fail2;
- }
- /* ROW-MAJOR IN GD 1.3 */
- im->pixels[y][x] = ch;
- }
- }
-
- return im;
-
-fail2:
- gdImageDestroy(im);
-fail1:
- return 0;
-}
-
-void _gdPutColors(gdImagePtr im, gdIOCtx *out)
-{
- int x, y;
- int i;
- int trans;
-
- gdPutC((unsigned char)im->colorsTotal, out);
- trans = im->transparent;
- if (trans == (-1)) {
- trans = 257;
- }
- gdPutWord(trans, out);
- for (i=0; (i<gdMaxColors); i++) {
- gdPutC((unsigned char)im->red[i], out);
- gdPutC((unsigned char)im->green[i], out);
- gdPutC((unsigned char)im->blue[i], out);
- }
-}
-
-static
-void _gdPutHeader(gdImagePtr im, gdIOCtx *out)
-{
- gdPutWord(im->sx, out);
- gdPutWord(im->sy, out);
-
- _gdPutColors(im, out);
-
-}
-
-static void _gdImageGd(gdImagePtr im, gdIOCtx *out)
-{
- int x, y;
-
- _gdPutHeader(im, out);
-
- for (y=0; (y < im->sy); y++) {
- for (x=0; (x < im->sx); x++) {
- /* ROW-MAJOR IN GD 1.3 */
- gdPutC((unsigned char)im->pixels[y][x], out);
- }
- }
-}
-
-void gdImageGd(gdImagePtr im, FILE *outFile)
-{
- gdIOCtx *out = gdNewFileCtx(outFile);
- _gdImageGd(im, out);
- out->free(out);
-}
-
-void* gdImageGdPtr(gdImagePtr im, int *size)
-{
- void *rv;
- gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
- _gdImageGd(im, out);
- rv = gdDPExtractData(out,size);
- out->free(out);
- return rv;
-}
-
-
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include "gd.h"
+
+#define TRUE 1
+#define FALSE 0
+
+/* Exported functions: */
+extern void gdImageGd(gdImagePtr im, FILE *out);
+
+
+/* Use this for commenting out debug-print statements. */
+/* Just use the first '#define' to allow all the prints... */
+/*#define GD2_DBG(s) (s) */
+#define GD2_DBG(s)
+
+/* */
+/* Shared code to read color tables from gd file. */
+/* */
+int _gdGetColors(gdIOCtx *in, gdImagePtr im)
+{
+ int i;
+
+ if (!gdGetByte(&im->colorsTotal, in)) {
+ goto fail1;
+ }
+ if (!gdGetWord(&im->transparent, in)) {
+ goto fail1;
+ }
+ if (im->transparent == 257) {
+ im->transparent = (-1);
+ }
+
+ GD2_DBG(printf("Pallette had %d colours (T=%d)\n",im->colorsTotal, im->transparent));
+
+ for (i=0; (i<gdMaxColors); i++) {
+ if (!gdGetByte(&im->red[i], in)) {
+ goto fail1;
+ }
+ if (!gdGetByte(&im->green[i], in)) {
+ goto fail1;
+ }
+ if (!gdGetByte(&im->blue[i], in)) {
+ goto fail1;
+ }
+ }
+
+ for (i=0; (i < im->colorsTotal); i++) {
+ im->open[i] = 0;
+ };
+
+ return TRUE;
+fail1:
+ return FALSE;
+}
+
+/* */
+/* Use the common basic header info to make the image object. */
+/* This is also called from _gd2CreateFromFile */
+/* */
+static
+gdImagePtr _gdCreateFromFile(gdIOCtx *in, int *sx, int *sy)
+{
+ int x, y;
+ int i;
+ gdImagePtr im;
+
+ if (!gdGetWord(sx, in)) {
+ goto fail1;
+ }
+ if (!gdGetWord(sy, in)) {
+ goto fail1;
+ }
+
+ GD2_DBG(printf("Image is %dx%d\n", *sx, *sy));
+
+ im = gdImageCreate(*sx, *sy);
+
+ if (!_gdGetColors(in, im)) {
+ goto fail2;
+ }
+
+ return im;
+fail2:
+ gdImageDestroy(im);
+fail1:
+ return 0;
+}
+
+gdImagePtr gdImageCreateFromGd(FILE *inFile)
+{
+ gdImagePtr im;
+ gdIOCtx *in;
+
+ in = gdNewFileCtx(inFile);
+ im = gdImageCreateFromGdCtx(in);
+
+ in->free(in);
+
+ return im;
+}
+
+gdImagePtr gdImageCreateFromGdCtx(gdIOCtxPtr in)
+{
+ int sx, sy;
+ int x, y;
+ int i;
+ gdImagePtr im;
+
+ /* Read the header */
+ im = _gdCreateFromFile(in, &sx, &sy);
+
+ if (im == NULL) {
+ goto fail1;
+ };
+
+ /* Then the data... */
+ for (y=0; (y<sy); y++) {
+ for (x=0; (x<sx); x++) {
+ int ch;
+ ch = gdGetC(in);
+ if (ch == EOF) {
+ goto fail2;
+ }
+ /* ROW-MAJOR IN GD 1.3 */
+ im->pixels[y][x] = ch;
+ }
+ }
+
+ return im;
+
+fail2:
+ gdImageDestroy(im);
+fail1:
+ return 0;
+}
+
+void _gdPutColors(gdImagePtr im, gdIOCtx *out)
+{
+ int x, y;
+ int i;
+ int trans;
+
+ gdPutC((unsigned char)im->colorsTotal, out);
+ trans = im->transparent;
+ if (trans == (-1)) {
+ trans = 257;
+ }
+ gdPutWord(trans, out);
+ for (i=0; (i<gdMaxColors); i++) {
+ gdPutC((unsigned char)im->red[i], out);
+ gdPutC((unsigned char)im->green[i], out);
+ gdPutC((unsigned char)im->blue[i], out);
+ }
+}
+
+static
+void _gdPutHeader(gdImagePtr im, gdIOCtx *out)
+{
+ gdPutWord(im->sx, out);
+ gdPutWord(im->sy, out);
+
+ _gdPutColors(im, out);
+
+}
+
+static void _gdImageGd(gdImagePtr im, gdIOCtx *out)
+{
+ int x, y;
+
+ _gdPutHeader(im, out);
+
+ for (y=0; (y < im->sy); y++) {
+ for (x=0; (x < im->sx); x++) {
+ /* ROW-MAJOR IN GD 1.3 */
+ gdPutC((unsigned char)im->pixels[y][x], out);
+ }
+ }
+}
+
+void gdImageGd(gdImagePtr im, FILE *outFile)
+{
+ gdIOCtx *out = gdNewFileCtx(outFile);
+ _gdImageGd(im, out);
+ out->free(out);
+}
+
+void* gdImageGdPtr(gdImagePtr im, int *size)
+{
+ void *rv;
+ gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
+ _gdImageGd(im, out);
+ rv = gdDPExtractData(out,size);
+ out->free(out);
+ return rv;
+}
+
+
diff --git a/src/gd_gd2.c b/src/gd_gd2.c
index 2ce0ade..12d19e0 100644
--- a/src/gd_gd2.c
+++ b/src/gd_gd2.c
@@ -1,728 +1,727 @@
-/*
-* gd_gd2.c
-*
-* Implements the I/O and support for the GD2 format.
-*
-* Changing the definition of GD2_DBG (below) will cause copious messages
-* to be displayed while it processes requests.
-*
-* Designed, Written & Copyright 1999, Philip Warner.
-*
-*/
-
-#include <stdio.h>
-#include <errno.h>
-#include <math.h>
-#include <string.h>
-#include <stdlib.h>
-#include <zlib.h>
-#include "gd.h"
-#include "io.h"
-
-#define TRUE 1
-#define FALSE 0
-
-/* Use this for commenting out debug-print statements. */
-/* Just use the first '#define' to allow all the prints... */
-/*#define GD2_DBG(s) (s) */
-#define GD2_DBG(s)
-
-typedef struct {
- int offset;
- int size;
- } t_chunk_info;
-
-/* */
-/* Read the extra info in the gd2 header. */
-/* */
-static
-int _gd2GetHeader(gdIOCtxPtr in, int *sx, int *sy,
- int *cs, int *vers, int *fmt, int *ncx, int *ncy, t_chunk_info **chunkIdx)
-{
- int i;
- int ch;
- char id[5];
- t_chunk_info *cidx;
- int sidx;
- int nc, csz;
-
- GD2_DBG(printf("Reading gd2 header info\n"));
-
- for (i = 0; i < 4; i++) {
- ch = gdGetC(in);
- if (ch == EOF) {
- goto fail1;
- };
- id[i] = ch;
- };
- id[4] = 0;
-
- GD2_DBG(printf("Got file code: %s\n", id));
-
- /* Equiv. of 'magick'. */
- if (strcmp(id,GD2_ID) != 0) {
- GD2_DBG(printf("Not a valid gd2 file\n"));
- goto fail1;
- };
-
- /* Version */
- if (gdGetWord(vers, in) != 1) {
- goto fail1;
- };
- GD2_DBG(printf("Version: %d\n", *vers));
-
- if (*vers != 1) {
- GD2_DBG(printf("Bad version: %d\n", *vers));
- goto fail1;
- };
-
- /* Image Size */
- if (!gdGetWord(sx, in)) {
- GD2_DBG(printf("Could not get x-size\n"));
- goto fail1;
- }
- if (!gdGetWord(sy, in)) {
- GD2_DBG(printf("Could not get y-size\n"));
- goto fail1;
- }
- GD2_DBG(printf("Image is %dx%d\n", *sx, *sy));
-
- /* Chunk Size */
- if (gdGetWord(cs, in) != 1) {
- goto fail1;
- };
- GD2_DBG(printf("ChunkSize: %d\n", *cs));
-
- if ( (*cs < GD2_CHUNKSIZE_MIN) || (*cs > GD2_CHUNKSIZE_MAX)) {
- GD2_DBG(printf("Bad chunk size: %d\n", *cs));
- goto fail1;
- };
-
- /* Data Format */
- if (gdGetWord(fmt, in) != 1) {
- goto fail1;
- };
- GD2_DBG(printf("Format: %d\n", *fmt));
-
- if ((*fmt != GD2_FMT_RAW) && (*fmt != GD2_FMT_COMPRESSED)) {
- GD2_DBG(printf("Bad data format: %d\n", *fmt));
- goto fail1;
- };
-
-
- /* # of chunks wide */
- if (gdGetWord(ncx, in) != 1) {
- goto fail1;
- };
- GD2_DBG(printf("%d Chunks Wide\n", *ncx));
-
- /* # of chunks high */
- if (gdGetWord(ncy, in) != 1) {
- goto fail1;
- };
- GD2_DBG(printf("%d Chunks vertically\n", *ncy));
-
- if ((*fmt) == GD2_FMT_COMPRESSED) {
- nc = (*ncx) * (*ncy);
- GD2_DBG(printf("Reading %d chunk index entries\n", nc));
- sidx = sizeof(t_chunk_info) * nc;
- cidx = calloc(sidx,1);
- for (i = 0; i < nc; i++) {
- if (gdGetInt(&cidx[i].offset, in) != 1) {
- goto fail1;
- };
- if (gdGetInt(&cidx[i].size, in) != 1) {
- goto fail1;
- };
- };
- *chunkIdx = cidx;
- };
-
- GD2_DBG(printf("gd2 header complete\n"));
-
- return 1;
-
-fail1:
- return 0;
-}
-
-static
-gdImagePtr _gd2CreateFromFile(gdIOCtxPtr in, int *sx, int *sy,
- int *cs, int *vers, int *fmt,
- int *ncx, int *ncy, t_chunk_info **cidx)
-{
- gdImagePtr im;
-
- if (_gd2GetHeader(in, sx, sy, cs, vers, fmt, ncx, ncy, cidx) != 1) {
- GD2_DBG(printf("Bad GD2 header\n"));
- goto fail1;
- }
-
- im = gdImageCreate(*sx, *sy);
- if (im == NULL) {
- GD2_DBG(printf("Could not create gdImage\n"));
- goto fail1;
- };
-
- if (!_gdGetColors(in, im)) {
- GD2_DBG(printf("Could not read color palette\n"));
- goto fail2;
- }
- GD2_DBG(printf("Image palette completed\n"));
-
- return im;
-
-fail2:
- gdImageDestroy(im);
- return 0;
-
-fail1:
- return 0;
-
-}
-
-static
-int _gd2ReadChunk(int offset, char *compBuf, int compSize, char *chunkBuf, uLongf *chunkLen, gdIOCtx *in)
-{
- int zerr;
-
- if (gdTell(in) != offset) {
- GD2_DBG(printf("Positioning in file to %d\n",offset));
- gdSeek(in,offset);
- } else {
- GD2_DBG(printf("Already Positioned in file to %d\n",offset));
- };
-
- /* Read and uncompress an entire chunk. */
- GD2_DBG(printf("Reading file\n"));
- if (gdGetBuf(compBuf, compSize, in) != compSize) {
- return FALSE;
- };
- GD2_DBG(printf("Got %d bytes. Uncompressing into buffer of %d bytes\n", compSize, *chunkLen));
- zerr = uncompress(chunkBuf, chunkLen, compBuf, compSize);
- if (zerr != Z_OK) {
- GD2_DBG(printf("Error %d from uncompress\n",zerr));
- return FALSE;
- };
- GD2_DBG(printf("Got chunk\n"));
- return TRUE;
-};
-
-gdImagePtr gdImageCreateFromGd2(FILE *inFile)
-{
- gdIOCtx *in = gdNewFileCtx(inFile);
- gdImagePtr im;
-
- im = gdImageCreateFromGd2Ctx(in);
-
- in->free(in);
-
- return im;
-}
-
-gdImagePtr gdImageCreateFromGd2Ctx(gdIOCtxPtr in)
-{
- int sx, sy;
- int i;
- int ncx, ncy, nc, cs, cx, cy;
- int x, y, ylo, yhi, xlo, xhi;
- int ch, vers, fmt;
- t_chunk_info *chunkIdx = NULL; /* So we can free it with impunity. */
- char *chunkBuf = NULL; /* So we can free it with impunity. */
- int chunkNum = 0;
- int chunkMax;
- uLongf chunkLen;
- int chunkPos;
- int compMax;
- char *compBuf = NULL; /* So we can free it with impunity. */
-
- gdImagePtr im;
-
- /* Get the header */
- im = _gd2CreateFromFile(in, &sx, &sy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx);
-
- if (im == NULL) {
- return 0;
- };
-
- nc = ncx * ncy;
-
- if (fmt == GD2_FMT_COMPRESSED) {
- /* Find the maximum compressed chunk size. */
- compMax = 0;
- for (i=0; (i < nc) ; i++) {
- if ( chunkIdx[i].size > compMax) {
- compMax = chunkIdx[i].size;
- };
- };
- compMax++;
-
- /* Allocate buffers */
- chunkMax = cs * cs;
- chunkBuf = calloc(chunkMax,1);
- compBuf = calloc(compMax,1);
- GD2_DBG(printf("Largest compressed chunk is %d bytes\n",compMax));
- };
-
-/* if ( (ncx != sx / cs) || (ncy != sy / cs)) { */
-/* goto fail2; */
-/* }; */
-
- /* Read the data... */
- for (cy=0; (cy < ncy); cy++) {
- for (cx=0; (cx < ncx); cx++) {
-
- ylo = cy * cs;
- yhi = ylo + cs;
- if (yhi > im->sy) {
- yhi = im->sy;
- };
-
- GD2_DBG(printf("Processing Chunk %d (%d, %d), y from %d to %d\n",chunkNum, cx, cy, ylo, yhi));
-
- if (fmt == GD2_FMT_COMPRESSED) {
-
- chunkLen = chunkMax;
-
- if (!_gd2ReadChunk( chunkIdx[chunkNum].offset,
- compBuf,
- chunkIdx[chunkNum].size,
- chunkBuf, &chunkLen, in))
- {
- GD2_DBG(printf("Error reading comproessed chunk\n"));
- goto fail2;
- };
-
- chunkPos = 0;
- };
-
- for (y= ylo ; (y < yhi); y++) {
-
- xlo = cx * cs;
- xhi = xlo + cs;
- if (xhi > im->sx) {
- xhi = im->sx;
- };
- /*GD2_DBG(printf("y=%d: ",y)); */
- if (fmt == GD2_FMT_RAW) {
- for (x= xlo ; x < xhi; x++) {
-
- ch = gdGetC(in);
- if (ch == EOF) {
- ch = 0;
- /*printf("EOF while reading\n"); */
- /*gdImageDestroy(im); */
- /*return 0; */
- }
- /*GD2_DBG(printf(" (%d, %d)", x, y)); */
- im->pixels[y][x] = ch;
- }
- } else {
- for (x= xlo ; x < xhi; x++) {
- im->pixels[y][x] = chunkBuf[chunkPos++];
- };
- };
- /*GD2_DBG(printf("\n")); */
- };
- chunkNum++;
- };
- };
-
- GD2_DBG(printf("Freeing memory\n"));
-
- free(chunkBuf);
- free(compBuf);
- free(chunkIdx);
-
- GD2_DBG(printf("Done\n"));
-
- return im;
-
-fail2:
- gdImageDestroy(im);
-fail1:
- free(chunkBuf);
- free(compBuf);
- free(chunkIdx);
- return 0;
-
-}
-
-gdImagePtr gdImageCreateFromGd2Part(FILE *inFile, int srcx, int srcy, int w, int h)
-{
- gdImagePtr im;
- gdIOCtx *in = gdNewFileCtx(inFile);
-
- im = gdImageCreateFromGd2PartCtx(in, srcx, srcy, w, h);
-
- in->free(in);
-
- return im;
-}
-
-gdImagePtr gdImageCreateFromGd2PartCtx(gdIOCtx *in, int srcx, int srcy, int w, int h)
-{
- int sx, sy, scx, scy, ecx, ecy, fsx, fsy;
- int nc, ncx, ncy, cs, cx, cy;
- int x, y, ylo, yhi, xlo, xhi;
- int dstart, dpos;
- int i;
- int ch, vers, fmt;
- t_chunk_info *chunkIdx = NULL;
- char *chunkBuf = NULL;
- int chunkNum;
- int chunkMax;
- uLongf chunkLen;
- int chunkPos;
- int compMax;
- char *compBuf = NULL;
-
- gdImagePtr im;
-
- /* */
- /* The next few lines are basically copied from gd2CreateFromFile */
- /* - we change the file size, so don't want to use the code directly. */
- /* but we do need to know the file size. */
- /* */
- if (_gd2GetHeader(in, &fsx, &fsy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx) != 1) {
- goto fail1;
- }
-
- GD2_DBG(printf("File size is %dx%d\n", fsx, fsy));
-
- /* This is the difference - make a file based on size of chunks. */
- im = gdImageCreate(w, h);
- if (im == NULL) {
- goto fail1;
- };
-
- if (!_gdGetColors(in, im)) {
- goto fail2;
- }
-
- /* Process the header info */
- nc = ncx * ncy;
-
- if (fmt == GD2_FMT_COMPRESSED) {
- /* Find the maximum compressed chunk size. */
- compMax = 0;
- for (i=0; (i < nc) ; i++) {
- if ( chunkIdx[i].size > compMax) {
- compMax = chunkIdx[i].size;
- };
- };
- compMax++;
-
- chunkMax = cs * cs;
- chunkBuf = calloc(chunkMax,1);
- compBuf = calloc(compMax,1);
- };
-
-/* Don't bother with this... */
-/* if ( (ncx != sx / cs) || (ncy != sy / cs)) { */
-/* goto fail2; */
-/* }; */
-
-
- /* Work out start/end chunks */
- scx = srcx / cs;
- scy = srcy / cs;
- if (scx < 0) { scx = 0;};
- if (scy < 0) { scy = 0;};
-
- ecx = (srcx + w) / cs;
- ecy = (srcy + h) / cs;
- if (ecx >= ncx) { ecx = ncx - 1;};
- if (ecy >= ncy) { ecy = ncy - 1;};
-
- /* Remember file position of image data. */
- dstart = gdTell(in);
- GD2_DBG(printf("Data starts at %d\n",dstart));
-
- /* Loop through the chunks. */
- for (cy=scy ; (cy <= ecy); cy++) {
-
- ylo = cy * cs;
- yhi = ylo + cs;
- if (yhi > fsy) {
- yhi = fsy;
- };
-
- for (cx=scx; (cx <= ecx); cx++) {
-
- xlo = cx * cs;
- xhi = xlo + cs;
- if (xhi > fsx) {
- xhi = fsx;
- };
-
- GD2_DBG(printf("Processing Chunk (%d, %d), from %d to %d\n",cx, cy, ylo, yhi));
-
- if (fmt == GD2_FMT_RAW) {
- GD2_DBG(printf("Using raw format data\n"));
- dpos = cy * (cs * fsx) + cx * cs * (yhi-ylo) + dstart;
-
- if (gdSeek(in, dpos) != 0) {
- printf("Error from seek: %d\n",errno);
- goto fail2;
- };
- GD2_DBG(printf("Reading (%d, %d) from position %d\n",cx,cy,dpos-dstart));
- } else {
- chunkNum = cx + cy * ncx;
-
- chunkLen = chunkMax;
- if (!_gd2ReadChunk( chunkIdx[chunkNum].offset,
- compBuf,
- chunkIdx[chunkNum].size,
- chunkBuf, &chunkLen, in))
- {
- printf("Error reading comproessed chunk\n");
- goto fail2;
- };
- chunkPos= 0;
- GD2_DBG(printf("Reading (%d, %d) from chunk %d\n",cx,cy,chunkNum));
- };
-
- GD2_DBG(printf(" into (%d, %d) - (%d, %d)\n", xlo, ylo, xhi, yhi));
- for (y=ylo ; (y < yhi); y++) {
-
- for (x= xlo ; x < xhi; x++) {
-
-
- if (fmt == GD2_FMT_RAW) {
- ch = gdGetC(in);
- if (ch == EOF) {
- ch = 0;
- /*printf("EOF while reading file\n"); */
- /*goto fail2; */
- };
- } else {
- ch = chunkBuf[chunkPos++];
- };
-
- /* Only use a point that is in the image. */
- if ( (x >= srcx) && (x < (srcx + w)) && (x < fsx) && (x >= 0)
- && (y >= srcy) && (y < (srcy + h)) && (y < fsy) && (y >= 0)
- )
- {
- im->pixels[y-srcy][x-srcx] = ch;
- }
- };
- };
- };
- };
-
- free(chunkBuf);
- free(compBuf);
- free(chunkIdx);
-
- return im;
-
-fail2:
- gdImageDestroy(im);
-fail1:
- free(chunkBuf);
- free(compBuf);
- free(chunkIdx);
-
- return 0;
-
-}
-
-static
-void _gd2PutHeader(gdImagePtr im, gdIOCtx *out, int cs, int fmt, int cx, int cy)
-{
- int i;
-
- /* Send the gd2 id, to verify file format. */
- for (i = 0; i < 4; i++) {
- gdPutC((unsigned char)(GD2_ID[i]), out);
- };
-
- /* */
- /* We put the version info first, so future versions can easily change header info. */
- /* */
- gdPutWord(GD2_VERS, out);
- gdPutWord(im->sx, out);
- gdPutWord(im->sy, out);
- gdPutWord(cs, out);
- gdPutWord(fmt, out);
- gdPutWord(cx, out);
- gdPutWord(cy, out);
-
-}
-
-static void _gdImageGd2(gdImagePtr im, gdIOCtx *out, int cs, int fmt)
-{
- int ncx, ncy, cx, cy;
- int x, y, ylo, yhi, xlo, xhi;
- int i;
- int chunkLen;
- int chunkNum = 0;
- char *chunkData = NULL; /* So we can free it with impunity. */
- char *compData = NULL; /* So we can free it with impunity. */
- uLongf compLen;
- int idxPos;
- int idxSize;
- t_chunk_info *chunkIdx = NULL;
- int posSave;
- int compMax;
-
- /*printf("Trying to write GD2 file\n"); */
-
- /* */
- /* Force fmt to a valid value since we don't return anything. */
- /* */
- if ( (fmt == 0) || ( (fmt != GD2_FMT_RAW) && (fmt != GD2_FMT_COMPRESSED) ) ) {
- fmt == GD2_FMT_COMPRESSED;
- };
-
- /* */
- /* Make sure chunk size is valid. These are arbitrary values; 64 because it seems */
- /* a little silly to expect performance improvements on a 64x64 bit scale, and */
- /* 4096 because we buffer one chunk, and a 16MB buffer seems a little largei - it may be */
- /* OK for one user, but for another to read it, they require the buffer. */
- /* */
- if (cs == 0) {
- cs = GD2_CHUNKSIZE;
- } else if (cs < GD2_CHUNKSIZE_MIN) {
- cs = GD2_CHUNKSIZE_MIN;
- } else if (cs > GD2_CHUNKSIZE_MAX) {
- cs = GD2_CHUNKSIZE_MAX;
- };
-
- /* Work out number of chunks. */
- ncx = im->sx / cs + 1;
- ncy = im->sy / cs + 1;
-
- /* Write the standard header. */
- _gd2PutHeader(im, out, cs, fmt, ncx, ncy);
-
- if (fmt == GD2_FMT_COMPRESSED) {
- /* */
- /* Work out size of buffer for compressed data, If CHUNKSIZE is large, */
- /* then these will be large! */
- /* */
- /* The zlib notes say output buffer size should be (input size) * 1.01 * 12 */
- /* - we'll use 1.02 to be paranoid. */
- /* */
- compMax = cs * cs * 1.02 + 12;
-
- /* */
- /* Allocate the buffers. */
- /* */
- chunkData = calloc(cs*cs,1);
- compData = calloc(compMax,1);
-
- /* */
- /* Save the file position of chunk index, and allocate enough space for */
- /* each chunk_info block . */
- /* */
- idxPos = gdTell(out);
- idxSize = ncx * ncy * sizeof(t_chunk_info);
- GD2_DBG(printf("Index size is %d\n", idxSize));
- gdSeek(out,idxPos+idxSize);
-
- chunkIdx = calloc(idxSize * sizeof(t_chunk_info),1);
- };
-
- _gdPutColors(im, out);
-
- GD2_DBG(printf("Size: %dx%d\n", im->sx, im->sy));
- GD2_DBG(printf("Chunks: %dx%d\n", ncx, ncy));
-
- for (cy=0; (cy < ncy); cy++) {
- for (cx=0; (cx < ncx); cx++) {
-
- ylo = cy * cs;
- yhi = ylo + cs;
- if (yhi > im->sy) {
- yhi = im->sy;
- };
-
- GD2_DBG(printf("Processing Chunk (%dx%d), y from %d to %d\n",cx, cy, ylo, yhi));
- chunkLen = 0;
- for (y= ylo ; (y < yhi); y++) {
-
- /*GD2_DBG(printf("y=%d: ",y)); */
-
- xlo = cx * cs;
- xhi = xlo + cs;
- if (xhi > im->sx) {
- xhi = im->sx;
- };
-
- if (fmt == GD2_FMT_COMPRESSED) {
- for (x= xlo ; x < xhi; x++) {
- /*GD2_DBG(printf("%d...",x)); */
- chunkData[chunkLen++] = im->pixels[y][x];
- };
- } else {
- for (x= xlo ; x < xhi; x++) {
- /*GD2_DBG(printf("%d, ",x)); */
- gdPutC((unsigned char)im->pixels[y][x], out);
- };
- };
- /*GD2_DBG(printf("y=%d done.\n",y)); */
- };
- if (fmt == GD2_FMT_COMPRESSED) {
- compLen = compMax;
- if (compress(&compData[0], &compLen, &chunkData[0], chunkLen) != Z_OK) {
- printf("Error from compressing\n");
- } else {
- chunkIdx[chunkNum].offset = gdTell(out);
- chunkIdx[chunkNum++].size = compLen;
- GD2_DBG(printf("Chunk %d size %d offset %d\n",chunkNum, chunkIdx[chunkNum-1].size, chunkIdx[chunkNum-1].offset));
-
- if (gdPutBuf(compData, compLen, out) <= 0) {
- /* Any alternate suggestions for handling this? */
- printf("Error %d on write\n", errno);
- };
- };
- };
- };
- };
- if (fmt == GD2_FMT_COMPRESSED) {
- /* Save the position, write the index, restore position (paranoia). */
- GD2_DBG(printf("Seeking %d to write index\n",idxPos));
- posSave = gdTell(out);
- gdSeek(out,idxPos);
- GD2_DBG(printf("Writing index\n"));
- for (x = 0; x < chunkNum; x++) {
- GD2_DBG(printf("Chunk %d size %d offset %d\n", x, chunkIdx[x].size, chunkIdx[x].offset));
- gdPutInt(chunkIdx[x].offset, out);
- gdPutInt(chunkIdx[x].size, out);
- };
- /* We don't use fwrite for *endian reasons. */
- /*fwrite(chunkIdx, sizeof(int)*2, chunkNum, out); */
- gdSeek(out, posSave);
- };
-
- GD2_DBG(printf("Freeing memory\n"));
- free(chunkData);
- free(compData);
- free(chunkIdx);
- GD2_DBG(printf("Done\n"));
-
- /*printf("Memory block size is %d\n",gdTell(out)); */
-
-}
-
-void gdImageGd2(gdImagePtr im, FILE *outFile, int cs, int fmt)
-{
- gdIOCtx *out = gdNewFileCtx(outFile);
- _gdImageGd2(im, out, cs, fmt);
- out->free(out);
-}
-
-void* gdImageGd2Ptr(gdImagePtr im, int cs, int fmt, int *size)
-{
- void *rv;
- gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
- _gdImageGd2(im, out, cs, fmt);
- rv = gdDPExtractData(out, size);
- out->free(out);
- return rv;
-}
-
-
+/*
+* gd_gd2.c
+*
+* Implements the I/O and support for the GD2 format.
+*
+* Changing the definition of GD2_DBG (below) will cause copious messages
+* to be displayed while it processes requests.
+*
+* Designed, Written & Copyright 1999, Philip Warner.
+*
+*/
+
+#include <stdio.h>
+#include <errno.h>
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include <zlib.h>
+#include "gd.h"
+
+#define TRUE 1
+#define FALSE 0
+
+/* Use this for commenting out debug-print statements. */
+/* Just use the first '#define' to allow all the prints... */
+/*#define GD2_DBG(s) (s) */
+#define GD2_DBG(s)
+
+typedef struct {
+ int offset;
+ int size;
+ } t_chunk_info;
+
+/* */
+/* Read the extra info in the gd2 header. */
+/* */
+static
+int _gd2GetHeader(gdIOCtxPtr in, int *sx, int *sy,
+ int *cs, int *vers, int *fmt, int *ncx, int *ncy, t_chunk_info **chunkIdx)
+{
+ int i;
+ int ch;
+ char id[5];
+ t_chunk_info *cidx;
+ int sidx;
+ int nc, csz;
+
+ GD2_DBG(printf("Reading gd2 header info\n"));
+
+ for (i = 0; i < 4; i++) {
+ ch = gdGetC(in);
+ if (ch == EOF) {
+ goto fail1;
+ };
+ id[i] = ch;
+ };
+ id[4] = 0;
+
+ GD2_DBG(printf("Got file code: %s\n", id));
+
+ /* Equiv. of 'magick'. */
+ if (strcmp(id,GD2_ID) != 0) {
+ GD2_DBG(printf("Not a valid gd2 file\n"));
+ goto fail1;
+ };
+
+ /* Version */
+ if (gdGetWord(vers, in) != 1) {
+ goto fail1;
+ };
+ GD2_DBG(printf("Version: %d\n", *vers));
+
+ if (*vers != 1) {
+ GD2_DBG(printf("Bad version: %d\n", *vers));
+ goto fail1;
+ };
+
+ /* Image Size */
+ if (!gdGetWord(sx, in)) {
+ GD2_DBG(printf("Could not get x-size\n"));
+ goto fail1;
+ }
+ if (!gdGetWord(sy, in)) {
+ GD2_DBG(printf("Could not get y-size\n"));
+ goto fail1;
+ }
+ GD2_DBG(printf("Image is %dx%d\n", *sx, *sy));
+
+ /* Chunk Size */
+ if (gdGetWord(cs, in) != 1) {
+ goto fail1;
+ };
+ GD2_DBG(printf("ChunkSize: %d\n", *cs));
+
+ if ( (*cs < GD2_CHUNKSIZE_MIN) || (*cs > GD2_CHUNKSIZE_MAX)) {
+ GD2_DBG(printf("Bad chunk size: %d\n", *cs));
+ goto fail1;
+ };
+
+ /* Data Format */
+ if (gdGetWord(fmt, in) != 1) {
+ goto fail1;
+ };
+ GD2_DBG(printf("Format: %d\n", *fmt));
+
+ if ((*fmt != GD2_FMT_RAW) && (*fmt != GD2_FMT_COMPRESSED)) {
+ GD2_DBG(printf("Bad data format: %d\n", *fmt));
+ goto fail1;
+ };
+
+
+ /* # of chunks wide */
+ if (gdGetWord(ncx, in) != 1) {
+ goto fail1;
+ };
+ GD2_DBG(printf("%d Chunks Wide\n", *ncx));
+
+ /* # of chunks high */
+ if (gdGetWord(ncy, in) != 1) {
+ goto fail1;
+ };
+ GD2_DBG(printf("%d Chunks vertically\n", *ncy));
+
+ if ((*fmt) == GD2_FMT_COMPRESSED) {
+ nc = (*ncx) * (*ncy);
+ GD2_DBG(printf("Reading %d chunk index entries\n", nc));
+ sidx = sizeof(t_chunk_info) * nc;
+ cidx = calloc(sidx,1);
+ for (i = 0; i < nc; i++) {
+ if (gdGetInt(&cidx[i].offset, in) != 1) {
+ goto fail1;
+ };
+ if (gdGetInt(&cidx[i].size, in) != 1) {
+ goto fail1;
+ };
+ };
+ *chunkIdx = cidx;
+ };
+
+ GD2_DBG(printf("gd2 header complete\n"));
+
+ return 1;
+
+fail1:
+ return 0;
+}
+
+static
+gdImagePtr _gd2CreateFromFile(gdIOCtxPtr in, int *sx, int *sy,
+ int *cs, int *vers, int *fmt,
+ int *ncx, int *ncy, t_chunk_info **cidx)
+{
+ gdImagePtr im;
+
+ if (_gd2GetHeader(in, sx, sy, cs, vers, fmt, ncx, ncy, cidx) != 1) {
+ GD2_DBG(printf("Bad GD2 header\n"));
+ goto fail1;
+ }
+
+ im = gdImageCreate(*sx, *sy);
+ if (im == NULL) {
+ GD2_DBG(printf("Could not create gdImage\n"));
+ goto fail1;
+ };
+
+ if (!_gdGetColors(in, im)) {
+ GD2_DBG(printf("Could not read color palette\n"));
+ goto fail2;
+ }
+ GD2_DBG(printf("Image palette completed\n"));
+
+ return im;
+
+fail2:
+ gdImageDestroy(im);
+ return 0;
+
+fail1:
+ return 0;
+
+}
+
+static
+int _gd2ReadChunk(int offset, char *compBuf, int compSize, char *chunkBuf, uLongf *chunkLen, gdIOCtx *in)
+{
+ int zerr;
+
+ if (gdTell(in) != offset) {
+ GD2_DBG(printf("Positioning in file to %d\n",offset));
+ gdSeek(in,offset);
+ } else {
+ GD2_DBG(printf("Already Positioned in file to %d\n",offset));
+ };
+
+ /* Read and uncompress an entire chunk. */
+ GD2_DBG(printf("Reading file\n"));
+ if (gdGetBuf(compBuf, compSize, in) != compSize) {
+ return FALSE;
+ };
+ GD2_DBG(printf("Got %d bytes. Uncompressing into buffer of %d bytes\n", compSize, *chunkLen));
+ zerr = uncompress(chunkBuf, chunkLen, compBuf, compSize);
+ if (zerr != Z_OK) {
+ GD2_DBG(printf("Error %d from uncompress\n",zerr));
+ return FALSE;
+ };
+ GD2_DBG(printf("Got chunk\n"));
+ return TRUE;
+};
+
+gdImagePtr gdImageCreateFromGd2(FILE *inFile)
+{
+ gdIOCtx *in = gdNewFileCtx(inFile);
+ gdImagePtr im;
+
+ im = gdImageCreateFromGd2Ctx(in);
+
+ in->free(in);
+
+ return im;
+}
+
+gdImagePtr gdImageCreateFromGd2Ctx(gdIOCtxPtr in)
+{
+ int sx, sy;
+ int i;
+ int ncx, ncy, nc, cs, cx, cy;
+ int x, y, ylo, yhi, xlo, xhi;
+ int ch, vers, fmt;
+ t_chunk_info *chunkIdx = NULL; /* So we can free it with impunity. */
+ char *chunkBuf = NULL; /* So we can free it with impunity. */
+ int chunkNum = 0;
+ int chunkMax;
+ uLongf chunkLen;
+ int chunkPos;
+ int compMax;
+ char *compBuf = NULL; /* So we can free it with impunity. */
+
+ gdImagePtr im;
+
+ /* Get the header */
+ im = _gd2CreateFromFile(in, &sx, &sy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx);
+
+ if (im == NULL) {
+ return 0;
+ };
+
+ nc = ncx * ncy;
+
+ if (fmt == GD2_FMT_COMPRESSED) {
+ /* Find the maximum compressed chunk size. */
+ compMax = 0;
+ for (i=0; (i < nc) ; i++) {
+ if ( chunkIdx[i].size > compMax) {
+ compMax = chunkIdx[i].size;
+ };
+ };
+ compMax++;
+
+ /* Allocate buffers */
+ chunkMax = cs * cs;
+ chunkBuf = calloc(chunkMax,1);
+ compBuf = calloc(compMax,1);
+ GD2_DBG(printf("Largest compressed chunk is %d bytes\n",compMax));
+ };
+
+/* if ( (ncx != sx / cs) || (ncy != sy / cs)) { */
+/* goto fail2; */
+/* }; */
+
+ /* Read the data... */
+ for (cy=0; (cy < ncy); cy++) {
+ for (cx=0; (cx < ncx); cx++) {
+
+ ylo = cy * cs;
+ yhi = ylo + cs;
+ if (yhi > im->sy) {
+ yhi = im->sy;
+ };
+
+ GD2_DBG(printf("Processing Chunk %d (%d, %d), y from %d to %d\n",chunkNum, cx, cy, ylo, yhi));
+
+ if (fmt == GD2_FMT_COMPRESSED) {
+
+ chunkLen = chunkMax;
+
+ if (!_gd2ReadChunk( chunkIdx[chunkNum].offset,
+ compBuf,
+ chunkIdx[chunkNum].size,
+ chunkBuf, &chunkLen, in))
+ {
+ GD2_DBG(printf("Error reading comproessed chunk\n"));
+ goto fail2;
+ };
+
+ chunkPos = 0;
+ };
+
+ for (y= ylo ; (y < yhi); y++) {
+
+ xlo = cx * cs;
+ xhi = xlo + cs;
+ if (xhi > im->sx) {
+ xhi = im->sx;
+ };
+ /*GD2_DBG(printf("y=%d: ",y)); */
+ if (fmt == GD2_FMT_RAW) {
+ for (x= xlo ; x < xhi; x++) {
+
+ ch = gdGetC(in);
+ if (ch == EOF) {
+ ch = 0;
+ /*printf("EOF while reading\n"); */
+ /*gdImageDestroy(im); */
+ /*return 0; */
+ }
+ /*GD2_DBG(printf(" (%d, %d)", x, y)); */
+ im->pixels[y][x] = ch;
+ }
+ } else {
+ for (x= xlo ; x < xhi; x++) {
+ im->pixels[y][x] = chunkBuf[chunkPos++];
+ };
+ };
+ /*GD2_DBG(printf("\n")); */
+ };
+ chunkNum++;
+ };
+ };
+
+ GD2_DBG(printf("Freeing memory\n"));
+
+ free(chunkBuf);
+ free(compBuf);
+ free(chunkIdx);
+
+ GD2_DBG(printf("Done\n"));
+
+ return im;
+
+fail2:
+ gdImageDestroy(im);
+fail1:
+ free(chunkBuf);
+ free(compBuf);
+ free(chunkIdx);
+ return 0;
+
+}
+
+gdImagePtr gdImageCreateFromGd2Part(FILE *inFile, int srcx, int srcy, int w, int h)
+{
+ gdImagePtr im;
+ gdIOCtx *in = gdNewFileCtx(inFile);
+
+ im = gdImageCreateFromGd2PartCtx(in, srcx, srcy, w, h);
+
+ in->free(in);
+
+ return im;
+}
+
+gdImagePtr gdImageCreateFromGd2PartCtx(gdIOCtx *in, int srcx, int srcy, int w, int h)
+{
+ int sx, sy, scx, scy, ecx, ecy, fsx, fsy;
+ int nc, ncx, ncy, cs, cx, cy;
+ int x, y, ylo, yhi, xlo, xhi;
+ int dstart, dpos;
+ int i;
+ int ch, vers, fmt;
+ t_chunk_info *chunkIdx = NULL;
+ char *chunkBuf = NULL;
+ int chunkNum;
+ int chunkMax;
+ uLongf chunkLen;
+ int chunkPos;
+ int compMax;
+ char *compBuf = NULL;
+
+ gdImagePtr im;
+
+ /* */
+ /* The next few lines are basically copied from gd2CreateFromFile */
+ /* - we change the file size, so don't want to use the code directly. */
+ /* but we do need to know the file size. */
+ /* */
+ if (_gd2GetHeader(in, &fsx, &fsy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx) != 1) {
+ goto fail1;
+ }
+
+ GD2_DBG(printf("File size is %dx%d\n", fsx, fsy));
+
+ /* This is the difference - make a file based on size of chunks. */
+ im = gdImageCreate(w, h);
+ if (im == NULL) {
+ goto fail1;
+ };
+
+ if (!_gdGetColors(in, im)) {
+ goto fail2;
+ }
+
+ /* Process the header info */
+ nc = ncx * ncy;
+
+ if (fmt == GD2_FMT_COMPRESSED) {
+ /* Find the maximum compressed chunk size. */
+ compMax = 0;
+ for (i=0; (i < nc) ; i++) {
+ if ( chunkIdx[i].size > compMax) {
+ compMax = chunkIdx[i].size;
+ };
+ };
+ compMax++;
+
+ chunkMax = cs * cs;
+ chunkBuf = calloc(chunkMax,1);
+ compBuf = calloc(compMax,1);
+ };
+
+/* Don't bother with this... */
+/* if ( (ncx != sx / cs) || (ncy != sy / cs)) { */
+/* goto fail2; */
+/* }; */
+
+
+ /* Work out start/end chunks */
+ scx = srcx / cs;
+ scy = srcy / cs;
+ if (scx < 0) { scx = 0;};
+ if (scy < 0) { scy = 0;};
+
+ ecx = (srcx + w) / cs;
+ ecy = (srcy + h) / cs;
+ if (ecx >= ncx) { ecx = ncx - 1;};
+ if (ecy >= ncy) { ecy = ncy - 1;};
+
+ /* Remember file position of image data. */
+ dstart = gdTell(in);
+ GD2_DBG(printf("Data starts at %d\n",dstart));
+
+ /* Loop through the chunks. */
+ for (cy=scy ; (cy <= ecy); cy++) {
+
+ ylo = cy * cs;
+ yhi = ylo + cs;
+ if (yhi > fsy) {
+ yhi = fsy;
+ };
+
+ for (cx=scx; (cx <= ecx); cx++) {
+
+ xlo = cx * cs;
+ xhi = xlo + cs;
+ if (xhi > fsx) {
+ xhi = fsx;
+ };
+
+ GD2_DBG(printf("Processing Chunk (%d, %d), from %d to %d\n",cx, cy, ylo, yhi));
+
+ if (fmt == GD2_FMT_RAW) {
+ GD2_DBG(printf("Using raw format data\n"));
+ dpos = cy * (cs * fsx) + cx * cs * (yhi-ylo) + dstart;
+
+ if (gdSeek(in, dpos) != 0) {
+ printf("Error from seek: %d\n",errno);
+ goto fail2;
+ };
+ GD2_DBG(printf("Reading (%d, %d) from position %d\n",cx,cy,dpos-dstart));
+ } else {
+ chunkNum = cx + cy * ncx;
+
+ chunkLen = chunkMax;
+ if (!_gd2ReadChunk( chunkIdx[chunkNum].offset,
+ compBuf,
+ chunkIdx[chunkNum].size,
+ chunkBuf, &chunkLen, in))
+ {
+ printf("Error reading comproessed chunk\n");
+ goto fail2;
+ };
+ chunkPos= 0;
+ GD2_DBG(printf("Reading (%d, %d) from chunk %d\n",cx,cy,chunkNum));
+ };
+
+ GD2_DBG(printf(" into (%d, %d) - (%d, %d)\n", xlo, ylo, xhi, yhi));
+ for (y=ylo ; (y < yhi); y++) {
+
+ for (x= xlo ; x < xhi; x++) {
+
+
+ if (fmt == GD2_FMT_RAW) {
+ ch = gdGetC(in);
+ if (ch == EOF) {
+ ch = 0;
+ /*printf("EOF while reading file\n"); */
+ /*goto fail2; */
+ };
+ } else {
+ ch = chunkBuf[chunkPos++];
+ };
+
+ /* Only use a point that is in the image. */
+ if ( (x >= srcx) && (x < (srcx + w)) && (x < fsx) && (x >= 0)
+ && (y >= srcy) && (y < (srcy + h)) && (y < fsy) && (y >= 0)
+ )
+ {
+ im->pixels[y-srcy][x-srcx] = ch;
+ }
+ };
+ };
+ };
+ };
+
+ free(chunkBuf);
+ free(compBuf);
+ free(chunkIdx);
+
+ return im;
+
+fail2:
+ gdImageDestroy(im);
+fail1:
+ free(chunkBuf);
+ free(compBuf);
+ free(chunkIdx);
+
+ return 0;
+
+}
+
+static
+void _gd2PutHeader(gdImagePtr im, gdIOCtx *out, int cs, int fmt, int cx, int cy)
+{
+ int i;
+
+ /* Send the gd2 id, to verify file format. */
+ for (i = 0; i < 4; i++) {
+ gdPutC((unsigned char)(GD2_ID[i]), out);
+ };
+
+ /* */
+ /* We put the version info first, so future versions can easily change header info. */
+ /* */
+ gdPutWord(GD2_VERS, out);
+ gdPutWord(im->sx, out);
+ gdPutWord(im->sy, out);
+ gdPutWord(cs, out);
+ gdPutWord(fmt, out);
+ gdPutWord(cx, out);
+ gdPutWord(cy, out);
+
+}
+
+static void _gdImageGd2(gdImagePtr im, gdIOCtx *out, int cs, int fmt)
+{
+ int ncx, ncy, cx, cy;
+ int x, y, ylo, yhi, xlo, xhi;
+ int i;
+ int chunkLen;
+ int chunkNum = 0;
+ char *chunkData = NULL; /* So we can free it with impunity. */
+ char *compData = NULL; /* So we can free it with impunity. */
+ uLongf compLen;
+ int idxPos;
+ int idxSize;
+ t_chunk_info *chunkIdx = NULL;
+ int posSave;
+ int compMax;
+
+ /*printf("Trying to write GD2 file\n"); */
+
+ /* */
+ /* Force fmt to a valid value since we don't return anything. */
+ /* */
+ if ( (fmt == 0) || ( (fmt != GD2_FMT_RAW) && (fmt != GD2_FMT_COMPRESSED) ) ) {
+ fmt == GD2_FMT_COMPRESSED;
+ };
+
+ /* */
+ /* Make sure chunk size is valid. These are arbitrary values; 64 because it seems */
+ /* a little silly to expect performance improvements on a 64x64 bit scale, and */
+ /* 4096 because we buffer one chunk, and a 16MB buffer seems a little largei - it may be */
+ /* OK for one user, but for another to read it, they require the buffer. */
+ /* */
+ if (cs == 0) {
+ cs = GD2_CHUNKSIZE;
+ } else if (cs < GD2_CHUNKSIZE_MIN) {
+ cs = GD2_CHUNKSIZE_MIN;
+ } else if (cs > GD2_CHUNKSIZE_MAX) {
+ cs = GD2_CHUNKSIZE_MAX;
+ };
+
+ /* Work out number of chunks. */
+ ncx = im->sx / cs + 1;
+ ncy = im->sy / cs + 1;
+
+ /* Write the standard header. */
+ _gd2PutHeader(im, out, cs, fmt, ncx, ncy);
+
+ if (fmt == GD2_FMT_COMPRESSED) {
+ /* */
+ /* Work out size of buffer for compressed data, If CHUNKSIZE is large, */
+ /* then these will be large! */
+ /* */
+ /* The zlib notes say output buffer size should be (input size) * 1.01 * 12 */
+ /* - we'll use 1.02 to be paranoid. */
+ /* */
+ compMax = cs * cs * 1.02 + 12;
+
+ /* */
+ /* Allocate the buffers. */
+ /* */
+ chunkData = calloc(cs*cs,1);
+ compData = calloc(compMax,1);
+
+ /* */
+ /* Save the file position of chunk index, and allocate enough space for */
+ /* each chunk_info block . */
+ /* */
+ idxPos = gdTell(out);
+ idxSize = ncx * ncy * sizeof(t_chunk_info);
+ GD2_DBG(printf("Index size is %d\n", idxSize));
+ gdSeek(out,idxPos+idxSize);
+
+ chunkIdx = calloc(idxSize * sizeof(t_chunk_info),1);
+ };
+
+ _gdPutColors(im, out);
+
+ GD2_DBG(printf("Size: %dx%d\n", im->sx, im->sy));
+ GD2_DBG(printf("Chunks: %dx%d\n", ncx, ncy));
+
+ for (cy=0; (cy < ncy); cy++) {
+ for (cx=0; (cx < ncx); cx++) {
+
+ ylo = cy * cs;
+ yhi = ylo + cs;
+ if (yhi > im->sy) {
+ yhi = im->sy;
+ };
+
+ GD2_DBG(printf("Processing Chunk (%dx%d), y from %d to %d\n",cx, cy, ylo, yhi));
+ chunkLen = 0;
+ for (y= ylo ; (y < yhi); y++) {
+
+ /*GD2_DBG(printf("y=%d: ",y)); */
+
+ xlo = cx * cs;
+ xhi = xlo + cs;
+ if (xhi > im->sx) {
+ xhi = im->sx;
+ };
+
+ if (fmt == GD2_FMT_COMPRESSED) {
+ for (x= xlo ; x < xhi; x++) {
+ /*GD2_DBG(printf("%d...",x)); */
+ chunkData[chunkLen++] = im->pixels[y][x];
+ };
+ } else {
+ for (x= xlo ; x < xhi; x++) {
+ /*GD2_DBG(printf("%d, ",x)); */
+ gdPutC((unsigned char)im->pixels[y][x], out);
+ };
+ };
+ /*GD2_DBG(printf("y=%d done.\n",y)); */
+ };
+ if (fmt == GD2_FMT_COMPRESSED) {
+ compLen = compMax;
+ if (compress(&compData[0], &compLen, &chunkData[0], chunkLen) != Z_OK) {
+ printf("Error from compressing\n");
+ } else {
+ chunkIdx[chunkNum].offset = gdTell(out);
+ chunkIdx[chunkNum++].size = compLen;
+ GD2_DBG(printf("Chunk %d size %d offset %d\n",chunkNum, chunkIdx[chunkNum-1].size, chunkIdx[chunkNum-1].offset));
+
+ if (gdPutBuf(compData, compLen, out) <= 0) {
+ /* Any alternate suggestions for handling this? */
+ printf("Error %d on write\n", errno);
+ };
+ };
+ };
+ };
+ };
+ if (fmt == GD2_FMT_COMPRESSED) {
+ /* Save the position, write the index, restore position (paranoia). */
+ GD2_DBG(printf("Seeking %d to write index\n",idxPos));
+ posSave = gdTell(out);
+ gdSeek(out,idxPos);
+ GD2_DBG(printf("Writing index\n"));
+ for (x = 0; x < chunkNum; x++) {
+ GD2_DBG(printf("Chunk %d size %d offset %d\n", x, chunkIdx[x].size, chunkIdx[x].offset));
+ gdPutInt(chunkIdx[x].offset, out);
+ gdPutInt(chunkIdx[x].size, out);
+ };
+ /* We don't use fwrite for *endian reasons. */
+ /*fwrite(chunkIdx, sizeof(int)*2, chunkNum, out); */
+ gdSeek(out, posSave);
+ };
+
+ GD2_DBG(printf("Freeing memory\n"));
+ free(chunkData);
+ free(compData);
+ free(chunkIdx);
+ GD2_DBG(printf("Done\n"));
+
+ /*printf("Memory block size is %d\n",gdTell(out)); */
+
+}
+
+void gdImageGd2(gdImagePtr im, FILE *outFile, int cs, int fmt)
+{
+ gdIOCtx *out = gdNewFileCtx(outFile);
+ _gdImageGd2(im, out, cs, fmt);
+ out->free(out);
+}
+
+void* gdImageGd2Ptr(gdImagePtr im, int cs, int fmt, int *size)
+{
+ void *rv;
+ gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
+ _gdImageGd2(im, out, cs, fmt);
+ rv = gdDPExtractData(out, size);
+ out->free(out);
+ return rv;
+}
+
+
diff --git a/src/gd_io.c b/src/gd_io.c
new file mode 100644
index 0000000..98b6fec
--- /dev/null
+++ b/src/gd_io.c
@@ -0,0 +1,157 @@
+/*
+* io.c
+*
+* Implements the imple I/O 'helper' routines.
+*
+* Not really essential, but these routines were used extensively in GD,
+* so they were moved here. They also make IOCtx calls look better...
+*
+* Written (or, at least, moved) 1999, Philip Warner.
+*
+*/
+
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include "gd.h"
+
+/* Use this for commenting out debug-print statements. */
+/* Just use the first '#define' to allow all the prints... */
+/*#define IO_DBG(s) (s) */
+#define IO_DBG(s)
+
+
+/*
+ * Write out a word to the I/O context pointer
+ */
+void
+Putword(int w, gdIOCtx *ctx)
+{
+ unsigned char buf[2];
+ buf[0] = w & 0xff;
+ buf[1] = (w / 256) & 0xff;
+ (ctx->putBuf)( ctx, (char *) buf, 2);
+}
+
+void
+Putchar(int c, gdIOCtx *ctx)
+{
+ (ctx->putC)( ctx, c & 0xff );
+}
+
+void gdPutC(const unsigned char c, gdIOCtx *ctx)
+{
+ (ctx->putC)(ctx, c);
+}
+
+void
+gdPutWord(int w, gdIOCtx *ctx)
+{
+ IO_DBG(printf("Putting word...\n"));
+ (ctx->putC)(ctx, (unsigned char)(w >> 8));
+ (ctx->putC)(ctx, (unsigned char)(w & 0xFF));
+ IO_DBG(printf("put.\n"));
+}
+
+void gdPutInt(int w, gdIOCtx *ctx)
+{
+ IO_DBG(printf("Putting int...\n"));
+ (ctx->putC)(ctx, (unsigned char)(w >> 24));
+ (ctx->putC)(ctx, (unsigned char)((w >> 16) & 0xFF));
+ (ctx->putC)(ctx, (unsigned char)((w >> 8) & 0xFF));
+ (ctx->putC)(ctx, (unsigned char)(w & 0xFF));
+ IO_DBG(printf("put.\n"));
+}
+
+int gdGetC(gdIOCtx *ctx)
+{
+ return ((ctx->getC)(ctx));
+}
+
+
+
+int gdGetByte(int *result, gdIOCtx *ctx)
+{
+ int r;
+ r = (ctx->getC)(ctx);
+ if (r == EOF) {
+ return 0;
+ }
+ *result = r;
+ return 1;
+}
+
+int gdGetWord(int *result, gdIOCtx *ctx)
+{
+ int r;
+ r = (ctx->getC)(ctx);
+ if (r == EOF) {
+ return 0;
+ }
+ *result = r << 8;
+ r = (ctx->getC)(ctx);
+ if (r == EOF) {
+ return 0;
+ }
+ *result += r;
+ return 1;
+}
+
+
+int gdGetInt(int *result, gdIOCtx *ctx)
+{
+ int r;
+ r = (ctx->getC)(ctx);
+ if (r == EOF) {
+ return 0;
+ }
+ *result = r << 24;
+
+ r = (ctx->getC)(ctx);
+ if (r == EOF) {
+ return 0;
+ }
+ *result += r << 16;
+
+ r = (ctx->getC)(ctx);
+ if (r == EOF) {
+ return 0;
+ }
+ *result += r << 8;
+
+ r = (ctx->getC)(ctx);
+ if (r == EOF) {
+ return 0;
+ }
+ *result += r;
+
+ return 1;
+}
+
+int gdPutBuf(const void *buf, int size, gdIOCtx* ctx)
+{
+ IO_DBG(printf("Putting buf...\n"));
+ return (ctx->putBuf)(ctx, buf, size);
+ IO_DBG(printf("put.\n"));
+}
+
+int gdGetBuf(void *buf, int size, gdIOCtx* ctx)
+{
+ return (ctx->getBuf)(ctx, buf, size);
+}
+
+
+int gdSeek(gdIOCtx *ctx, int pos)
+{
+ IO_DBG(printf("Seeking...\n"));
+ return ((ctx->seek)(ctx, pos));
+ IO_DBG(printf("Done.\n"));
+}
+
+long gdTell(gdIOCtx *ctx)
+{
+ IO_DBG(printf("Telling...\n"));
+ return ((ctx->tell)(ctx));
+ IO_DBG(printf("told.\n"));
+}
+
diff --git a/src/gd_io.h b/src/gd_io.h
new file mode 100644
index 0000000..5c0bd24
--- /dev/null
+++ b/src/gd_io.h
@@ -0,0 +1,39 @@
+#ifndef GD_IO_H
+#define GD_IO_H 1
+
+#include <stdio.h>
+
+typedef struct gdIOCtx {
+ int (*getC)(struct gdIOCtx*);
+ int (*getBuf)(struct gdIOCtx*, void*, int);
+
+ void (*putC)(struct gdIOCtx*, int);
+ int (*putBuf)(struct gdIOCtx*, const void*, int);
+
+ int (*seek)(struct gdIOCtx*, const int);
+ long (*tell)(struct gdIOCtx*);
+
+ void (*free)(struct gdIOCtx*);
+
+} gdIOCtx;
+
+typedef struct gdIOCtx *gdIOCtxPtr;
+
+void Putword(int w, gdIOCtx *ctx);
+void Putchar(int c, gdIOCtx *ctx);
+
+void gdPutC(const unsigned char c, gdIOCtx *ctx);
+int gdPutBuf(const void *, int, gdIOCtx*);
+void gdPutWord(int w, gdIOCtx *ctx);
+void gdPutInt(int w, gdIOCtx *ctx);
+
+int gdGetC(gdIOCtx *ctx);
+int gdGetBuf(void *, int, gdIOCtx*);
+int gdGetByte(int *result, gdIOCtx *ctx);
+int gdGetWord(int *result, gdIOCtx *ctx);
+int gdGetInt(int *result, gdIOCtx *ctx);
+
+int gdSeek(gdIOCtx *ctx, const int);
+long gdTell(gdIOCtx *ctx);
+
+#endif
diff --git a/src/gd_io_dp.c b/src/gd_io_dp.c
new file mode 100644
index 0000000..fe8191b
--- /dev/null
+++ b/src/gd_io_dp.c
@@ -0,0 +1,375 @@
+/*
+* io_dp.c
+*
+* Implements the dynamic pointer interface.
+*
+* Based on GD.pm code by Lincoln Stein for interfacing to libgd.
+* Added support for reading as well as support for 'tell' and 'seek'.
+*
+* As will all I/O modules, most functions are for local use only (called
+* via function pointers in the I/O context).
+*
+* gdDPExtractData is the exception to this: it will return the pointer to
+* the internal data, and reset the internal storage.
+*
+* Written/Modified 1999, Philip Warner.
+*
+*/
+
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include "gd.h"
+
+#define TRUE 1
+#define FALSE 0
+
+/* this is used for creating images in main memory*/
+typedef struct dpStruct {
+ void* data;
+ int logicalSize;
+ int realSize;
+ int dataGood;
+ int pos;
+} dynamicPtr;
+
+typedef struct dpIOCtx {
+ gdIOCtx ctx;
+ dynamicPtr *dp;
+} dpIOCtx;
+
+typedef struct dpIOCtx *dpIOCtxPtr;
+
+
+/* these functions operate on in-memory dynamic pointers */
+static int allocDynamic (dynamicPtr* dp,int initialSize, void *data);
+static int appendDynamic (dynamicPtr* dp, const void* src, int size);
+static int reallocDynamic (dynamicPtr* dp, int required);
+static int trimDynamic (dynamicPtr* dp);
+static void freeDynamic (dynamicPtr* dp);
+static void freeDynamicCtx(struct gdIOCtx* ctx);
+static dynamicPtr* newDynamic(int initialSize, void *data);
+
+static int dynamicPutbuf( struct gdIOCtx*, const void *, int );
+static void dynamicPutchar( struct gdIOCtx*, int a );
+
+static int dynamicGetbuf( gdIOCtxPtr ctx, void *buf, int len);
+static int dynamicGetchar( gdIOCtxPtr ctx );
+
+static int dynamicSeek(struct gdIOCtx*, const int);
+static long dynamicTell(struct gdIOCtx*);
+
+/* return data as a dynamic pointer */
+gdIOCtx* gdNewDynamicCtx (int initialSize, void *data) {
+ dpIOCtx *ctx;
+ dynamicPtr* dp;
+
+ ctx = (dpIOCtx*) malloc(sizeof(dpIOCtx));
+ if (ctx == NULL) {
+ return NULL;
+ }
+
+ dp = newDynamic(initialSize, data);
+ if (!dp) {
+ free(ctx);
+ return NULL;
+ };
+
+ ctx->dp = dp;
+
+ ctx->ctx.getC = dynamicGetchar;
+ ctx->ctx.putC = dynamicPutchar;
+
+ ctx->ctx.getBuf = dynamicGetbuf;
+ ctx->ctx.putBuf = dynamicPutbuf;
+
+ ctx->ctx.seek = dynamicSeek;
+ ctx->ctx.tell = dynamicTell;
+
+ ctx->ctx.free = freeDynamicCtx;
+
+ return (gdIOCtx*)ctx;
+};
+
+void* gdDPExtractData(struct gdIOCtx* ctx, int *size)
+{
+ dynamicPtr *dp;
+ dpIOCtx *dctx;
+ void *data;
+
+ dctx = (dpIOCtx*) ctx;
+ dp = dctx->dp;
+
+ /* clean up the data block and return it */
+ if (dp->dataGood) {
+ trimDynamic(dp);
+ *size = dp->logicalSize;
+ data = dp->data;
+ } else {
+ *size = 0;
+ data = NULL;
+ if (dp->data != NULL) {
+ free(dp->data);
+ }
+ }
+
+ dp->data = NULL;
+ dp->realSize=0;
+ dp->logicalSize=0;
+
+ return data;
+}
+
+static
+void freeDynamicCtx(struct gdIOCtx* ctx)
+{
+ dynamicPtr *dp;
+ dpIOCtx *dctx;
+
+ dctx = (dpIOCtx*) ctx;
+ dp = dctx->dp;
+
+ free(ctx);
+
+ /* clean up the data block and return it */
+ if (dp->data != NULL) {
+ free(dp->data);
+ }
+
+ free(dp);
+}
+
+static long dynamicTell(struct gdIOCtx* ctx)
+{
+ dpIOCtx *dctx;
+
+ dctx = (dpIOCtx*) ctx;
+ return (dctx->dp->pos);
+}
+
+static int dynamicSeek(struct gdIOCtx* ctx, const int pos)
+{
+ int bytesNeeded;
+ char* tmp;
+ dynamicPtr *dp;
+ dpIOCtx *dctx;
+
+ dctx = (dpIOCtx*) ctx;
+ dp = dctx->dp;
+
+ if (!dp->dataGood) return FALSE;
+
+ bytesNeeded = pos;
+ if (bytesNeeded > dp->realSize) {
+ if (!reallocDynamic(dp,dp->realSize*2)) {
+ dp->dataGood = FALSE;
+ return FALSE;
+ }
+ }
+
+ /* if we get here, we can be sure that we have enough bytes
+ to copy safely */
+
+ /* Extend the logical size if we seek beyond EOF. */
+ if (pos > dp->logicalSize) {
+ dp->logicalSize = pos;
+ };
+
+ dp->pos = pos;
+
+ return TRUE;
+}
+
+/* return data as a dynamic pointer */
+static dynamicPtr* newDynamic (int initialSize, void *data) {
+ dynamicPtr* dp;
+ dp = (dynamicPtr*) malloc(sizeof(dynamicPtr));
+ if (dp == NULL) {
+ return NULL;
+ }
+
+ if (!allocDynamic(dp,initialSize, data))
+ return NULL;
+
+ dp->pos = 0;
+
+ return dp;
+};
+
+static int
+dynamicPutbuf( struct gdIOCtx* ctx, const void *buf, int size )
+{
+ dpIOCtx *dctx;
+ dctx = (dpIOCtx*) ctx;
+
+ appendDynamic(dctx->dp,buf,size);
+
+ if (dctx->dp->dataGood) {
+ return size;
+ } else {
+ return -1;
+ };
+
+}
+
+static void
+dynamicPutchar( struct gdIOCtx* ctx, int a )
+{
+ unsigned char b;
+ dpIOCtxPtr dctx;
+
+ b = a;
+ dctx = (dpIOCtxPtr) ctx;
+
+ appendDynamic(dctx->dp,&b,1);
+}
+
+static int
+dynamicGetbuf( gdIOCtxPtr ctx, void *buf, int len)
+{
+ int rlen, remain;
+ dpIOCtxPtr dctx;
+ dynamicPtr* dp;
+
+ dctx = (dpIOCtxPtr) ctx;
+ dp = dctx->dp;
+
+ remain = dp->logicalSize - dp->pos;
+ if (remain >= len) {
+ rlen = len;
+ } else {
+ if (remain == 0) {
+ return EOF;
+ }
+ rlen = remain;
+ }
+
+ memcpy(buf, (void*)((int)dp->data + dp->pos), rlen);
+ dp->pos += rlen;
+
+ return rlen;
+}
+
+static int
+dynamicGetchar( gdIOCtxPtr ctx )
+{
+ unsigned char b;
+ int rv;
+
+ rv = dynamicGetbuf(ctx, &b, 1);
+
+ if (rv != 1) {
+ return EOF;
+ } else {
+ return b ;/* (b & 0xff); */
+ }
+}
+
+/* *********************************************************************
+ *
+ * InitDynamic - Return a dynamically resizable void*
+ *
+ * *********************************************************************
+ */
+static int
+allocDynamic (dynamicPtr* dp,int initialSize, void *data) {
+
+ if (data == NULL) {
+ dp->logicalSize = 0;
+ dp->dataGood = FALSE;
+ dp->data = malloc(initialSize);
+ } else {
+ dp->logicalSize = initialSize;
+ dp->dataGood = TRUE;
+ dp->data = data;
+ }
+
+ if (dp->data !=NULL) {
+ dp->realSize = initialSize;
+ dp->dataGood = TRUE;
+ dp->pos = 0;
+ return TRUE;
+ } else {
+ dp->realSize = 0;
+ return FALSE;
+ }
+}
+
+/* append bytes to the end of a dynamic pointer */
+static int
+appendDynamic (dynamicPtr* dp, const void* src, int size) {
+ int bytesNeeded;
+ char* tmp;
+
+ if (!dp->dataGood) return FALSE;
+
+/* bytesNeeded = dp->logicalSize + size; */
+ bytesNeeded = dp->pos + size;
+
+ if (bytesNeeded > dp->realSize) {
+ if (!reallocDynamic(dp,bytesNeeded*2)) {
+ dp->dataGood = FALSE;
+ return FALSE;
+ }
+ }
+
+ /* if we get here, we can be sure that we have enough bytes
+ to copy safely */
+ /*printf("Mem OK Size: %d, Pos: %d\n", dp->realSize, dp->pos); */
+
+ tmp = (char*)dp->data;
+ memcpy((void*)(tmp+(dp->pos)),src,size);
+ dp->pos += size;
+
+ if (dp->pos > dp->logicalSize) {
+ dp->logicalSize = dp->pos;
+ };
+
+ return TRUE;
+}
+
+/* grow (or shrink) dynamic pointer */
+static int
+reallocDynamic (dynamicPtr* dp, int required) {
+ void* newPtr;
+
+ /* First try realloc(). If that doesn't work, make a new
+ memory block and copy. */
+ if (newPtr = realloc(dp->data,required)) {
+ dp->realSize = required;
+ dp->data = newPtr;
+ return TRUE;
+ }
+
+ /* create a new pointer */
+ newPtr = malloc(required);
+ if (!newPtr) {
+ dp->dataGood = FALSE;
+ return FALSE;
+ }
+
+ /* copy the old data into it */
+ memcpy(newPtr,dp->data,dp->logicalSize);
+ free(dp->data);
+ dp->data = newPtr;
+
+ dp->realSize = required;
+ return TRUE;
+}
+
+/* trim pointer so that its real and logical sizes match */
+static int
+trimDynamic (dynamicPtr* dp) {
+ return reallocDynamic(dp,dp->logicalSize);
+}
+
+/* dispose of the dynamic pointer */
+static void
+freeDynamic (dynamicPtr* dp) {
+ if (dp->data != NULL) {
+ free(dp->data);
+ dp->data = NULL;
+ }
+ dp->realSize=0;
+ dp->logicalSize=0;
+}
diff --git a/src/gd_io_file.c b/src/gd_io_file.c
new file mode 100644
index 0000000..3c63149
--- /dev/null
+++ b/src/gd_io_file.c
@@ -0,0 +1,127 @@
+/*
+* io_file.c
+*
+* Implements the file interface.
+*
+* As will all I/O modules, most functions are for local use only (called
+* via function pointers in the I/O context).
+*
+* Most functions are just 'wrappers' for standard file functions.
+*
+* Written/Modified 1999, Philip Warner.
+*
+*/
+
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include "gd.h"
+
+/* this is used for creating images in main memory*/
+
+typedef struct fileIOCtx {
+ gdIOCtx ctx;
+ FILE *f;
+} fileIOCtx;
+
+struct fileIOCtx *fileIOCtxPtr;
+
+gdIOCtx* newFileCtx(FILE *f);
+
+static int fileGetbuf( gdIOCtx*, void *, int );
+static int filePutbuf( gdIOCtx*, const void *, int );
+static void filePutchar( gdIOCtx*, int );
+static int fileGetchar( gdIOCtx* ctx);
+
+static int fileSeek(struct gdIOCtx*, const int);
+static long fileTell(struct gdIOCtx*);
+static void freeFileCtx(gdIOCtx *ctx);
+
+/* return data as a dynamic pointer */
+gdIOCtx* gdNewFileCtx (FILE *f) {
+ fileIOCtx *ctx;
+
+ ctx = (fileIOCtx*) malloc(sizeof(fileIOCtx));
+ if (ctx == NULL) {
+ return NULL;
+ }
+
+ ctx->f = f;
+
+ ctx->ctx.getC = fileGetchar;
+ ctx->ctx.putC = filePutchar;
+
+ ctx->ctx.getBuf = fileGetbuf;
+ ctx->ctx.putBuf = filePutbuf;
+
+ ctx->ctx.tell = fileTell;
+ ctx->ctx.seek = fileSeek;
+
+ ctx->ctx.free = freeFileCtx;
+
+ return (gdIOCtx*)ctx;
+};
+
+static
+void freeFileCtx(gdIOCtx *ctx)
+{
+ free(ctx);
+}
+
+
+static int
+filePutbuf( gdIOCtx* ctx, const void *buf, int size )
+{
+ fileIOCtx *fctx;
+ fctx = (fileIOCtx*) ctx;
+
+ return fwrite(buf, 1, size, fctx->f);
+
+}
+
+static int
+fileGetbuf( gdIOCtx* ctx, void *buf, int size )
+{
+ fileIOCtx *fctx;
+ fctx = (fileIOCtx*) ctx;
+
+ return (fread(buf, 1, size, fctx->f));
+
+}
+
+static void
+filePutchar( gdIOCtx* ctx, int a )
+{
+ unsigned char b;
+ fileIOCtx *fctx;
+ fctx = (fileIOCtx*) ctx;
+
+ b = a;
+
+ putc(b, fctx->f);
+}
+
+static int fileGetchar( gdIOCtx* ctx)
+{
+ fileIOCtx *fctx;
+ fctx = (fileIOCtx*) ctx;
+
+ return getc(fctx->f);
+}
+
+static int fileSeek(struct gdIOCtx* ctx, const int pos)
+{
+ fileIOCtx *fctx;
+ fctx = (fileIOCtx*) ctx;
+
+ return (fseek(fctx->f, pos, SEEK_SET) == 0);
+}
+
+static long fileTell(struct gdIOCtx* ctx)
+{
+ fileIOCtx *fctx;
+ fctx = (fileIOCtx*) ctx;
+
+ return ftell(fctx->f);
+}
+
diff --git a/src/gd_io_ss.c b/src/gd_io_ss.c
new file mode 100644
index 0000000..7392a87
--- /dev/null
+++ b/src/gd_io_ss.c
@@ -0,0 +1,147 @@
+/*
+* io_ss.c
+*
+* Implements the Source/Sink interface.
+*
+* As will all I/O modules, most functions are for local use only (called
+* via function pointers in the I/O context).
+*
+* The Source/Sink model is the primary 'user' interface for alternate data
+* sources; the IOCtx interface is intended (at least in version 1.5) to be
+* used internally until it settles down a bit.
+*
+* This module just layers the Source/Sink interface on top of the IOCtx; no
+* support is provided for tell/seek, so GD2 writing is not possible, and
+* retrieving parts of GD2 files is also not possible.
+*
+* A new SS context does not need to be created with both a Source and a Sink.
+*
+* Written/Modified 1999, Philip Warner.
+*
+*/
+
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include "gd.h"
+
+/* this is used for creating images in main memory*/
+
+typedef struct ssIOCtx {
+ gdIOCtx ctx;
+ gdSourcePtr src;
+ gdSinkPtr snk;
+} ssIOCtx;
+
+typedef struct ssIOCtx *ssIOCtxPtr;
+
+gdIOCtx* gdNewSSCtx(gdSourcePtr src, gdSinkPtr snk);
+
+static int sourceGetbuf( gdIOCtx*, void *, int );
+static int sourceGetchar( gdIOCtx* ctx);
+static int sinkPutbuf( gdIOCtx* ctx, const void *buf, int size );
+static void sinkPutchar( gdIOCtx* ctx, int a );
+static void freeSsCtx(gdIOCtx *ctx);
+
+/* return data as a dynamic pointer */
+gdIOCtx* gdNewSSCtx (gdSourcePtr src, gdSinkPtr snk) {
+ ssIOCtxPtr ctx;
+
+ ctx = (ssIOCtxPtr) malloc(sizeof(ssIOCtx));
+ if (ctx == NULL) {
+ return NULL;
+ }
+
+ ctx->src = src;
+ ctx->snk = snk;
+
+ ctx->ctx.getC = sourceGetchar;
+ ctx->ctx.getBuf = sourceGetbuf;
+
+ ctx->ctx.putC = sinkPutchar;
+ ctx->ctx.putBuf = sinkPutbuf;
+
+ ctx->ctx.tell = NULL;
+ ctx->ctx.seek = NULL;
+
+ ctx->ctx.free = freeSsCtx;
+
+ return (gdIOCtx*)ctx;
+};
+
+static
+void freeSsCtx(gdIOCtx *ctx)
+{
+ free(ctx);
+}
+
+
+static int
+sourceGetbuf( gdIOCtx* ctx, void *buf, int size )
+{
+ ssIOCtx *lctx;
+ int res;
+
+ lctx = (ssIOCtx*) ctx;
+
+ res = ((lctx->src->source)(lctx->src->context, buf, size));
+
+/*
+** Translate the return values from the Source object:
+** 0 is EOF, -1 is error
+*/
+
+ if (res == 0) {
+ return EOF;
+ } else if (res < 0) {
+ return 0;
+ } else {
+ return res;
+ };
+
+}
+
+static int sourceGetchar( gdIOCtx* ctx)
+{
+ int res;
+ unsigned char buf;
+
+ res = sourceGetbuf(ctx, &buf, 1);
+
+ if (res == 1) {
+ return buf;
+ } else {
+ return EOF;
+ };
+
+}
+
+static int
+sinkPutbuf( gdIOCtx* ctx, const void *buf, int size )
+{
+ ssIOCtxPtr lctx;
+ int res;
+
+ lctx = (ssIOCtx*) ctx;
+
+ res = (lctx->snk->sink)(lctx->snk->context, buf, size);
+
+ if (res <= 0) {
+ return 0;
+ } else {
+ return res;
+ };
+
+}
+
+static void
+sinkPutchar( gdIOCtx* ctx, int a )
+{
+ unsigned char b;
+
+ b = a;
+ sinkPutbuf(ctx, &b, 1);
+
+}
+
+
diff --git a/src/gd_png.c b/src/gd_png.c
new file mode 100644
index 0000000..de1f008
--- /dev/null
+++ b/src/gd_png.c
@@ -0,0 +1,227 @@
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include "gd.h"
+#include "png.h"
+
+#define TRUE 1
+#define FALSE 0
+
+/* Exported functions */
+extern void gdImagePng(gdImagePtr im, FILE *out);
+extern gdImagePtr gdImageCreateFromPng(FILE *in);
+
+gdImagePtr gdImageCreateFromPng(FILE *inFile)
+{
+ gdImagePtr im;
+ gdIOCtx *in = gdNewFileCtx(inFile);
+ im = gdImageCreateFromPngCtx(in);
+ in->free(in);
+ return im;
+}
+
+void png_read_data(png_structp png_ptr,
+ png_bytep data, png_size_t length)
+{
+ gdGetBuf(data, length, (gdIOCtx *)
+ png_get_io_ptr(png_ptr));
+}
+
+gdImagePtr gdImageCreateFromPngCtx(gdIOCtxPtr in)
+{
+ gdImagePtr im;
+ png_structp png_ptr;
+ png_infop info_ptr;
+ int i;
+ png_ptr = malloc(sizeof(png_struct));
+ if (!png_ptr) {
+ return 0;
+ }
+ info_ptr = malloc(sizeof(png_info));
+ if (!info_ptr) {
+ return 0;
+ }
+ if (setjmp(png_ptr->jmpbuf)) {
+ png_write_destroy(png_ptr);
+ free(png_ptr);
+ free(info_ptr);
+ return 0;
+ }
+ png_info_init(info_ptr);
+ png_read_init(png_ptr);
+ png_set_read_fn(png_ptr,
+ (void *) in,
+ png_read_data);
+ /* Turn non-palette PNGs into palette PNGs. This will
+ go away in a future 24-bit GD. It's not a very
+ good way of doing things. */
+ if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) {
+ png_colorp std_color_cube;
+ int r, g, b;
+ int i = 0;
+ std_color_cube = malloc(sizeof(png_color) * 216);
+ for (r = 0; (r < 6); r++) {
+ for (g = 0; (g < 6); g++) {
+ for (b = 0; (b < 6); b++) {
+ std_color_cube[i].red =
+ r * 51;
+ std_color_cube[i].green =
+ g * 51;
+ std_color_cube[i].blue =
+ b * 51;
+ i++;
+ }
+ }
+ }
+ png_set_dither(png_ptr, std_color_cube,
+ 216, 216,
+ NULL, 0);
+ }
+ png_read_info(png_ptr, info_ptr);
+ if (info_ptr->valid &PNG_INFO_gAMA) {
+ png_set_gamma(png_ptr, 2.0, info_ptr->gamma);
+ } else {
+ png_set_gamma(png_ptr, 2.0, 0.45);
+ }
+ im = gdImageCreate(info_ptr->width,
+ info_ptr->height);
+ if (!im) {
+ longjmp(png_ptr->jmpbuf, 1);
+ }
+ im->interlace = info_ptr->interlace_type ? 1 : 0;
+ png_set_strip_16(png_ptr);
+ png_set_packing(png_ptr);
+ png_read_update_info(png_ptr, info_ptr);
+ /* This works because gd's internal data structure
+ happens to be compatible at this time. */
+ png_read_image(png_ptr, (png_bytepp) im->pixels);
+ png_read_end(png_ptr, info_ptr);
+ for (i = 0; (i < info_ptr -> num_palette); i++) {
+ im->red[i] = info_ptr -> palette[i].red;
+ im->green[i] = info_ptr -> palette[i].green;
+ im->blue[i] = info_ptr -> palette[i].blue;
+ im->open[i] = 0;
+ }
+ im->colorsTotal = info_ptr -> num_palette;
+ png_destroy_read_struct(
+ &png_ptr, &info_ptr,
+ (png_infopp) 0);
+ return im;
+}
+
+void png_write_data(png_structp png_ptr,
+ png_bytep data, png_size_t length)
+{
+ gdPutBuf(data, length, (gdIOCtx *)
+ png_get_io_ptr(png_ptr));
+}
+
+void png_flush_data(png_structp png_ptr)
+{
+}
+
+static void _gdImagePng(gdImagePtr im, gdIOCtx *out)
+{
+ int x, y;
+ int depth = 1;
+ int allocated = 2;
+ int i;
+ png_structp png_ptr;
+ png_infop info_ptr;
+ png_ptr = malloc(sizeof(png_struct));
+ if (!png_ptr) {
+ return;
+ }
+ info_ptr = malloc(sizeof(png_info));
+ if (!info_ptr) {
+ return;
+ }
+ if (setjmp(png_ptr->jmpbuf)) {
+ png_write_destroy(png_ptr);
+ free(png_ptr);
+ free(info_ptr);
+ return;
+ }
+ png_info_init(info_ptr);
+ png_write_init(png_ptr);
+ png_set_write_fn(png_ptr,
+ (void *) out,
+ png_write_data,
+ png_flush_data);
+ while (allocated < im->colorsTotal) {
+ allocated <<= 1;
+ depth++;
+ }
+ /* Legal PNG palette bit depths are 1, 2, 4, and 8. */
+ if (depth > 2) {
+ if (depth > 4) {
+ depth = 8;
+ } else {
+ depth = 4;
+ }
+ }
+ info_ptr->width = im->sx;
+ info_ptr->height = im->sy;
+ info_ptr->bit_depth = depth;
+ info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
+ if (im->interlace) {
+ info_ptr->interlace_type = 1;
+ } else {
+ info_ptr->interlace_type = 0;
+ }
+ info_ptr->valid |= PNG_INFO_PLTE;
+ info_ptr->palette = (png_colorp) malloc(sizeof(png_color) *
+ im->colorsTotal);
+ for (i = 0; (i < im->colorsTotal); i++) {
+ info_ptr->palette[i].red = im->red[i];
+ info_ptr->palette[i].green = im->green[i];
+ info_ptr->palette[i].blue = im->blue[i];
+ }
+ info_ptr->num_palette = im->colorsTotal;
+ if (im->transparent != -1) {
+ info_ptr->trans = (png_bytep) malloc(1);
+ info_ptr->trans[0] = im->transparent;
+ info_ptr->num_trans = 1;
+ }
+ png_write_info(png_ptr, info_ptr);
+ png_set_packing(png_ptr);
+ /* NOTE: this is dependent on the current
+ representation of pixels! It happens
+ to be compatible with libpng. */
+ png_write_image(png_ptr, (png_byte **) im->pixels);
+ png_write_end(png_ptr, info_ptr);
+ png_write_destroy(png_ptr);
+ if (info_ptr->palette) {
+ free(info_ptr->palette);
+ }
+ if (info_ptr->trans) {
+ free(info_ptr->trans);
+ }
+ free(png_ptr);
+ free(info_ptr);
+}
+
+void gdImagePng(gdImagePtr im, FILE *outFile)
+{
+ gdIOCtx *out = gdNewFileCtx(outFile);
+ _gdImagePng(im, out);
+ out->free(out);
+}
+
+void gdImagePngCtx(gdImagePtr im, gdIOCtx *out)
+{
+ _gdImagePng(im, out);
+}
+
+void* gdImagePngPtr(gdImagePtr im, int *size)
+{
+ void *rv;
+ gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
+ _gdImagePng(im, out);
+ rv = gdDPExtractData(out, size);
+ out->free(out);
+ return rv;
+}
+
+
diff --git a/src/gd_ss.c b/src/gd_ss.c
new file mode 100644
index 0000000..fffeef7
--- /dev/null
+++ b/src/gd_ss.c
@@ -0,0 +1,38 @@
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include "gd.h"
+
+#define TRUE 1
+#define FALSE 0
+
+/* Exported functions: */
+extern void gdImagePngToSink(gdImagePtr im, gdSinkPtr out);
+extern gdImagePtr gdImageCreateFromPngSource(gdSourcePtr inSource);
+
+/* Use this for commenting out debug-print statements. */
+/* Just use the first '#define' to allow all the prints... */
+/*#define GD_SS_DBG(s) (s) */
+#define GD_SS_DBG(s)
+
+void gdImagePngToSink(gdImagePtr im, gdSinkPtr outSink)
+{
+ gdIOCtx *out = gdNewSSCtx(NULL,outSink);
+ gdImagePngCtx(im, out);
+ out->free(out);
+}
+
+gdImagePtr gdImageCreateFromPngSource(gdSourcePtr inSource)
+{
+ gdIOCtx *in = gdNewSSCtx(inSource, NULL);
+ gdImagePtr im;
+
+ im = gdImageCreateFromPngCtx(in);
+
+ in->free(in);
+
+ return im;
+}
+
+
diff --git a/src/gddemo.c b/src/gddemo.c
index 87f0b98..857498c 100644
--- a/src/gddemo.c
+++ b/src/gddemo.c
@@ -33,17 +33,17 @@ int main(void)
/* Set transparent color. */
gdImageColorTransparent(im_out, white);
- /* Try to load demoin.gif and paste part of it into the
+ /* Try to load demoin.png and paste part of it into the
output image. */
- in = fopen("demoin.gif", "rb");
+ in = fopen("demoin.png", "rb");
if (!in) {
fprintf(stderr, "Can't load source image; this demo\n");
- fprintf(stderr, "is much more impressive if demoin.gif\n");
+ fprintf(stderr, "is much more impressive if demoin.png\n");
fprintf(stderr, "is available.\n");
im_in = 0;
} else {
- im_in = gdImageCreateFromGif(in);
+ im_in = gdImageCreateFromPng(in);
fclose(in);
/* Now copy, and magnify as we do so */
gdImageCopyResized(im_out, im_in,
@@ -100,9 +100,9 @@ int main(void)
/* Make output image interlaced (allows "fade in" in some viewers,
and in the latest web browsers) */
gdImageInterlace(im_out, 1);
- out = fopen("demoout.gif", "wb");
- /* Write GIF */
- gdImageGif(im_out, out);
+ out = fopen("demoout.png", "wb");
+ /* Write PNG */
+ gdImagePng(im_out, out);
fclose(out);
gdImageDestroy(im_out);
if (im_in) {
diff --git a/src/gdparttopng.c b/src/gdparttopng.c
new file mode 100644
index 0000000..5dfbd2e
--- /dev/null
+++ b/src/gdparttopng.c
@@ -0,0 +1,48 @@
+#include <stdio.h>
+#include "gd.h"
+
+/* A short program which converts a .png file into a .gd file, for
+ your convenience in creating images on the fly from a
+ basis image that must be loaded quickly. The .gd format
+ is not intended to be a general-purpose format. */
+
+int main(int argc, char **argv)
+{
+ gdImagePtr im;
+ FILE *in, *out;
+ int x, y, w, h;
+
+ if (argc != 7) {
+ fprintf(stderr, "Usage: gdparttopng filename.gd filename.png x y w h\n");
+ exit(1);
+ }
+ in = fopen(argv[1], "rb");
+ if (!in) {
+ fprintf(stderr, "Input file does not exist!\n");
+ exit(1);
+ }
+
+ x = atoi(argv[3]);
+ y = atoi(argv[4]);
+ w = atoi(argv[5]);
+ h = atoi(argv[6]);
+
+ printf("Extracting from (%d, %d), size is %dx%d\n", x, y, w, h);
+
+ im = gdImageCreateFromGd2Part(in, x, y, w, h);
+ fclose(in);
+ if (!im) {
+ fprintf(stderr, "Input is not in PNG format!\n");
+ exit(1);
+ }
+ out = fopen(argv[2], "wb");
+ if (!out) {
+ fprintf(stderr, "Output file cannot be written to!\n");
+ gdImageDestroy(im);
+ exit(1);
+ }
+ gdImagePng(im, out);
+ fclose(out);
+ gdImageDestroy(im);
+}
+
diff --git a/src/gdtest.c b/src/gdtest.c
index 0d73872..6962d90 100644
--- a/src/gdtest.c
+++ b/src/gdtest.c
@@ -1,13 +1,15 @@
#include <stdio.h>
#include "gd.h"
-/* A short program which converts a .gif file into a .gd file, for
+/* A short program which converts a .png file into a .gd file, for
your convenience in creating images on the fly from a
basis image that must be loaded quickly. The .gd format
is not intended to be a general-purpose format. */
void CompareImages(char *msg, gdImagePtr im1, gdImagePtr im2);
+static int freadWrapper(void *context, char *buf, int len);
+static int fwriteWrapper(void *context, const char *buffer, int len);
int main(int argc, char **argv)
{
@@ -20,10 +22,11 @@ int main(int argc, char **argv)
char of[256];
int colRed, colBlu;
int idx;
-
+ gdSource imgsrc;
+ gdSink imgsnk;
if (argc != 2) {
- fprintf(stderr, "Usage: gdtest filename.gif\n");
+ fprintf(stderr, "Usage: gdtest filename.png\n");
exit(1);
}
in = fopen(argv[1], "rb");
@@ -31,10 +34,10 @@ int main(int argc, char **argv)
fprintf(stderr, "Input file does not exist!\n");
exit(1);
}
- im = gdImageCreateFromGif(in);
+ im = gdImageCreateFromPng(in);
rewind(in);
- ref = gdImageCreateFromGif(in);
+ ref = gdImageCreateFromPng(in);
fclose(in);
@@ -44,31 +47,31 @@ int main(int argc, char **argv)
/* */
- /* Send to GIF File then Ptr */
+ /* Send to PNG File then Ptr */
/* */
- sprintf(of, "%s.gif", argv[1]);
+ sprintf(of, "%s.png", argv[1]);
out = fopen(of, "wb");
- gdImageGif(im, out);
+ gdImagePng(im, out);
fclose(out);
in = fopen(of, "rb");
if (!in) {
- fprintf(stderr, "GIF Output file does not exist!\n");
+ fprintf(stderr, "PNG Output file does not exist!\n");
exit(1);
}
- im2 = gdImageCreateFromGif(in);
+ im2 = gdImageCreateFromPng(in);
fclose(in);
- CompareImages("GD->GIF File->GD", ref, im2);
+ CompareImages("GD->PNG File->GD", ref, im2);
unlink(of);
gdImageDestroy(im2);
- iptr = gdImageGifPtr(im,&sz);
+ iptr = gdImagePngPtr(im,&sz);
ctx = gdNewDynamicCtx(sz,iptr);
- im2 = gdImageCreateFromGifCtx(ctx);
+ im2 = gdImageCreateFromPngCtx(ctx);
- CompareImages("GD->GIF ptr->GD", ref, im2);
+ CompareImages("GD->PNG ptr->GD", ref, im2);
gdImageDestroy(im2);
ctx->free(ctx);
@@ -141,50 +144,57 @@ int main(int argc, char **argv)
gdImageDestroy(im2);
ctx->free(ctx);
-#ifdef LZW_LICENCED
- /* */
- /* Send to LZW File then Ptr */
- /* */
- sprintf(of, "%s.lzw", argv[1]);
- out = fopen(of, "wb");
- gdImageLzw(im, out);
- fclose(out);
+ /*
+ ** Test gdImageCreateFromPngSource'
+ **/
- in = fopen(of, "rb");
- if (!in) {
- fprintf(stderr, "LZW Output file does not exist!\n");
- exit(1);
- }
- im2 = gdImageCreateFromGif(in);
- fclose(in);
+ in = fopen(argv[1], "rb");
- CompareImages("GD->LZW File->GD", ref, im2);
+ imgsrc.source = freadWrapper;
+ imgsrc.context = in;
+ im2 = gdImageCreateFromPngSource(&imgsrc);
+ fclose(in);
- unlink(of);
- gdImageDestroy(im2);
+ if (im2 == NULL) {
+ printf("GD Source: ERROR Null returned by gdImageCreateFromPngSource\n");
+ } else {
+ CompareImages("GD Source", ref, im2);
+ gdImageDestroy(im2);
+ };
- iptr = gdImageLzwPtr(im,&sz);
- /*printf("Got ptr %d (size %d)\n",iptr, sz); */
- ctx = gdNewDynamicCtx(sz,iptr);
- /*printf("Got ctx %d\n",ctx); */
- im2 = gdImageCreateFromGifCtx(ctx);
- /*printf("Got img2 %d\n",im2); */
- CompareImages("GD->LZW ptr->GD", ref, im2);
+ /*
+ ** Test gdImagePngToSink'
+ **/
- gdImageDestroy(im2);
- ctx->free(ctx);
-#endif
+ sprintf(of, "%s.snk", argv[1]);
+ out = fopen(of, "wb");
+ imgsnk.sink = fwriteWrapper;
+ imgsnk.context = out;
+ gdImagePngToSink(im, &imgsnk);
+ fclose(out);
+ in = fopen(of, "rb");
+ if (!in) {
+ fprintf(stderr, "GD Sink: ERROR - GD Sink Output file does not exist!\n");
+ } else {
+ im2 = gdImageCreateFromPng(in);
+ fclose(in);
+
+ CompareImages("GD Sink", ref, im2);
+ gdImageDestroy(im2);
+ };
+
+ unlink(of);
/* */
/* Test Extraction */
/* */
- in = fopen("test/gdtest_200_300_150_100.gif", "rb");
+ in = fopen("test/gdtest_200_300_150_100.png", "rb");
if (!in) {
- fprintf(stderr, "gdtest_200_300_150_100.gif does not exist!\n");
+ fprintf(stderr, "gdtest_200_300_150_100.png does not exist!\n");
exit(1);
}
- im2 = gdImageCreateFromGif(in);
+ im2 = gdImageCreateFromPng(in);
fclose(in);
@@ -196,7 +206,7 @@ int main(int argc, char **argv)
im3 = gdImageCreateFromGd2Part(in, 200, 300, 150, 100);
fclose(in);
- CompareImages("GD2Part (gdtest.gd2, gdtest_200_300_150_100.gif)", im2, im3);
+ CompareImages("GD2Part (gdtest.gd2, gdtest_200_300_150_100.png)", im2, im3);
gdImageDestroy(im2);
gdImageDestroy(im3);
@@ -204,12 +214,12 @@ int main(int argc, char **argv)
/* */
/* Copy Blend */
/* */
- in = fopen("test/gdtest.gif", "rb");
+ in = fopen("test/gdtest.png", "rb");
if (!in) {
- fprintf(stderr, "gdtest.gif does not exist!\n");
+ fprintf(stderr, "gdtest.png does not exist!\n");
exit(1);
}
- im2 = gdImageCreateFromGif(in);
+ im2 = gdImageCreateFromPng(in);
fclose(in);
im3 = gdImageCreate(100, 60);
@@ -226,18 +236,18 @@ int main(int argc, char **argv)
gdImageDestroy(im3);
- in = fopen("test/gdtest_merge.gif", "rb");
+ in = fopen("test/gdtest_merge.png", "rb");
if (!in) {
fprintf(stderr, "gdtest.gd2 does not exist!\n");
exit(1);
}
- im3 = gdImageCreateFromGif(in);
+ im3 = gdImageCreateFromPng(in);
fclose(in);
printf("[Merged Image has %d colours]\n",im2->colorsTotal);
- CompareImages("Merged (gdtest.gif, gdtest_merge.gif)", im2, im3);
+ CompareImages("Merged (gdtest.png, gdtest_merge.png)", im2, im3);
- /*out = fopen("gdtest_merge.gif", "wb"); */
+ /*out = fopen("gdtest_merge.png", "wb"); */
/*gdImageLzw(im2, out); */
/*fclose(out); */
@@ -257,7 +267,7 @@ void CompareImages(char *msg, gdImagePtr im1, gdImagePtr im2)
bad = (1==0);
if (im1->sx != im2->sx) {
- printf("%s: image x-size differs\n",msg);
+ printf("%s: ERROR image x-size differs\n",msg);
bad = (1==1);
}
@@ -276,20 +286,20 @@ void CompareImages(char *msg, gdImagePtr im1, gdImagePtr im2)
p2 = im2->pixels[y][x];
if (im1->red[p1] != im2->red[p2]) {
- printf("%s: image colours differ\n",msg);
+ printf("%s: ERROR image colours differ\n",msg);
bad = (1==1);
break;
}
if (im1->green[p1] != im2->green[p2]) {
- printf("%s: image colours differ\n",msg);
+ printf("%s: ERROR image colours differ\n",msg);
bad = (1==1);
break;
}
if (im1->blue[p1] != im2->blue[p2]) {
- printf("%s: image colours differ\n",msg);
+ printf("%s: ERROR image colours differ\n",msg);
bad = (1==1);
break;
}
@@ -304,3 +314,15 @@ void CompareImages(char *msg, gdImagePtr im1, gdImagePtr im2)
}
}
+
+static int freadWrapper(void *context, char *buf, int len)
+{
+ int got = fread(buf, 1, len, (FILE *) context);
+ return got;
+}
+
+static int fwriteWrapper(void *context, const char *buffer, int len)
+{
+ return fwrite(buffer, 1, len, (FILE *) context);
+}
+
diff --git a/src/gdtopng.c b/src/gdtopng.c
new file mode 100644
index 0000000..d62acf6
--- /dev/null
+++ b/src/gdtopng.c
@@ -0,0 +1,38 @@
+#include <stdio.h>
+#include "gd.h"
+
+/* A short program which converts a .png file into a .gd file, for
+ your convenience in creating images on the fly from a
+ basis image that must be loaded quickly. The .gd format
+ is not intended to be a general-purpose format. */
+
+int main(int argc, char **argv)
+{
+ gdImagePtr im;
+ FILE *in, *out;
+ if (argc != 3) {
+ fprintf(stderr, "Usage: gdtopng filename.gd filename.png\n");
+ exit(1);
+ }
+ in = fopen(argv[1], "rb");
+ if (!in) {
+ fprintf(stderr, "Input file does not exist!\n");
+ exit(1);
+ }
+ im = gdImageCreateFromGd(in);
+ fclose(in);
+ if (!im) {
+ fprintf(stderr, "Input is not in PNG format!\n");
+ exit(1);
+ }
+ out = fopen(argv[2], "wb");
+ if (!out) {
+ fprintf(stderr, "Output file cannot be written to!\n");
+ gdImageDestroy(im);
+ exit(1);
+ }
+ gdImagePng(im, out);
+ fclose(out);
+ gdImageDestroy(im);
+}
+
diff --git a/src/pngtogd.c b/src/pngtogd.c
new file mode 100644
index 0000000..8a7691e
--- /dev/null
+++ b/src/pngtogd.c
@@ -0,0 +1,38 @@
+#include <stdio.h>
+#include "gd.h"
+
+/* A short program which converts a .png file into a .gd file, for
+ your convenience in creating images on the fly from a
+ basis image that must be loaded quickly. The .gd format
+ is not intended to be a general-purpose format. */
+
+int main(int argc, char **argv)
+{
+ gdImagePtr im;
+ FILE *in, *out;
+ if (argc != 3) {
+ fprintf(stderr, "Usage: pngtogd filename.png filename.gd\n");
+ exit(1);
+ }
+ in = fopen(argv[1], "rb");
+ if (!in) {
+ fprintf(stderr, "Input file does not exist!\n");
+ exit(1);
+ }
+ im = gdImageCreateFromPng(in);
+ fclose(in);
+ if (!im) {
+ fprintf(stderr, "Input is not in PNG format!\n");
+ exit(1);
+ }
+ out = fopen(argv[2], "wb");
+ if (!out) {
+ fprintf(stderr, "Output file cannot be written to!\n");
+ gdImageDestroy(im);
+ exit(1);
+ }
+ gdImageGd(im, out);
+ fclose(out);
+ gdImageDestroy(im);
+}
+
diff --git a/src/pngtogd2.c b/src/pngtogd2.c
new file mode 100644
index 0000000..c206b02
--- /dev/null
+++ b/src/pngtogd2.c
@@ -0,0 +1,44 @@
+#include <stdio.h>
+#include "gd.h"
+
+/* A short program which converts a .png file into a .gd file, for
+ your convenience in creating images on the fly from a
+ basis image that must be loaded quickly. The .gd format
+ is not intended to be a general-purpose format. */
+
+int main(int argc, char **argv)
+{
+ gdImagePtr im;
+ FILE *in, *out;
+ int cs, fmt;
+
+ if (argc != 5) {
+ fprintf(stderr, "Usage: pngtogd2 filename.png filename.gd2 cs fmt\n");
+ fprintf(stderr, " where cs is the chunk size\n");
+ fprintf(stderr, " fmt is 1 for raw, 2 for compressed\n");
+ exit(1);
+ }
+ in = fopen(argv[1], "rb");
+ if (!in) {
+ fprintf(stderr, "Input file does not exist!\n");
+ exit(1);
+ }
+ im = gdImageCreateFromPng(in);
+ fclose(in);
+ if (!im) {
+ fprintf(stderr, "Input is not in PNG format!\n");
+ exit(1);
+ }
+ out = fopen(argv[2], "wb");
+ if (!out) {
+ fprintf(stderr, "Output file cannot be written to!\n");
+ gdImageDestroy(im);
+ exit(1);
+ }
+ cs = atoi(argv[3]);
+ fmt = atoi(argv[4]);
+ gdImageGd2(im, out, cs, fmt);
+ fclose(out);
+ gdImageDestroy(im);
+}
+
diff --git a/src/webpng.c b/src/webpng.c
new file mode 100644
index 0000000..3ddd9f6
--- /dev/null
+++ b/src/webpng.c
@@ -0,0 +1,191 @@
+/* Bring in the gd library functions */
+#include "gd.h"
+
+/* Bring in standard I/O and string manipulation functions */
+#include <stdio.h>
+#include <string.h>
+
+int main(int argc, char **argv)
+{
+ FILE *in;
+ FILE *out;
+ char outFn[20];
+ int useStdinStdout=0;
+
+ /* Declare our image pointer */
+ gdImagePtr im = 0;
+ int i;
+ /* We'll clear 'no' once we know the user has made a
+ reasonable request. */
+ int no = 1;
+ /* We'll set 'write' once we know the user's request
+ requires that the image be written back to disk. */
+ int write = 0;
+ /* C programs always get at least one argument; we want at
+ least one more (the image), more in practice. */
+ if (argc < 2 || !strcmp(argv[1], "--help")) {
+ no = 1;
+ goto usage;
+ }
+
+ /* The last argument should be the image. Open the file. */
+ if (strcmp("-", argv[argc-1])==0) { /* - is synonymous with STDIN */
+ useStdinStdout = 1;
+ in = stdin;
+ } else {
+ in = fopen(argv[argc-1], "rb");
+ }
+ if (!in) {
+ fprintf(stderr,
+ "Error: can't open file %s.\n", argv[argc-1]);
+ exit(1);
+ }
+ /* Now load the image. */
+ im = gdImageCreateFromPng(in);
+ fclose(in);
+ /* If the load failed, it must not be a PNG file. */
+ if (!im) {
+ fprintf(stderr,
+ "Error: %s is not a valid png file.\n", argv[argc-1]);
+ exit(1);
+ }
+ /* Consider each argument in turn. */
+ for (i=1; (i < (argc-1)); i++) {
+ /* -i turns on and off interlacing. */
+ if (!strcmp(argv[i], "--help")) {
+ /* Every program should use this for help! :) */
+ no = 1;
+ goto usage;
+ } else if (!strcmp(argv[i], "-i")) {
+ if (i == (argc-2)) {
+ fprintf(stderr,
+ "Error: -i specified without y or n.\n");
+ no = 1;
+ goto usage;
+ }
+ if (!strcmp(argv[i+1], "y")) {
+ /* Set interlace. */
+ gdImageInterlace(im, 1);
+ } else if (!strcmp(argv[i+1], "n")) {
+ /* Clear interlace. */
+ gdImageInterlace(im, 0);
+ } else {
+ fprintf(stderr,
+ "Error: -i specified without y or n.\n");
+ no = 1;
+ goto usage;
+ }
+ i++;
+ no = 0;
+ write = 1;
+ } else if (!strcmp(argv[i], "-t")) {
+ /* Set transparent index (or none). */
+ int index;
+ if (i == (argc-2)) {
+ fprintf(stderr,
+ "Error: -t specified without a color table index.\n");
+ no = 1;
+ goto usage;
+ }
+ if (!strcmp(argv[i+1], "none")) {
+ /* -1 means not transparent. */
+ gdImageColorTransparent(im, -1);
+ } else {
+ /* OK, get an integer and set the index. */
+ index = atoi(argv[i+1]);
+ gdImageColorTransparent(im, index);
+ }
+ i++;
+ write = 1;
+ no = 0;
+ } else if (!strcmp(argv[i], "-l")) {
+ /* List the colors in the color table. */
+ int j;
+ /* Tabs used below. */
+ printf("Index Red Green Blue\n");
+ for (j=0; (j < gdImageColorsTotal(im)); j++) {
+ /* Use access macros to learn colors. */
+ printf("%d %d %d %d\n",
+ j,
+ gdImageRed(im, j),
+ gdImageGreen(im, j),
+ gdImageBlue(im, j));
+ }
+ no = 0;
+ } else if (!strcmp(argv[i], "-d")) {
+ /* Output dimensions, etc. */
+ int t;
+ printf("Width: %d Height: %d Colors: %d\n",
+ gdImageSX(im), gdImageSY(im),
+ gdImageColorsTotal(im));
+ t = gdImageGetTransparent(im);
+ if (t != (-1)) {
+ printf("Transparent index: %d\n", t);
+ } else {
+ /* -1 means the image is not transparent. */
+ printf("Transparent index: none\n");
+ }
+ if (gdImageGetInterlaced(im)) {
+ printf("Interlaced: yes\n");
+ } else {
+ printf("Interlaced: no\n");
+ }
+ no = 0;
+ } else {
+ fprintf(stderr, "Unknown argument: %s\n", argv[i]);
+ break;
+ }
+ }
+usage:
+ if (no) {
+ /* If the command failed, output an explanation. */
+ fprintf(stderr,
+"Usage: webpng [-i y|n ] [-l] [-t index|off ] [-d] pngname.png\n"
+
+" -i [y|n] Turns on/off interlace\n"
+" -l Prints the table of color indexes\n"
+" -t [index] Set the transparent color to the specified index (0-255 or none)\n"
+" -d Reports the dimensions and other characteristics of the image.\n"
+"\n"
+"If you specify '-' as the input file, stdin/stdout will be used input/output.\n"
+);
+ }
+ if (write) {
+ if (useStdinStdout) {
+ out = stdout;
+ } else {
+ /* Open a temporary file. */
+
+ /* "temp.tmp" is not good temporary filename. */
+ sprintf(outFn, "webpng.tmp%d", getpid());
+ out = fopen(outFn, "wb");
+
+ if (!out) {
+ fprintf(stderr,
+ "Unable to write to %s -- exiting\n", outFn);
+ exit(1);
+ }
+ }
+
+ /* Write the new png. */
+ gdImagePng(im, out);
+
+ if (!useStdinStdout) {
+ fclose(out);
+ /* Erase the old png. */
+ unlink(argv[argc-1]);
+ /* Rename the new to the old. */
+ if (rename(outFn, argv[argc-1])!=0) {
+ perror("rename");
+ exit(1);
+ }
+ }
+ }
+ /* Delete the image from memory. */
+ if (im) {
+ gdImageDestroy(im);
+ }
+ /* All's well that ends well. */
+ return 0;
+}
+