Commits

Anonymous committed 5742a41

- sync to 2.0.29

  • Participants
  • Parent commits a4e6625

Comments (0)

Files changed (9)

 
 static void gdImageBrushApply (gdImagePtr im, int x, int y);
 static void gdImageTileApply (gdImagePtr im, int x, int y);
-int gdImageGetTrueColorPixel (gdImagePtr im, int x, int y);
+BGD_DECLARE(int) gdImageGetTrueColorPixel (gdImagePtr im, int x, int y);
 
 BGD_DECLARE(gdImagePtr) gdImageCreate (int sx, int sy)
 {
     {
       for (y = 0; y < (to->sy); y++)
 	{
-	  p = gdImageGetPixel (to, x, y);
+          /* Optimization: no gdImageGetPixel */
+	  p = to->pixels[y][x];
 	  if (xlate[p] == -1)
 	    {
 	      /* This ought to use HWB, but we don't have an alpha-aware
 	      /*      p,  to->red[p], to->green[p], to->blue[p], to->alpha[p], */
 	      /*      xlate[p], from->red[xlate[p]], from->green[xlate[p]], from->blue[xlate[p]], from->alpha[xlate[p]]); */
 	    };
-	  gdImageSetPixel (to, x, y, xlate[p]);
+          /* Optimization: no gdImageSetPixel */
+	  to->pixels[y][x] = xlate[p];
 	};
     };
 
     }
 }
 
-int
-gdImageGetTrueColorPixel (gdImagePtr im, int x, int y)
+BGD_DECLARE(int) gdImageGetTrueColorPixel (gdImagePtr im, int x, int y)
 {
   int p = gdImageGetPixel (im, x, y);
   if (!im->trueColor)
   int *sty;
   /* We only need to use floating point to determine the correct
      stretch vector for one line's worth. */
-  double accum;
+  if (overflow2(sizeof (int), srcW)) {
+    return;
+  }
+  if (overflow2(sizeof (int), srcH)) {
+    return;
+  }
   stx = (int *) gdMalloc (sizeof (int) * srcW);
   sty = (int *) gdMalloc (sizeof (int) * srcH);
-  accum = 0;
   /* Fixed by Mao Morimoto 2.0.16 */
   for (i = 0; (i < srcW); i++)
     {
 
 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)
 
   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++;
 /* That could help to adjust intersections  to produce a nice */
 /* interior_extrema. */
 
+#if 0
 static void horizontalLine(gdImagePtr im, int minx, int maxx, int y,
 	int fill_color);
+#endif
 
 BGD_DECLARE(void) gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
 {
 
   if (!im->polyAllocated)
     {
+      if (overflow2(sizeof (int), n)) {
+        return;
+      }
       im->polyInts = (int *) gdMalloc (sizeof (int) * n);
       im->polyAllocated = n;
     }
 /*1.4           int interLast = 0; */
 /*              int dirLast = 0; */
 /*              int interFirst = 1; */
-      int yshift = 0;
+/* 2.0.26+      int yshift = 0; */
       if (c == gdAntiAliased) {
         fill_color = im->AA_color;
       } else {
 	{
           int minx = im->polyInts[i];
           int maxx = im->polyInts[i + 1];
-          horizontalLine(im, minx, maxx, y, fill_color);
+          /* 2.0.29: back to gdImageLine to prevent segfaults when
+            performing a pattern fill */
+          gdImageLine (im, im->polyInts[i], y, im->polyInts[i + 1], y,
+            fill_color);
 	}
     }
   /* If we are drawing this AA, then redraw the border with AA lines. */
   } 
 }
 
+#if 0
 static void horizontalLine(gdImagePtr im, int minx, int maxx, int y,
 	int fill_color)
 {
     }
   }
 }
+#endif
 
