]> granicus.if.org Git - php/commitdiff
(PHP imagecolormatch) makes a palette image match the colours in the
authorTim Toohey <ttoohey@php.net>
Thu, 22 Aug 2002 07:28:26 +0000 (07:28 +0000)
committerTim Toohey <ttoohey@php.net>
Thu, 22 Aug 2002 07:28:26 +0000 (07:28 +0000)
                      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)

ext/gd/gd.c
ext/gd/libgd/gd.c
ext/gd/libgd/gd.h
ext/gd/libgd/gd_topal.c
ext/gd/php_gd.h

index b37af9e633d52ba7c11ee5598fa8ccf1378cf273..e1187df28f6157530d06c7f0af0f263b1a4f1763 100644 (file)
@@ -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}
 };
 /* }}} */
@@ -336,6 +340,12 @@ PHP_MINIT_FUNCTION(gd)
        REGISTER_LONG_CONSTANT("IMG_ARC_CHORD", gdChord, CONST_CS | CONST_PERSISTENT);
        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) {
index 364b39e6abfb164e88fd5a924bb2b1567901cf71..454f1bf30eda22c20d8a8b9673c0dbb2f7f48685 100644 (file)
@@ -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;
+       }
+}
index 9f6718564998d61c58954b21fc259dd643423907..4c8fb90fe9a9b993f9935cf5a6417c2210aa408c 100644 (file)
@@ -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,
index 06bfc4100d298f1fb54042dcc77f3eb8cbc97f0e..33d62741d7ef4e4dcbed154159f75a93751ec1cf 100644 (file)
@@ -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;
+}
index 44d91cac472c4a284dd11530d5e91db5f0dbe0b1..f70afb43a9be9e1aa0990ff0785e31f18446f4d9 100644 (file)
@@ -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