Skip to content

Commit 828f911

Browse files
committed
Fix #43828: broken transparency of imagearc for truecolor in blendingmode
No pixel of a filled arc must ever be drawn multiple times. Otherwise we get artifacts regarding transparency. That happens with the current implementation of gdImageFilledArc() unless gdChord or gdNoFill are set. When gdPie is set, however, the filled arc is drawn in wedges, which are polygons of three points, and so some overlap is natural. To resolve the issue, we stick with the current algorithm of calculating the wedges, but instead of drawing each polygon separately, we put the relevant points in a large array, and draw a single polygon. That also is supposed to improve the performance considerably. Note that this modification will change the results when gdImageSetStyle() or gdImageSetBrush() are used, but we believe that this modification is also an improvement in this regard, even though it still might not make much sense to use these functions with gdImageFilledArc(). The respective fix for libgd is <libgd/libgd@e7e20d6>.
1 parent bd19195 commit 828f911

File tree

3 files changed

+50
-16
lines changed

3 files changed

+50
-16
lines changed

ext/gd/libgd/gd.c

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1625,9 +1625,7 @@ long lsqrt (long n)
16251625
/* s and e are integers modulo 360 (degrees), with 0 degrees
16261626
being the rightmost extreme and degrees changing clockwise.
16271627
cx and cy are the center in pixels; w and h are the horizontal
1628-
and vertical diameter in pixels. Nice interface, but slow.
1629-
See gd_arc_f_buggy.c for a better version that doesn't
1630-
seem to be bug-free yet. */
1628+
and vertical diameter in pixels. */
16311629

16321630
void gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color)
16331631
{
@@ -1636,8 +1634,8 @@ void gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int
16361634

16371635
void gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color, int style)
16381636
{
1639-
gdPoint pts[3];
1640-
int i;
1637+
gdPoint pts[363];
1638+
int i, pti;
16411639
int lx = 0, ly = 0;
16421640
int fx = 0, fy = 0;
16431641

@@ -1665,7 +1663,7 @@ void gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e
16651663
}
16661664
}
16671665

1668-
for (i = s; i <= e; i++) {
1666+
for (i = s, pti = 1; i <= e; i++, pti++) {
16691667
int x, y;
16701668
x = ((long) gdCosT[i % 360] * (long) w / (2 * 1024)) + cx;
16711669
y = ((long) gdSinT[i % 360] * (long) h / (2 * 1024)) + cy;
@@ -1674,19 +1672,28 @@ void gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e
16741672
if (style & gdNoFill) {
16751673
gdImageLine(im, lx, ly, x, y, color);
16761674
} else {
1677-
/* This is expensive! */
1678-
pts[0].x = lx;
1679-
pts[0].y = ly;
1680-
pts[1].x = x;
1681-
pts[1].y = y;
1682-
pts[2].x = cx;
1683-
pts[2].y = cy;
1684-
gdImageFilledPolygon(im, pts, 3, color);
1685-
}
1675+
if (y == ly) {
1676+
pti--; /* don't add this point */
1677+
if (((i > 270 || i < 90) && x > lx) || ((i > 90 && i < 270) && x < lx)) {
1678+
/* replace the old x coord, if increasing on the
1679+
right side or decreasing on the left side */
1680+
pts[pti].x = x;
1681+
}
1682+
} else {
1683+
pts[pti].x = x;
1684+
pts[pti].y = y;
1685+
}
1686+
}
16861687
}
16871688
} else {
16881689
fx = x;
16891690
fy = y;
1691+
if (!(style & (gdChord | gdNoFill))) {
1692+
pts[0].x = cx;
1693+
pts[0].y = cy;
1694+
pts[pti].x = x;
1695+
pts[pti].y = y;
1696+
}
16901697
}
16911698
lx = x;
16921699
ly = y;
@@ -1713,6 +1720,10 @@ void gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e
17131720
gdImageLine(im, cx, cy, lx, ly, color);
17141721
gdImageLine(im, cx, cy, fx, fy, color);
17151722
}
1723+
} else {
1724+
pts[pti].x = cx;
1725+
pts[pti].y = cy;
1726+
gdImageFilledPolygon(im, pts, pti+1, color);
17161727
}
17171728
}
17181729
}

ext/gd/tests/bug43828.phpt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
--TEST--
2+
Bug #43828 (broken transparency of imagearc for truecolor in blendingmode)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('gd')) die('skip ext/gd not available');
6+
?>
7+
--FILE--
8+
<?php
9+
10+
$im = imagecreatetruecolor(100,100);
11+
12+
$transparent = imagecolorallocatealpha($im, 255, 255, 255, 80);
13+
imagefilledrectangle($im, 0,0, 99,99, $transparent);
14+
$color = imagecolorallocatealpha($im, 0, 255, 0, 100);
15+
imagefilledarc($im, 49, 49, 99,99, 0 , 360, $color, IMG_ARC_PIE);
16+
17+
ob_start();
18+
imagepng($im);
19+
echo md5(ob_get_clean());
20+
imagedestroy($im);
21+
?>
22+
--EXPECT--
23+
3d82e4525f19790ae1055366e2a36917

ext/gd/tests/imagecolorallocatealpha_basic.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,5 @@ var_dump(md5(base64_encode($imgsrc)));
2626
var_dump($corA);
2727
?>
2828
--EXPECT--
29-
string(32) "2a6424e4cb4e1b7391dfff74bf136bde"
29+
string(32) "f95489d97f4f1a5c4dc265388922d1ec"
3030
int(842163455)

0 commit comments

Comments
 (0)