-inline static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t);
+static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t);
 
 BGD_DECLARE(void) gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels)
 {
     {
       gdFree (im->style);
     }
+  if (overflow2(sizeof (int), noOfPixels)) {
+    return;
+  }   	
   im->style = (int *) gdMalloc (sizeof (int) * noOfPixels);
   memcpy (im->style, style, sizeof (int) * noOfPixels);
   im->styleLength = noOfPixels;
   return cmpStatus;
 }
 
+
+/* Thanks to Frank Warmerdam for this superior implementation
+	of gdAlphaBlend(), which merges alpha in the
+	destination color much better. */
+
 BGD_DECLARE(int) gdAlphaBlend (int dst, int src)
 {
-  /* 2.0.12: TBB: alpha in the destination should be a 
-     component of the result. Thanks to Frank Warmerdam for
-     pointing out the issue. */
-  return ((((gdTrueColorGetAlpha (src) *
-	     gdTrueColorGetAlpha (dst)) / gdAlphaMax) << 24) +
-	  ((((gdAlphaTransparent - gdTrueColorGetAlpha (src)) *
-	     gdTrueColorGetRed (src) / gdAlphaMax) +
-	    (gdTrueColorGetAlpha (src) *
-	     gdTrueColorGetRed (dst)) / gdAlphaMax) << 16) +
-	  ((((gdAlphaTransparent - gdTrueColorGetAlpha (src)) *
-	     gdTrueColorGetGreen (src) / gdAlphaMax) +
-	    (gdTrueColorGetAlpha (src) *
-	     gdTrueColorGetGreen (dst)) / gdAlphaMax) << 8) +
-	  (((gdAlphaTransparent - gdTrueColorGetAlpha (src)) *
-	    gdTrueColorGetBlue (src) / gdAlphaMax) +
-	   (gdTrueColorGetAlpha (src) *
-	    gdTrueColorGetBlue (dst)) / gdAlphaMax));
+    int src_alpha = gdTrueColorGetAlpha(src);
+    int dst_alpha, alpha, red, green, blue;
+    int src_weight, dst_weight, tot_weight;
+
+/* -------------------------------------------------------------------- */
+/*      Simple cases we want to handle fast.                            */
+/* -------------------------------------------------------------------- */
+    if( src_alpha == gdAlphaOpaque )
+        return src;
+
+    dst_alpha = gdTrueColorGetAlpha(dst);
+    if( src_alpha == gdAlphaTransparent )
+        return dst;
+    if( dst_alpha == gdAlphaTransparent )
+        return src;
+
+/* -------------------------------------------------------------------- */
+/*      What will the source and destination alphas be?  Note that      */
+/*      the destination weighting is substantially reduced as the       */
+/*      overlay becomes quite opaque.                                   */
+/* -------------------------------------------------------------------- */
+    src_weight = gdAlphaTransparent - src_alpha;
+    dst_weight = (gdAlphaTransparent - dst_alpha) * src_alpha / gdAlphaMax;
+    tot_weight = src_weight + dst_weight;
+    
+/* -------------------------------------------------------------------- */
+/*      What red, green and blue result values will we use?             */
+/* -------------------------------------------------------------------- */
+    alpha = src_alpha * dst_alpha / gdAlphaMax;
+
+    red = (gdTrueColorGetRed(src) * src_weight
+           + gdTrueColorGetRed(dst) * dst_weight) / tot_weight;
+    green = (gdTrueColorGetGreen(src) * src_weight
+           + gdTrueColorGetGreen(dst) * dst_weight) / tot_weight;
+    blue = (gdTrueColorGetBlue(src) * src_weight
+           + gdTrueColorGetBlue(dst) * dst_weight) / tot_weight;
+
+/* -------------------------------------------------------------------- */
+/*      Return merged result.                                           */
+/* -------------------------------------------------------------------- */
+    return ((alpha << 24) + (red << 16) + (green << 8) + blue);
 }
 
 BGD_DECLARE(void) gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg)
 #define BLEND_COLOR(a, nc, c, cc) \
 nc = (cc) + (((((c) - (cc)) * (a)) + ((((c) - (cc)) * (a)) >> 8) + 0x80) >> 8);
 
