diff options
-rw-r--r-- | src/gd.c | 2710 | ||||
-rw-r--r-- | src/gd.h | 54 | ||||
-rw-r--r-- | src/gd2copypal.c | 2 | ||||
-rw-r--r-- | src/gd2time.c | 2 | ||||
-rw-r--r-- | src/gd2topng.c | 38 | ||||
-rw-r--r-- | src/gd_gd.c | 401 | ||||
-rw-r--r-- | src/gd_gd2.c | 1455 | ||||
-rw-r--r-- | src/gd_io.c | 157 | ||||
-rw-r--r-- | src/gd_io.h | 39 | ||||
-rw-r--r-- | src/gd_io_dp.c | 375 | ||||
-rw-r--r-- | src/gd_io_file.c | 127 | ||||
-rw-r--r-- | src/gd_io_ss.c | 147 | ||||
-rw-r--r-- | src/gd_png.c | 227 | ||||
-rw-r--r-- | src/gd_ss.c | 38 | ||||
-rw-r--r-- | src/gddemo.c | 14 | ||||
-rw-r--r-- | src/gdparttopng.c | 48 | ||||
-rw-r--r-- | src/gdtest.c | 136 | ||||
-rw-r--r-- | src/gdtopng.c | 38 | ||||
-rw-r--r-- | src/pngtogd.c | 38 | ||||
-rw-r--r-- | src/pngtogd2.c | 44 | ||||
-rw-r--r-- | src/webpng.c | 191 |
21 files changed, 3904 insertions, 2377 deletions
@@ -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; +} @@ -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; +} + |