Anonymous avatar Anonymous committed b14040d

- sync to 2.0.17

Comments (0)

Files changed (8)

 }
 fileIOCtx;
 
-struct fileIOCtx *fileIOCtxPtr;
-
 gdIOCtx *newFileCtx (FILE * f);
 
 static int fileGetbuf (gdIOCtx *, void *, int);
   if (jpeg_finish_decompress (&cinfo) != TRUE)
     fprintf (stderr, "gd-jpeg: warning: jpeg_finish_decompress"
 	     " reports suspended data source\n");
-
+  /* Thanks to Truxton Fulton */
+  if(cinfo.err->num_warnings>0)
+    goto error ;
 
   jpeg_destroy_decompress (&cinfo);
   gdFree (row);
   volatile int transparent = im->transparent;
   volatile int remap = FALSE;
 
-
 #ifndef PNG_SETJMP_NOT_SUPPORTED
   png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
 				     &gdPngJmpbufStruct, gdPngErrorHandler,
      What to ideally do for truecolor images depends, alas, on the image.
      gd is intentionally imperfect and doesn't spend a lot of time
      fussing with such things. */
-/*  png_set_filter(png_ptr, 0, PNG_FILTER_NONE);  */
+
+  /* Faster if this is uncommented, but may produce larger truecolor files.
+    Wait for gdImagePngCtxEx. */
+#if 0
+   png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
+#endif
 
   /* 2.0.12: this is finally a parameter */
   png_set_compression_level (png_ptr, level);
    * interlaced images, but interlacing causes some serious complications. */
   if (im->trueColor)
     {
+      /* performance optimizations by Phong Tran */
       int channels = im->saveAlphaFlag ? 4 : 3;
       /* Our little 7-bit alpha channel trick costs us a bit here. */
       png_bytep *row_pointers;
+      unsigned char* pOutputRow;
+      int **ptpixels=im->tpixels;
+      int *pThisRow;
+      unsigned char a;
+      int thisPixel;
+      png_bytep *prow_pointers;
+      int saveAlphaFlag=im->saveAlphaFlag;
       row_pointers = gdMalloc (sizeof (png_bytep) * height);
       if (row_pointers == NULL)
 	{
 	  fprintf (stderr, "gd-png error: unable to allocate row_pointers\n");
 	}
+      prow_pointers=row_pointers;
       for (j = 0; j < height; ++j)
 	{
-	  int bo = 0;
-	  if ((row_pointers[j] =
+         if ((*prow_pointers = 
 	       (png_bytep) gdMalloc (width * channels)) == NULL)
 	    {
 	      fprintf (stderr, "gd-png error: unable to allocate rows\n");
 		gdFree (row_pointers[i]);
 	      return;
 	    }
+         pOutputRow=*prow_pointers++;
+         pThisRow=*ptpixels++;
 	  for (i = 0; i < width; ++i)
 	    {
-	      unsigned char a;
-	      row_pointers[j][bo++] = gdTrueColorGetRed (im->tpixels[j][i]);
-	      row_pointers[j][bo++] = gdTrueColorGetGreen (im->tpixels[j][i]);
-	      row_pointers[j][bo++] = gdTrueColorGetBlue (im->tpixels[j][i]);
-	      if (im->saveAlphaFlag)
+            thisPixel=*pThisRow++;
+            *pOutputRow++=gdTrueColorGetRed(thisPixel);
+            *pOutputRow++=gdTrueColorGetGreen(thisPixel);
+            *pOutputRow++=gdTrueColorGetBlue(thisPixel);
+
+            if (saveAlphaFlag)
 		{
 		  /* convert the 7-bit alpha channel to an 8-bit alpha channel.
 		     We do a little bit-flipping magic, repeating the MSB
 		     as the LSB, to ensure that 0 maps to 0 and
 		     127 maps to 255. We also have to invert to match
 		     PNG's convention in which 255 is opaque. */
-		  a = gdTrueColorGetAlpha (im->tpixels[j][i]);
+               a = gdTrueColorGetAlpha (thisPixel);
 		  /* Andrew Hull: >> 6, not >> 7! (gd 2.0.5) */
-		  row_pointers[j][bo++] = 255 - ((a << 1) + (a >> 6));
+               *pOutputRow++ = 255 - ((a << 1) + (a >> 6));
 		}
 	    }
 	}
   cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total >> 1)) / total);
   cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total >> 1)) / total);
 #else
