diff -ru old/php-5.0.2/configure php-5.0.2/configure
--- old/php-5.0.2/configure	2004-09-24 00:26:32.000000000 +0300
+++ php-5.0.2/configure	2004-10-19 08:57:34.560094663 +0300
@@ -31989,6 +31989,9 @@
 
   cat >> confdefs.h <<\EOF
 #define HAVE_GD_BUNDLED 1
+#define HAVE_GD_GIF_CREATE 1
+#define HAVE_GD_GIF_CTX 1
+#define HAVE_GD_GIF_ANIM 1
 EOF
 
   cat >> confdefs.h <<\EOF
@@ -36318,6 +36321,60 @@
   echo "$ac_t""no" 1>&6
 
     LDFLAGS=$save_old_LDFLAGS
+    unset ac_cv_func_gd
+    
+  
+fi
+
+  
+  save_old_LDFLAGS=$LDFLAGS
+  LDFLAGS=" -L$GD_LIB $GD_SHARED_LIBADD  $LDFLAGS"
+  echo $ac_n "checking for gdImageGifAnimBegin in -lgd""... $ac_c" 1>&6
+echo "configure:32003: checking for gdImageGifAnimBegin in -lgd" >&5
+ac_lib_var=`echo gd'_'gdImageGifAnimBegin | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lgd  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 32011 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gdImageGifAnimBegin();
+
+int main() {
+gdImageGifAnimBegin()
+; return 0; }
+EOF
+if { (eval echo configure:32022: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  
+    LDFLAGS=$save_old_LDFLAGS
+    cat >> confdefs.h <<\EOF
+#define HAVE_GD_GIF_ANIM 1
+EOF
+
+  
+else
+  echo "$ac_t""no" 1>&6
+
+    LDFLAGS=$save_old_LDFLAGS
     ext_shared=$save_ext_shared
     unset ac_cv_func_gd
     
diff -ru old/php-5.0.2/ext/gd/config.m4 php-5.0.2/ext/gd/config.m4
--- old/php-5.0.2/ext/gd/config.m4	2004-07-27 15:44:35.000000000 +0300
+++ php-5.0.2/ext/gd/config.m4	2004-10-19 08:57:34.587090922 +0300
@@ -257,6 +257,7 @@
   PHP_CHECK_LIBRARY(gd, gdImageColorClosestHWB, [AC_DEFINE(HAVE_COLORCLOSESTHWB,     1, [ ])], [], [ -L$GD_LIB $GD_SHARED_LIBADD ])
   PHP_CHECK_LIBRARY(gd, gdImageColorResolve,    [AC_DEFINE(HAVE_GDIMAGECOLORRESOLVE, 1, [ ])], [], [ -L$GD_LIB $GD_SHARED_LIBADD ])
   PHP_CHECK_LIBRARY(gd, gdImageGifCtx,          [AC_DEFINE(HAVE_GD_GIF_CTX,          1, [ ])], [], [ -L$GD_LIB $GD_SHARED_LIBADD ])
+  PHP_CHECK_LIBRARY(gd, gdImageGifAnimBegin,    [AC_DEFINE(HAVE_GD_GIF_ANIM,         1, [ ])], [], [ -L$GD_LIB $GD_SHARED_LIBADD ])
   PHP_CHECK_LIBRARY(gd, gdCacheCreate,          [AC_DEFINE(HAVE_GD_CACHE_CREATE,     1, [ ])], [], [ -L$GD_LIB $GD_SHARED_LIBADD ])
   PHP_CHECK_LIBRARY(gd, gdFontCacheShutdown,    [AC_DEFINE(HAVE_GD_THREAD_SAFE,      1, [ ])], [], [ -L$GD_LIB $GD_SHARED_LIBADD ])
   PHP_CHECK_LIBRARY(gd, gdNewDynamicCtxEx,      [AC_DEFINE(HAVE_GD_DYNAMIC_CTX_EX,    1, [ ])], [], [ -L$GD_LIB $GD_SHARED_LIBADD ])
diff -ru old/php-5.0.2/ext/gd/gd.c php-5.0.2/ext/gd/gd.c
--- old/php-5.0.2/ext/gd/gd.c	2004-08-17 02:08:56.000000000 +0300
+++ php-5.0.2/ext/gd/gd.c	2004-10-19 08:57:34.662080529 +0300
@@ -253,6 +253,11 @@
 #ifdef HAVE_GD_GIF_CREATE
 	PHP_FE(imagegif,								NULL)
 #endif
+#ifdef HAVE_GD_GIF_ANIM
+	PHP_FE(imagegifanimbegin,						NULL)
+	PHP_FE(imagegifanimadd,							NULL)
+	PHP_FE(imagegifanimend,							NULL)
+#endif
 #ifdef HAVE_GD_JPG
 	PHP_FE(imagejpeg,								NULL)
 #endif
@@ -1847,12 +1852,36 @@
 #ifdef HAVE_GD_GIF_CTX
 	_php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GIF, "GIF", gdImageGifCtx);
 #else
+
+#ifdef HAVE_GD_BUNDLED
+#error "I really think there should be ctx version of imagegif in the bundled GD library.  Fix the configuration."
+#endif
+
 	_php_image_output(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GIF, "GIF", gdImageGif);
 #endif
 }
 /* }}} */
 #endif /* HAVE_GD_GIF_CREATE */
 
+#ifdef HAVE_GD_GIF_ANIM
+/* {{{ proto int imagegifanimbegin(int im [, string filename [, int GlobalColormap [, int Loops]]])
+   Begin GIF animation.  Image parameter is only used for size and colormap,
+   all animation frames must be added separately. */
+PHP_FUNCTION(imagegifanimbegin)
+{
+	_php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GIFANIMBEGIN, "GIF", gdImageGifAnimBeginCtx);
+}
+/* }}} */
+
+/* {{{ proto int imagegifanimadd(int im [, string filename [, int LocalColormap [, LeftOfs [, int TopOfs [, int Delay [, int Disposal [, int previm]]]]]]])
+   Append GIF image to animation */
+PHP_FUNCTION(imagegifanimadd)
+{
+	_php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GIFANIMADD, "GIF", gdImageGifAnimAddCtx);
+}
+/* }}} */
+#endif /* HAVE_GD_GIF_ANIM */
+
 #ifdef HAVE_GD_PNG
 /* {{{ proto bool imagepng(resource im [, string filename])
    Output PNG image to browser or file */
diff -ru old/php-5.0.2/ext/gd/gd_ctx.c php-5.0.2/ext/gd/gd_ctx.c
--- old/php-5.0.2/ext/gd/gd_ctx.c	2004-01-28 18:25:12.000000000 +0200
+++ php-5.0.2/ext/gd/gd_ctx.c	2004-10-19 09:24:12.799612064 +0300
@@ -49,23 +49,28 @@
 /* {{{ _php_image_output_ctx */
 static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, void (*func_p)())
 {
-	zval **imgind, **file, **quality;
-	gdImagePtr im;
+	zval **imgind, **file, **quality, **lo, **to, **del, **dis, **previmind;
+	gdImagePtr im, previm = 0;
 	char *fn = NULL;
 	FILE *fp = NULL;
 	int argc = ZEND_NUM_ARGS();
 	int q = -1, i;
+#ifdef HAVE_GD_GIF_ANIM
+	int LeftOfs = -1, TopOfs = -1, Delay = -1, Disposal = -1;
+#endif /* HAVE_GD_GIF_ANIM */
 	gdIOCtx *ctx;
 
 	/* The third (quality) parameter for Wbmp stands for the threshold when called from image2wbmp().
 	 * The third (quality) parameter for Wbmp and Xbm stands for the foreground color index when called
 	 * from imagey<type>().
+	 * The quality parameter for GIF animation stands for colormap inclusion. 1==include local/global colormap
+	 * The LeftOfs parameter for GIF animation begin stands for NETSCAPE2.0 Loop count extension.
 	 */
 
 	if (argc < 2 && image_type == PHP_GDIMG_TYPE_XBM) {
 		WRONG_PARAM_COUNT;
 	}
-	if (argc < 1 || argc > 3 || zend_get_parameters_ex(argc, &imgind, &file, &quality) == FAILURE)
+	if (argc < 1 || argc > 8 || zend_get_parameters_ex(argc, &imgind, &file, &quality, &lo, &to, &del, &dis, &previmind) == FAILURE) 
 	{
 		WRONG_PARAM_COUNT;
 	}
@@ -75,11 +80,32 @@
 	if (argc > 1) {
 		convert_to_string_ex(file);
 		fn = Z_STRVAL_PP(file);
-		if (argc == 3) {
-			convert_to_long_ex(quality);
-			q = Z_LVAL_PP(quality);/* or colorindex for foreground of BW images (defaults to black) */
-		}
 	}
+	if (argc >= 3) {
+		convert_to_long_ex(quality);
+		q = Z_LVAL_PP(quality);/* or colorindex for foreground of BW images (defaults to black) */
+	}
+#ifdef HAVE_GD_GIF_ANIM
+	if (argc >= 4) {
+		convert_to_long_ex(lo);
+		LeftOfs = Z_LVAL_PP(lo);
+	}
+	if (argc >= 5) {
+		convert_to_long_ex(to);
+		TopOfs = Z_LVAL_PP(to);
+	}
+	if (argc >= 6) {
+		convert_to_long_ex(del);
+		Delay = Z_LVAL_PP(del);
+	}
+	if (argc >= 7) {
+		convert_to_long_ex(dis);
+		Disposal = Z_LVAL_PP(dis);
+	}
+	if (argc >= 8) {
+		ZEND_FETCH_RESOURCE(previm, gdImagePtr, previmind, -1, "Image", phpi_get_le_gd());
+	}
+#endif /* HAVE_GD_GIF_ANIM */
 
 	if ((argc == 2) || (argc > 2 && Z_STRLEN_PP(file))) {
 		if (!fn || fn == empty_string || php_check_open_basedir(fn TSRMLS_CC)) {
@@ -87,7 +113,7 @@
 			RETURN_FALSE;
 		}
 
-		fp = VCWD_FOPEN(fn, "wb");
+		fp = VCWD_FOPEN(fn, PHP_GDIMG_TYPE_GIFANIMADD == image_type ? "ab" : "wb");
 		if (!fp) {
 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open '%s' for writing", fn);
 			RETURN_FALSE;
@@ -133,6 +159,14 @@
 				(*func_p)(im, q, ctx);
 			}
 			break;
+#ifdef HAVE_GD_GIF_ANIM
+		case PHP_GDIMG_TYPE_GIFANIMBEGIN:
+			(*func_p)(im, ctx, q, LeftOfs);
+			break;
+		case PHP_GDIMG_TYPE_GIFANIMADD:
+			(*func_p)(im, ctx, q, LeftOfs, TopOfs, Delay, Disposal, previm);
+			break;
+#endif /* HAVE_GD_GIF_ANIM */
 		default:
 			(*func_p)(im, ctx);
 			break;
@@ -153,6 +187,75 @@
 }
 /* }}} */
 
+#ifdef HAVE_GD_GIF_ANIM
+/* {{{ proto int imagegifanimend([string filename])
+   Write end mark to gif animation. */
+PHP_FUNCTION(imagegifanimend)
+{
+	zval **file;
+	char *fn = NULL;
+	FILE *fp = NULL;
+	int argc = ZEND_NUM_ARGS();
+	gdIOCtx *ctx;
+
+	if (argc < 0 || argc > 1 || zend_get_parameters_ex(argc, &file) == FAILURE) {
+		ZEND_WRONG_PARAM_COUNT();
+	}
+
+	if (argc >= 1) {
+		convert_to_string_ex(file);
+		fn = Z_STRVAL_PP(file);
+	}
+
+	if ((argc == 1) || (argc > 1 && Z_STRLEN_PP(file))) {
+		if (!fn || fn == empty_string || php_check_open_basedir(fn TSRMLS_CC)) {
+			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid filename '%s'", fn);
+			RETURN_FALSE;
+		}
+
+		fp = VCWD_FOPEN(fn, "ab");
+		if (!fp) {
+			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open '%s' for writing", fn);
+			RETURN_FALSE;
+		}
+
+		ctx = gdNewFileCtx(fp);
+	} else {
+		ctx = emalloc(sizeof(gdIOCtx));
+		ctx->putC = _php_image_output_putc;
+		ctx->putBuf = _php_image_output_putbuf;
+#if HAVE_LIBGD204
+		ctx->gd_free = _php_image_output_ctxfree;
+#else
+		ctx->free = _php_image_output_ctxfree;
+#endif		
+
+#if APACHE && defined(CHARSET_EBCDIC)
+		/* XXX this is unlikely to work any more thies@thieso.net */
+		/* This is a binary file already: avoid EBCDIC->ASCII conversion */
+		ap_bsetflag(php3_rqst->connection->client, B_EBCDIC2ASCII, 0);
+#endif
+	}
+
+	/* This could be coded in here, as it only outputs ';' */
+	gdImageGifAnimEndCtx(ctx);
+
+#if HAVE_LIBGD204	
+	ctx->gd_free(ctx);
+#else
+	ctx->free(ctx);
+#endif		
+
+	if(fp) {
+		fflush(fp);
+		fclose(fp);
+	}
+	
+    RETURN_TRUE;
+}
+/* }}} */
+#endif /* HAVE_GD_GIF_ANIM */
+
 /*
  * Local variables:
  * tab-width: 4
diff -ru old/php-5.0.2/ext/gd/libgd/gd.c php-5.0.2/ext/gd/libgd/gd.c
--- old/php-5.0.2/ext/gd/libgd/gd.c	2004-05-24 22:52:28.000000000 +0300
+++ php-5.0.2/ext/gd/libgd/gd.c	2004-10-19 08:46:34.761142126 +0300
@@ -2953,6 +2953,18 @@
 
 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);
+}
+
+void gdImageOpenPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
+{
 	int i;
 	int lx, ly;
 	typedef void (*image_line)(gdImagePtr im, int x1, int y1, int x2, int y2, int color);
@@ -2976,7 +2988,6 @@
 	}
 	lx = p->x;
 	ly = p->y;
-	draw_line(im, lx, ly, p[n - 1].x, p[n - 1].y, c);
 	for (i = 1; i < n; i++) {
 		p++;
 		draw_line(im, lx, ly, p->x, p->y, c);
diff -ru old/php-5.0.2/ext/gd/libgd/gdft.c php-5.0.2/ext/gd/libgd/gdft.c
--- old/php-5.0.2/ext/gd/libgd/gdft.c	2004-06-09 17:50:05.000000000 +0300
+++ php-5.0.2/ext/gd/libgd/gdft.c	2004-10-19 08:44:57.977744305 +0300
@@ -817,9 +817,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 -ru old/php-5.0.2/ext/gd/libgd/gd_gif_out.c php-5.0.2/ext/gd/libgd/gd_gif_out.c
--- old/php-5.0.2/ext/gd/libgd/gd_gif_out.c	2004-07-23 01:59:11.000000000 +0300
+++ php-5.0.2/ext/gd/libgd/gd_gif_out.c	2004-10-19 08:48:29.466021376 +0300
@@ -3,6 +3,7 @@
 #include <string.h>
 #include <stdlib.h>
 #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 @@
 	}
 }
 
+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;
+}
+
+void gdImageGifAnimBegin (gdImagePtr im, FILE *outFile, int GlobalCM, int Loops)
+{
+  gdIOCtx *out = gdNewFileCtx (outFile);
+  gdImageGifAnimBeginCtx (im, out, GlobalCM, Loops);
+  out->gd_free (out);
+}
+
+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; i<ColorMapSize; ++i ) {
+			gdPutC( im->red[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 );
+	}
+}
+
+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;
+}
+
+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;
+}
+
+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);
+	}
+}
+
+void gdImageGifAnimEnd(FILE *outFile)
+{
+#if 1
+  putc (';', outFile);
+#else
+  gdIOCtx *out = gdNewFileCtx (outFile);
+  gdImageGifAnimEndCtx (out);
+  out->gd_free (out);
+#endif
+}
+
+void * gdImageGifAnimEndPtr (int *size)
+{
+  char *rv = (char *) gdMalloc (1);
+  *rv = ';';
+  *size = 1;
+  return (void *)rv;
+}
+
+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<ColorMapSize; ++i ) {
+			gdPutC( Red[i], fp );
+			gdPutC( Green[i], fp );
+			gdPutC( Blue[i], fp );
+		}
+
+        /*
+         * Write out the initial code size
+         */
+        gdPutC( InitCodeSize, fp );
+
+        /*
+         * Go and actually compress the data
+         */
+        compress( InitCodeSize+1, fp, im, &ctx );
+
+        /*
+         * Write out a Zero-length packet (to end the series)
+         */
+        gdPutC( 0, fp );
+}
+
 /***************************************************************************
  *
  *  GIFCOMPR.C       - GIF Image compression routines
diff -ru old/php-5.0.2/ext/gd/libgd/gd.h php-5.0.2/ext/gd/libgd/gd.h
--- old/php-5.0.2/ext/gd/libgd/gd.h	2004-07-23 01:59:11.000000000 +0300
+++ php-5.0.2/ext/gd/libgd/gd.h	2004-10-19 09:00:54.584365045 +0300
@@ -348,6 +348,7 @@
 } gdPoint, *gdPointPtr;
 
 void gdImagePolygon(gdImagePtr im, gdPointPtr p, int n, int c);
+void gdImageOpenPolygon (gdImagePtr im, gdPointPtr p, int n, int c);
 void gdImageFilledPolygon(gdImagePtr im, gdPointPtr p, int n, int c);
 
 /* These functions still work with truecolor images,
@@ -463,6 +464,16 @@
 gdImagePtr gdImageCreateFromGifCtx(gdIOCtxPtr in);
 gdImagePtr gdImageCreateFromGifSource(gdSourcePtr in);
 
+void gdImageGifAnimBegin(gdImagePtr im, FILE *outFile, int GlobalCM, int Loops);
+void gdImageGifAnimAdd(gdImagePtr im, FILE *outFile, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm);
+void gdImageGifAnimEnd(FILE *outFile);
+void gdImageGifAnimBeginCtx(gdImagePtr im, gdIOCtx *out, int GlobalCM, int Loops);
+void gdImageGifAnimAddCtx(gdImagePtr im, gdIOCtx *out, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm);
+void gdImageGifAnimEndCtx(gdIOCtx *out);
+void *gdImageGifAnimBeginPtr(gdImagePtr im, int *size, int GlobalCM, int Loops);
+void *gdImageGifAnimAddPtr(gdImagePtr im, int *size, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm);
+void *gdImageGifAnimEndPtr(int *size);
+
 /* A custom data sink. For backwards compatibility. Use
 	gdIOCtx instead. */
 /* The sink function must return -1 on error, otherwise the number
diff -ru old/php-5.0.2/ext/gd/php_gd.h php-5.0.2/ext/gd/php_gd.h
--- old/php-5.0.2/ext/gd/php_gd.h	2004-01-08 19:32:08.000000000 +0200
+++ php-5.0.2/ext/gd/php_gd.h	2004-10-19 09:02:18.605711736 +0300
@@ -40,6 +40,8 @@
 #define PHP_GDIMG_TYPE_GD       8
 #define PHP_GDIMG_TYPE_GD2      9
 #define PHP_GDIMG_TYPE_GD2PART 10
+#define PHP_GDIMG_TYPE_GIFANIMBEGIN 11
+#define PHP_GDIMG_TYPE_GIFANIMADD 12
 
 #ifdef PHP_WIN32
 #define PHP_GD_API __declspec(dllexport)
@@ -137,6 +139,9 @@
 PHP_FUNCTION(imagefontheight);
 
 PHP_FUNCTION(imagegif );
+PHP_FUNCTION(imagegifanimbegin);
+PHP_FUNCTION(imagegifanimadd);
+PHP_FUNCTION(imagegifanimend);
 PHP_FUNCTION(imagejpeg );
 PHP_FUNCTION(imagepng);
 PHP_FUNCTION(imagewbmp);
diff -ru old/php-5.0.2/main/php_config.h.in php-5.0.2/main/php_config.h.in
--- old/php-5.0.2/main/php_config.h.in	2004-09-24 00:26:44.000000000 +0300
+++ php-5.0.2/main/php_config.h.in	2004-10-19 09:04:24.991177007 +0300
@@ -1418,6 +1418,9 @@
 #undef HAVE_GD_GIF_CREATE
 
 /*   */
+#undef HAVE_GD_GIF_ANIM
+
+/*   */
 #undef HAVE_GD_IMAGEELLIPSE
 
 /*   */
