Anonymous avatar Anonymous committed 22d55c5

- sync to 1.8.4

Comments (0)

Files changed (25)

 AR=ar
 
 #If you don't have FreeType, libjpeg and/or Xpm installed, including the
-#header files, uncomment this (default).
-CFLAGS=-O
+#header files, uncomment this (default). You really must install
+#libpng and zlib to get anywhere if you wish to create PNG images.
+CFLAGS=-O -DHAVE_LIBPNG -DHAVE_LIBJPEG
+
 #If you do have FreeType, libjpeg and/or Xpm fully installed, uncomment a
 #variation of this and comment out the line above. See also LIBS below.
-#CFLAGS=-O  -DHAVE_XPM -DHAVE_JPEG -DHAVE_LIBTTF
+#CFLAGS=-O -DHAVE_LIBXPM -DHAVE_LIBPNG -DHAVE_LIBJPEG \
+#	-DHAVE_LIBFREETYPE -DHAVE_LIBTTF 
+
+#To use the old FreeType 1.x library, add this additional #define
+#to the line above
+#-DHAVE_LIBTTF 
 
-#If you don't have FreeType and/or Xpm fully installed, uncomment this
+#If you don't have FreeType Xpm fully installed, uncomment this
 #(default).
 
 #PLEASE NOTE: YOU MAY HAVE TO JUGGLE THE ORDER OF THE LIBRARIES.
 #Some systems are very picky about link order. They don't all agree
 #on the right order, either.
 
-LIBS=-lm -lgd -lpng -lz
+LIBS=-lgd -lpng -lz -lm
 
 #If you do have FreeType, JPEG and/or Xpm fully installed, uncomment a 
 #variation of this and comment out the line above. Note that
 #Xpm requires X11. See also CFLAGS above.
 
-#PLEASE NOTE: YOU MAY HAVE TO JUGGLE THE ORDER OF THE LIBRARIES.
-#Some systems are very picky about link order. They don't all agree
-#on the right order, either.
+#LIBS=-lgd -lpng -lz -ljpeg -lfreetype -lm -lttf
 
-#LIBS=-lm -lgd -lpng -lz -ljpeg -lttf -lXpm -lX11
+#Note: for Freetype 1.x, use DHAVE_LIBTTF and -lttf instead.
 
-#Typical install locations for freetype, zlib, xpm, libjpeg and libpng header files.
-#If yours are somewhere else, change this. 
-#-I. is important to ensure that the version of gd you are installing
-#is used, and not an older release in your directory tree somewhere.
+#Typical install locations for freetype, zlib, xpm, libjpeg and libpng header 
+#files. If yours are somewhere else, change this. -I. is important to 
+#ensure that the version of gd you are installing is used, and not an 
+#older release in your directory tree somewhere.
 
-INCLUDEDIRS=-I. -I/usr/local/include -I/usr/include/X11 -I/usr/X11R6/include/X11
+INCLUDEDIRS=-I. -I/usr/include/freetype2 -I/usr/include/X11 -I/usr/X11R6/include/X11 -I/usr/local/include 
 
 #Typical install locations for freetype, zlib, xpm and libpng libraries.
 #If yours are somewhere else, other than a standard location
 #-L. as this allows the gd library itself to be found.
 #Put -L. first so that old versions of the gd library elsewhere
 #on your system can't cause conflicts while building a new one.
+#This line shouldn't hurt if you don't actually have some of the
+#optional libraries and directories.
 LIBDIRS=-L. -L/usr/local/lib -L/usr/lib/X11 -L/usr/X11R6/lib
 
 #Location where libgd.a should be installed by "make install".
 #
 #
 
-VERSION=1.8.1
+VERSION=1.8.4
 
 CC=$(COMPILER) $(INCLUDEDIRS)
 LINK=$(CC) $(LIBDIRS) $(LIBS)
 PROGRAMS=$(BIN_PROGRAMS) $(TEST_PROGRAMS)
 
 BIN_PROGRAMS=pngtogd pngtogd2 gdtopng gd2topng gd2copypal gdparttopng webpng
-TEST_PROGRAMS=gdtest gddemo gd2time gdtestttf
+TEST_PROGRAMS=gdtest gddemo gd2time gdtestft gdtestttf
 
 all: libgd.a $(PROGRAMS)
 
 gd2time: gd2time.o libgd.a
 	$(CC) gd2time.o -o gd2time	$(LIBDIRS) $(LIBS)
 
+gdtestft: gdtestft.o libgd.a
+	$(CC) --verbose gdtestft.o -o gdtestft $(LIBDIRS) $(LIBS)
 gdtestttf: gdtestttf.o libgd.a
-	$(CC) gdtestttf.o -o gdtestttf	$(LIBDIRS) $(LIBS)
+	$(CC) --verbose gdtestttf.o -o gdtestttf $(LIBDIRS) $(LIBS)
 
 libgd.a: gd.o gd_gd.o gd_gd2.o gd_io.o gd_io_dp.o gd_io_file.o gd_ss.o \
 	gd_io_ss.o gd_png.o gd_jpeg.o gdxpm.o gdfontt.o gdfonts.o gdfontmb.o gdfontl.o \
-	gdfontg.o gdtables.o gdttf.o gdcache.o gdkanji.o  wbmp.o gd_wbmp.o \
-	gd.h gdfontt.h gdfonts.h gdfontmb.h gdfontl.h gdfontg.h
+	gdfontg.o gdtables.o gdft.o gdttf.o gdcache.o gdkanji.o wbmp.o \
+	gd_wbmp.o gdhelpers.o gd.h gdfontt.h gdfonts.h gdfontmb.h gdfontl.h \
+	gdfontg.h gdhelpers.h
 	rm -f libgd.a
 	$(AR) rc libgd.a gd.o gd_gd.o gd_gd2.o gd_io.o gd_io_dp.o \
 		gd_io_file.o gd_ss.o gd_io_ss.o gd_png.o gd_jpeg.o gdxpm.o \
 		gdfontt.o gdfonts.o gdfontmb.o gdfontl.o gdfontg.o \
-		gdtables.o gdttf.o gdcache.o gdkanji.o wbmp.o gd_wbmp.o
+		gdtables.o gdft.o gdttf.o gdcache.o gdkanji.o wbmp.o \
+		gd_wbmp.o gdhelpers.o
 	-ranlib libgd.a
 
 clean:
 #NMAKE makefile for Windows 95/98/NT developers.
 #Produces a static library (libgd.lib). Thanks to Joe Gregorio.
+#This is out of date.
 
 COMPILER=cl
 
 
 #If you do have FreeType and/or Xpm fully installed, uncomment a
 #variation of this and comment out the line above. See also LIBS below.
-#CFLAGS=-O -DHAVE_XPM -DHAVE_LIBTTF
+#CFLAGS=-O -DHAVE_LIBXPM -DHAVE_LIBJPEG -DHAVE_LIBPNG -DHAVE_LIBTTF
+
+# -DHAVE_LIBFREETYPE can be used instead of -DHAVE_TTF to use the
+# newer FreeType2 libraries
 
 #Libraries required for applications 
 LIBS=gd.lib libpng.lib zlib.lib 
 PROGRAMS=$(BIN_PROGRAMS) $(TEST_PROGRAMS)
 
 BIN_PROGRAMS=pngtogd.exe pngtogd2.exe gdtopng.exe gd2topng.exe gd2copypal.exe gdparttopng.exe webpng.exe
-TEST_PROGRAMS=gdtest.exe gddemo.exe gd2time.exe gdtestttf.exe
+TEST_PROGRAMS=gdtest.exe gddemo.exe gd2time.exe gdtestttf.exe gdtestft.exe
 
 all: gd.lib $(PROGRAMS)
 
 gdtestttf.exe: gdtestttf.c gd.lib
 	$(CC) gdtestttf.c 	$(LIBDIRS) $(LIBS)
 
+gdtestft.exe: gdtestft.c gd.lib
+	$(CC) gdtestft.c 	$(LIBDIRS) $(LIBS)
+
 OBJS=gd.obj gd_gd.obj gd_gd2.obj gd_io.obj gd_io_dp.obj gd_io_file.obj gd_ss.obj \
 	gd_io_ss.obj gd_png.obj gdxpm.obj gdfontt.obj gdfonts.obj gdfontmb.obj gdfontl.obj \
-	gdfontg.obj gdtables.obj gdttf.obj gdcache.obj gdkanji.obj gd_jpeg.obj
+	gdfontg.obj gdtables.obj gdttf.obj gdft.c gdcache.obj gdkanji.obj gd_jpeg.obj
 
 gd.lib:  $(OBJS) gd.h gdfontt.h gdfonts.h gdfontmb.h gdfontl.h gdfontg.h	
 	$(AR) $(OBJS) $(GDLIBS) 
-#ifndef _OSD_POSIX	/* _OSD_POSIX defines *alloc() in stdlib.h */
-#include <malloc.h>
-#endif /*_OSD_POSIX*/
 #include <stdio.h>
 #include <math.h>
 #include <string.h>
 #include <stdlib.h>
 #include <zlib.h>
 #include "gd.h"
+#include "gdhelpers.h"
 
 #ifdef _OSD_POSIX	/* BS2000 uses the EBCDIC char set instead of ASCII */
 #define CHARSET_EBCDIC
 };
 #endif /*CHARSET_EBCDIC*/
 