-  im->red[icolor] = (int) ((c0total + (total >> 1)) / total);
-  im->green[icolor] = (int) ((c1total + (total >> 1)) / total);
-  im->blue[icolor] = (int) ((c2total + (total >> 1)) / total);
+  /* 2.0.16: Paul den Dulk found an occasion where total can be 0 */
+  if (count) {
+    im->red[icolor] = (int) ((c0total + (total >> 1)) / total);
+    im->green[icolor] = (int) ((c1total + (total >> 1)) / total);
+    im->blue[icolor] = (int) ((c2total + (total >> 1)) / total);
+  } else {
+    im->red[icolor] = 255;
+    im->green[icolor] = 255;
+    im->blue[icolor] = 255;
+  }
 #endif
 }
 
 #else
 
 #include "gdcache.h"
-#include "freetype/freetype.h"
-#include "freetype/ftglyph.h"
+/* 2.0.16 Christophe Thomas: starting with FreeType 2.1.6, this is
+  mandatory, and it has been supported for a long while. */
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
 
 /* number of fonts cached before least recently used is replaced */
 #define FONTCACHESIZE 6
  * if building this version of gd separate from graphviz.
  */
 #ifndef DEFAULT_FONTPATH
+#if defined(__APPLE__) || (defined(__MWERKS__) && defined(macintosh))
+#define DEFAULT_FONTPATH "/usr/share/fonts/truetype:/System/Library/Fonts:/Library/Fonts"
+#else
 #define DEFAULT_FONTPATH "/usr/share/fonts/truetype"
 #endif
+#endif
 #ifndef PATHSEPARATOR
 #define PATHSEPARATOR ":"
 #endif
 	  if (access (fullname, R_OK) == 0)
 	    {
 	      font_found++;
+              /* 2.0.16: memory leak fixed, Gustavo Scotti */ 		
+              gdFree(path);
 	      break;
 	    }
 	}
 	      font_found++;
 	      break;
 	    }
+	  sprintf (fullname, "%s/%s.dfont", dir, name);
+	  if (access (fullname, R_OK) == 0)
+	    {
+	      font_found++;
+	      break;
+	    }
 	}
       gdFree (path);
       if (font_found)
   gdFree (fullname);
 
 /* FIXME - This mapping stuff is imcomplete - where is the spec? */
+/* EAM   - It's worse than that. It's pointless to match character encodings here. */
+/*         As currently written, the stored a->face->charmap only matches one of   */
+/*         the actual charmaps and we cannot know at this stage if it is the right */
+/*         one. We should just skip all this stuff, and check in gdImageStringFTEx */
+/*         if some particular charmap is preferred and if so whether it is held in */
+/*         one of the a->face->charmaps[0..num_charmaps].                          */
+/*         And why is it so bad not to find any recognized charmap?  The user may  */
+/*         still know what mapping to use, even if we do not.  In that case we can */
+/*         just use the map in a->face->charmaps[num_charmaps] and be done with it.*/
 
   a->have_char_map_unicode = 0;
   a->have_char_map_big5 = 0;
       charmap = a->face->charmaps[n];
       platform = charmap->platform_id;
       encoding = charmap->encoding_id;