-inline static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t)
+static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t)
 {
 	int dr,dg,db,p,r,g,b;
 	p = gdImageGetPixel(im,x,y);
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #ifndef GD_H
 #define GD_H 1
 
 	and other languages. This breaks ABI compatibility
 	with previous DLL revs, but it's necessary. */
 
+/* 2.0.29: WIN32 programmers can declare the NONDLL macro if they
+	wish to build gd as a static library or by directly including
+	the gd sources in a project. */
+
+#ifndef WIN32
+#define NONDLL 1
+#endif /* WIN32 */
+
+#ifdef NONDLL
+#define BGD_DECLARE(rt) extern rt
+#else
 #ifdef BGDWIN32
 #define BGD_DECLARE(rt) __declspec(dllexport) rt __stdcall
 #else
-#ifdef WIN32
 #define BGD_DECLARE(rt) __declspec(dllimport) rt _stdcall
-#else
-/* 2.0.19: should be 'extern', especially for font data pointers */
-#define BGD_DECLARE(rt) extern rt
-#endif /* WIN32 */
 #endif /* BGDWIN32 */
+#endif /* NONDLL */
 
 /* 2.0.20: for actual storage of exported data, functions don't need this,
   currently needed only for font pointers */
+#ifdef NONDLL
+/* 2.0.25: bring back extern */
+#define BGD_EXPORT_DATA_PROT extern
+#define BGD_EXPORT_DATA_IMPL
+#else
 #ifdef BGDWIN32
 #define BGD_EXPORT_DATA_PROT __declspec(dllexport) extern
 #define BGD_EXPORT_DATA_IMPL __declspec(dllexport)
 #else
-#ifdef WIN32
 #define BGD_EXPORT_DATA_PROT __declspec(dllimport) extern
 #define BGD_EXPORT_DATA_IMPL __declspec(dllimport) 
-#else
-/* 2.0.25: bring back extern */
-#define BGD_EXPORT_DATA_PROT extern
-#define BGD_EXPORT_DATA_IMPL
-#endif /* WIN32 */
 #endif /* BGDWIN32 */
+#endif /* NONDLL */
 
 #ifdef __cplusplus
 extern "C"
 BGD_DECLARE(gdImagePtr) gdImageCreateFromPng (FILE * fd);
 BGD_DECLARE(gdImagePtr) gdImageCreateFromPngCtx (gdIOCtxPtr in);
 BGD_DECLARE(gdImagePtr) gdImageCreateFromPngPtr (int size, void *data);
+
+/* These read the first frame only */
 BGD_DECLARE(gdImagePtr) gdImageCreateFromGif (FILE * fd);
 BGD_DECLARE(gdImagePtr) gdImageCreateFromGifCtx (gdIOCtxPtr in);
 BGD_DECLARE(gdImagePtr) gdImageCreateFromGifPtr (int size, void *data);
 	allowing for many useful effects. */
 
 BGD_DECLARE(void) gdImageSetPixel (gdImagePtr im, int x, int y, int color);
+/* FreeType 2 text output with hook to extra flags */
 
 BGD_DECLARE(int) gdImageGetPixel (gdImagePtr im, int x, int y);
+BGD_DECLARE(int) gdImageGetTrueColorPixel (gdImagePtr im, int x, int y);
+
+/* translate a fontconfig fontpattern into a fontpath. return NULL if OK, else return error string */
+BGD_DECLARE(char *) font_pattern(char **fontpath, char *fontpattern);
+
+/* translate a font file basename, or relative file name, or a list of such, into a fontpath, retun NULL if OK, else return error string */
+BGD_DECLARE(char *) font_path(char **fontpath, char *name_list);
 
 /* Now a No-Op, but kept for binary compatibility. */
 BGD_DECLARE(void) gdImageAABlend (gdImagePtr im);
 				   for in the above order. */
     int hdpi;                   /* if (flags & gdFTEX_RESOLUTION) */
     int vdpi;			/* if (flags & gdFTEX_RESOLUTION) */
+    char *xshow;	/* if (flags & gdFTEX_XSHOW)
+			   then, on return, xshow is a malloc'ed
+			   string contining xshow position data for
+			   the last string.
+
+			   NB. The caller is responsible for gdFree'ing
+			   the xshow string. 
+			 */
+    char *fontpath;	/* if (flags & gdFTEX_RETURNFONTPATHNAME)
+                           then, on return, fontpath is a malloc'ed
+                           string containing the actual font file path name
+                           used, which can be interesting when fontconfig
+                           is in use. 
+
+                           The caller is responsible for gdFree'ing the
+                           fontpath string.
+			*/
 
   }
   gdFTStringExtra, *gdFTStringExtraPtr;
 #define gdFTEX_LINESPACE 1
 #define gdFTEX_CHARMAP 2
 #define gdFTEX_RESOLUTION 4