-extern int gdCosT[1024];
-extern int gdSinT[1024];
+extern int gdCosT[];
+extern int gdSinT[];
 
 static void gdImageBrushApply(gdImagePtr im, int x, int y);
 static void gdImageTileApply(gdImagePtr im, int x, int y);
 {
 	int i;
 	gdImagePtr im;
-	im = (gdImage *) malloc(sizeof(gdImage));
+	im = (gdImage *) gdMalloc(sizeof(gdImage));
 	/* NOW ROW-MAJOR IN GD 1.3 */
-	im->pixels = (unsigned char **) malloc(sizeof(unsigned char *) * sy);
+	im->pixels = (unsigned char **) gdMalloc(sizeof(unsigned char *) * sy);
 	im->polyInts = 0;
 	im->polyAllocated = 0;
 	im->brush = 0;
 	im->style = 0;
 	for (i=0; (i<sy); i++) {
 		/* NOW ROW-MAJOR IN GD 1.3 */
-		im->pixels[i] = (unsigned char *) calloc(
+		im->pixels[i] = (unsigned char *) gdCalloc(
 			sx, sizeof(unsigned char));
 	}	
 	im->sx = sx;
 {
 	int i;
 	for (i=0; (i<im->sy); i++) {
-		free(im->pixels[i]);
+		gdFree(im->pixels[i]);
 	}	
-	free(im->pixels);
+	gdFree(im->pixels);
 	if (im->polyInts) {
-			free(im->polyInts);
+			gdFree(im->polyInts);
 	}
 	if (im->style) {
-		free(im->style);
+		gdFree(im->style);
 	}
-	free(im);
+	gdFree(im);
 }
 
 int gdImageColorClosest(gdImagePtr im, int r, int g, int b)
 		case 5: RETURN_RGB(v, w, n);  
 	}  
 
+    return RGB;
+
 }
 
 int gdImageColorClosestHWB(gdImagePtr im, int r, int g, int b)
 {
 	int i;
-	long rd, gd, bd;
+	/* long rd, gd, bd; */
 	int ct = (-1);
 	int first = 1;
 	float mindist = 0;
         int c, dc;
         int x, y;
         int tox, toy;
-        int i;
 	int ncR, ncG, ncB;
+#if 0
+        int i;
         int colorMap[gdMaxColors];
         for (i=0; (i<gdMaxColors); i++) {
                 colorMap[i] = (-1);
         }
+#endif
         toy = dstY;
         for (y=srcY; (y < (srcY + h)); y++) {
                 tox = dstX;
         int c, dc;
         int x, y;
         int tox, toy;
-        int i;
 	int ncR, ncG, ncB;
-        int colorMap[gdMaxColors];
 	float g;
+#if 0
+        int i;
+        int colorMap[gdMaxColors];
 
         for (i=0; (i<gdMaxColors); i++) {
                 colorMap[i] = (-1);
         }
+#endif
         toy = dstY;
         for (y=srcY; (y < (srcY + h)); y++) {
                 tox = dstX;
 	/* We only need to use floating point to determine the correct
 		stretch vector for one line's worth. */
 	double accum;
-	stx = (int *) malloc(sizeof(int) * srcW);
-	sty = (int *) malloc(sizeof(int) * srcH);
+	stx = (int *) gdMalloc(sizeof(int) * srcW);
+	sty = (int *) gdMalloc(sizeof(int) * srcH);
 	accum = 0;
 	for (i=0; (i < srcW); i++) {
 		int got;
 			toy++;
 		}
 	}
-	free(stx);
-	free(sty);
+	gdFree(stx);
+	gdFree(sty);
 }
 
 gdImagePtr
 		return;
 	}
 	if (!im->polyAllocated) {
-		im->polyInts = (int *) malloc(sizeof(int) * n);
+		im->polyInts = (int *) gdMalloc(sizeof(int) * n);
 		im->polyAllocated = n;
 	}		
 	if (im->polyAllocated < n) {
 		while (im->polyAllocated < n) {
 			im->polyAllocated *= 2;
 		}	
-		im->polyInts = (int *) realloc(im->polyInts,
+		im->polyInts = (int *) gdRealloc(im->polyInts,
 			sizeof(int) * im->polyAllocated);
 	}
 	miny = p[0].y;
 void gdImageSetStyle(gdImagePtr im, int *style, int noOfPixels)
 {
 	if (im->style) {
-		free(im->style);
+		gdFree(im->style);
 	}
 	im->style = (int *) 
-		malloc(sizeof(int) * noOfPixels);
+		gdMalloc(sizeof(int) * noOfPixels);
 	memcpy(im->style, style, sizeof(int) * noOfPixels);
 	im->styleLength = noOfPixels;
 	im->stylePos = 0;
 		cmpStatus |= GD_CMP_TRANSPARENT;
 	}
 
+	sx = im1->sx;
 	if (im1->sx != im2->sx) {
 		cmpStatus |= GD_CMP_SIZE_X + GD_CMP_IMAGE;
-		if (im1->sx < im2->sx) {
-			sx = im1->sx;
-		} else {
+		if (im2->sx < im1->sx) {
 			sx = im2->sx;
 		}
-	} else {
-		sx = im1->sx;
 	}
 
+	sy = im1->sy;
 	if (im1->sy != im2->sy) {
 		cmpStatus |= GD_CMP_SIZE_Y + GD_CMP_IMAGE;
-		if (im1->sy < im2->sy) {
-			sy = im1->sy;
-		} else {
+		if (im2->sy < im1->sy) {
 			sy = im2->sy;
 		}
 	}
 		cmpStatus |= GD_CMP_NUM_COLORS;
 	}
 
-	for ( y = 0 ; (y<im1->sy) ; y++ ) {
-		for ( x = 0 ; (x < im1->sx) ; x++ ) {
+	for ( y = 0 ; (y < sy) ; y++ ) {
+		for ( x = 0 ; (x < sx) ; x++ ) {
 			p1 = im1->pixels[y][x];
 			p2 = im2->pixels[y][x];
 
 extern "C" {
 #endif
 
+/* default fontpath for unix systems */
+#define DEFAULT_FONTPATH "/usr/share/fonts/truetype"
+#define PATHSEPARATOR ":"
+
 /* gd.h: declarations file for the graphic-draw module.
  * Permission to use, copy, modify, and distribute this software and its
  * documentation for any purpose and without fee is hereby granted, provided
 gdImagePtr gdImageCreate(int sx, int sy);
 gdImagePtr gdImageCreateFromPng(FILE *fd);
 gdImagePtr gdImageCreateFromPngCtx(gdIOCtxPtr in);
+gdImagePtr gdImageCreateFromWBMP(FILE *inFile);
+gdImagePtr gdImageCreateFromWBMPCtx(gdIOCtx *infile); 
+gdImagePtr gdImageCreateFromJpeg(FILE *infile);
+gdImagePtr gdImageCreateFromJpegCtx(gdIOCtx *infile);
 
 /* A custom data source. */
 /* The source function must return -1 on error, otherwise the number
 void gdImageString16(gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color);
 void gdImageStringUp16(gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color);
 
-char *gdImageStringTTF(gdImage *im, int *brect, int fg, char *fontname,
+/* FreeType 1.x text output (DEPRECATED) */
+char *gdImageStringTTF(gdImage *im, int *brect, int fg, char *fontlist,
                 double ptsize, double angle, int x, int y, char *string);
 
-/* Point type for use in polygon drawing. */
+/* FreeType 2 text output (NIFTY) */
+char *gdImageStringFT(gdImage *im, int *brect, int fg, char *fontlist,
+                double ptsize, double angle, int x, int y, char *string);
 
+/* Point type for use in polygon drawing. */
 typedef struct {
 	int x, y;
 } gdPoint, *gdPointPtr;
 
 void gdImageWBMP(gdImagePtr image, int fg, FILE *out);
 void gdImageWBMPCtx(gdImagePtr image, int fg, gdIOCtx *out);
-void *gdImageWBMPPtr(gdImagePtr im, int *size, int fg);
-gdImagePtr gdImageCreateFromWBMP(FILE *inFile);
-gdImagePtr gdImageCreateFromWBMPCtx(gdIOCtx *infile); 
 
+/* Guaranteed to correctly free memory returned
+	by the gdImage*Ptr functions */
+void gdFree(void *m);
+
+/* Best to free this memory with gdFree(), not free() */
+void *gdImageWBMPPtr(gdImagePtr im, int *size, int fg);
 
 void gdImageJpeg(gdImagePtr im, FILE *out, int quality);
 void gdImageJpegCtx(gdImagePtr im, gdIOCtx *out, int quality);
+
+/* Best to free this memory with gdFree(), not free() */
 void *gdImageJpegPtr(gdImagePtr im, int *size, int quality);
-gdImagePtr gdImageCreateFromJpeg(FILE *infile);
-gdImagePtr gdImageCreateFromJpegCtx(gdIOCtx *infile);
 
 /* A custom data sink. For backwards compatibility. Use
 	gdIOCtx instead. */
 
 void gdImageGd(gdImagePtr im, FILE *out);
 void gdImageGd2(gdImagePtr im, FILE *out, int cs, int fmt);
+
+/* Best to free this memory with gdFree(), not free() */
 void* gdImagePngPtr(gdImagePtr im, int *size);
+
+/* Best to free this memory with gdFree(), not free() */
 void* gdImageGdPtr(gdImagePtr im, int *size);
+
+/* Best to free this memory with gdFree(), not free() */
 void* gdImageGd2Ptr(gdImagePtr im, int cs, int fmt, int *size);
+
 void gdImageArc(gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color);
 void gdImageFillToBorder(gdImagePtr im, int x, int y, int border, int color);
 void gdImageFill(gdImagePtr im, int x, int y, int color);
 gdIOCtx* gdNewSSCtx(gdSourcePtr in, gdSinkPtr out);
 void* gdDPExtractData(struct gdIOCtx* ctx, int *size);
 
-
 #define GD2_CHUNKSIZE           128 
 #define GD2_CHUNKSIZE_MIN	64
 #define GD2_CHUNKSIZE_MAX       4096
 #define GD_CMP_BACKGROUND	64	/* Background colour */
 #define GD_CMP_INTERLACE	128	/* Interlaced setting */
 
+/* resolution affects ttf font rendering, particularly hinting */
+#define GD_RESOLUTION           96      /* pixels per inch */
+
 #ifdef __cplusplus
 }
 #endif
 #include <stdlib.h>
 #include <zlib.h>
 #include "gd.h"
+#include "gdhelpers.h"
 
 #define TRUE 1
 #define FALSE 0
 		nc = (*ncx) * (*ncy);
                 GD2_DBG(printf("Reading %d chunk index entries\n", nc));
 		sidx = sizeof(t_chunk_info) * nc;
-		cidx = calloc(sidx,1);
+		cidx = gdCalloc(sidx,1);
 		for (i = 0; i < nc; i++) {
 			if (gdGetInt(&cidx[i].offset, in) != 1) {
 				goto fail1;
         int ncx, ncy, nc, cs, cx, cy;
         int x, y, ylo, yhi, xlo, xhi;
 	int ch, vers, fmt;
-	t_chunk_info *chunkIdx = NULL; /* So we can free it with impunity. */
-	char	*chunkBuf = NULL; /* So we can free it with impunity. */
+	t_chunk_info *chunkIdx = NULL; /* So we can gdFree it with impunity. */
+	char	*chunkBuf = NULL; /* So we can gdFree it with impunity. */
 	int	chunkNum = 0;
 	int	chunkMax;
 	uLongf 	chunkLen;
 	int	chunkPos;
 	int 	compMax;
-	char	*compBuf = NULL; /* So we can free it with impunity. */
+	char	*compBuf = NULL; /* So we can gdFree it with impunity. */
 
         gdImagePtr im;
 
 
 		/* Allocate buffers */
 		chunkMax = cs * cs;
-		chunkBuf = calloc(chunkMax,1);
-		compBuf = calloc(compMax,1);
+		chunkBuf = gdCalloc(chunkMax,1);
+		compBuf = gdCalloc(compMax,1);
 		GD2_DBG(printf("Largest compressed chunk is %d bytes\n",compMax));
 	};
 
 
 	GD2_DBG(printf("Freeing memory\n"));
 
-	free(chunkBuf);
-	free(compBuf);
-	free(chunkIdx);
+	gdFree(chunkBuf);
+	gdFree(compBuf);
+	gdFree(chunkIdx);
 
 	GD2_DBG(printf("Done\n"));
 
 
 fail2:
         gdImageDestroy(im);
-        free(chunkBuf);
-        free(compBuf);
-	free(chunkIdx);
+        gdFree(chunkBuf);
+        gdFree(compBuf);
+	gdFree(chunkIdx);
         return 0;
 
 }
                 compMax++;
 
                 chunkMax = cs * cs;
-                chunkBuf = calloc(chunkMax,1);
-                compBuf = calloc(compMax,1);
+                chunkBuf = gdCalloc(chunkMax,1);
+                compBuf = gdCalloc(compMax,1);
         };
 
 /*	Don't bother with this... */
                 };
         };
 
-        free(chunkBuf);
-        free(compBuf);
-	free(chunkIdx);
+        gdFree(chunkBuf);
+        gdFree(compBuf);
+	gdFree(chunkIdx);
 
         return im;
 
 fail2:
         gdImageDestroy(im);
 fail1:
-        free(chunkBuf);
-        free(compBuf);
-	free(chunkIdx);
+        gdFree(chunkBuf);
+        gdFree(compBuf);
+	gdFree(chunkIdx);
 
         return 0;
 
         int x, y, ylo, yhi, xlo, xhi;
         int     chunkLen;
         int     chunkNum = 0;
-        char    *chunkData = NULL; /* So we can free it with impunity. */
-        char    *compData = NULL; /* So we can free it with impunity. */
+        char    *chunkData = NULL; /* So we can gdFree it with impunity. */
+        char    *compData = NULL; /* So we can gdFree it with impunity. */
         uLongf  compLen;
         int     idxPos;
         int     idxSize;
 		/* */
 		/* Allocate the buffers.  */
 		/* */
-		chunkData = calloc(cs*cs,1);
-		compData = calloc(compMax,1);
+		chunkData = gdCalloc(cs*cs,1);
+		compData = gdCalloc(compMax,1);
 
 		/* */
         	/* Save the file position of chunk index, and allocate enough space for */
 		GD2_DBG(printf("Index size is %d\n", idxSize));
         	gdSeek(out,idxPos+idxSize);
 
-        	chunkIdx = calloc(idxSize * sizeof(t_chunk_info),1);
+        	chunkIdx = gdCalloc(idxSize * sizeof(t_chunk_info),1);
 	};
 
 	_gdPutColors(im, out);
 	};
 
         GD2_DBG(printf("Freeing memory\n"));
-	free(chunkData);
-	free(compData);
-	free(chunkIdx);
+	gdFree(chunkData);
+	gdFree(compData);
+	gdFree(chunkIdx);
         GD2_DBG(printf("Done\n"));
 
 	/*printf("Memory block size is %d\n",gdTell(out)); */
 }
 
 