+
+/* EAM DEBUG - Newer versions of libfree2 make it easier by defining encodings */
+#ifdef FT_ENCODING_MS_SYMBOL
+      if (charmap->encoding == FT_ENCODING_MS_SYMBOL
+      ||  charmap->encoding == FT_ENCODING_ADOBE_CUSTOM
+      ||  charmap->encoding == FT_ENCODING_ADOBE_STANDARD) {
+      	a->have_char_map_unicode = 1;
+	found = charmap;
+	a->face->charmap = charmap;
+	return (void *)a;
+      }
+#endif /* FT_ENCODING_MS_SYMBOL */
+/* EAM DEBUG */
+
       if ((platform == 3 && encoding == 1)	/* Windows Unicode */
 	  || (platform == 3 && encoding == 0)	/* Windows Symbol */
 	  || (platform == 2 && encoding == 1)	/* ISO Unicode */
 	  pcr = pc;
 	  y = pen_y + row;
 	  /* clip if out of bounds */
-	  if (y >= im->sy || y < 0)
+          /* 2.0.16: clipping rectangle, not image bounds */		
+	  if ((y > im->cy2) || (y < im->cy1))
 	    continue;
 	  for (col = 0; col < bitmap.width; col++, pc++)
 	    {
 	      level = gdAlphaMax - level;
 	      x = pen_x + col;
 	      /* clip if out of bounds */
-	      if (x >= im->sx || x < 0)
+              /* 2.0.16: clip to clipping rectangle, Matt McNabb */
+	      if ((x > im->cx2) || (x < im->cx1))
 		continue;
 	      /* get pixel location in gd buffer */
 	      tpixel = &im->tpixels[y][x];
 extern int any2eucjp (char *, char *, unsigned int);
 
 /* Persistent font cache until explicitly cleared */
-/*     Fonts can be used across multiple images */
+/* Fonts can be used across multiple images */
+
+/* 2.0.16: thread safety (the font cache is shared) */
+gdMutexDeclare(gdFontCacheMutex);
 static gdCache_head_t *fontCache;
 static FT_Library library;
 
 void
-gdFreeFontCache ()
+gdFontCacheShutdown ()
 {
   if (fontCache)
     {
+      gdMutexShutdown(gdFontCacheMutex);
       gdCacheDelete (fontCache);
       FT_Done_FreeType (library);
+      /* 2.0.16: Gustavo Scotti: make sure we don't free this twice */
+      fontCache = 0;
     }
 }
 
 			    ptsize, angle, x, y, string, 0);
 }
 
+int gdFontCacheSetup(void)
+{
+	if (fontCache) {
+		/* Already set up */
+		return 0;
+	}
+	gdMutexSetup(gdFontCacheMutex);
+	if (FT_Init_FreeType (&library))
+	{
+		gdMutexShutdown(gdFontCacheMutex);
+		return -1;
+	}
+	fontCache = gdCacheCreate (FONTCACHESIZE,
+		 fontTest, fontFetch, fontRelease);
+	return 0;
+}
+
 char *
 gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist,
 		   double ptsize, double angle, int x, int y, char *string,
    *   colorindexes.          -- 27.06.2001 <krisku@arrak.fi>
    */
   gdCache_head_t *tc_cache;
-
   if (strex)
     {
       if ((strex->flags & gdFTEX_LINESPACE) == gdFTEX_LINESPACE)
 			    tweenColorRelease);
 
 /***** initialize font library and font cache on first call ******/
-
   if (!fontCache)
     {
-      if (FT_Init_FreeType (&library))
-	{
-	  gdCacheDelete (tc_cache);
-	  return "Failure to initialize font library";
-	}
-      fontCache = gdCacheCreate (FONTCACHESIZE,
-				 fontTest, fontFetch, fontRelease);
+      if (gdFontCacheSetup() != 0) {
+	gdCacheDelete (tc_cache);
+        return "Failure to initialize font library";
+      }
     }
 /*****/
-
+  gdMutexLock(gdFontCacheMutex);
   /* get the font (via font cache) */
   fontkey.fontlist = fontlist;
   fontkey.library = &library;
   if (!font)
     {
       gdCacheDelete (tc_cache);
+      gdMutexUnlock(gdFontCacheMutex);
       return fontCache->error;
     }
   face = font->face;		/* shortcut */
 			GD_RESOLUTION, GD_RESOLUTION))
     {
       gdCacheDelete (tc_cache);
+      gdMutexUnlock(gdFontCacheMutex);
       return "Could not set character size";
     }
 
   if (!mfound)
     {
       /* No character set found! */
+      gdMutexUnlock(gdFontCacheMutex);
       return "No character set found";
     }
 
 	  next++;
 	  continue;
 	}