+#define gdFTEX_DISABLE_KERNING 8
+#define gdFTEX_XSHOW 16
+/* The default unless gdFTUseFontConfig(1); has been called:
+  fontlist is a full or partial font file pathname or list thereof 
+  (i.e. just like before 2.0.29) */
+#define gdFTEX_FONTPATHNAME 32
+/* Necessary to use fontconfig patterns instead of font pathnames
+  as the fontlist argument, unless gdFTUseFontConfig(1); has 
+  been called. New in 2.0.29 */
+#define gdFTEX_FONTCONFIG 64
+/* Sometimes interesting when fontconfig is used: the fontpath
+  element of the structure above will contain a gdMalloc'd string
+  copy of the actual font file pathname used, if this flag is set 
+   when the call is made */
+#define gdFTEX_RETURNFONTPATHNAME 128
+
+/* If flag is nonzero, the fontlist parameter to gdImageStringFT 
+  and gdImageStringFTEx shall be assumed to be a fontconfig font pattern
+  if fontconfig was compiled into gd. This function returns zero
+  if fontconfig is not available, nonzero otherwise. */
+BGD_DECLARE(int) gdFTUseFontConfig(int flag);
 
 /* These are NOT flags; set one in 'charmap' if you set the
 	gdFTEX_CHARMAP bit in 'flags'. */
   gdPoint, *gdPointPtr;
 
 BGD_DECLARE(void) gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c);
+BGD_DECLARE(void) gdImageOpenPolygon (gdImagePtr im, gdPointPtr p, int n, int c);
 BGD_DECLARE(void) gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c);
 
 /* These functions still work with truecolor images, 
 BGD_DECLARE(void) gdImagePng (gdImagePtr im, FILE * out);
 BGD_DECLARE(void) gdImagePngCtx (gdImagePtr im, gdIOCtx * out);
 BGD_DECLARE(void) gdImageGifCtx (gdImagePtr im, gdIOCtx * out);
-  /* 2.0.12: Compression level: 0-9 or -1, where 0 is NO COMPRESSION at all,
-     1 is FASTEST but produces larger files, 9 provides the best
-     compression (smallest files) but takes a long time to compress, and
-     -1 selects the default compiled into the zlib library. */
+
+/* 2.0.12: Compression level: 0-9 or -1, where 0 is NO COMPRESSION at all,
+  1 is FASTEST but produces larger files, 9 provides the best
+  compression (smallest files) but takes a long time to compress, and
+  -1 selects the default compiled into the zlib library. */
 BGD_DECLARE(void) gdImagePngEx (gdImagePtr im, FILE * out, int level);
 BGD_DECLARE(void) gdImagePngCtxEx (gdImagePtr im, gdIOCtx * out, int level);
 
 BGD_DECLARE(void) gdFree (void *m);
 
 /* Best to free this memory with gdFree(), not free() */
