diff -ruN old/gd-2.0.28/gd.c gd-2.0.28/gd.c --- old/gd-2.0.28/gd.c 2004-07-02 00:30:30.000000000 +0300 +++ gd-2.0.28/gd.c 2004-10-12 16:47:41.000000000 +0300 @@ -2519,6 +2519,18 @@ BGD_DECLARE(void) gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c) { + if (!n) + { + return; + } + + + gdImageLine (im, p->x, p->y, p[n - 1].x, p[n - 1].y, c); + gdImageOpenPolygon (im, p, n, c); +} + +BGD_DECLARE(void) gdImageOpenPolygon (gdImagePtr im, gdPointPtr p, int n, int c) +{ int i; int lx, ly; if (!n) @@ -2529,7 +2541,6 @@ 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++; diff -ruN old/gd-2.0.28/gdcmpgif.c gd-2.0.28/gdcmpgif.c --- old/gd-2.0.28/gdcmpgif.c 1970-01-01 02:00:00.000000000 +0200 +++ gd-2.0.28/gdcmpgif.c 2004-10-20 17:37:18.922400224 +0300 @@ -0,0 +1,85 @@ +#include +#include /* For unlink function */ +#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. */ + +void CompareImages(char *msg, gdImagePtr im1, gdImagePtr im2); + + +int main(int argc, char **argv) +{ + gdImagePtr im1, im2; + FILE *in; + + if (argc != 3) { + fprintf(stderr, "Usage: gdcmpgif filename.gif filename.gif\n"); + exit(1); + } + in = fopen(argv[1], "rb"); + if (!in) { + fprintf(stderr, "Input file does not exist!\n"); + exit(1); + } + im1 = gdImageCreateFromGif(in); + fclose(in); + + if (!im1) { + fprintf(stderr, "Input is not in GIF format!\n"); + exit(1); + } + + in = fopen(argv[2], "rb"); + if (!in) { + fprintf(stderr, "Input file 2 does not exist!\n"); + exit(1); + } + im2 = gdImageCreateFromGif(in); + fclose(in); + + if (!im2) { + fprintf(stderr, "Input 2 is not in GIF format!\n"); + exit(1); + } + + CompareImages("gdcmpgif", im1, im2); + + gdImageDestroy(im1); + gdImageDestroy(im2); + + return 0; +} + +void CompareImages(char *msg, gdImagePtr im1, gdImagePtr im2) +{ + int cmpRes; + + cmpRes = gdImageCompare(im1, im2); + + if (cmpRes & GD_CMP_IMAGE) { + printf("%%%s: ERROR images differ: BAD\n",msg); + } else if (cmpRes != 0) { + printf("%%%s: WARNING images differ: WARNING - Probably OK\n",msg); + } else { + printf("%%%s: OK\n",msg); + return; + } + + if (cmpRes & (GD_CMP_SIZE_X + GD_CMP_SIZE_Y)) { + printf("-%s: INFO image sizes differ\n",msg); + } + + if (cmpRes & GD_CMP_NUM_COLORS) { + printf("-%s: INFO number of pallette entries differ %d Vs. %d\n",msg, + im1->colorsTotal, im2->colorsTotal); + } + + if (cmpRes & GD_CMP_COLOR) { + printf("-%s: INFO actual colours of pixels differ\n",msg); + } +} + + diff -ruN old/gd-2.0.28/gdft.c gd-2.0.28/gdft.c --- old/gd-2.0.28/gdft.c 2004-06-24 19:59:18.000000000 +0300 +++ gd-2.0.28/gdft.c 2004-10-18 11:43:54.000000000 +0300 @@ -1011,9 +1011,11 @@ if (FT_Set_Char_Size (face, 0, (FT_F26Dot6) (ptsize * 64), hdpi, vdpi)) { +#if 0 gdCacheDelete (tc_cache); gdMutexUnlock (gdFontCacheMutex); return "Could not set character size"; +#endif } matrix.xx = (FT_Fixed) (cos_a * (1 << 16)); diff -ruN old/gd-2.0.28/gd_gif_out.c gd-2.0.28/gd_gif_out.c --- old/gd-2.0.28/gd_gif_out.c 2004-07-21 21:17:18.000000000 +0300 +++ gd-2.0.28/gd_gif_out.c 2004-10-18 17:13:04.000000000 +0300 @@ -3,6 +3,7 @@ #include #include #include "gd.h" +#include "gdhelpers.h" /* Code drawn from ppmtogif.c, from the pbmplus package ** @@ -90,6 +91,7 @@ static void BumpPixel (GifCtx *ctx); static int GIFNextPixel (gdImagePtr im, GifCtx *ctx); static void GIFEncode (gdIOCtxPtr fp, int GWidth, int GHeight, int GInterlace, int Background, int Transparent, int BitsPerPixel, int *Red, int *Green, int *Blue, gdImagePtr im); +static void GIFAnimEncode (gdIOCtxPtr fp, int IWidth, int IHeight, int LeftOfs, int TopOfs, int GInterlace, int Transparent, int Delay, int Disposal, int BitsPerPixel, int *Red, int *Green, int *Blue, gdImagePtr im); static void compress (int init_bits, gdIOCtx *outfile, gdImagePtr im, GifCtx *ctx); static void output (code_int code, GifCtx *ctx); static void cl_block (GifCtx *ctx); @@ -141,6 +143,322 @@ } } +BGD_DECLARE(void *) gdImageGifAnimBeginPtr (gdImagePtr im, int *size, int GlobalCM, int Loops) +{ + void *rv; + gdIOCtx *out = gdNewDynamicCtx (2048, NULL); + gdImageGifAnimBeginCtx(im, out, GlobalCM, Loops); + rv = gdDPExtractData (out, size); + out->gd_free (out); + return rv; +} + +BGD_DECLARE(void) gdImageGifAnimBegin (gdImagePtr im, FILE *outFile, int GlobalCM, int Loops) +{ + gdIOCtx *out = gdNewFileCtx (outFile); + gdImageGifAnimBeginCtx (im, out, GlobalCM, Loops); + out->gd_free (out); +} + +BGD_DECLARE(void) gdImageGifAnimBeginCtx(gdImagePtr im, gdIOCtxPtr out, int GlobalCM, int Loops) +{ + int B; + int RWidth, RHeight; + int Resolution; + int ColorMapSize; + int BitsPerPixel; + int Background = 0; + int i; + + /* Default is to use global color map */ + if (GlobalCM < 0) GlobalCM = 1; + + BitsPerPixel = colorstobpp(im->colorsTotal); + ColorMapSize = 1 << BitsPerPixel; + + RWidth = im->sx; + RHeight = im->sy; + + Resolution = BitsPerPixel; + + /* + * Write the Magic header + */ + gdPutBuf("GIF89a", 6, out ); + + /* + * Write out the screen width and height + */ + gifPutWord( RWidth, out ); + gifPutWord( RHeight, out ); + + /* + * Indicate that there is a global colour map + */ + B = GlobalCM ? 0x80 : 0; + + /* + * OR in the resolution + */ + B |= (Resolution - 1) << 5; + + /* + * OR in the Bits per Pixel + */ + B |= (BitsPerPixel - 1); + + /* + * Write it out + */ + gdPutC( B, out ); + + /* + * Write out the Background colour + */ + gdPutC( Background, out ); + + /* + * Byte of 0's (future expansion) + */ + gdPutC( 0, out ); + + /* + * Write out the Global Colour Map + */ + if (GlobalCM) + for( i=0; ired[i], out ); + gdPutC( im->green[i], out ); + gdPutC( im->blue[i], out ); + } + + if (Loops >= 0) { + gdPutBuf( "!\377\13NETSCAPE2.0\3\1", 16, out ); + gifPutWord( Loops, out ); + gdPutC( 0, out ); + } +} + +BGD_DECLARE(void *) gdImageGifAnimAddPtr (gdImagePtr im, int *size, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm) +{ + void *rv; + gdIOCtx *out = gdNewDynamicCtx (2048, NULL); + gdImageGifAnimAddCtx(im, out, LocalCM, LeftOfs, TopOfs, Delay, Disposal, previm); + rv = gdDPExtractData (out, size); + out->gd_free (out); + return rv; +} + +BGD_DECLARE(void) gdImageGifAnimAdd (gdImagePtr im, FILE * outFile, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm) +{ + gdIOCtx *out = gdNewFileCtx (outFile); + gdImageGifAnimAddCtx (im, out, LocalCM, LeftOfs, TopOfs, Delay, Disposal, previm); + out->gd_free (out); +} + +static int +comparewithmap (gdImagePtr im1, gdImagePtr im2, int c1, int c2, int *colorMap) +{ + if (!colorMap) + return c1 == c2; + if (-2 != colorMap[c1]) + return colorMap[c1] == c2; + return (colorMap[c1] = gdImageColorExactAlpha (im2, im1->red[c1], im1->green[c1], im1->blue[c1], im1->alpha[c1])) + == c2; +} + +BGD_DECLARE(void) gdImageGifAnimAddCtx(gdImagePtr im, gdIOCtxPtr out, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm) +{ + gdImagePtr pim = 0, tim = im; + int interlace, transparent, BitsPerPixel; + interlace = im->interlace; + transparent = im->transparent; + + /* Default is no local color map */ + if (LocalCM < 0) LocalCM = 0; + if (im->trueColor) { + /* Expensive, but the only way that produces an + acceptable result: mix down to a palette + based temporary image. */ + pim = gdImageCreatePaletteFromTrueColor(im, 1, 256); + if (!pim) { + return; + } + tim = pim; + } + if (previm) { + /* create optimized animation. Compare this image to + the previous image and crop the temporary copy of + current image to include only changed rectangular + area. Also replace unchanged pixels inside this + area with transparent color. Transparent color + needs to be already allocated! + Preconditions: + TopOfs, LeftOfs are assumed 0 + + Images should be of same size. If not, a temporary + copy is made with the same size as previous image. + + */ + gdImagePtr prev_pim = 0, prev_tim = previm; + int x, y; + int min_x; + int min_y = tim->sy; + int max_x; + int max_y; + int colorMap[256]; + + if (previm->trueColor) { + prev_pim = gdImageCreatePaletteFromTrueColor(previm, 1, 256); + if (!prev_pim) { + return; + } + prev_tim = prev_pim; + } + for (x = 0; x < 256; ++x) + colorMap[x] = -2; + + /* First find bounding box of changed areas. */ + /* first find the top changed row */ + for (y = 0; y < tim->sy; ++y) + for (x = 0; x < tim->sx; ++x) + if (!comparewithmap(prev_tim, tim, + prev_tim->pixels[y][x], + tim->pixels[y][x], + colorMap)) { + min_y = max_y = y; + min_x = max_x = x; + goto break_top; + } + break_top: + if (tim->sy == min_y) { + /* No changes in this frame!! Encode empty image. */ + transparent = 0; + min_x = min_y = 1; + max_x = max_y = 0; + } else { + /* Then the bottom row */ + for (y = tim->sy - 1; y > min_y; --y) + for (x = 0; x < tim->sx; ++x) + if (!comparewithmap + (prev_tim, tim, + prev_tim->pixels[y][x], + tim->pixels[y][x], + colorMap)) { + max_y = y; + if (x < min_x) min_x = x; + if (x > max_x) max_x = x; + goto break_bot; + } + break_bot: + /* left side */ + for (x = 0; x < min_x; ++x) + for (y = min_y; y <= max_y; ++y) + if (!comparewithmap + (prev_tim, tim, + prev_tim->pixels[y][x], + tim->pixels[y][x], + colorMap)) { + min_x = x; + goto break_left; + } + break_left: + /* right side */ + for (x = tim->sx-1; x > max_x; --x) + for (y = min_y; y <= max_y; ++y) + if (!comparewithmap + (prev_tim, tim, + prev_tim->pixels[y][x], + tim->pixels[y][x], + colorMap)) { + max_x = x; + goto break_right; + } + break_right: + ; + } + + LeftOfs = min_x; + TopOfs = min_y; + Disposal = 1; + + /* Make a copy of the image with the new offsets. + But only if necessary. */ + if (min_x != 0 || max_x != tim->sx-1 + || min_y != 0 || max_y != tim->sy-1 + || transparent >= 0) { + gdImagePtr pim2 + = gdImageCreate(max_x-min_x+1, max_y-min_y+1); + if (!pim2) { + if (prev_pim) + gdImageDestroy (prev_pim); + goto fail_end; + } + gdImagePaletteCopy (pim2, LocalCM ? tim : prev_tim); + gdImageCopy (pim2, tim, 0, 0, min_x, min_y, + max_x-min_x+1, max_y-min_y+1); + if (pim) + gdImageDestroy (pim); + tim = pim = pim2; + } + + /* now let's compare pixels for transparent + optimization. But only if transparent is set. */ + if (transparent >= 0) { + for (y = 0; y < tim->sy; ++y) + for (x = 0; x < tim->sx; ++x) + if (comparewithmap + (prev_tim, tim, + prev_tim->pixels[min_y+y][min_x+x], + tim->pixels[y][x], 0)) { + gdImageSetPixel (tim, x, y, + transparent); + break; + } + } + if (prev_pim) + gdImageDestroy (prev_pim); + } + BitsPerPixel = colorstobpp(tim->colorsTotal); + /* All set, let's do it. */ + GIFAnimEncode( + out, tim->sx, tim->sy, LeftOfs, TopOfs, interlace, transparent, + Delay, Disposal, BitsPerPixel, + LocalCM ? tim->red : 0, tim->green, tim->blue, tim); + fail_end: + if (pim) { + /* Destroy palette based temporary image. */ + gdImageDestroy( pim); + } +} + +BGD_DECLARE(void) gdImageGifAnimEnd(FILE *outFile) +{ +#if 1 + putc (';', outFile); +#else + gdIOCtx *out = gdNewFileCtx (outFile); + gdImageGifAnimEndCtx (out); + out->gd_free (out); +#endif +} + +BGD_DECLARE(void *) gdImageGifAnimEndPtr (int *size) +{ + char *rv = (char *) gdMalloc (1); + *rv = ';'; + *size = 1; + return (void *)rv; +} + +BGD_DECLARE(void) gdImageGifAnimEndCtx(gdIOCtx *out) +{ + /* + * Write the GIF file terminator + */ + gdPutC( ';', out ); +} + static int colorstobpp(int colors) { @@ -406,6 +724,122 @@ gdPutC( ';', fp ); } +static void +GIFAnimEncode(gdIOCtxPtr fp, int IWidth, int IHeight, int LeftOfs, int TopOfs, int GInterlace, int Transparent, int Delay, int Disposal, int BitsPerPixel, int *Red, int *Green, int *Blue, gdImagePtr im) +{ + int B; + int ColorMapSize; + int InitCodeSize; + int i; + GifCtx ctx; + ctx.Interlace = GInterlace; + ctx.in_count = 1; + memset(&ctx, 0, sizeof(ctx)); + ColorMapSize = 1 << BitsPerPixel; + + if (LeftOfs < 0) LeftOfs = 0; + if (TopOfs < 0) TopOfs = 0; + if (Delay < 0) Delay = 100; + if (Disposal < 0) Disposal = 1; + + ctx.Width = IWidth; + ctx.Height = IHeight; + + /* + * Calculate number of bits we are expecting + */ + ctx.CountDown = (long)ctx.Width * (long)ctx.Height; + + /* + * Indicate which pass we are on (if interlace) + */ + ctx.Pass = 0; + + /* + * The initial code size + */ + if( BitsPerPixel <= 1 ) + InitCodeSize = 2; + else + InitCodeSize = BitsPerPixel; + + /* + * Set up the current x and y position + */ + ctx.curx = ctx.cury = 0; + + /* + * Write out extension for image animation and looping + */ + gdPutC( '!', fp ); + gdPutC( 0xf9, fp ); + gdPutC( 4, fp ); + gdPutC( (Transparent >= 0 ? 1 : 0) + | (Disposal << 2), fp ); + gdPutC( (unsigned char)(Delay & 255), fp ); + gdPutC( (unsigned char)((Delay >> 8) & 255), fp ); + gdPutC( (unsigned char) Transparent, fp ); + gdPutC( 0, fp ); + + /* + * Write an Image separator + */ + gdPutC( ',', fp ); + + /* + * Write out the Image header + */ + gifPutWord( LeftOfs, fp ); + gifPutWord( TopOfs, fp ); + gifPutWord( ctx.Width, fp ); + gifPutWord( ctx.Height, fp ); + + /* + * Indicate that there is a local colour map + */ + B = (Red && Green && Blue) ? 0x80 : 0; + + /* + * OR in the interlacing + */ + B |= ctx.Interlace ? 0x40 : 0; + + /* + * OR in the Bits per Pixel + */ + B |= (Red && Green && Blue) ? (BitsPerPixel - 1) : 0; + + /* + * Write it out + */ + gdPutC( B, fp ); + + /* + * Write out the Local Colour Map + */ + if (Red && Green && Blue) + for( i=0; i +#include "gd.h" + +/* A short program which converts a .gif 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: gd2togif filename.gd2 filename.gif\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 GIF format!\n"); + exit(1); + } + out = fopen(argv[2], "wb"); + if (!out) { + fprintf(stderr, "Output file cannot be written to!\n"); + gdImageDestroy(im); + exit(1); + } + gdImageGif(im, out); + fclose(out); + gdImageDestroy(im); + + return 0; +} + diff -ruN old/gd-2.0.28/giftogd2.c gd-2.0.28/giftogd2.c --- old/gd-2.0.28/giftogd2.c 1970-01-01 02:00:00.000000000 +0200 +++ gd-2.0.28/giftogd2.c 2004-10-20 17:37:18.949396449 +0300 @@ -0,0 +1,48 @@ +#include +#include + +#include "gd.h" + +/* A short program which converts a .gif 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: giftogd2 filename.gif 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 = gdImageCreateFromGif(in); + fclose(in); + if (!im) { + fprintf(stderr, "Input is not in GIF 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); + + return 0; +} + diff -ruN old/gd-2.0.28/index.html gd-2.0.28/index.html --- old/gd-2.0.28/index.html 2004-07-22 16:36:48.000000000 +0300 +++ gd-2.0.28/index.html 2004-10-19 12:23:42.000000000 +0300 @@ -119,6 +119,8 @@ Portions relating to WBMP copyright 2000, 2001, 2002, 2003, 2004 Maurice Szmurlo and Johan Van den Brande.

+Portions relating to GIF animations copyright 2004 Jaakko Hyvätti (jaakko.hyvatti@iki.fi) +

Permission has been granted to copy, distribute and modify gd in any context without fee, including a commercial application, provided that this notice is present in user-accessible supporting documentation. @@ -205,6 +207,25 @@

  • fly, by Martin Gleeson
+

+

What's new in this GIFANIM patch?

+

+

What's new in version 2.0.28?

@@ -1558,7 +1579,8 @@

gdPoint (TYPE)
Represents a point in the coordinate space of the image; used -by gdImagePolygon and +by gdImagePolygon, +gdImageOpenPolygon and gdImageFilledPolygon.
 typedef struct {
@@ -1568,7 +1590,8 @@
 
gdPointPtr (TYPE)
A pointer to a gdPoint structure; passed -as an argument to gdImagePolygon +as an argument to gdImagePolygon, +gdImageOpenPolygon and gdImageFilledPolygon.
gdFTStringExtra (TYPE) @@ -2073,7 +2096,7 @@ (FUNCTION)
gdImageGif outputs the specified image to the specified -file in PNG format. The file must be open for writing. Under MSDOS +file in GIF format. The file must be open for writing. Under MSDOS and all versions of Windows, it is important to use "wb" as opposed to simply "w" as the mode when opening the file, and under Unix there is no penalty for doing so. gdImageGif does not @@ -2121,6 +2144,174 @@ malloc, free, etc. are used both at library build time and at application build time. The 'size' parameter receives the total size of the block of memory. + +
+void gdImageGifAnimBegin(gdImagePtr im, FILE *out, int GlobalCM, int Loops) +
+ +void gdImageGifAnimBeginCtx(gdImagePtr im, gdIOCtx *out, int GlobalCM, int Loops) + +(FUNCTION) + +
This function must be called as the first function when creating a +GIF animation. It writes the correct GIF file headers to selected +file output, and prepares for frames to be added for the animation. +The image argument is not used to produce an image frame to the file, +it is only used to establish the GIF animation frame size, interlacing +options and the color palette. gdImageGifAnimAdd needs to be used to +add the first and subsequent frames to the animation, and the animation +must be terminated by writing semicolon character (;) to it or using +gdImageGifAnimEnd to do that. +

+ +The GlobalCM flag indicates if a global color map (or palette) is used +in the GIF89A header. The default is to use global map, as this +reduces the size of the animation. Of course if the color maps of +individual frames differ, global color map may not be a good idea. +GlobalCM=1 means write global color map, GlobalCM=0 means do not, and +GlobalCM=-1 means do the default, which currently is to use global +color map. + +

+ +If Loops is 0 or greater, the Netscape 2.0 extension for animation +loop count is written. 0 means infinite loop count. -1 means that +the extension is not added which results in no looping. -1 is the +default. + +

+void* gdImageGifAnimBeginPtr(gdImagePtr im, int *size, int GlobalCM, int Loops) +(FUNCTION) +
Identical to gdImageGifAnimBegin except that it returns a pointer +to a memory area with the GIF data. This memory must be freed by the +caller when it is no longer needed. The caller must invoke +gdFree(), not free(), unless the caller is absolutely certain that the +same implementations of malloc, free, etc. are used both at library +build time and at application build time. The 'size' +parameter receives the total size of the block of memory. + +
+void gdImageGifAnimAdd(gdImagePtr im, FILE *out, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm) +
+ +void gdImageGifAnimAddCtx(gdImagePtr im, gdIOCtx *out, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm) + +(FUNCTION) + +
This function writes GIF animation frames to GIF animation, which +was initialized with gdImageGifAnimBegin. With LeftOfs and +TopOfs you can place this frame in different offset than (0,0) inside +the image screen as defined in gdImageGifAnimBegin. Delay between the +previous frame and this frame is in 1/100s units. Disposal is usually +and by default 1. Setting the LocalCM flag to 1 adds a local palette +for this image to the animation. Otherwise the global palette is +assumed and the user must make sure the palettes match. Use gdImagePaletteCopy to do that. + +

+ +Compression is activated by giving the previous image as a parameter. +This function then compares the images and only writes the changed +pixels to the new frame in animation. The Disposal parameter for +optimized animations must be set to 1, also for the first frame. +LeftOfs and TopOfs parameters are ignored for optimized frames. To +achieve bes optimization, it is usually best to use global color map. +To allow gdImageGifAnimAdd to compress unchanged pixels with +transparent color, the image must include a transparent color. + +

+... inside a function ...
+gdImagePtr im, im2, im3;
+int black, white, trans;
+FILE *out;
+/* Create the image */
+im = gdImageCreate(100, 100);
+/* Allocate background */
+white = gdImageColorAllocate(im, 255, 255, 255);
+/* Allocate drawing color */
+black = gdImageColorAllocate(im, 0, 0, 0);
+/* Allocate transparent color for animation compression */
+trans = gdImageColorAllocate(im, 1, 1, 1);
+/* Draw rectangle */
+gdImageRectangle(im, 0, 0, 10, 10, black);
+/* Open output file in binary mode */
+out = fopen("anim.gif", "wb");
+/* Write GIF header.  Use global color map.  Loop a few times */
+gdImageGifAnimBegin(im, out, 1, 3);
+/* Write the first frame.  No local color map.  Delay = 1s */
+gdImageGifAnimAdd(im, out, 0, 0, 0, 100, 1, NULL);
+/* construct the second frame */
+im2 = gdImageCreate(100, 100);
+/* Allocate background to make it white */
+(void)gdImageColorAllocate(im2, 255, 255, 255);
+/* Make sure the palette is identical */
+gdImagePaletteCopy (im2, im);
+/* Draw something */
+gdImageRectangle(im2, 0, 0, 15, 15, black);
+/* Allow animation compression with transparent pixels */
+gdImageColorTransparent (im2, trans);
+/* Add the second frame */
+gdImageGifAnimAdd(im2, out, 0, 0, 0, 100, 1, im);
+/* construct the second frame */
+im3 = gdImageCreate(100, 100);
+/* Allocate background to make it white */
+(void)gdImageColorAllocate(im3, 255, 255, 255);
+/* Make sure the palette is identical */
+gdImagePaletteCopy (im3, im);
+/* Draw something */
+gdImageRectangle(im3, 0, 0, 15, 20, black);
+/* Allow animation compression with transparent pixels */
+gdImageColorTransparent (im3, trans);
+/* Add the third frame, compressing against the second one */
+gdImageGifAnimAdd(im3, out, 0, 0, 0, 100, 1, im2);
+/* Write the end marker */
+/* gdImageGifAnimEnd(out); is the same as the following: */
+putc (';', out);
+/* Close file */
+fclose(out);
+/* Destroy images */
+gdImageDestroy(im);
+gdImageDestroy(im2);
+gdImageDestroy(im3);
+
+ +
+void* gdImageGifAnimAddPtr(gdImagePtr im, int *size, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm) +(FUNCTION) +
Identical to gdImageGifAnimAdd except that it returns a pointer +to a memory area with the GIF data. This memory must be freed by the +caller when it is no longer needed. The caller must invoke +gdFree(), not free(), unless the caller is absolutely certain that the +same implementations of malloc, free, etc. are used both at library +build time and at application build time. The 'size' +parameter receives the total size of the block of memory. + +
+void gdImageGifAnimEnd(FILE *out) +
+ +void gdImageGifAnimEndCtx(gdIOCtx *out) + +(FUNCTION) + +
Writes semicolon character (;) to the output file. This +terminates the GIF file properly. You can omit the call to +gdImageGifAnimEnd and just print out the semicolon. + +
+void* gdImageGifAnimEndPtr(int *size) +(FUNCTION) + +
Returns a one byte string containing the semicolon character (;). +Returns a pointer to a memory area with that string. This memory must +be freed by the caller when it is no longer needed. The caller +must invoke gdFree(), not free(), unless the caller is absolutely +certain that the same implementations of malloc, free, etc. are used +both at library build time and at application build time. The +'size' parameter receives the total size of the block of memory. The +string ";" can be used in place of this function. +
void gdImagePng(gdImagePtr im, FILE *out)
@@ -2544,6 +2735,13 @@ /* Destroy it */ gdImageDestroy(im);
+
void gdImageOpenPolygon(gdImagePtr im, gdPointPtr points, int pointsTotal, int color) +(FUNCTION) +
+gdImageOpenPolygon is used to draw a sequence of lines with the verticies +(at least 3) specified, using the color index specified. Unlike +gdImagePolygon, the enpoints of the line +sequence are not connected to a closed polygon.
void gdImageRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color) (FUNCTION)
@@ -2824,7 +3022,8 @@ percentage of the background, depending on how much of the pixel in question is actually within the boundaries of the line being drawn. All line-drawing functions, -such as gdImageLine and +such as gdImageLine, +gdImageOpenPolygon and gdImagePolygon, will draw antialiased lines if the special "color" gdAntiAliased is used when calling them. @@ -2910,7 +3109,8 @@ setting the transparent color index of the brush image with gdImageColorTransparent, a brush of any shape can be created. All line-drawing functions, -such as gdImageLine and +such as gdImageLine, +gdImageOpenPolygon and gdImagePolygon, will use the current brush if the special "color" gdBrushed or gdStyledBrushed @@ -3089,7 +3289,7 @@
void gdImageSetThickness(gdImagePtr im, int thickness) (FUNCTION)
gdImageSetThickness determines the width of lines drawn by the -gdImageLine, gdImagePolygon +gdImageLine, gdImagePolygon, gdImageOpenPolygon and related functions, in pixels.
 ... inside a function ...
@@ -5113,16 +5313,26 @@
 gdImageFillToBorder |
 gdImageFilledRectangle |
 gdImageGd |
-gdImageGd2 |
+gdImageGd2 |
 gdImageGetInterlaced |
 gdImageGetPixel |
 gdImageGetTransparent |
+gdImageGifAnimAdd |
+gdImageGifAnimAddCtx |
+gdImageGifAnimAddPtr |
+gdImageGifAnimBegin |
+gdImageGifAnimBeginCtx |
+gdImageGifAnimBeginPtr |
+gdImageGifAnimEnd |
+gdImageGifAnimEndCtx |
+gdImageGifAnimEndPtr |
 gdImageGreen |
 gdImageInterlace |
 gdImageJpeg |
 gdImageJpegCtx |
 gdImageLine |
 gdImageFilledPolygon |
+gdImageOpenPolygon |
 gdImagePaletteCopy |
 gdImagePng |
 gdImagePngEx |
diff -ruN old/gd-2.0.28/Makefile.am gd-2.0.28/Makefile.am
--- old/gd-2.0.28/Makefile.am	2004-07-17 19:09:27.000000000 +0300
+++ gd-2.0.28/Makefile.am	2004-10-20 17:24:22.309921279 +0300
@@ -5,7 +5,7 @@
 
 SUBDIRS = config test
 
-bin_PROGRAMS = annotate gdparttopng gdtopng gd2copypal gd2topng pngtogd pngtogd2 webpng
+bin_PROGRAMS = annotate gdparttopng gdtopng gd2copypal gd2topng pngtogd pngtogd2 webpng gd2togif gdcmpgif giftogd2
 
 bin_SCRIPTS = bdftogd config/gdlib-config
 
diff -ruN old/gd-2.0.28/Makefile.in gd-2.0.28/Makefile.in
--- old/gd-2.0.28/Makefile.in	2004-07-22 16:36:55.000000000 +0300
+++ gd-2.0.28/Makefile.in	2004-10-20 17:33:46.779055931 +0300
@@ -135,7 +135,7 @@
 
 SUBDIRS = config test
 
-bin_PROGRAMS = annotate gdparttopng gdtopng gd2copypal gd2topng pngtogd pngtogd2 webpng
+bin_PROGRAMS = annotate gdparttopng gdtopng gd2copypal gd2topng pngtogd pngtogd2 webpng gd2togif gdcmpgif giftogd2
 
 bin_SCRIPTS = bdftogd config/gdlib-config
 
@@ -169,6 +169,7 @@
 libgd_la_OBJECTS = $(am_libgd_la_OBJECTS)
 bin_PROGRAMS = annotate$(EXEEXT) gdparttopng$(EXEEXT) gdtopng$(EXEEXT) \
 	gd2copypal$(EXEEXT) gd2topng$(EXEEXT) pngtogd$(EXEEXT) \
+	gd2togif$(EXEEXT) gdcmpgif$(EXEEXT) giftogd2$(EXEEXT) \
 	pngtogd2$(EXEEXT) webpng$(EXEEXT)
 noinst_PROGRAMS = fontsizetest$(EXEEXT) fontwheeltest$(EXEEXT) \
 	gdtest$(EXEEXT) gddemo$(EXEEXT) gd2time$(EXEEXT) \
@@ -211,6 +212,16 @@
 gd2topng_LDADD = $(LDADD)
 gd2topng_DEPENDENCIES = ./libgd.la
 gd2topng_LDFLAGS =
+gd2togif_SOURCES = gd2togif.c
+gd2togif_OBJECTS = gd2togif.$(OBJEXT)
+gd2togif_LDADD = $(LDADD)
+gd2togif_DEPENDENCIES = ./libgd.la
+gd2togif_LDFLAGS =
+gdcmpgif_SOURCES = gdcmpgif.c
+gdcmpgif_OBJECTS = gdcmpgif.$(OBJEXT)
+gdcmpgif_LDADD = $(LDADD)
+gdcmpgif_DEPENDENCIES = ./libgd.la
+gdcmpgif_LDFLAGS =
 gddemo_SOURCES = gddemo.c
 gddemo_OBJECTS = gddemo.$(OBJEXT)
 gddemo_LDADD = $(LDADD)
@@ -236,6 +247,11 @@
 gdtopng_LDADD = $(LDADD)
 gdtopng_DEPENDENCIES = ./libgd.la
 gdtopng_LDFLAGS =
+giftogd2_SOURCES = giftogd2.c
+giftogd2_OBJECTS = giftogd2.$(OBJEXT)
+giftogd2_LDADD = $(LDADD)
+giftogd2_DEPENDENCIES = ./libgd.la
+giftogd2_LDFLAGS =
 pngtogd_SOURCES = pngtogd.c
 pngtogd_OBJECTS = pngtogd.$(OBJEXT)
 pngtogd_LDADD = $(LDADD)
@@ -273,6 +289,8 @@
 @AMDEP_TRUE@	./$(DEPDIR)/fontwheeltest.Po ./$(DEPDIR)/gd.Plo \
 @AMDEP_TRUE@	./$(DEPDIR)/gd2copypal.Po ./$(DEPDIR)/gd2time.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/gd2topng.Po ./$(DEPDIR)/gd_gd.Plo \
+@AMDEP_TRUE@    ./$(DEPDIR)/gd2togif.Po ./$(DEPDIR)/gdcmpgif.Po \
+@AMDEP_TRUE@    ./$(DEPDIR)/giftogd2.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/gd_gd2.Plo ./$(DEPDIR)/gd_gif_in.Plo \
 @AMDEP_TRUE@	./$(DEPDIR)/gd_gif_out.Plo ./$(DEPDIR)/gd_io.Plo \
 @AMDEP_TRUE@	./$(DEPDIR)/gd_io_dp.Plo ./$(DEPDIR)/gd_io_file.Plo \
@@ -301,6 +319,8 @@
 DIST_SOURCES = $(libgd_la_SOURCES) annotate.c circletexttest.c \
 	fontsizetest.c fontwheeltest.c gd2copypal.c gd2time.c \
 	gd2topng.c gddemo.c gdparttopng.c gdtest.c gdtestft.c gdtopng.c \
+	gd_gif_in.c gd_gif_out.c gd_biggif_out.c gd_lzw_out.c \
+	gd2togif.c gdcmpgif.c giftogd2.c \
 	pngtogd.c pngtogd2.c testac.c testtr.c webpng.c
 HEADERS = $(include_HEADERS)
 
@@ -314,7 +334,7 @@
 	Makefile.in aclocal.m4 config.hin configure configure.ac \
 	depcomp install-sh missing mkinstalldirs
 DIST_SUBDIRS = $(SUBDIRS)
-SOURCES = $(libgd_la_SOURCES) annotate.c circletexttest.c fontsizetest.c fontwheeltest.c gd2copypal.c gd2time.c gd2topng.c gddemo.c gdparttopng.c gdtest.c gdtestft.c gdtopng.c pngtogd.c pngtogd2.c testac.c testtr.c webpng.c
+SOURCES = $(libgd_la_SOURCES) annotate.c circletexttest.c fontsizetest.c fontwheeltest.c gd2copypal.c gd2time.c gd2topng.c gddemo.c gdparttopng.c gdtest.c gdtestft.c gdtopng.c pngtogd.c pngtogd2.c testac.c testtr.c webpng.c gd2togif.c gdcmpgif.c giftogd2.c
 
 all: config.h
 	$(MAKE) $(AM_MAKEFLAGS) all-recursive
@@ -441,6 +461,12 @@
 gd2topng$(EXEEXT): $(gd2topng_OBJECTS) $(gd2topng_DEPENDENCIES) 
 	@rm -f gd2topng$(EXEEXT)
 	$(LINK) $(gd2topng_LDFLAGS) $(gd2topng_OBJECTS) $(gd2topng_LDADD) $(LIBS)
+gd2togif$(EXEEXT): $(gd2togif_OBJECTS) $(gd2togif_DEPENDENCIES)
+	@rm -f gd2togif$(EXEEXT)
+	$(LINK) $(gd2togif_LDFLAGS) $(gd2togif_OBJECTS) $(gd2togif_LDADD) $(LIBS)
+gdcmpgif$(EXEEXT): $(gdcmpgif_OBJECTS) $(gdcmpgif_DEPENDENCIES)
+	@rm -f gdcmpgif$(EXEEXT)
+	$(LINK) $(gdcmpgif_LDFLAGS) $(gdcmpgif_OBJECTS) $(gdcmpgif_LDADD) $(LIBS)
 gddemo$(EXEEXT): $(gddemo_OBJECTS) $(gddemo_DEPENDENCIES) 
 	@rm -f gddemo$(EXEEXT)
 	$(LINK) $(gddemo_LDFLAGS) $(gddemo_OBJECTS) $(gddemo_LDADD) $(LIBS)
@@ -456,6 +482,9 @@
 gdtopng$(EXEEXT): $(gdtopng_OBJECTS) $(gdtopng_DEPENDENCIES) 
 	@rm -f gdtopng$(EXEEXT)
 	$(LINK) $(gdtopng_LDFLAGS) $(gdtopng_OBJECTS) $(gdtopng_LDADD) $(LIBS)
+giftogd2$(EXEEXT): $(giftogd2_OBJECTS) $(giftogd2_DEPENDENCIES)
+	@rm -f giftogd2$(EXEEXT)
+	$(LINK) $(giftogd2_LDFLAGS) $(giftogd2_OBJECTS) $(giftogd2_LDADD) $(LIBS)
 pngtogd$(EXEEXT): $(pngtogd_OBJECTS) $(pngtogd_DEPENDENCIES) 
 	@rm -f pngtogd$(EXEEXT)
 	$(LINK) $(pngtogd_LDFLAGS) $(pngtogd_OBJECTS) $(pngtogd_LDADD) $(LIBS)
@@ -506,6 +535,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gd2copypal.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gd2time.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gd2topng.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gd2togif.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gd_gd.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gd_gd2.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gd_gif_in.Plo@am__quote@
@@ -520,6 +550,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gd_topal.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gd_wbmp.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdcache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdcmpgif.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gddemo.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdfontg.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdfontl.Plo@am__quote@
@@ -536,6 +567,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdtestft.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdtopng.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdxpm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/giftogd2.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pngtogd.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pngtogd2.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testac.Po@am__quote@
diff -ruN old/gd-2.0.28/makefile.sample gd-2.0.28/makefile.sample
--- old/gd-2.0.28/makefile.sample	2004-05-24 17:25:16.000000000 +0300
+++ gd-2.0.28/makefile.sample	2004-10-20 17:34:53.427739936 +0300
@@ -40,7 +40,7 @@
 
 PROGRAMS=$(BIN_PROGRAMS) $(TEST_PROGRAMS)
 
-BIN_PROGRAMS=pngtogd pngtogd2 gdtopng gd2topng gd2copypal gdparttopng webpng
+BIN_PROGRAMS=pngtogd pngtogd2 gdtopng gd2topng gd2copypal gdparttopng webpng gd2togif gdcmpgif giftogd2
 TEST_PROGRAMS=gdtest gddemo gd2time gdtestft testac fontsizetest fontwheeltest
 
 default: instructions
@@ -74,6 +74,9 @@
 	sh ./install-item 755 gd2copypal $(INSTALL_BIN)/gd2copypal
 	sh ./install-item 755 gdparttopng $(INSTALL_BIN)/gdparttopng
 	sh ./install-item 755 webpng $(INSTALL_BIN)/webpng
+	sh ./install-item 755 gd2togif $(INSTALL_BIN)/gd2togif
+	sh ./install-item 755 gdcmpgif $(INSTALL_BIN)/gdcmpgif
+	sh ./install-item 755 giftogd2 $(INSTALL_BIN)/giftogd2
 	sh ./install-item 755 bdftogd $(INSTALL_BIN)/bdftogd
 	sh ./install-item 644 gd.h $(INSTALL_INCLUDE)/gd.h
 	sh ./install-item 644 gdcache.h $(INSTALL_INCLUDE)/gdcache.h
@@ -105,6 +108,15 @@
 gd2topng: gd2topng.o
 	$(CC) gd2topng.o -o gd2topng	$(LIBDIRS) $(LIBS)
 
+gd2togif: gd2togif.o
+	$(CC) gd2togif.o -o gd2togif    $(LIBDIRS) $(LIBS)
+
+gdcmpgif: gdcmpgif.o
+	$(CC) gdcmpgif.o -o gdcmpgif    $(LIBDIRS) $(LIBS)
+
+giftogd2: giftogd2.o
+	$(CC) giftogd2.o -o giftogd2      $(LIBDIRS) $(LIBS)
+
 gd2copypal: gd2copypal.o
 	$(CC) gd2copypal.o -o gd2copypal	$(LIBDIRS) $(LIBS)