summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph M. Becker <cmbecker69@gmx.de>2019-01-10 16:11:23 +0100
committerChristoph M. Becker <cmbecker69@gmx.de>2019-01-10 16:11:23 +0100
commit6b4cdbaade1b077e8f0eceecb0e07921fed00aff (patch)
tree7966f9da36372a5766c661f7b65485dc0690418e
parent772b1cb245ebe19e220a2552d1e2b700d15f2c68 (diff)
downloadphp-git-6b4cdbaade1b077e8f0eceecb0e07921fed00aff.tar.gz
Fix #73281: imagescale(…, IMG_BILINEAR_FIXED) can cause black border
We port the upstream fixes for libgd/libgd#329 and libgd/libgd#224.
-rw-r--r--NEWS2
-rw-r--r--ext/gd/libgd/gd_interpolation.c91
-rw-r--r--ext/gd/tests/bug73281.phpt45
3 files changed, 57 insertions, 81 deletions
diff --git a/NEWS b/NEWS
index 8334a2a7fa..fc828fac69 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,8 @@ PHP NEWS
. Fixed bug #77339 (__callStatic may get incorrect arguments). (Dmitry)
- GD:
+ . Fixed bug #73281 (imagescale(…, IMG_BILINEAR_FIXED) can cause black border).
+ (cmb)
. Fixed bug #77272 (imagescale() may return image resource on failure). (cmb)
. Fixed bug #77391 (1bpp BMPs may fail to be loaded). (Romain Déoux, cmb)
diff --git a/ext/gd/libgd/gd_interpolation.c b/ext/gd/libgd/gd_interpolation.c
index 81395cb87e..19780498a9 100644
--- a/ext/gd/libgd/gd_interpolation.c
+++ b/ext/gd/libgd/gd_interpolation.c
@@ -662,43 +662,7 @@ static inline int getPixelOverflowTC(gdImagePtr im, const int x, const int y, co
}
return c;
} else {
- register int border = 0;
-
- if (y < im->cy1) {
- border = im->tpixels[0][im->cx1];
- goto processborder;
- }
-
- if (y < im->cy1) {
- border = im->tpixels[0][im->cx1];
- goto processborder;
- }
-
- if (y > im->cy2) {
- if (x >= im->cx1 && x <= im->cx1) {
- border = im->tpixels[im->cy2][x];
- goto processborder;
- } else {
- return gdTrueColorAlpha(0, 0, 0, 127);
- }
- }
-
- /* y is bound safe at this point */
- if (x < im->cx1) {
- border = im->tpixels[y][im->cx1];
- goto processborder;
- }
-
- if (x > im->cx2) {
- border = im->tpixels[y][im->cx2];
- }
-
-processborder:
- if (border == im->transparent) {
- return gdTrueColorAlpha(0, 0, 0, 127);
- } else{
- return gdTrueColorAlpha(gdTrueColorGetRed(border), gdTrueColorGetGreen(border), gdTrueColorGetBlue(border), 127);
- }
+ return bgColor;
}
}
@@ -713,42 +677,7 @@ static inline int getPixelOverflowPalette(gdImagePtr im, const int x, const int
}
return colorIndex2RGBA(c);
} else {
- register int border = 0;
- if (y < im->cy1) {
- border = gdImageGetPixel(im, im->cx1, 0);
- goto processborder;
- }
-
- if (y < im->cy1) {
- border = gdImageGetPixel(im, im->cx1, 0);
- goto processborder;
- }
-
- if (y > im->cy2) {
- if (x >= im->cx1 && x <= im->cx1) {
- border = gdImageGetPixel(im, x, im->cy2);
- goto processborder;
- } else {
- return gdTrueColorAlpha(0, 0, 0, 127);
- }
- }
-
- /* y is bound safe at this point */
- if (x < im->cx1) {
- border = gdImageGetPixel(im, im->cx1, y);
- goto processborder;
- }
-
- if (x > im->cx2) {
- border = gdImageGetPixel(im, im->cx2, y);
- }
-
-processborder:
- if (border == im->transparent) {
- return gdTrueColorAlpha(0, 0, 0, 127);
- } else{
- return colorIndex2RGBcustomA(border, 127);
- }
+ return bgColor;
}
}
@@ -1308,11 +1237,11 @@ static gdImagePtr gdImageScaleBilinearPalette(gdImagePtr im, const unsigned int
f_b1, f_b2, f_b3, f_b4,
f_a1, f_a2, f_a3, f_a4;
- /* zero for the background color, nothig gets outside anyway */
+ /* 0 for bgColor; (n,m) is supposed to be valid anyway */
pixel1 = getPixelOverflowPalette(im, n, m, 0);
- pixel2 = getPixelOverflowPalette(im, n + 1, m, 0);
- pixel3 = getPixelOverflowPalette(im, n, m + 1, 0);
- pixel4 = getPixelOverflowPalette(im, n + 1, m + 1, 0);
+ pixel2 = getPixelOverflowPalette(im, n + 1, m, pixel1);
+ pixel3 = getPixelOverflowPalette(im, n, m + 1, pixel1);
+ pixel4 = getPixelOverflowPalette(im, n + 1, m + 1, pixel1);
f_r1 = gd_itofx(gdTrueColorGetRed(pixel1));
f_r2 = gd_itofx(gdTrueColorGetRed(pixel2));
@@ -1400,11 +1329,11 @@ static gdImagePtr gdImageScaleBilinearTC(gdImagePtr im, const unsigned int new_w
f_b1, f_b2, f_b3, f_b4,
f_a1, f_a2, f_a3, f_a4;
dwSrcTotalOffset = m + n;
- /* 0 for bgColor, nothing gets outside anyway */
+ /* 0 for bgColor; (n,m) is supposed to be valid anyway */
pixel1 = getPixelOverflowTC(im, n, m, 0);
- pixel2 = getPixelOverflowTC(im, n + 1, m, 0);
- pixel3 = getPixelOverflowTC(im, n, m + 1, 0);
- pixel4 = getPixelOverflowTC(im, n + 1, m + 1, 0);
+ pixel2 = getPixelOverflowTC(im, n + 1, m, pixel1);
+ pixel3 = getPixelOverflowTC(im, n, m + 1, pixel1);
+ pixel4 = getPixelOverflowTC(im, n + 1, m + 1, pixel1);
f_r1 = gd_itofx(gdTrueColorGetRed(pixel1));
f_r2 = gd_itofx(gdTrueColorGetRed(pixel2));
diff --git a/ext/gd/tests/bug73281.phpt b/ext/gd/tests/bug73281.phpt
new file mode 100644
index 0000000000..162ee1b33a
--- /dev/null
+++ b/ext/gd/tests/bug73281.phpt
@@ -0,0 +1,45 @@
+--TEST--
+Bug #73281 (imagescale(…, IMG_BILINEAR_FIXED) can cause black border)
+--SKIPIF--
+<?php
+if (!extension_loaded('gd')) die('skip gd extension not available');
+if (!GD_BUNDLED && version_compare(GD_VERSION, '2.2.3', '<=')) die('skip upstream fix not yet released');
+?>
+--FILE--
+<?php
+$coordinates = [[0, 0], [0, 199], [199, 199], [199, 0]];
+
+$src = imagecreatetruecolor(100, 100);
+$white = imagecolorallocate($src, 255, 255, 255);
+imagefilledrectangle($src, 0,0, 99,99, $white);
+$dst = imagescale($src, 200, 200, IMG_BILINEAR_FIXED);
+echo "truecolor source\n";
+foreach ($coordinates as $coordinate) {
+ list($x, $y) = $coordinate;
+ printf("%3d, %3d: %x\n", $x, $y, imagecolorat($dst, $x, $y));
+}
+
+$src = imagecreate(100, 100);
+$white = imagecolorallocate($src, 255, 255, 255);
+imagefilledrectangle($src, 0,0, 99,99, $white);
+$dst = imagescale($src, 200, 200, IMG_BILINEAR_FIXED);
+echo "\npalette source\n";
+foreach ($coordinates as $coordinate) {
+ list($x, $y) = $coordinate;
+ printf("%3d, %3d: %x\n", $x, $y, imagecolorat($dst, $x, $y));
+}
+?>
+===DONE===
+--EXPECT--
+truecolor source
+ 0, 0: ffffff
+ 0, 199: ffffff
+199, 199: ffffff
+199, 0: ffffff
+
+palette source
+ 0, 0: ffffff
+ 0, 199: ffffff
+199, 199: ffffff
+199, 0: ffffff
+===DONE===