ID:               22103
 User updated by:  [EMAIL PROTECTED]
 Reported By:      [EMAIL PROTECTED]
 Status:           Verified
 Bug Type:         GD related
 Operating System: Linux
 PHP Version:      4.3.0
 New Comment:

I wrote a drop in replacement for the GD gdImageFilledArc() which works
with alpha-blending. Replace the gdImageFilledArc() in gd.c with the
following function. Which is reasonable fast.


void 
gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s,
int e, int color, int style)
{
    /* 
       This replacement for the original gdImageFilledArc() completely
mimics
       the original behavior. This includes the behaviour I would
consider a bug 
       where a style of IMG_ARC_CHORD is the same as IMG_ARC_PIE for
filled arcs. 

       The benefit of this implementation is that this will also work
for
       colors where alpha-blending is used.
       
       This algorithm uses GD standard sin & cos tables for quick
lookup. 
       However, this also limits the accuracy to 1 degree. This means
that
       very very large arc's will look "squarish". However for any
normal
       sizes, say < 2000 pixels, this is not really a problem in
practice.
    */

    gdPoint p[362];

    /* Sanity check */
    if( w < 0 || h < 0 ) return;

    /* Make sure angles are positive and e > s */
    while( s < 0 ) s += 360;
    while( e < 0 ) e += 360;
    while( e < s ) e += 360;

    s %= 360; 
    
    if( e > 360 ) 
        e %= 360;

    /* In the algorithm we need to ue the radius */
    w /= 2;
    h /= 2;

    /* We handle the chord and pie cases separately */
    if( style & gdChord ) {
        int x1,y1,x2,y2;
        x1 = cx + ((long) gdCosT[s] * (long) w / 1024 );
        y1 = cy + ((long) gdSinT[s] * (long) h / 1024 );
        x2 = cx + ((long) gdCosT[e] * (long) w / 1024 );
        y2 = cy + ((long) gdSinT[e] * (long) h / 1024 );
        if( style & gdNoFill ) {
            if( style & gdEdged ) {
                p[0].x = cx; p[0].y = cy;
                p[1].x = x1; p[1].y = y1;
                p[2].x = x2; p[2].y = y2;
                p[3].x = cx; p[3].y = cy;
                gdImagePolygon (im, p, 4, color);           
            }
            else {
                gdImageLine (im, x1, y1, x2, y2, color);        
            }
        }
        else {
            p[0].x = cx; p[0].y = cy;
            p[1].x = x1; p[1].y = y1;
            p[2].x = x2; p[2].y = y2;
            p[3].x = cx; p[3].y = cy;
            gdImageFilledPolygon (im, p, 4, color);         
        }
    }
    else {
        /* style must be gdPie */
        int i=0, a=s;
        if( style & gdEdged || ! (style & gdNoFill) ) {
            p[0].x = cx; p[0].y = cy;
            i=1;
        }

        while( a <= e ) {
            p[i].x = cx + ((long) gdCosT[a] * (long) w / 1024 );
            p[i].y = cy + ((long) gdSinT[a] * (long) h / 1024 );
            ++i;
            ++a;
        }

        if( style & gdEdged || ! (style & gdNoFill) ) {
            p[i].x = cx; p[i].y = cy;
            ++i;
        }

        if( style & gdNoFill ) {
            gdImagePolygon (im, p, i, color);       
        }
        else {
            gdImageFilledPolygon (im, p,i , color);         
        }
    }
}


Previous Comments:
------------------------------------------------------------------------

[2003-02-07 20:16:15] [EMAIL PROTECTED]

Hello,

Thank's for the report.

<Since I'm doing a lot of graphic stuff I'll see if I can come up with
a new algorithm to do this. I'm afraid however that any correct
algortihm will be quite CPU expensive.>

I have already solved this problem with a quit nice and fast algorithm.
I have to check if I can add it to the current 4_3 HEAD.

Doing something better with ellipse then what GD currently does is not
very difficult (actually it's nothing else than a filled polygon with
many connected lines, kind of ugly things to draw a simple ellipse).

pierre


------------------------------------------------------------------------

[2003-02-07 11:06:00] [EMAIL PROTECTED]

I had a look in the source in GD. 
The problem is the way the gdImageFilledArc() is implemented. 

The algorithm there is flawed for alpha-blending. It fills the arc by
drawing a series of filled polygons (triangles) centerd in the middle
of the ellipse and out to the edge of the ellipse with 1 degree
separation between the end points. This will make the interior points
overlap and create the moire pattern.

Unfortunately there isn't a simple solution to this. Doing a floodfill
to a specific color wan't work since we don't know the canvas we are
drawing on.

Since I'm doing a lot of graphic stuff I'll see if I can come up with a
new algorithm to do this. I'm afraid however that any correct algortihm
will be quite CPU expensive.

------------------------------------------------------------------------

[2003-02-07 09:44:44] [EMAIL PROTECTED]

The problem still exist in snapshot 200302071430. 

I haven't had time to look at the GD code but this is most likely a
design flaw and not a straight bug. Fixing this will probably require a
new fill algorithm for ellipses that can guarantee that the same pixel
inside the ellipse will only be painted exactly one time.

The script below demonstrates this bug
and the resulting image can also be viewed at
http://www.aditus.nu/jpgraph/bbimages/filledellipsebug.png


<?php
header("Content-type: image/png");

// Create a truecolor image with alpha blending
$im = imagecreatetruecolor(200,200);
imagealphablending ($im,true);

// Background color
$bkg = imagecolorresolvealpha($im, 255,255,255,0);

// Red with ~70% alpha blending (90/127)
$red = imagecolorresolvealpha($im, 255,0,0,90);

// White background
imagefilledrectangle($im,0,0,200,200,$bkg);

// Filled circle (with moire' patterns)
imagefilledellipse($im,100,100,120,120,$red);

imagepng($im);
imagedestroy($im);
?>

------------------------------------------------------------------------

[2003-02-07 06:36:22] [EMAIL PROTECTED]

Please try using this CVS snapshot:

  http://snaps.php.net/php4-STABLE-latest.tar.gz
 
For Windows:
 
  http://snaps.php.net/win32/php4-win32-STABLE-latest.zip


There were couple of fixes in GD in CVS.
If it still fails, please provide a short example script.


------------------------------------------------------------------------

[2003-02-06 22:18:03] [EMAIL PROTECTED]

(Using built-in GD 2.x in PHP 4.3.0)

imagefilledellipse() creates moire' patterns inside the filled ellipse
when alpha blending is enabled.

The problem seems to be that the fill algorithm strokes the same point
within the ellipse several times and due to the alpha blending of
single pixels creates several color shades within the ellipse.

This is fine as long as a solid fill is used but does not work together
with alpha blending. 



------------------------------------------------------------------------


-- 
Edit this bug report at http://bugs.php.net/?id=22103&edit=1

Reply via email to