-  void *gdImageWBMPPtr (gdImagePtr im, int *size, int fg);
+BGD_DECLARE(void *) gdImageWBMPPtr (gdImagePtr im, int *size, int fg);
 
 /* 100 is highest quality (there is always a little loss with JPEG).
 	0 is lowest. 10 is about the lowest useful setting. */
 /* Best to free this memory with gdFree(), not free() */
 BGD_DECLARE(void *) gdImageJpegPtr (gdImagePtr im, int *size, int quality);
 
+/* Legal values for Disposal. gdDisposalNone is always used by
+	the built-in optimizer if previm is passed. */
+
+enum {
+	gdDisposalUnknown,
+	gdDisposalNone,
+	gdDisposalRestoreBackground,
+	gdDisposalRestorePrevious
+};
+
+BGD_DECLARE(void) gdImageGifAnimBegin(gdImagePtr im, FILE *outFile, int GlobalCM, int Loops);
+BGD_DECLARE(void) gdImageGifAnimAdd(gdImagePtr im, FILE *outFile, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm);
+BGD_DECLARE(void) gdImageGifAnimEnd(FILE *outFile);
+BGD_DECLARE(void) gdImageGifAnimBeginCtx(gdImagePtr im, gdIOCtx *out, int GlobalCM, int Loops);
+BGD_DECLARE(void) gdImageGifAnimAddCtx(gdImagePtr im, gdIOCtx *out, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm);
+BGD_DECLARE(void) gdImageGifAnimEndCtx(gdIOCtx *out);
+BGD_DECLARE(void *) gdImageGifAnimBeginPtr(gdImagePtr im, int *size, int GlobalCM, int Loops);
+BGD_DECLARE(void *) gdImageGifAnimAddPtr(gdImagePtr im, int *size, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm);
+BGD_DECLARE(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
 /* resolution affects ttf font rendering, particularly hinting */
 #define GD_RESOLUTION           96	/* pixels per inch */
 
+#ifdef __cplusplus
+}
+#endif
+
 /* newfangled special effects */
 #include "gdfx.h"
 
+#endif				/* GD_H */
+
 #ifdef __cplusplus
 }
 #endif
-
-#endif				/* GD_H */

File src/gd2togif.c

 	gdImageGif(im, out);
 	fclose(out);
 	gdImageDestroy(im);
+
+	return 0;
 }
 

File src/gd_gd2.c

 #endif
 
 #include <stdio.h>
-#include <errno.h>
+/* 2.0.29: no more errno.h, makes windows happy */
 #include <math.h>
 #include <string.h>
 #include <stdlib.h>
 	         Longstanding bug. 01/16/03 */
 	      if (!gdSeek (in, dpos))
 		{
-		  printf ("Error from seek: %d\n", errno);
+		  fprintf (stderr, "Seek error\n");
 		  goto fail2;
 		};
 	      GD2_DBG (printf
 
 		  if (gdPutBuf (compData, compLen, out) <= 0)
 		    {
-		      /* Any alternate suggestions for handling this? */
-		      printf ("Error %d on write\n", errno);
+			fprintf(stderr, "gd write error\n");
 		    };
 		};
 	    };

File src/gd_gif_out.c

 #include <string.h>
 #include <stdlib.h>
 #include "gd.h"