-int gdSeek(gdIOCtx *ctx, int pos)
+int gdSeek(gdIOCtx *ctx, const int pos)
 {
 	IO_DBG(printf("Seeking...\n"));
 	return ((ctx->seek)(ctx, pos));
 #include <string.h>
 #include <stdlib.h>
 #include "gd.h"
+#include "gdhelpers.h"
 
 #define TRUE 1
 #define FALSE 0
 /* these functions operate on in-memory dynamic pointers */
 static int allocDynamic (dynamicPtr* dp,int initialSize, void *data);
 static int appendDynamic (dynamicPtr* dp, const void* src, int size);
-static int reallocDynamic (dynamicPtr* dp, int required);
+static int gdReallocDynamic (dynamicPtr* dp, int required);
 static int trimDynamic (dynamicPtr* dp);
-static void freeDynamicCtx(struct gdIOCtx* ctx);
+static void gdFreeDynamicCtx(struct gdIOCtx* ctx);
 static dynamicPtr* newDynamic(int initialSize, void *data);
 
 static int dynamicPutbuf( struct gdIOCtx*, const void *, int );
   dpIOCtx 	*ctx;
   dynamicPtr* 	dp;
 
-  ctx = (dpIOCtx*) malloc(sizeof(dpIOCtx));
+  ctx = (dpIOCtx*) gdMalloc(sizeof(dpIOCtx));
   if (ctx == NULL) {
     return NULL;
   }
 
   dp = newDynamic(initialSize, data);
   if (!dp) {
-    free(ctx);
+    gdFree(ctx);
     return NULL;
   };
 
   ctx->ctx.seek = dynamicSeek;
   ctx->ctx.tell = dynamicTell;
 
-  ctx->ctx.free = freeDynamicCtx;
+  ctx->ctx.free = gdFreeDynamicCtx;
 
   return (gdIOCtx*)ctx;
 }
     *size = 0;
     data = NULL;
     if (dp->data != NULL) {
-      free(dp->data);
+      gdFree(dp->data);
     }
   }
 
 }
 
 static
