cvs: php4 /ext/gd gd.c php_gd.h /ext/gd/libgd gd.c gd.h gd_topal.c

From: Date: Thu, 22 Aug 2002 07:28:26 +0000
Subject: cvs: php4 /ext/gd gd.c php_gd.h /ext/gd/libgd gd.c gd.h gd_topal.c
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-13548@lists.php.net to get a copy of this message
ttoohey Thu Aug 22 03:28:26 2002 EDT Modified files: /php4/ext/gd gd.c php_gd.h /php4/ext/gd/libgd gd.c gd.h gd_topal.c Log: (PHP imagecolormatch) makes a palette image match the colours in the true-color version. (PHP imagelayereffect) extended alpha-channel mixing effects for the bundled GD library @Added ImageColorMatch() and ImageLayerEffect() functions @which work with the bundled GD library (ttoohey)

Index: php4/ext/gd/gd.c diff -u php4/ext/gd/gd.c:1.202 php4/ext/gd/gd.c:1.203 --- php4/ext/gd/gd.c:1.202 Sun Jul 28 06:00:37 2002 +++ php4/ext/gd/gd.c Thu Aug 22 03:28:24 2002 @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: gd.c,v 1.202 2002/07/28 10:00:37 helly Exp $ */ +/* $Id: gd.c,v 1.203 2002/08/22 07:28:24 ttoohey Exp $ */ /* gd 1.2 is copyright 1994, 1995, Quest Protein Database Center, Cold Spring Harbor Labs. */ @@ -260,6 +260,10 @@ #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 @@ 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 @@ } /* }}} */ +#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 @@ } /* }}} */ +#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 @@ 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 @@ 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 @@ _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 @@ 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) { Index: php4/ext/gd/php_gd.h diff -u php4/ext/gd/php_gd.h:1.41 php4/ext/gd/php_gd.h:1.42 --- php4/ext/gd/php_gd.h:1.41 Fri Jun 28 08:35:30 2002 +++ php4/ext/gd/php_gd.h Thu Aug 22 03:28:25 2002 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_gd.h,v 1.41 2002/06/28 12:35:30 sniper Exp $ */ +/* $Id: php_gd.h,v 1.42 2002/08/22 07:28:25 ttoohey Exp $ */ #ifndef PHP_GD_H #define PHP_GD_H @@ -154,6 +154,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); Index: php4/ext/gd/libgd/gd.c diff -u php4/ext/gd/libgd/gd.c:1.13 php4/ext/gd/libgd/gd.c:1.14 --- php4/ext/gd/libgd/gd.c:1.13 Mon Aug 12 15:09:26 2002 +++ php4/ext/gd/libgd/gd.c Thu Aug 22 03:28:25 2002 @@ -665,26 +665,28 @@ 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; } } @@ -2573,4 +2575,79 @@ 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; + } } Index: php4/ext/gd/libgd/gd.h diff -u php4/ext/gd/libgd/gd.h:1.3 php4/ext/gd/libgd/gd.h:1.4 --- php4/ext/gd/libgd/gd.h:1.3 Fri Jun 14 10:48:33 2002 +++ php4/ext/gd/libgd/gd.h Thu Aug 22 03:28:26 2002 @@ -67,6 +67,11 @@ #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 @@ -334,6 +339,11 @@ it can be negative) and the quality loss is ugly. */ 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 Index: php4/ext/gd/libgd/gd_topal.c diff -u php4/ext/gd/libgd/gd_topal.c:1.3 php4/ext/gd/libgd/gd_topal.c:1.4 --- php4/ext/gd/libgd/gd_topal.c:1.3 Sun Aug 11 10:05:30 2002 +++ php4/ext/gd/libgd/gd_topal.c Thu Aug 22 03:28:26 2002 @@ -1682,3 +1682,56 @@ 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; +}
« previous php.cvs (#13548) next »