summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/gd/gd.c81
-rw-r--r--ext/gd/libgd/gd.c115
-rw-r--r--ext/gd/libgd/gd.h10
-rw-r--r--ext/gd/libgd/gd_topal.c53
-rw-r--r--ext/gd/php_gd.h5
5 files changed, 240 insertions, 24 deletions
diff --git a/ext/gd/gd.c b/ext/gd/gd.c
index b37af9e633..e1187df28f 100644
--- a/ext/gd/gd.c
+++ b/ext/gd/gd.c
@@ -260,6 +260,10 @@ function_entry gd_functions[] = {
#ifdef HAVE_GD_WBMP
PHP_FE(image2wbmp, NULL)
#endif
+#if HAVE_GD_BUNDLED
+ PHP_FE(imagelayereffect, NULL)
+ PHP_FE(imagecolormatch, NULL)
+#endif
{NULL, NULL, NULL}
};
/* }}} */
@@ -337,6 +341,12 @@ PHP_MINIT_FUNCTION(gd)
REGISTER_LONG_CONSTANT("IMG_ARC_NOFILL", gdNoFill, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("IMG_ARC_EDGED", gdEdged, CONST_CS | CONST_PERSISTENT);
#endif
+#if HAVE_GD_BUNDLED
+ REGISTER_LONG_CONSTANT("IMG_EFFECT_REPLACE", gdEffectReplace, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("IMG_EFFECT_ALPHABLEND", gdEffectAlphaBlend, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("IMG_EFFECT_NORMAL", gdEffectNormal, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("IMG_EFFECT_OVERLAY", gdEffectOverlay, CONST_CS | CONST_PERSISTENT);
+#endif
return SUCCESS;
}
/* }}} */
@@ -639,6 +649,44 @@ PHP_FUNCTION(imagetruecolortopalette)
}
/* }}} */
+#if HAVE_GD_BUNDLED
+/* {{{ proto void imagecolormatch(resource im1, resource im2)
+ Makes the colors of the palette version of an image more closely match the true color version */
+PHP_FUNCTION(imagecolormatch)
+{
+ zval **IM1, **IM2;
+ gdImagePtr im1, im2;
+ int result;
+
+ if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &IM1, &IM2 ) == FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+
+ ZEND_FETCH_RESOURCE(im1, gdImagePtr, IM1, -1, "Image", le_gd);
+ ZEND_FETCH_RESOURCE(im2, gdImagePtr, IM2, -1, "Image", le_gd);
+
+ result = gdImageColorMatch(im1, im2);
+ switch( result )
+ {
+ case -1:
+ php_error_docref(NULL, E_ERROR, "Image1 must be TrueColor" );
+ RETURN_FALSE;
+ break;
+ case -2:
+ php_error_docref(NULL, E_ERROR, "Image2 must be Palette" );
+ RETURN_FALSE;
+ break;
+ case -3:
+ php_error_docref(NULL, E_ERROR, "Image1 and Image2 must be the same size" );
+ RETURN_FALSE;
+ break;
+ }
+
+ RETURN_TRUE;
+}
+/* }}} */
+#endif
+
/* {{{ proto void imagesetthickness(resource im, int thickness)
Set line thickness for drawing lines, ellipses, rectangles, polygons etc. */
PHP_FUNCTION(imagesetthickness)
@@ -738,6 +786,28 @@ PHP_FUNCTION(imagealphablending)
}
/* }}} */
+#if HAVE_GD_BUNDLED
+/* {{{ proto void imagelayereffect(resource im, int effect)
+ Set the alpha blending flag to use the bundled libgd layering effects */
+PHP_FUNCTION(imagelayereffect)
+{
+ zval **IM, **effect;
+ gdImagePtr im;
+
+ if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &IM, &effect) == FAILURE) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+
+ ZEND_FETCH_RESOURCE(im, gdImagePtr, IM, -1, "Image", le_gd);
+ convert_to_long_ex(effect);
+
+ gdImageAlphaBlending(im, Z_LVAL_PP(effect) );
+
+ RETURN_TRUE;
+}
+/* }}} */
+#endif
+
/* {{{ proto int imagecolorresolvealpha(resource im, int red, int green, int blue, int alpha)
Resolve/Allocate a colour with an alpha level. Works for true colour and palette based images */
PHP_FUNCTION(imagecolorresolvealpha)
@@ -2975,7 +3045,7 @@ PHP_FUNCTION(imagepstext)
int space;
int *f_ind;
int h_lines, v_lines, c_ind;
- int rd, gr, bl, fg_rd, fg_gr, fg_bl, bg_rd, bg_gr, bg_bl, _fg, _bg;
+ int rd, gr, bl, al, fg_rd, fg_gr, fg_bl, fg_al, bg_rd, bg_gr, bg_bl, bg_al, _fg, _bg;
int aa[16], aa_steps;
int width, amount_kern, add_width;
double angle, extend;
@@ -3024,16 +3094,19 @@ PHP_FUNCTION(imagepstext)
fg_rd = gdImageRed (bg_img, _fg);
fg_gr = gdImageGreen(bg_img, _fg);
fg_bl = gdImageBlue (bg_img, _fg);
+ fg_al = gdImageAlpha(bg_img, _fg);
bg_rd = gdImageRed (bg_img, _bg);
bg_gr = gdImageGreen(bg_img, _bg);
bg_bl = gdImageBlue (bg_img, _bg);
+ bg_al = gdImageAlpha(bg_img, _bg);
for (i = 0; i < aa_steps; i++) {
rd = bg_rd+(double)(fg_rd-bg_rd)/aa_steps*(i+1);
gr = bg_gr+(double)(fg_gr-bg_gr)/aa_steps*(i+1);
bl = bg_bl+(double)(fg_bl-bg_bl)/aa_steps*(i+1);
- aa[i] = gdImageColorResolve(bg_img, rd, gr, bl);
+ al = bg_al+(double)(fg_al-bg_al)/aa_steps*(i+1);
+ aa[i] = gdImageColorResolveAlpha(bg_img, rd, gr, bl, al);
}
T1_AASetBitsPerPixel(8);
@@ -3058,7 +3131,7 @@ PHP_FUNCTION(imagepstext)
_str = Z_STRVAL_PP(str);
- if (width) {
+ {
extend = T1_GetExtend(*f_ind);
str_path = T1_GetCharOutline(*f_ind, _str[0], Z_LVAL_PP(sz), transform);
@@ -3074,8 +3147,6 @@ PHP_FUNCTION(imagepstext)
str_path = T1_ConcatOutlines(str_path, char_path);
}
str_img = T1_AAFillOutline(str_path, 0);
- } else {
- str_img = T1_AASetString(*f_ind, _str, Z_STRLEN_PP(str), space, T1_KERNING, Z_LVAL_PP(sz), transform);
}
if (T1_errno) {
diff --git a/ext/gd/libgd/gd.c b/ext/gd/libgd/gd.c
index 364b39e6ab..454f1bf30e 100644
--- a/ext/gd/libgd/gd.c
+++ b/ext/gd/libgd/gd.c
@@ -665,26 +665,28 @@ gdImageSetPixel (gdImagePtr im, int x, int y, int color)
gdImageTileApply (im, x, y);
break;
default:
- if (gdImageBoundsSafe (im, x, y))
- {
- if (im->trueColor)
- {
- if (im->alphaBlendingFlag)
- {
- im->tpixels[y][x] =
- gdAlphaBlend (im->tpixels[y][x],
- color);
- }
- else
- {
- im->tpixels[y][x] = color;
+ if (gdImageBoundsSafe (im, x, y)) {
+ if (im->trueColor) {
+ switch( im->alphaBlendingFlag )
+ {
+ default:
+ case gdEffectReplace :
+ im->tpixels[y][x] = color;
+ break;
+ case gdEffectAlphaBlend :
+ im->tpixels[y][x] = gdAlphaBlend(im->tpixels[y][x], color);
+ break;
+ case gdEffectNormal :
+ im->tpixels[y][x] = gdFullAlphaBlend(im->tpixels[y][x], color);
+ break;
+ case gdEffectOverlay :
+ im->tpixels[y][x] = gdLayerOverlay(im->tpixels[y][x], color);
+ break;
+ }
+ } else {
+ im->pixels[y][x] = color;
}
- }
- else
- {
- im->pixels[y][x] = color;
- }
- }
+ }
break;
}
}
@@ -2574,3 +2576,78 @@ gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg)
{
im->saveAlphaFlag = saveAlphaArg;
}
+
+int
+gdFullAlphaBlend (int dst, int src)
+{
+ int a1, a2;
+ a1 = gdAlphaTransparent - gdTrueColorGetAlpha(src);
+ a2 = gdAlphaTransparent - gdTrueColorGetAlpha(dst);
+
+ return ( ((gdAlphaTransparent - ((a1+a2)-(a1*a2/gdAlphaMax))) << 24) +
+ (gdAlphaBlendColor( gdTrueColorGetRed(src), gdTrueColorGetRed(dst), a1, a2 ) << 16) +
+ (gdAlphaBlendColor( gdTrueColorGetGreen(src), gdTrueColorGetGreen(dst), a1, a2 ) << 8) +
+ (gdAlphaBlendColor( gdTrueColorGetBlue(src), gdTrueColorGetBlue(dst), a1, a2 ))
+ );
+}
+
+int
+gdAlphaBlendColor( int b1, int b2, int a1, int a2 )
+{
+ int c;
+ int w;
+
+ /* deal with special cases */
+
+ if( (gdAlphaMax == a1) || (0 == a2) ) {
+ /* the back pixel can't be seen */
+ return b1;
+ } else if(0 == a1) {
+ /* the front pixel can't be seen */
+ return b2;
+ } else if(gdAlphaMax == a2) {
+ /* the back pixel is opaque */
+ return ( a1 * b1 + ( gdAlphaMax - a1 ) * b2 ) / gdAlphaMax;
+ }
+
+ /* the general case */
+ w = ( a1 * ( gdAlphaMax - a2 ) / ( gdAlphaMax - a1 * a2 / gdAlphaMax ) * b1 + \
+ a2 * ( gdAlphaMax - a1 ) / ( gdAlphaMax - a1 * a2 / gdAlphaMax ) * b2 ) / gdAlphaMax;
+ c = (a2 * b2 + ( gdAlphaMax - a2 ) * w ) / gdAlphaMax;
+ return ( a1 * b1 + ( gdAlphaMax - a1 ) * c ) / gdAlphaMax;
+}
+
+int
+gdLayerOverlay (int dst, int src)
+{
+ int a1, a2;
+ a1 = gdAlphaMax - gdTrueColorGetAlpha(dst);
+ a2 = gdAlphaMax - gdTrueColorGetAlpha(src);
+ return ( ((gdAlphaMax - a1*a2/gdAlphaMax) << 24) +
+ (gdAlphaOverlayColor( gdTrueColorGetRed(src), gdTrueColorGetRed(dst), gdRedMax ) << 16) +
+ (gdAlphaOverlayColor( gdTrueColorGetGreen(src), gdTrueColorGetGreen(dst), gdGreenMax ) << 8) +
+ (gdAlphaOverlayColor( gdTrueColorGetBlue(src), gdTrueColorGetBlue(dst), gdBlueMax ))
+ );
+}
+
+int
+gdAlphaOverlayColor( int src, int dst, int max )
+{
+ /* this function implements the algorithm
+ *
+ * for dst[rgb] < 0.5,
+ * c[rgb] = 2.src[rgb].dst[rgb]
+ * and for dst[rgb] > 0.5,
+ * c[rgb] = -2.src[rgb].dst[rgb] + 2.dst[rgb] + 2.src[rgb] - 1
+ *
+ */
+
+ dst = dst << 1;
+ if( dst > max ) {
+ /* in the "light" zone */
+ return dst + (src << 1) - (dst * src / max) - max;
+ } else {
+ /* in the "dark" zone */
+ return dst * src / max;
+ }
+}
diff --git a/ext/gd/libgd/gd.h b/ext/gd/libgd/gd.h
index 9f67185649..4c8fb90fe9 100644
--- a/ext/gd/libgd/gd.h
+++ b/ext/gd/libgd/gd.h
@@ -67,6 +67,11 @@ extern "C" {
#define gdTrueColorGetRed(c) (((c) & 0xFF0000) >> 16)
#define gdTrueColorGetGreen(c) (((c) & 0x00FF00) >> 8)
#define gdTrueColorGetBlue(c) ((c) & 0x0000FF)
+#define gdEffectReplace 0
+#define gdEffectAlphaBlend 1
+#define gdEffectNormal 2
+#define gdEffectOverlay 3
+
/* This function accepts truecolor pixel values only. The
source color is composited with the destination color
@@ -335,6 +340,11 @@ void gdImageColorDeallocate(gdImagePtr im, int color);
void gdImageTrueColorToPalette(gdImagePtr im, int ditherFlag, int colorsWanted);
+/* An attempt at getting the results of gdImageTrueColorToPalette
+ to look a bit more like the original (im1 is the original
+ and im2 is the palette version */
+int gdImageColorMatch(gdImagePtr im1, gdImagePtr im2);
+
/* Specifies a color index (if a palette image) or an
RGB color (if a truecolor image) which should be
considered 100% transparent. FOR TRUECOLOR IMAGES,
diff --git a/ext/gd/libgd/gd_topal.c b/ext/gd/libgd/gd_topal.c
index 06bfc4100d..33d62741d7 100644
--- a/ext/gd/libgd/gd_topal.c
+++ b/ext/gd/libgd/gd_topal.c
@@ -1682,3 +1682,56 @@ outOfMemory:
gdFree (cquantize);
}
}
+
+/* bring the palette colors in im2 to be closer to im1
+ *
+ */
+int
+gdImageColorMatch (gdImagePtr im1, gdImagePtr im2)
+{
+ unsigned long *buf; /* stores our calculations */
+ unsigned long *bp; /* buf ptr */
+ int color, rgb;
+ int x,y;
+ int count;
+
+ if( !im1->trueColor ) {
+ return -1; /* im1 must be True Color */
+ }
+ if( im2->trueColor ) {
+ return -2; /* im2 must be indexed */
+ }
+ if( (im1->sx != im2->sx) || (im1->sy != im2->sy) ) {
+ return -3; /* the images are meant to be the same dimensions */
+ }
+
+ buf = (unsigned long *)malloc( sizeof(unsigned long) * 5 * im2->colorsTotal );
+ memset( buf, 0, sizeof(unsigned long) * 5 * im2->colorsTotal );
+
+ for( x=0; x<im1->sx; x++ ) {
+ for( y=0; y<im1->sy; y++ ) {
+ color = im2->pixels[y][x];
+ rgb = im1->tpixels[y][x];
+ bp = buf + (color * 5);
+ (*(bp++))++;
+ *(bp++) += gdTrueColorGetRed(rgb);
+ *(bp++) += gdTrueColorGetGreen(rgb);
+ *(bp++) += gdTrueColorGetBlue(rgb);
+ *(bp++) += gdTrueColorGetAlpha(rgb);
+ }
+ }
+ bp = buf;
+ for( color=0; color<im2->colorsTotal; color++ ) {
+ count = *(bp++);
+ if( count > 0 ) {
+ im2->red[color] = *(bp++) / count;
+ im2->green[color] = *(bp++) / count;
+ im2->blue[color] = *(bp++) / count;
+ im2->alpha[color] = *(bp++) / count;
+ } else {
+ bp += 4;
+ }
+ }
+ free(buf);
+ return 0;
+}
diff --git a/ext/gd/php_gd.h b/ext/gd/php_gd.h
index 44d91cac47..f70afb43a9 100644
--- a/ext/gd/php_gd.h
+++ b/ext/gd/php_gd.h
@@ -155,6 +155,11 @@ PHP_FUNCTION(jpeg2wbmp);
PHP_FUNCTION(png2wbmp);
PHP_FUNCTION(image2wbmp);
+#if HAVE_GD_BUNDLED
+PHP_FUNCTION(imagelayereffect);
+PHP_FUNCTION(imagecolormatch);
+#endif
+
PHP_GD_API int phpi_get_le_gd(void);
#else