+
+/* EAM DEBUG */
+#ifdef FT_ENCODING_MS_SYMBOL
+      if (font->face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
+	{
+         /* I do not know the significance of the constant 0xf000. */
+         /* It was determined by inspection of the character codes */
+         /* stored in Microsoft font symbol.ttf                    */
+           len = gdTcl_UtfToUniChar (next, &ch);
+           ch |= 0xf000;
+           next += len;
+	} else
+#endif /* FT_ENCODING_MS_SYMBOL */
+/* EAM DEBUG */
+	
       switch (m)
 	{
 	case gdFTEX_Unicode:
       if (err)
 	{
 	  gdCacheDelete (tc_cache);
+          gdMutexUnlock(gdFontCacheMutex);
 	  return "Problem loading glyph";
 	}
 
 	      if (err)
 		{
 		  gdCacheDelete (tc_cache);
+                  gdMutexUnlock(gdFontCacheMutex);
 		  return "Problem rendering glyph";
 		}
 	    }
   if (tmpstr)
     gdFree (tmpstr);
   gdCacheDelete (tc_cache);
+  gdMutexUnlock(gdFontCacheMutex);
   return (char *) NULL;
 }
 
+#include "gd.h"
+#include <math.h>
+
+/* In tests this is sufficient to prevent obvious artifacts */
+#define MAG 4
+
+#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])
+
+char *gdImageStringFTCircle(
+	gdImagePtr im,
+	int cx,
+	int cy,
+	double radius,
+	double textRadius,
+	double fillPortion,
+	char *font,
+	double points,
+	char *top,
+	char *bottom,
+	int fgcolor)
+{
+	char *err;
+	int w;
+	int brect[8];
+	int sx1, sx2, sy1, sy2, sx, sy;
+	int x, y;
+	int fr, fg, fb, fa;
+	int ox, oy;
+	double prop;
+	gdImagePtr im1;
+	gdImagePtr im2;
+	gdImagePtr im3;
+	/* obtain brect so that we can size the image */
+	err = gdImageStringFT ((gdImagePtr) NULL, 
+		&brect[0], 0, font, points * MAG, 0, 0, 0, bottom);
+	if (err)
+	{
+		return err;
+	}
+	sx1 = MAXX (brect) - MINX (brect) + 6;
+	sy1 = MAXY (brect) - MINY (brect) + 6;
+	err = gdImageStringFT ((gdImagePtr) NULL, 
+		&brect[0], 0, font, points * MAG, 0, 0, 0, top);
+	if (err)
+	{
+		return err;
+	}
+	sx2 = MAXX (brect) - MINX (brect) + 6;
+	sy2 = MAXY (brect) - MINY (brect) + 6;
+	/* Pad by 4 pixels to allow for slight errors
+		observed in the bounding box returned by freetype */
+	if (sx1 > sx2) {
+		sx = sx1 * 2 + 4;
+	} else {
+		sx = sx2 * 2 + 4;
+	}
+	if (sy1 > sy2) {
+		sy = sy1;
+	} else {
+		sy = sy2;
+	}
+	im1 = gdImageCreateTrueColor(sx, sy); 
+	if (!im1) {
+		return "could not create first image";
+	}
+	err = gdImageStringFT (im1, 0, gdTrueColor(255, 255, 255), 
+		font, points * MAG, 
+		0, ((sx / 2) - sx1) / 2, points * MAG, bottom);
+	if (err) {
+		gdImageDestroy(im1);
+		return err;
+	}
+	/* We don't know the descent, which would be needed to do this
+		with the angle parameter. Instead, implement a simple
+		flip operation ourselves. */
+	err = gdImageStringFT (im1, 0, gdTrueColor(255, 255, 255), 
+		font, points * MAG, 
+		0, sx / 2 + ((sx / 2) - sx2) / 2, points * MAG, top);
+	if (err) {
+		gdImageDestroy(im1);
+		return err;
+	}
+	/* Flip in place is tricky, be careful not to double-swap things */
+	if (sy & 1) {
+		for (y = 0; (y <= (sy / 2)); y++) {
+			int xlimit = sx - 2;
+			if (y == (sy / 2)) {
+				/* If there is a "middle" row, be careful
+					not to swap twice! */
+				xlimit -= (sx / 4);
+			}
+			for (x = (sx / 2) + 2; (x < xlimit); x++) {
+				int t;
+				int ox = sx - x + (sx / 2) - 1;
+				int oy = sy - y - 1;
+				t = im1->tpixels[oy][ox];
+				im1->tpixels[oy][ox] = im1->tpixels[y][x];
+				im1->tpixels[y][x] = t;
+			}
+		}
+	} else {
+		for (y = 0; (y < (sy / 2)); y++) {
+			int xlimit = sx - 2;
+			for (x = (sx / 2) + 2; (x < xlimit); x++) {
+				int t;
+				int ox = sx - x + (sx / 2) - 1;
+				int oy = sy - y - 1;
+				t = im1->tpixels[oy][ox];
+				im1->tpixels[oy][ox] = im1->tpixels[y][x];
+				im1->tpixels[y][x] = t;
+			}
+		}
+	}
+#if STEP_PNGS
+	{
+		FILE *out = fopen("gdfx1.png", "wb");
+		gdImagePng(im1, out);
+		fclose(out);
+	}
+#endif /* STEP_PNGS */
+	/* Resample taller; the exact proportions of the text depend on the
+		ratio of textRadius to radius, and the value of fillPortion */
+	if (sx > sy * 10) {
+		w = sx;
+	} else {
+		w = sy * 10;
+	}
+	im2 = gdImageCreateTrueColor(w, w);
+	if (!im2) {
+		gdImageDestroy(im1);
+		return "could not create resampled image";
+	}
+	prop = textRadius / radius;
+	gdImageCopyResampled(im2, im1, 
+		gdImageSX(im2) * (1.0 - fillPortion) / 4, 
+		sy * 10 * (1.0 - prop), 
+		0, 0,
+		gdImageSX(im2) * fillPortion / 2, sy * 10 * prop,
+		gdImageSX(im1) / 2, gdImageSY(im1));
+	gdImageCopyResampled(im2, im1, 
+		(gdImageSX(im2) / 2) + 
+			gdImageSX(im2) * (1.0 - fillPortion) / 4, 
+		sy * 10 * (1.0 - prop), 
+		gdImageSX(im1) / 2, 0,
+		gdImageSX(im2) * fillPortion / 2, sy * 10 * prop,
+		gdImageSX(im1) / 2, gdImageSY(im1));
+#if STEP_PNGS
+	{
+		FILE *out = fopen("gdfx2.png", "wb");
+		gdImagePng(im2, out);
+		fclose(out);
+	}
+#endif /* STEP_PNGS */
+	/* Ready to produce a circle */
+	im3 = gdImageSquareToCircle(im2, radius);
+	gdImageDestroy(im1);
+	gdImageDestroy(im2);
+	/* Now blend im3 with the destination. Cheat a little. The
+		source (im3) is white-on-black, so we can use the
+		red component as a basis for alpha as long as we're
+		careful to shift off the extra bit and invert
+		(alpha ranges from 0 to 127 where 0 is OPAQUE). 
+		Also be careful to allow for an alpha component
+		in the fgcolor parameter itself (gug!) */
+	fr = gdTrueColorGetRed(fgcolor);
+	fg = gdTrueColorGetGreen(fgcolor);
+	fb = gdTrueColorGetBlue(fgcolor);
+	fa = gdTrueColorGetAlpha(fgcolor);
+	ox = cx - (im3->sx / 2); 
+	oy = cy - (im3->sy / 2); 
+	for (y = 0; (y < im3->sy); y++) {
+		for (x = 0; (x < im3->sx); x++) {
+			int a = gdTrueColorGetRed(im3->tpixels[y][x]) >> 1;
+			a *= (127 - fa);
+			a /= 127;
+			a = 127 - a;	
+			gdImageSetPixel(im, x + ox, y + oy,
+				gdTrueColorAlpha(fr, fg, fb, a));
+		}
+	}			
+	gdImageDestroy(im3);
+	return 0;
+}
+
+#if GDFX_MAIN
+
+int
+main (int argc, char *argv[])
+{
+	FILE *in;
+	FILE *out;
+	gdImagePtr im;
+	int radius;
+	/* Create an image of text on a circle, with an
+		alpha channel so that we can copy it onto a
+		background */
+	in = fopen("eleanor.jpg", "rb");
+	if (!in) {
+		im = gdImageCreateTrueColor(300, 300);
+	} else {
+		im = gdImageCreateFromJpeg(in);
+		fclose(in);
+	}
+	if (gdImageSX(im) < gdImageSY(im)) {
+		radius = gdImageSX(im) / 2;
+	} else {
+		radius = gdImageSY(im) / 2;
+	}
+	gdStringFTCircle(
+		im,
+		gdImageSX(im) / 2,
+		gdImageSY(im) / 2,
+		radius,
+		radius / 2,
+		0.8,
+		"arial",
+		24,
+		"top text",
+		"bottom text",
+		gdTrueColorAlpha(240, 240, 255, 32));
+	out = fopen("gdfx.png", "wb");
+	if (!out) {
+		fprintf(stderr, "Can't create gdfx.png\n");
+		return 1;
+	}
+	gdImagePng(im, out);
+	fclose(out);
+	gdImageDestroy(im);
+	return 0;
+}
+
+#endif /* GDFX_MAIN */
+
+/* Note: don't change these */
+#define SUPER 2
+#define SUPERBITS1 1
+#define SUPERBITS2 2
+
+gdImagePtr gdImageSquareToCircle(gdImagePtr im, int radius)
+{
+	int x, y;
+	double c;
+	gdImagePtr im2;
+	if (im->sx != im->sy) {
+		/* Source image must be square */
+		return 0;
+	}
+	im2 = gdImageCreateTrueColor(radius * 2, radius * 2);
+	/* Supersampling for a nicer result */
+	c = (im2->sx / 2) * SUPER;
+	for (y = 0; (y < im2->sy * SUPER); y++) {
+		for (x = 0; (x < im2->sx * SUPER); x++) {
+			double rho = sqrt((x - c) * (x - c) +
+				(y - c) * (y - c));
+			int pix;
+			int cpix;
+			double theta;
+			double ox;
+			double oy;
+			int red, green, blue, alpha;
+			if (rho > c) {
+				continue;
+			}
+			theta = atan2(x - c, y - c) + PI / 2;
+			if (theta < 0) {
+				theta += 2 * PI;
+			}
+			/* Undo supersampling */
+			oy = (rho * im->sx) / (im2->sx * SUPER / 2);
+			ox = theta * im->sx / (3.141592653 * 2);
+			pix = gdImageGetPixel(im, ox, oy); 
+			cpix = im2->tpixels[y >> SUPERBITS1][x >> SUPERBITS1];
+			red = (gdImageRed(im, pix) >> SUPERBITS2) + gdTrueColorGetRed(cpix);
+			green = (gdImageGreen(im, pix) >> SUPERBITS2) + gdTrueColorGetGreen(cpix);
+			blue = (gdImageBlue(im, pix) >> SUPERBITS2) + gdTrueColorGetBlue(cpix);
+			alpha = (gdImageAlpha(im, pix) >> SUPERBITS2) + gdTrueColorGetAlpha(cpix);
+			im2->tpixels[y >> SUPERBITS1][x >> SUPERBITS1] = gdTrueColorAlpha(
+				red, green, blue, alpha);
+		}
+	}	
+	/* Restore full dynamic range, 0-63 yields 0-252. Replication of
+		first 2 bits in last 2 bits has the desired effect. Note
+		slightly different arithmetic for alpha which is 7-bit. 
+		NOTE: only correct for SUPER == 2 */
+	for (y = 0; (y < im2->sy); y++) {
+		for (x = 0; (x < im2->sx); x++) {
+			/* Copy first 2 bits to last 2 bits, matching the
+				dynamic range of the original cheaply */
+			int cpix = im2->tpixels[y][x];
+
+			im2->tpixels[y][x] = gdTrueColorAlpha(
+					(gdTrueColorGetRed(cpix) & 0xFC) +
+					((gdTrueColorGetRed(cpix) & 0xC0) >> 6),
+					(gdTrueColorGetGreen(cpix) & 0xFC) +
+					((gdTrueColorGetGreen(cpix) & 0xC0) >> 6),
+					(gdTrueColorGetBlue(cpix) & 0xFC) +
+					((gdTrueColorGetBlue(cpix) & 0xC0) >> 6),
+					(gdTrueColorGetAlpha(cpix) & 0x7C) +
+					((gdTrueColorGetAlpha(cpix) & 0x60) >> 6));
+		}	
+	}					
+	return im2;
+}
+
+/* 2.0.16: Called by gdImageSharpen to avoid excessive code repetition
+    Added on 2003-11-19 by
+    Paul Troughton (paul<dot>troughton<at>ieee<dot>org)
+    Given filter coefficents and colours of three adjacent pixels, 
+returns new colour for centre pixel
+*/
+
+int gdImageSubSharpen (int pc, int c, int nc, float inner_coeff, float 
+outer_coeff) {
+         float red, green, blue, alpha;
+
+         red = inner_coeff * gdTrueColorGetRed (c) + outer_coeff * 
+(gdTrueColorGetRed (pc) + gdTrueColorGetRed (nc));
+         green = inner_coeff * gdTrueColorGetGreen (c) + outer_coeff * 
+(gdTrueColorGetGreen (pc) + gdTrueColorGetGreen (nc));
+         blue = inner_coeff * gdTrueColorGetBlue (c) + outer_coeff * 
+(gdTrueColorGetBlue (pc) + gdTrueColorGetBlue (nc));
+         alpha = gdTrueColorGetAlpha (c);
+
+         /* Clamping, as can overshoot bounds in either direction */
+         if (red > 255.0f) {
+                 red = 255.0f;
+         }
+         if (green > 255.0f) {
+                 green = 255.0f;
+         }
+         if (blue > 255.0f) {
+                 blue = 255.0f;
+         }
+         if (red < 0.0f) {
+                 red = 0.0f;
+         }
+         if (green < 0.0f) {
+                 green = 0.0f;
+         }
+         if (blue < 0.0f) {
+                 blue = 0.0f;
+         }
+
+         return gdTrueColorAlpha ((int) red, (int) green, (int) blue, 
+(int) alpha);
+}
+
+/*
+  * Sharpen function added on 2003-11-19
+  * by Paul Troughton (paul<dot>troughton<at>ieee<dot>org)
+  * Simple 3x3 convolution kernel
+  * Makes use of seperability
+  * Faster, but less flexible, than full-blown unsharp masking
+  * pct is sharpening percentage, and can be greater than 100
+  * Silently does nothing to non-truecolor images
+  * Silently does nothing for pct<0, as not a useful blurring function
+  * Leaves transparency/alpha-channel untouched
+  */
+void gdImageSharpen (gdImagePtr im, int pct)
+{
+         int x, y;
+         int sx, sy;
+         float inner_coeff, outer_coeff;
+
+         sx = im->sx;
+         sy = im->sy;
+
+         /* Must sum to 1 to avoid overall change in brightness.
+          * Scaling chosen so that pct=100 gives 1-D filter [-1 6 -1]/4,
+          * resulting in a 2-D filter [1 -6 1; -6 36 -6; 1 -6 1]/16,
+          * which gives noticeable, but not excessive, sharpening
+          */
+
+         outer_coeff = -pct / 400.0;
+         inner_coeff = 1 - 2 * outer_coeff;
+
+         /* Don't try to do anything with non-truecolor images, as 
+pointless,
+          * nor for pct<=0, as small kernel size leads to nasty 
+artefacts when blurring
+          */
+         if ( (im->trueColor) && (pct>0) ) {
+
+                 /* First pass, 1-D convolution column-wise */
+                 for (x = 0; x < sx; x++) {
+
+                         /* pc is colour of previous pixel; c of the 
+current pixel and nc of the next */
+                         int pc, c, nc;
+
+                         /* Replicate edge pixel at image boundary */
+                         pc = gdImageGetPixel (im, x, 0);
+
+                         /* Stop looping before last pixel to avoid 
+conditional within loop */
+                         for (y = 0; y < sy-1; y++) {
+
+                                 c = gdImageGetPixel (im, x, y);
+
+                                 nc = gdImageGetTrueColorPixel (im, x, 
+y+1);
+
+                                 /* Update centre pixel to new colour */
+                                 gdImageSetPixel(im, x, y, 
+gdImageSubSharpen (pc, c, nc, inner_coeff, outer_coeff) );
+
+                                 /* Save original colour of current 
+pixel for next time round */
+                                 pc = c;
+                         }
+
+                         /* Deal with last pixel, replicating current 
+pixel at image boundary */
+                         c = gdImageGetPixel (im, x, y);
+                         gdImageSetPixel(im, x, y, gdImageSubSharpen 
+(pc, c, c, inner_coeff, outer_coeff) );
+                 }
+
+                 /* Second pass, 1-D convolution row-wise */
+                 for (y = 0; y < sy; y++) {
+                         int pc, c, nc;
+                         pc = gdImageGetPixel (im, 0, y);
+                         for (x = 0; x < sx-1; x++) {
+                                 int c, nc;
+                                 c = gdImageGetPixel (im, x, y);
+                                 nc = gdImageGetTrueColorPixel (im, x+1, 
+y);
+                                 gdImageSetPixel(im, x, y, 
+gdImageSubSharpen (pc, c, nc, inner_coeff, outer_coeff) );
+                                 pc = c;
+                         }
+                         c = gdImageGetPixel (im, x, y);
+                         gdImageSetPixel(im, x, y, gdImageSubSharpen 
+(pc, c, c, inner_coeff, outer_coeff) );
+                 }
+         }
+}
+
+
+#ifndef GDFX_H
+#define GDFX_H 1
+
+#include "gd.h"
+
+/* im MUST be square, but can have any size. Returns a new image 
+	of width and height radius * 2, in which the X axis of
+	the original has been remapped to theta (angle) and the Y axis
+	of the original has been remapped to rho (distance from center).
+	This is known as a "polar coordinate transform." */
+
+gdImagePtr gdImageSquareToCircle(gdImagePtr im, int radius);
+
+/* Draws the text 'top' and 'bottom' on 'im', curved along the
+	edge of a circle of radius 'radius', with its
+	center at 'cx' and 'cy'. 'top' is written clockwise
+	along the top; 'bottom' is written counterclockwise
+	along the bottom. 'textRadius' determines the 'height'
+	of each character; if 'textRadius' is 1/2 of 'radius',
+	characters extend halfway from the edge to the center.
+	'fillPortion' varies from 0 to 1.0, with useful values
+	from about 0.4 to 0.9, and determines how much of the
+	180 degrees of arc assigned to each section of text
+	is actually occupied by text; 0.9 looks better than
+	1.0 which is rather crowded. 'font' is a freetype
+	font; see gdImageStringFT. 'points' is passed to the
+	freetype engine and has an effect on hinting; although
+	the size of the text is determined by radius, textRadius,
+	and fillPortion, you should pass a point size that
+	'hints' appropriately -- if you know the text will be
+	large, pass a large point size such as 24.0 to get the 
+	best results. 'fgcolor' can be any color, and may have
+	an alpha component, do blending, etc. 
+
+	Returns 0 on success, or an error string. */	
+
+char *gdImageStringFTCircle(
+	gdImagePtr im,
+	int cx,
+	int cy,
+	double radius,
+	double textRadius,
+	double fillPortion,
+	char *font,
+	double points,
+	char *top,
+	char *bottom,
+	int fgcolor);
+
+ /* 2.0.16: 
+  * Sharpen function added on 2003-11-19
+  * by Paul Troughton (paul<dot>troughton<at>ieee<dot>org)
+  * Simple 3x3 convolution kernel
+  * Makes use of seperability
+  * Faster, but less flexible, than full-blown unsharp masking
+  * pct is sharpening percentage, and can be greater than 100
+  * Silently does nothing to non-truecolor images
+  * Silently does nothing for pct<0, as not a useful blurring function
+  * Leaves transparency/alpha-channel untouched
+  */
+
+void gdImageSharpen (gdImagePtr im, int pct);
+
+#endif /* GDFX_H */
+
 void *gdMalloc (size_t size);
 void *gdRealloc (void *ptr, size_t size);
 
+/* 2.0.16: portable mutex support for thread safety. */
+
+#ifdef WIN32
+#define gdMutexDeclare(x) CRITICAL_SECTION x
+#define gdMutexSetup(x) InitializeCriticalSection(&x)
+#define gdMutexShutdown(x) DeleteCriticalSection(&x)
+#define gdMutexLock(x) EnterCriticalSection(&x)
+#define gdMutexUnlock(x) LeaveCriticalSection(&x)
+#else
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#define gdMutexDeclare(x) pthread_mutex_t x
+#define gdMutexSetup(x) pthread_mutex_init(&x, 0)
+#define gdMutexShutdown(x) pthread_mutex_destroy(&x)
+#define gdMutexLock(x) pthread_mutex_lock(&x)
+#define gdMutexUnlock(x) pthread_mutex_unlock(&x)
+#else
+#define gdMutexDeclare(x)
+#define gdMutexSetup(x) 
+#define gdMutexShutdown(x) 
+#define gdMutexLock(x) 
+#define gdMutexUnlock(x) 
+#endif /* HAVE_PTHREAD */
+#endif /* WIN32 */
+
 #endif /* GDHELPERS_H */
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.