+#include "gdhelpers.h"
 
 /* Code drawn from ppmtogif.c, from the pbmplus package
 **
 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);
 	}
 }
 
+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; 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 );
+	}
+}
+
+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)
 {
         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
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #ifndef GD_IO_H
 #define GD_IO_H 1
 
  long gdTell (gdIOCtx * ctx);
 
 #endif
+
+#ifdef __cplusplus
+}
+#endif

File src/gd_io_dp.c

 	{
 	  return FALSE;
 	}
+      if (overflow2(dp->realSize, 2)) {
+        return FALSE;
+      }
       if (!gdReallocDynamic (dp, dp->realSize * 2))
 	{
 	  dp->dataGood = FALSE;
 	{
 	  return FALSE;
 	}
+      if (overflow2(dp->realSize, 2)) {
+        return FALSE;
+      }
       if (!gdReallocDynamic (dp, bytesNeeded * 2))
 	{
 	  dp->dataGood = FALSE;

File src/gd_jpeg.c

 #ifdef HAVE_LIBJPEG
 #include "gdhelpers.h"
 
+/* JCE undef two symbols that we don't need anymore but which are
+   may be defined in config.h from ./configure but which are
+   redefined incompatibly in jpeglib.h */
+#undef HAVE_STDDEF_H
+#undef HAVE_STDLIB_H
+
 /* 1.8.1: remove dependency on jinclude.h */
 #include "jpeglib.h"
 #include "jerror.h"
   if (jpeg_finish_decompress (&cinfo) != TRUE)
     fprintf (stderr, "gd-jpeg: warning: jpeg_finish_decompress"
 	     " reports suspended data source\n");
-  /* Thanks to Truxton Fulton */
+  /* TBB 2.0.29: we should do our best to read whatever we can read, and a 
+    warning is a warning. A fatal error on warnings doesn't make sense. */
+#if 0
+  /* This was originally added by Truxton Fulton */
   if (cinfo.err->num_warnings > 0)
     goto error;
+#endif
 
   jpeg_destroy_decompress (&cinfo);
   gdFree (row);

File src/gd_png.c

 
   /* allocate space for the PNG image data */
   rowbytes = png_get_rowbytes (png_ptr, info_ptr);
+  if (overflow2(rowbytes, height)) {
+    png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
+    return NULL;
+  }  
   if ((image_data = (png_bytep) gdMalloc (rowbytes * height)) == NULL)
     {
       fprintf (stderr, "gd-png error: cannot allocate image data\n");
       png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
       return NULL;
     }
+  if (overflow2(height, sizeof (png_bytep))) {
+    png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
+    gdFree (image_data);
+    return NULL;
+  }    
   if ((row_pointers =
        (png_bytepp) gdMalloc (height * sizeof (png_bytep))) == NULL)
     {
       int thisPixel;
       png_bytep *prow_pointers;
       int saveAlphaFlag = im->saveAlphaFlag;
+      if (overflow2(sizeof (png_bytep), height)) {
+        return;
+      } 
       row_pointers = gdMalloc (sizeof (png_bytep) * height);
       if (row_pointers == NULL)
 	{
 	  fprintf (stderr, "gd-png error: unable to allocate row_pointers\n");
+          /* 2.0.29: return was missing */
+          return;
 	}
       prow_pointers = row_pointers;
       for (j = 0; j < height; ++j)
 	{
-	  if ((*prow_pointers =
-	       (png_bytep) gdMalloc (width * channels)) == NULL)
+          if (overflow2(width, channels) || ((*prow_pointers =
+	       (png_bytep) gdMalloc (width * channels)) == NULL))
 	    {
 	      fprintf (stderr, "gd-png error: unable to allocate rows\n");
 	      for (i = 0; i < j; ++i)
 		gdFree (row_pointers[i]);
+              /* 2.0.29: memory leak TBB */
+              free(row_pointers);
 	      return;
 	    }
 	  pOutputRow = *prow_pointers++;
       if (remap)
 	{
 	  png_bytep *row_pointers;
+          if (overflow2(sizeof (png_bytep), height)) {
+            return;
+          }
 	  row_pointers = gdMalloc (sizeof (png_bytep) * height);
 	  if (row_pointers == NULL)
 	    {
 	      fprintf (stderr,
 		       "gd-png error: unable to allocate row_pointers\n");
+              /* TBB: return missing */
+              return;
 	    }
 	  for (j = 0; j < height; ++j)
 	    {
 		  fprintf (stderr, "gd-png error: unable to allocate rows\n");
 		  for (i = 0; i < j; ++i)
 		    gdFree (row_pointers[i]);
+                  /* TBB: memory leak */
+		  gdFree (row_pointers);
 		  return;
 		}
 	      for (i = 0; i < width; ++i)