-void freeDynamicCtx(struct gdIOCtx* ctx)
+void gdFreeDynamicCtx(struct gdIOCtx* ctx)
 {
   dynamicPtr            *dp;
   dpIOCtx               *dctx;
   dctx = (dpIOCtx*) ctx;
   dp = dctx->dp;
 
-  free(ctx);
+  gdFree(ctx);
 
   /* clean up the data block and return it */
   if (dp->data != NULL) {
-    free(dp->data);
+    gdFree(dp->data);
     dp->data = NULL;
   }
 
   dp->realSize=0;
   dp->logicalSize=0;
 
-  free(dp);
+  gdFree(dp);
 
 }
 
 
   bytesNeeded = pos;
   if (bytesNeeded > dp->realSize) {
-    if (!reallocDynamic(dp,dp->realSize*2)) {
+    if (!gdReallocDynamic(dp,dp->realSize*2)) {
       dp->dataGood = FALSE;
       return FALSE;
     }
 /* return data as a dynamic pointer */
 static dynamicPtr* newDynamic (int initialSize, void *data) {
   dynamicPtr* dp;
-  dp = (dynamicPtr*) malloc(sizeof(dynamicPtr));
+  dp = (dynamicPtr*) gdMalloc(sizeof(dynamicPtr));
   if (dp == NULL) {
     return NULL;
   }
   if (data == NULL) {
       dp->logicalSize = 0;
       dp->dataGood = FALSE;
-      dp->data = malloc(initialSize);
+      dp->data = gdMalloc(initialSize);
   } else {
       dp->logicalSize = initialSize;
       dp->dataGood = TRUE;
   bytesNeeded = dp->pos + size;
 
   if (bytesNeeded > dp->realSize) {
-    if (!reallocDynamic(dp,bytesNeeded*2)) {
+    if (!gdReallocDynamic(dp,bytesNeeded*2)) {
       dp->dataGood = FALSE;
       return FALSE;
     }
 
 /* grow (or shrink) dynamic pointer */
 static int
-reallocDynamic (dynamicPtr* dp, int required) {
+gdReallocDynamic (dynamicPtr* dp, int required) {
   void* newPtr;
 
-  /* First try realloc().  If that doesn't work, make a new
+  /* First try gdRealloc().  If that doesn't work, make a new
      memory block and copy. */
-  if ( (newPtr = realloc(dp->data,required)) ) {
+  if ( (newPtr = gdRealloc(dp->data,required)) ) {
     dp->realSize = required;
     dp->data = newPtr;
     return TRUE;
   }
 
   /* create a new pointer */
-  newPtr = malloc(required);
+  newPtr = gdMalloc(required);
   if (!newPtr) {
     dp->dataGood = FALSE;
     return FALSE;
 
   /* copy the old data into it */
   memcpy(newPtr,dp->data,dp->logicalSize);
-  free(dp->data);
+  gdFree(dp->data);
   dp->data = newPtr;
 
   dp->realSize = required;
 /* trim pointer so that its real and logical sizes match */
 static int
 trimDynamic (dynamicPtr* dp) {
-  return reallocDynamic(dp,dp->logicalSize);
+  return gdReallocDynamic(dp,dp->logicalSize);
 }
 
 #include <string.h>
 #include <stdlib.h>
 #include "gd.h"
+#include "gdhelpers.h"
 
 /* this is used for creating images in main memory*/
 
 
 static int fileSeek(struct gdIOCtx*, const int);
 static long fileTell(struct gdIOCtx*);
-static void freeFileCtx(gdIOCtx *ctx);
+static void gdFreeFileCtx(gdIOCtx *ctx);
 
 /* return data as a dynamic pointer */
 gdIOCtx* gdNewFileCtx (FILE *f) {
   fileIOCtx 	*ctx;
 
-  ctx = (fileIOCtx*) malloc(sizeof(fileIOCtx));
+  ctx = (fileIOCtx*) gdMalloc(sizeof(fileIOCtx));
   if (ctx == NULL) {
     return NULL;
   }
   ctx->ctx.tell = fileTell;
   ctx->ctx.seek = fileSeek;
 
-  ctx->ctx.free = freeFileCtx;
+  ctx->ctx.free = gdFreeFileCtx;
 
   return (gdIOCtx*)ctx;
 }
 
 static 
-void freeFileCtx(gdIOCtx *ctx)
+void gdFreeFileCtx(gdIOCtx *ctx)
 {
-  free(ctx);
+  gdFree(ctx);
 }
 
 
 #include <string.h>
 #include <stdlib.h>
 #include "gd.h"
+#include "gdhelpers.h"
 
 /* this is used for creating images in main memory*/
 
 static int sourceGetchar( gdIOCtx* ctx);
 static int sinkPutbuf( gdIOCtx* ctx, const void *buf, int size );
 static void sinkPutchar( gdIOCtx* ctx, int a );
-static void freeSsCtx(gdIOCtx *ctx);
+static void gdFreeSsCtx(gdIOCtx *ctx);
 
 /* return data as a dynamic pointer */
 gdIOCtx* gdNewSSCtx (gdSourcePtr src, gdSinkPtr snk) {
   ssIOCtxPtr 	ctx;
 
-  ctx = (ssIOCtxPtr) malloc(sizeof(ssIOCtx));
+  ctx = (ssIOCtxPtr) gdMalloc(sizeof(ssIOCtx));
   if (ctx == NULL) {
     return NULL;
   }
   ctx->ctx.tell = NULL;
   ctx->ctx.seek = NULL;
 
-  ctx->ctx.free = freeSsCtx;
+  ctx->ctx.free = gdFreeSsCtx;
 
   return (gdIOCtx*)ctx;
 }
 
 static
-void freeSsCtx(gdIOCtx *ctx)
+void gdFreeSsCtx(gdIOCtx *ctx)
 {
-  free(ctx);
+  gdFree(ctx);
 }
 
 
  * major CGI brain damage
  */
 
-#ifdef HAVE_JPEG
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <setjmp.h>
 #include "jpeglib.h"
 #include "jerror.h"
 #include "gd.h"
+#include "gdhelpers.h"
+
+#ifdef HAVE_LIBJPEG
 
-static const char * const GD_JPEG_VERSION = "1.0";
+static const char * const GD_JPEG_VERSION = "2.0";
 
 typedef struct _jmpbuf_wrapper {
     jmp_buf jmpbuf;
     struct jpeg_compress_struct cinfo;
     struct jpeg_error_mgr jerr;
     int i, j, jidx;
-    /* volatile so we can free it on return from longjmp */
+    /* volatile so we can gdFree it on return from longjmp */
     volatile JSAMPROW row = 0;
     JSAMPROW rowptr[1];
     jmpbuf_wrapper jmpbufw;
     if (setjmp(jmpbufw.jmpbuf) != 0) {
 	/* we're here courtesy of longjmp */
 	if (row)
-	    free(row);
+	    gdFree(row);
 	return;
     }
 
 
     jpeg_gdIOCtx_dest(&cinfo, outfile);
 
-    row = (JSAMPROW)calloc(1, cinfo.image_width * cinfo.input_components
+    row = (JSAMPROW)gdCalloc(1, cinfo.image_width * cinfo.input_components
 			   * sizeof(JSAMPLE));
     if (row == 0) {
 	fprintf(stderr, "gd-jpeg: error: unable to allocate JPEG row "
-		"structure: calloc returns NULL\n");
+		"structure: gdCalloc returns NULL\n");
 	jpeg_destroy_compress(&cinfo);
 	return;
     }
 
     jpeg_finish_compress(&cinfo);
     jpeg_destroy_compress(&cinfo);
-    free(row);
+    gdFree(row);
 }
 
 gdImagePtr gdImageCreateFromJpeg(FILE *inFile)
     struct jpeg_decompress_struct cinfo;
     struct jpeg_error_mgr jerr;
     jmpbuf_wrapper jmpbufw;
-    /* volatile so we can free them after longjmp */
+    /* volatile so we can gdFree them after longjmp */
     volatile JSAMPROW row = 0;
     volatile gdImagePtr im = 0;
     JSAMPROW rowptr[1];
     if (setjmp(jmpbufw.jmpbuf) != 0) {
 	/* we're here courtesy of longjmp */
 	if (row)
-	    free(row);
+	    gdFree(row);
 	if (im)
 	    gdImageDestroy(im);
 	return 0;
 #endif
     }
 
-    row = calloc(cinfo.output_width, sizeof(JSAMPLE));
+    row = gdCalloc(cinfo.output_width, sizeof(JSAMPLE));
     if (row == 0) {
 	fprintf(stderr, "gd-jpeg: error: unable to allocate row for"
-		" JPEG scanline: calloc returns NULL\n");
+		" JPEG scanline: gdCalloc returns NULL\n");
 	goto error;
     }
     rowptr[0] = row;
 
 
     jpeg_destroy_decompress(&cinfo);
-    free(row);
+    gdFree(row);
     return im;
 
 error:
     jpeg_destroy_decompress(&cinfo);
     if (row)
-	free(row);
+	gdFree(row);
     if (im)
 	gdImageDestroy(im);
     return 0;
 {
   my_src_ptr src = (my_src_ptr) cinfo->src;
   size_t nbytes = 0;
-  size_t got;
-  char *s;
+  /* size_t got; */
+  /* char *s; */
   memset(src->buffer, 0, INPUT_BUF_SIZE);
   while (nbytes < INPUT_BUF_SIZE) {
 	  int got = gdGetBuf(src->buffer + nbytes, 
 void
 term_source (j_decompress_ptr cinfo)
 {
+#if 0
+/* never used */
 	my_src_ptr src = (my_src_ptr) cinfo->src;
+#endif
 }
 
 
 #include <string.h>
 #include <stdlib.h>
 #include "gd.h"
+#include "gdhelpers.h"
 #include "png.h"    /* includes zlib.h and setjmp.h */
 
 #define TRUE 1
 #define FALSE 0
 
+#ifdef HAVE_LIBPNG
+
 /*---------------------------------------------------------------------------
 
     gd_png.c                 Copyright 1999 Greg Roelofs and Thomas Boutell
 
   ---------------------------------------------------------------------------*/
 
+#ifndef PNG_SETJMP_NOT_SUPPORTED
 typedef struct _jmpbuf_wrapper {
   jmp_buf jmpbuf;
 } jmpbuf_wrapper;
 
   longjmp(jmpbuf_ptr->jmpbuf, 1);
 }
-
+#endif
 
 static void gdPngReadData(png_structp png_ptr,
 	png_bytep data, png_size_t length)
     if (!png_check_sig(sig, 8))
         return NULL;   /* bad signature */
 
+#ifndef PNG_SETJMP_NOT_SUPPORTED
     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, &gdPngJmpbufStruct,
       gdPngErrorHandler, NULL);
+#else
+    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+#endif
     if (png_ptr == NULL) {
         fprintf(stderr, "gd-png error: cannot allocate libpng main struct\n");
         return NULL;
 
     /* setjmp() must be called in every non-callback function that calls a
      * PNG-reading libpng function */
+#ifndef PNG_SETJMP_NOT_SUPPORTED
     if (setjmp(gdPngJmpbufStruct.jmpbuf)) {
         fprintf(stderr, "gd-png error: setjmp returns error condition\n");
         png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
         return NULL;
     }
+#endif
 
     png_set_sig_bytes(png_ptr, 8);  /* we already read the 8 signature bytes */
 
         case PNG_COLOR_TYPE_GRAY:
         case PNG_COLOR_TYPE_GRAY_ALPHA:
             /* create a fake palette and check for single-shade transparency */
-            if ((palette = (png_colorp)malloc(256*sizeof(png_color))) == NULL) {
+            if ((palette = (png_colorp)gdMalloc(256*sizeof(png_color))) == NULL) {
                 fprintf(stderr, "gd-png error: cannot allocate gray palette\n");
                 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
                 return NULL;
                  * transparent pixels will be mapped into the transparent entry.
                  * There is no particularly good way around this in the case
                  * that all 256 8-bit shades are used, but one could write some
-                 * custom 16-bit code to handle the case where there are free
+                 * custom 16-bit code to handle the case where there are gdFree
                  * palette entries.  This error will be extremely rare in
                  * general, though.  (Quite possibly there is only one such
                  * image in existence.) */
         case PNG_COLOR_TYPE_RGB:
         case PNG_COLOR_TYPE_RGB_ALPHA:
             /* allocate a palette and check for single-shade transparency */
-            if ((palette = (png_colorp)malloc(256*sizeof(png_color))) == NULL) {
+            if ((palette = (png_colorp)gdMalloc(256*sizeof(png_color))) == NULL) {
                 fprintf(stderr, "gd-png error: cannot allocate RGB palette\n");
                 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
                 return NULL;
 
     /* allocate space for the PNG image data */
     rowbytes = png_get_rowbytes(png_ptr, info_ptr);
-    if ((image_data = (png_bytep)malloc(rowbytes*height)) == 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 ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) {
+    if ((row_pointers = (png_bytepp)gdMalloc(height*sizeof(png_bytep))) == NULL) {
         fprintf(stderr, "gd-png error: cannot allocate row pointers\n");
         png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
-        free(image_data);
+        gdFree(image_data);
         return NULL;
     }
 
     if ((im = gdImageCreate((int)width, (int)height)) == NULL) {
         fprintf(stderr, "gd-png error: cannot allocate gdImage struct\n");
         png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
-        free(image_data);
-        free(row_pointers);
+        gdFree(image_data);
+        gdFree(row_pointers);
         return NULL;
     }
 
 #endif
 
     if (palette_allocated)
-        free(palette);
-    free(image_data);
-    free(row_pointers);
+        gdFree(palette);
+    gdFree(image_data);
+    gdFree(row_pointers);
 
     return im;
 }
     volatile int remap = FALSE;
 
 
+#ifndef PNG_SETJMP_NOT_SUPPORTED
     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
       &gdPngJmpbufStruct, gdPngErrorHandler, NULL);
+#else
+    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+#endif
     if (png_ptr == NULL) {
         fprintf(stderr, "gd-png error: cannot allocate libpng main struct\n");
         return;
         return;
     }
 
+#ifndef PNG_SETJMP_NOT_SUPPORTED
     if (setjmp(gdPngJmpbufStruct.jmpbuf)) {
         fprintf(stderr, "gd-png error: setjmp returns error condition\n");
         png_destroy_write_struct(&png_ptr, &info_ptr);
         return;
     }
+#endif
 
     png_set_write_fn(png_ptr, (void *)outfile, gdPngWriteData, gdPngFlushData);
 
      * interlaced images, but interlacing causes some serious complications. */
     if (remap) {
         png_bytep *row_pointers;
-	row_pointers = malloc(sizeof(png_bytep) * height);
+	row_pointers = gdMalloc(sizeof(png_bytep) * height);
         if (row_pointers == NULL) {
             fprintf(stderr, "gd-png error: unable to allocate row_pointers\n");
         }
         for (j = 0;  j < height;  ++j) {
-            if ((row_pointers[j] = (png_bytep)malloc(width)) == NULL) {
+            if ((row_pointers[j] = (png_bytep)gdMalloc(width)) == NULL) {
                 fprintf(stderr, "gd-png error: unable to allocate rows\n");
                 for (i = 0;  i < j;  ++i)
-                    free(row_pointers[i]);
+                    gdFree(row_pointers[i]);
                 return;
             }
             for (i = 0;  i < width;  ++i)
         png_write_end(png_ptr, info_ptr);
 
         for (j = 0;  j < height;  ++j)
-            free(row_pointers[j]);
-	free(row_pointers);
+            gdFree(row_pointers[j]);
+	gdFree(row_pointers);
     } else {
         png_write_image(png_ptr, im->pixels);
         png_write_end(png_ptr, info_ptr);
 }
 
 
+#endif /* HAVE_LIBPNG */
    	----------------------------------------------------------------------------
 */
 
+#include <gd.h>
 #include <gdfonts.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <limits.h>
 
-#include "gd.h"
 #include "wbmp.h"
 
 
 ** Wrapper around gdPutC for use with writewbmp
 **
 */
-int gd_putout( int i, void * out )
+void gd_putout( int i, void * out )
 {
     gdPutC( i , (gdIOCtx *) out );
 }   
 	/* write the WBMP to a gd file descriptor */		
 	if ( writewbmp( wbmp, &gd_putout, out ) )
 		fprintf(stderr, "Could not save WBMP\n");
-	/* des submitted this bugfix: free the memory. */
+	/* des submitted this bugfix: gdFree the memory. */
 	freewbmp(wbmp);
 }
 
 */
 gdImagePtr	gdImageCreateFromWBMPCtx( gdIOCtx *infile )
 {
-	FILE *wbmp_file;
+	/* FILE *wbmp_file; */
 	Wbmp *wbmp;
     gdImagePtr im = NULL; 
 	int black, white;
+#include "gd.h"
+#include "gdhelpers.h"
+
 #ifdef HAVE_LIBTTF
+#define NEED_CACHE 1
+#else
+#ifdef HAVE_LIBFREETYPE
+#define NEED_CACHE 1
+#endif
+#endif
+
+#ifdef NEED_CACHE
 
 /* 
  * gdcache.c
 {
 	gdCache_head_t *head; 
 
-	head = (gdCache_head_t *)malloc(sizeof(gdCache_head_t));
+	head = (gdCache_head_t *)gdMalloc(sizeof(gdCache_head_t));
 	head->mru = NULL;
 	head->size = size;
 	head->gdCacheTest = gdCacheTest;
 		(*(head->gdCacheRelease))(elem->userdata);
 		prev = elem;
 		elem = elem->next;
-		free((char *)prev);
+		gdFree((char *)prev);
 	}
-	free((char *)head);
+	gdFree((char *)head);
 }
 
 void *
 		return NULL;
 	}
 	if (i < head->size) {  /* cache still growing - add new elem */
-		elem = (gdCache_element_t *)malloc(sizeof(gdCache_element_t));
+		elem = (gdCache_element_t *)gdMalloc(sizeof(gdCache_element_t));
 	}
 	else { /* cache full - replace least-recently-used */
 		/* preveprev becomes new end of list */
 {
 	key_value_t *map;
 
-	map = (key_value_t *)malloc(sizeof(key_value_t));
+	map = (key_value_t *)gdMalloc(sizeof(key_value_t));
 	map->key = *(int *)key;
 	map->value = 3;
 
 static void
 cacheRelease( void *map)
 {
-	free( (char *)map );
+	gdFree( (char *)map );
 }
 
 int
+/********************************************/
+/* gd interface to freetype library         */
+/*                                          */
+/* John Ellson   ellson@lucent.com          */
+/********************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "gd.h"
+#include "gdhelpers.h"
+
+#ifndef MSWIN32
+#include <unistd.h>
+#else
+#define R_OK 2
+#endif
+
+/* number of antialised colors for indexed bitmaps */
+#define NUMCOLORS 8
+
+#ifndef HAVE_LIBFREETYPE
+char * gdImageStringFT(gdImage *im, int *brect, int fg, char *fontlist,
+	double ptsize, double angle, int x, int y, char *string)
+{
+#ifdef HAVE_LIBTTF
+	return gdImageStringTTF(im,brect,fg,fontlist,ptsize,angle,x,y,string);
+#else
+	return "libgd was not built with FreeType font support\n";
+#endif
+}
+#else
+
+#include "gdcache.h"
+#include "freetype/freetype.h"
+#include "freetype/ftglyph.h"
+
+/* number of fonts cached before least recently used is replaced */
+#define FONTCACHESIZE 6
+
+/* number of antialias color lookups cached */
+#define TWEENCOLORCACHESIZE 32
+
+/*
+ * Line separation as a factor of font height.  
+ *	No space between if LINESPACE = 1.00 
+ *	Line separation will be rounded up to next pixel row.
+ */
+#define LINESPACE 1.05
+
+/*
+ * The character (space) used to separate alternate fonts in the
+ * fontlist parameter to gdImageStringFT.
+ */
+#define LISTSEPARATOR " "
+
+/*
+ * DEFAULT_FONTPATH and PATHSEPARATOR are host type dependent and
+ * are normally set by configure in gvconfig.h.  These are just
+ * some last resort values that might match some Un*x system
+ * if building this version of gd separate from graphviz.
+ */
+#ifndef DEFAULT_FONTPATH
+#define DEFAULT_FONTPATH "/usr/share/fonts/truetype"
+#endif
+#ifndef PATHSEPARATOR
+#define PATHSEPARATOR ":"
+#endif
+
+#ifndef TRUE
+#define FALSE 0
+#define TRUE !FALSE
+#endif
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+typedef struct {
+	char		*fontlist;	/* key */
+	FT_Library	*library;
+	FT_Face		face;
+	FT_Bool		have_char_map_unicode,
+			have_char_map_big5,
+			have_char_map_sjis,
+			have_char_map_apple_roman;
+	gdCache_head_t	*glyphCache;
+} font_t;
+
+typedef struct {
+	char		*fontlist;	/* key */
+	FT_Library	*library;
+} fontkey_t;
+
+typedef struct { 
+    unsigned char       pixel;		/* key */
+    unsigned char       bgcolor;	/* key */
+    int			fgcolor;	/* key */ /* -ve means no antialias */
+    gdImagePtr          im;		/* key */
+    unsigned char       tweencolor;
+} tweencolor_t;
+
+typedef struct {
+    unsigned char       pixel;		/* key */
+    unsigned char       bgcolor;	/* key */
+    int			fgcolor;	/* key */ /* -ve means no antialias */
+    gdImagePtr          im;		/* key */
+} tweencolorkey_t;  
+
+/********************************************************************
+ * gdTcl_UtfToUniChar is borrowed from Tcl ...
+ */
+/*
+ * tclUtf.c --
+ *
+ *	Routines for manipulating UTF-8 strings.
+ *
+ * Copyright (c) 1997-1998 Sun Microsystems, Inc.
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
+ * SCCS: @(#) tclUtf.c 1.25 98/01/28 18:02:43
+ */
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * gdTcl_UtfToUniChar --
+ *
+ *	Extract the Tcl_UniChar represented by the UTF-8 string.  Bad
+ *	UTF-8 sequences are converted to valid Tcl_UniChars and processing
+ *	continues.  Equivalent to Plan 9 chartorune().
+ *
+ *	The caller must ensure that the source buffer is long enough that
+ *	this routine does not run off the end and dereference non-existent
+ *	memory looking for trail bytes.  If the source buffer is known to
+ *	be '\0' terminated, this cannot happen.  Otherwise, the caller
+ *	should call Tcl_UtfCharComplete() before calling this routine to
+ *	ensure that enough bytes remain in the string.
+ *
+ * Results:
+ *	*chPtr is filled with the Tcl_UniChar, and the return value is the
+ *	number of bytes from the UTF-8 string that were consumed.
+ *
+ * Side effects:
+ *	None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+#ifdef JISX0208
+#include "jisx0208.h"
+#endif
+ 
+#define Tcl_UniChar int
+#define TCL_UTF_MAX 3
+static int
+gdTcl_UtfToUniChar(char *str, Tcl_UniChar *chPtr)
+/* str is the UTF8 next character pointer */
+/* chPtr is the int for the result */
+{
+	int byte;
+    
+	/* HTML4.0 entities in decimal form, e.g. &#197; */
+	byte = *((unsigned char *) str);
+	if (byte == '&') {
+		int i, n=0;
+
+		byte = *((unsigned char *) (str+1));
+		if (byte == '#') {
+			for (i = 2; i < 8; i++) {
+				byte = *((unsigned char *) (str+i));
+				if (byte >= '0' && byte <= '9') {
+					n = (n * 10) + (byte - '0');
+				} 
+				else
+					break;
+			}
+			if (byte == ';') {
+				*chPtr = (Tcl_UniChar) n;
+				return ++i;
+			}
+		}
+	}
+	 
+	/*
+	 * Unroll 1 to 3 byte UTF-8 sequences, use loop to handle longer ones.
+	 */
+
+	byte = *((unsigned char *) str);
+#ifdef JISX0208
+	if (0xA1 <= byte && byte <= 0xFE) {
+		int jiscode, ku, ten;
+
+		jiscode = 0x100 * (byte & 0x7F) + (str[1] & 0x7F);
+		ku = (jiscode >> 8) - 0x20;
+		ten = (jiscode % 256) - 0x20;
+		if ( (ku < 1 || ku > 92) || (ten < 1 || ten > 94) ) {
+			*chPtr = (Tcl_UniChar) byte;
+			return 1;
+		}
+
+		*chPtr = (Tcl_UniChar) UnicodeTbl[ku - 1][ten - 1];
+		return 2;
+	} else
+#endif /* JISX0208 */
+	if (byte < 0xC0) {
+		/*
+		 * Handles properly formed UTF-8 characters between
+		 * 0x01 and 0x7F.  Also treats \0 and naked trail
+		 * bytes 0x80 to 0xBF as valid characters representing
+		 * themselves.
+		 */
+
+		*chPtr = (Tcl_UniChar) byte;
+		return 1;
+	} else if (byte < 0xE0) {
+		if ((str[1] & 0xC0) == 0x80) {
+			/*
+			 * Two-byte-character lead-byte followed
+			 * by a trail-byte.
+			 */
+	     
+			*chPtr = (Tcl_UniChar) (((byte & 0x1F) << 6)
+				| (str[1] & 0x3F));
+			return 2;
+		}
+		/*
+	 	 * A two-byte-character lead-byte not followed by trail-byte
+	 	 * represents itself.
+	 	 */
+	 	
+		*chPtr = (Tcl_UniChar) byte;
+		return 1;
+    	} else if (byte < 0xF0) {
+		if (((str[1] & 0xC0) == 0x80) && ((str[2] & 0xC0) == 0x80)) {
+			/*
+			 * Three-byte-character lead byte followed by
+			 * two trail bytes.
+			 */
+	
+	    		*chPtr = (Tcl_UniChar) (((byte & 0x0F) << 12) 
+		    		| ((str[1] & 0x3F) << 6) | (str[2] & 0x3F));
+	    		return 3;
+		}
+		/*
+		 * A three-byte-character lead-byte not followed by
+		 * two trail-bytes represents itself.
+		 */
+	
+		*chPtr = (Tcl_UniChar) byte;
+		return 1;
+    	}
+#if TCL_UTF_MAX > 3
+	else {
+		int ch, total, trail;
+
+		total = totalBytes[byte];
+		trail = total - 1;
+		if (trail > 0) {
+			ch = byte & (0x3F >> trail);
+			do {
+				str++;
+				if ((*str & 0xC0) != 0x80) {
+					*chPtr = byte;
+					return 1;
+				}
+				ch <<= 6;
+				ch |= (*str & 0x3F);
+				trail--;
+			} while (trail > 0);
+			*chPtr = ch;
+			return total;
+		}
+	}
+#endif
+
+	*chPtr = (Tcl_UniChar) byte;
+	return 1;
+}
+
+/********************************************************************/
+/* font cache functions                                             */
+
+static int
+fontTest ( void *element, void *key )
+{
+	font_t *a=(font_t *)element;
+	fontkey_t *b=(fontkey_t *)key;
+
+	return (strcmp(a->fontlist, b->fontlist) == 0);
+}
+
+static void *
+fontFetch ( char **error, void *key )
+{
+	font_t			*a;
+	fontkey_t		*b=(fontkey_t *)key;
+	int			n;
+	int			font_found=0;
+	unsigned short		platform, encoding;
+	char			*fontsearchpath, *fontpath, *fontlist;
+	char			*fullname = NULL;
+	char			*name, *path, *dir;
+	char			*strtok_ptr;
+	FT_Error		err;
+	FT_CharMap		found=0;
+	FT_CharMap		charmap;
+
+	a = (font_t *)gdMalloc(sizeof(font_t));
+	a->fontlist = strdup(b->fontlist);
+	a->library = b->library;
+
+	/*
+	 * Search the pathlist for any of a list of font names.
+	 */
+	fontsearchpath = getenv("GDFONTPATH");
+	if (! fontsearchpath ) fontsearchpath = DEFAULT_FONTPATH;
+        path = strdup(fontsearchpath);
+	fontlist = strdup(a->fontlist);
+
+	/*
+	 * Must use gd_strtok_r else pointer corrupted by strtok in nested loop.
+	 */
+	for (name = gd_strtok_r(fontlist,LISTSEPARATOR,&strtok_ptr); name;
+			name = gd_strtok_r(0,LISTSEPARATOR,&strtok_ptr)) {
+
+        	/*
+		 * Allocate an oversized buffer that is guaranteed to be
+		 * big enough for all paths to be tested.
+		 */
+		fullname = gdRealloc(fullname,
+			strlen(fontsearchpath) + strlen(name) + 6);
+		/* if name is an absolute filename then test directly */
+		if (*name == '/') {
+                	sprintf(fullname,"%s",name);
+                	if (access(fullname,R_OK) == 0) {font_found++; break;}
+		}
+        	for (dir = strtok(path,PATHSEPARATOR); dir;
+				dir = strtok(0,PATHSEPARATOR)) {
+                	sprintf(fullname,"%s/%s.ttf",dir,name);
+                	if (access(fullname,R_OK) == 0) {font_found++; break;}
+        	}
+		if (font_found) break;
+	}
+       	gdFree(path);
+        gdFree(fontlist);
+        if (! font_found) {
+                *error = "Could not find/open font";
+		return NULL;
+        }
+
+	err = FT_New_Face(*b->library, fullname, 0, &a->face);
+	if (err) {
+		*error = "Could not read font";
+		return NULL;
+	}
+       	gdFree(fullname);
+	
+/* FIXME - This mapping stuff is imcomplete - where is the spec? */
+
+	a->have_char_map_unicode = 0;
+	a->have_char_map_big5 = 0;
+	a->have_char_map_sjis = 0;
+	a->have_char_map_apple_roman = 0;
+	for (n = 0; n < a->face->num_charmaps; n++) {
+		charmap = a->face->charmaps[n];
+		platform = charmap->platform_id;
+		encoding = charmap->encoding_id;
+		if ((platform == 3 && encoding == 1)	/* Windows Unicode */
+		 || (platform == 3 && encoding == 0)	/* Windows Symbol */
+		 || (platform == 2 && encoding == 1)	/* ISO Unicode */
+		 || (platform == 0)) {			/* Apple Unicode */
+			a->have_char_map_unicode = 1;
+			found = charmap;
+		} else
+		if (platform == 3 && encoding == 4) {	/* Windows Big5 */
+			a->have_char_map_big5 = 1;
+			found = charmap;
+		} else
+		if (platform == 3 && encoding == 2) {	/* Windows Sjis */
+			a->have_char_map_sjis = 1;
+			found = charmap;
+		} else
+		if ((platform == 1 && encoding == 0)	/* Apple Roman */
+		 || (platform == 2 && encoding == 0)) {	/* ISO ASCII */
+			a->have_char_map_apple_roman = 1;
+			found = charmap;
+		}
+	}
+	if (!found) {
+		*error = "Unable to find a CharMap that I can handle";
+		return NULL;
+	}
+
+	return (void *)a;
+}
+
+static void
+fontRelease( void *element )
+{
+	font_t *a=(font_t *)element;
+
+	FT_Done_Face(a->face);
+	gdFree(a->fontlist);
+	gdFree( (char *)element );
+}
+
+/********************************************************************/
+/* tweencolor cache functions                                            */
+
+static int
+tweenColorTest (void *element, void *key)
+{ 
+    tweencolor_t *a=(tweencolor_t *)element;
+    tweencolorkey_t *b=(tweencolorkey_t *)key;
+    
+    return (a->pixel == b->pixel    
+         && a->bgcolor == b->bgcolor
+         && a->fgcolor == b->fgcolor
+         && a->im == b->im);
+} 
+
+/*
+ * Computes a color in im's color table that is part way between
+ * the background and foreground colors proportional to the gray
+ * pixel value in the range 0-NUMCOLORS. The fg and bg colors must already
+ * be in the color table.
+ */
+static void *
+tweenColorFetch (char **error, void *key)
+{
+	tweencolor_t *a;
+	tweencolorkey_t *b=(tweencolorkey_t *)key;
+	int pixel, npixel, bg, fg;
+	gdImagePtr im;
+   
+	a = (tweencolor_t *)gdMalloc(sizeof(tweencolor_t));
+	pixel = a->pixel = b->pixel;
+	bg = a->bgcolor = b->bgcolor;
+	fg = a->fgcolor = b->fgcolor;
+	im = b->im;
+
+	/* if fg is specified by a negative color idx, then don't antialias */
+	if (fg <0) {
+		a->tweencolor = -fg;
+	} else {
+		npixel = NUMCOLORS - pixel;
+		a->tweencolor = gdImageColorResolve(im,
+			(pixel * im->red[fg] + npixel * im->red[bg]) / NUMCOLORS,
+			(pixel * im->green[fg] + npixel * im->green[bg]) / NUMCOLORS,
+			(pixel * im->blue[fg] + npixel * im->blue[bg]) / NUMCOLORS);
+	}
+	return (void *)a;
+}   
+        
+static void
+tweenColorRelease(void *element)
+{   
+    gdFree((char *)element);
+}   
+
+/* draw_bitmap - transfers glyph bitmap to GD image */
+static char *
+gdft_draw_bitmap(gdImage *im, int fg, FT_Bitmap bitmap, int pen_x, int pen_y) {
+	char			*pixel;
+	int			x, y, row, col, pc;
+
+	tweencolor_t		*tc_elem;
+	tweencolorkey_t		tc_key;
+
+	/* initialize tweenColorCache on first call */
+	static gdCache_head_t	*tc_cache;
+
+	if ( ! tc_cache ) {
+		tc_cache = gdCacheCreate(TWEENCOLORCACHESIZE,
+			tweenColorTest, tweenColorFetch, tweenColorRelease);
+	}
+
+	/* copy to gif, mapping colors */
+	tc_key.fgcolor = fg;
+	tc_key.im = im;
+	for (row = 0; row < bitmap.rows; row++) {
+		pc = row * bitmap.pitch;
+		y = pen_y + row;
+
+ 		/* clip if out of bounds */
+		if (y >= im->sy || y < 0) continue;
+
+		for (col = 0; col < bitmap.width; col++, pc++) {
+			if (bitmap.pixel_mode == ft_pixel_mode_grays) {
+				/*
+				 * Round to NUMCOLORS levels of antialiasing for
+				 * index color images since only 256 colors are
+				 * available.
+				 */
+				tc_key.pixel = ((bitmap.buffer[pc] * NUMCOLORS)
+					 + bitmap.num_grays/2)
+						/ (bitmap.num_grays - 1);
+			} else
+			if (bitmap.pixel_mode == ft_pixel_mode_mono) {
+				tc_key.pixel = ((bitmap.buffer[pc/8]
+					<< (pc%8)) & 128) ? NUMCOLORS : 0;
+			} else {
+				return "Unsupported ft_pixel_mode";
+			}
+
+			if (tc_key.pixel > 0) { /* if not background */
+				x = pen_x + col;
+
+				/* clip if out of bounds */
+				if (x >= im->sx || x < 0) continue;
+
+				/* get pixel location in gd buffer */
+				pixel = &im->pixels[y][x];
+				if (tc_key.pixel == NUMCOLORS) {
+					/* use fg color directly */
+					*pixel = fg;
+				} else {
+					/* find antialised color */
+					tc_key.bgcolor = *pixel;
+					tc_elem = (tweencolor_t *)gdCacheGet(
+						tc_cache, &tc_key);
+					*pixel = tc_elem->tweencolor;
+				}
+			}
+		}
+	}
+	return (char *)NULL;
+}
+
+extern int any2eucjp(char *, char *, unsigned int);
+
+/********************************************************************/
+/* gdImageStringFT -  render a utf8 string onto a gd image          */ 
+
+char * gdImageStringFT(gdImage *im, int *brect, int fg, char *fontlist,
+		double ptsize, double angle, int x, int y, char *string)
+{
+	FT_F26Dot6	ur_x=0, ur_y=0, ll_x=0, ll_y=0;
+	FT_F26Dot6	advance_x, advance_y;
+	FT_BBox		bbox;
+	FT_Matrix	matrix;
+	FT_Vector	pen, delta;
+	FT_Face		face;
+	FT_Glyph	image;
+	FT_GlyphSlot	slot;
+	FT_Error	err;
+	FT_Bool		use_kerning;
+	FT_UInt		glyph_index, previous;
+	double		sin_a = sin(angle);
+	double		cos_a = cos(angle);
+	int		len, i=0, ch;
+	int		x1=0, y1=0;
+	font_t		*font;
+	fontkey_t	fontkey;
+	char		*next;
+	char		*tmpstr = 0;
+
+	/***** initialize font library and font cache on first call ******/
+	static gdCache_head_t	*fontCache;
+	static FT_Library 	library;
+
+	if (! fontCache) {
+		if (FT_Init_FreeType(&library)) {
+			return "Failure to initialize font library";
+		}
+		fontCache = gdCacheCreate( FONTCACHESIZE,
+			fontTest, fontFetch, fontRelease);
+	}
+	/*****/
+
+	/* get the font (via font cache) */
+	fontkey.fontlist = fontlist;
+	fontkey.library = &library;
+	font = (font_t *)gdCacheGet(fontCache, &fontkey);
+	if (! font) {
+		return fontCache->error;
+	}
+	face = font->face;		/* shortcut */
+	slot = face->glyph;  		/* shortcut */
+
+	if (FT_Set_Char_Size(face, 0, (FT_F26Dot6)(ptsize*64),
+			GD_RESOLUTION, GD_RESOLUTION)) {
+		return "Could not set character size";
+	}
+
+	matrix.xx = (FT_Fixed) (cos_a * (1<<16));
+	matrix.yx = (FT_Fixed) (sin_a * (1<<16));
+	matrix.xy = - matrix.yx;
+	matrix.yy = matrix.xx;
+
+	pen.x = pen.y = 0;	   /* running position of rotated string */
+
+	use_kerning = FT_HAS_KERNING(face);
+	previous = 0;
+
+	advance_x = advance_y = 0; /* running position (26.6) of right string */
+
+#ifndef JISX0208
+	if (font->have_char_map_sjis) {
+#endif
+		if (tmpstr = (char *)gdMalloc(BUFSIZ)) {
+			any2eucjp(tmpstr, string, BUFSIZ);
+			next=tmpstr;
+		} else {
+			next=string;
+		}
+#ifndef JISX0208
+	} else {
+		next=string;
+	}
+#endif
+	while (*next) {	  
+		ch = *next;
+
+		/* carriage returns */
+		if (ch == '\r') {
+			advance_x = 0;
+			x1 = (advance_x * cos_a - advance_y * sin_a + 32) / 64;
+			y1 = (advance_x * sin_a + advance_y * cos_a + 32) / 64;
+			pen.x = pen.y = 0;
+			previous = 0; /* clear kerning flag */
+			next++;
+			continue;
+		}
+		/* newlines */
+		if (ch == '\n') {
+			advance_y -= face->size->metrics.height * LINESPACE;
+			advance_y = (advance_y-32) & -64; /* round to next pixel row */
+			x1 = (advance_x * cos_a - advance_y * sin_a + 32) / 64;
+			y1 = (advance_x * sin_a + advance_y * cos_a + 32) / 64;
+			pen.x = pen.y = 0;
+			previous = 0; /* clear kerning flag */
+			next++;
+			continue;
+		}
+
+		if (font->have_char_map_unicode) {
+			/* use UTF-8 mapping from ASCII */
+			len = gdTcl_UtfToUniChar(next, &ch);
+			next += len;
+		} else if (font->have_char_map_sjis) {
+			unsigned char c;
+			int jiscode;
+	
+			c = *next;
+			if ( 0xA1 <= c && c <= 0xFE ) {
+				next++;
+				jiscode = 0x100 * (c & 0x7F) + ((*next) & 0x7F);
+	
+				ch = (jiscode >> 8) & 0xFF;
+				jiscode &= 0xFF;
+	
+				if (ch & 1) jiscode += 0x40 - 0x21;
+				else        jiscode += 0x9E - 0x21;
+	
+				if (jiscode >= 0x7F) jiscode++;
+				ch = (ch - 0x21) / 2 + 0x81;
+				if (ch >= 0xA0) ch += 0x40;
+	
+				ch = (ch << 8) + jiscode;
+			} else {
+				ch = c & 0xFF; /* don't extend sign */
+			}
+			next++;
+		} else {
+			/*
+		 	 * Big 5 mapping:
+		 	 * use "JIS-8 half-width katakana" coding from 8-bit characters. Ref:
+		 	 * ftp://ftp.ora.com/pub/examples/nutshell/ujip/doc/japan.inf-032092.sjs
+		 	 */
+			ch = (*next) & 0xFF;	/* don't extend sign */
+			next++;
+			if (ch >= 161		/* first code of JIS-8 pair */
+		 	    && *next) {		/* don't advance past '\0' */
+				/* TBB: Fix from Kwok Wah On: & 255 needed */
+				ch = (ch * 256) + ((*next) & 255);
+				next++;
+			}
+		}
+	
+		FT_Set_Transform(face, &matrix, &pen);
+	
+		/* Convert character code to glyph index */
+		glyph_index = FT_Get_Char_Index( face, ch );
+
+		/* retieve kerning distance and move pen position */
+		if ( use_kerning && previous && glyph_index ) {
+			FT_Get_Kerning( face, previous, glyph_index, 
+				ft_kerning_default, &delta );
+			pen.x += delta.x >> 6;
+		}
+
+		/* load glyph image into the slot (erase previous one) */
+		err = FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER);
+		if (err) {
+			return "Problem loading glyph";
+		}
+
+		/* if null *im, or invalid color,
+			 then assume user just wants brect */
+		if (im && fg <= 255 && fg >= -255) {
+
+        		/* now, draw to our target surface */
+			gdft_draw_bitmap(im, fg, slot->bitmap,
+				x + x1 + pen.x + slot->bitmap_left,
+				y - y1 + pen.y - slot->bitmap_top);
+		}
+
+       		/* increment pen position */
+		pen.x += slot->advance.x >> 6;
+		pen.y -= slot->advance.y >> 6;
+
+		/* record current glyph index for kerning */
+		previous = glyph_index;
+	
+		if (brect) { /* only if need brect */
+			if (! i++) { /* if first character, init BB corner values */
+                                ll_x = slot->metrics.horiBearingX;
+                                ll_y = slot->metrics.horiBearingY - slot->metrics.height;
+                                ur_x = slot->metrics.horiBearingX + slot->metrics.width;
+                                ur_y = slot->metrics.horiBearingY;
+                        }
+                        else {
+                                if (! advance_x) ll_x = MIN(slot->metrics.horiBearingX, ll_x);
+                                ll_y = MIN(advance_y + slot->metrics.horiBearingY - slot->metrics.height, ll_y);
+                                ur_x = MAX(advance_x + slot->metrics.horiBearingX + slot->metrics.width, ur_x);
+                                if (! advance_y) ur_y = MAX(slot->metrics.horiBearingY, ur_y);
+                        }
+		}
+
+		advance_x += slot->metrics.horiAdvance;
+	}
+
+	if (brect) {  /* only if need brect */
+		/* rotate bounding rectangle */
+		brect[0] = (int)(ll_x * cos_a - ll_y * sin_a);
+		brect[1] = (int)(ll_x * sin_a + ll_y * cos_a);
+		brect[2] = (int)(ur_x * cos_a - ll_y * sin_a);
+		brect[3] = (int)(ur_x * sin_a + ll_y * cos_a);
+		brect[4] = (int)(ur_x * cos_a - ur_y * sin_a);
+		brect[5] = (int)(ur_x * sin_a + ur_y * cos_a);
+		brect[6] = (int)(ll_x * cos_a - ur_y * sin_a);
+		brect[7] = (int)(ll_x * sin_a + ur_y * cos_a);
+	
+		/* scale, round and offset brect */
+		i = 0;
+		while (i<8) {
+			brect[i] = x + (brect[i] + 32) / 64;
+			i++;
+			brect[i] = y - (brect[i] + 32) / 64;
+			i++;
+		}
+	}
+
+	if ( tmpstr ) gdFree(tmpstr);
+	return (char *)NULL;
+}
+
+#endif /* HAVE_LIBFREETYPE */
+#include "gd.h"
+#include "gdhelpers.h"
+#include <stdlib.h>
+
+/* TBB: gd_strtok_r is not portable; provide an implementation */
+
+#define SEP_TEST (separators[*((unsigned char *) s)])
+
+char *gd_strtok_r(char *s, char *sep, char **state)
+{
+	char separators[256];
+	char *start;
+	char *result = 0;
+	memset(separators, 0, sizeof(separators));	
+	while (*sep) {
+		separators[*((unsigned char *) sep)] = 1;
+		sep++;
+	}
+	if (!s) {
+		/* Pick up where we left off */
+		s = *state;
+	}
+	start = s;	
+	/* 1. EOS */
+	if (!(*s)) {
+		*state = s;
+		return 0;
+	}
+	/* 2. Leading separators, if any */
+	if (SEP_TEST) {
+		do {
+			s++;
+		} while (SEP_TEST);
+		/* 2a. EOS after separators only */
+		if (!(*s)) {
+			*state = s;
+			return 0;
+		}
+	}
+	/* 3. A token */
+	result = s;
+	do {
+		/* 3a. Token at end of string */
+		if (!(*s)) {
+			*state = s;
+			return result;
+		}
+		s++;
+	} while (!SEP_TEST);
+	/* 4. Terminate token and skip trailing separators */
+	*s = '\0';	
+	do {
+		s++;	
+	} while (SEP_TEST);	
+	/* 5. Return token */
+	*state = s;
+	return result;
+}
+
+void *gdCalloc(size_t nmemb, size_t size)
+{
+	return calloc(nmemb, size);
+}
+
+void *gdMalloc(size_t size)
+{
+	return malloc(size);
+}
+
+void *gdRealloc(void *ptr, size_t size)
+{
+	return realloc(ptr, size);
+}
+
+void gdFree(void *ptr)
+{
+	free(ptr);
+}
+
+#ifndef GDHELPERS_H 
+#define GDHELPERS_H 1
+
+/* TBB: strtok_r is not universal; provide an implementation of it. */
+
+extern char *gd_strtok_r(char *s, char *sep, char **state);
+
+/* These functions wrap memory management. gdFree is
+	in gd.h, where callers can utilize it to correctly
+	free memory allocated by these functions with the
+	right version of free(). */
+void *gdCalloc(size_t nmemb, size_t size);
+void *gdMalloc(size_t size);
+void *gdRealloc(void *ptr, size_t size);
+
+#endif /* GDHELPERS_H */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include "gd.h"
+#include "gdhelpers.h"
+
 #ifdef HAVE_STDARG_H
 #include <stdarg.h>
 #endif
 	if (handaku && *p2 >= 110 && *p2 <= 122) (*p2) += 2;
 }
 
+/* Recast strcpy to handle unsigned chars used below. */
+#define ustrcpy(A,B) (strcpy((char*)(A),(const char*)(B)))
+
 #ifdef __STDC__
 static void do_convert(unsigned char *to, unsigned char *from, const char *code)
 #else
 
 	if (j >= BUFSIZ) {
 		error("output buffer overflow at do_convert()");
-		strcpy(to, from);
+		ustrcpy(to, from);
 	} else
 		to[j] = '\0';
 #endif /* HAVE_ICONV */
 		case NEC:
 			debug("Kanji code is NEC Kanji.");
 			error("cannot convert NEC Kanji.");
-			strcpy(tmp, from);
+			ustrcpy(tmp, from);
 			kanji = FALSE;
 			break;
 		case EUC:
 			debug("Kanji code is EUC.");
-			strcpy(tmp, from);
+			ustrcpy(tmp, from);
 			break;
 		case SJIS:
 			debug("Kanji code is SJIS.");
 			break;
 		case EUCORSJIS:
 			debug("Kanji code is EUC or SJIS.");
-			strcpy(tmp, from);
+			ustrcpy(tmp, from);
 			kanji = FALSE;
 			break;
 		case ASCII:
 			debug("This is ASCII string.");
-			strcpy(tmp, from);
+			ustrcpy(tmp, from);
 			kanji = FALSE;
 			break;
 		default:
 			debug("This string includes unknown code.");
-			strcpy(tmp, from);
+			ustrcpy(tmp, from);
 			kanji = FALSE;
 			break;
 	}
 
 		if (j >= BUFSIZ) {
 			error("output buffer overflow at Hankaku --> Zenkaku");
-			strcpy(to, tmp);
+			ustrcpy(to, tmp);
 		} else
 			to[j] = '\0';
 	} else
-		strcpy(to, tmp);
+		ustrcpy(to, tmp);
 
 	return kanji;
 }
 	ret = do_check_and_conv(tmp_dest, src);
 	if (strlen((const char *)tmp_dest) >= dest_max) {
 		error("output buffer overflow");
-		strcpy(dest, src);
+		ustrcpy(dest, src);
 		return -1;
 	}
-	strcpy(dest, tmp_dest);
+	ustrcpy(dest, tmp_dest);
 	return ret;
 }
 
 	unsigned char *t;
 	unsigned int i;
 
-	t = (unsigned char *)malloc(BUFSIZ);
+	t = (unsigned char *)gdMalloc(BUFSIZ);
 	any2eucjp(t, s, BUFSIZ);
 	i = strlen(t);
-	free(t);
+	gdFree(t);
 	return i;
 }
 #endif
 	printf("input : %d bytes\n", strlen(input));
 	printf("output: %d bytes\n", strwidth(input));
 
-	output = (unsigned char *)malloc(BUFSIZ);
+	output = (unsigned char *)gdMalloc(BUFSIZ);
 	any2eucjp(output, input, BUFSIZ);
 	str = output;
 	while(*str != '\0') putchar(*(str++));
 	putchar('\n');
-	free(output);
+	gdFree(output);
 
 	return 0;
 }
+#include "gd.h"
+#include <string.h>
+
+#define PI 3.141592
+#define DEG2RAD(x) ((x)*PI/180.)
+
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+
+#define MAX4(x,y,z,w) \
+	((MAX((x),(y))) > (MAX((z),(w))) ? (MAX((x),(y))) : (MAX((z),(w))))
+#define MIN4(x,y,z,w) \
+	((MIN((x),(y))) < (MIN((z),(w))) ? (MIN((x),(y))) : (MIN((z),(w))))
+
+#define MAXX(x) MAX4(x[0],x[2],x[4],x[6])
+#define MINX(x) MIN4(x[0],x[2],x[4],x[6])
+#define MAXY(x) MAX4(x[1],x[3],x[5],x[7])
+#define MINY(x) MIN4(x[1],x[3],x[5],x[7])
+
+int main(int argc, char *argv[])
+{
+#ifndef HAVE_LIBFREETYPE
+	fprintf(stderr, "gd was not compiled with HAVE_LIBFREETYPE defined.\n");
+	fprintf(stderr, "Install the FreeType library, including the\n");
+	fprintf(stderr, "header files. Then edit the gd Makefile, type\n");