]> granicus.if.org Git - php/commitdiff
Fix #43475: Styled thick horizontal lines are scrambled
authorChristoph M. Becker <cmb@php.net>
Wed, 15 Jun 2016 18:58:06 +0000 (20:58 +0200)
committerChristoph M. Becker <cmb@php.net>
Thu, 16 Jun 2016 11:59:00 +0000 (13:59 +0200)
Thick lines are drawn by gdImageFilledRectangle(), which iterates over
the x ordinate first (Z order) to apply the style pattern. While this works
fine for vertical and diagonal lines, it obviously fails for horizontal
lines, which have to be iterated over in N order.

To fix this bug, we introduce the helpers  gdImageFilled(H|V)Rectangle(),
which may be reused for other purposes as well.

This is basically the same fix as libgd/libgd/c2b91dbc.

ext/gd/libgd/gd.c
ext/gd/tests/bug43475.phpt [new file with mode: 0644]
ext/gd/tests/bug43475.png [new file with mode: 0644]

index 5170f4f8c049fb8c9f45c99cd9794cd56f58701b..89c7dbdd5852c843017eb63949e82ef324ff1f47 100644 (file)
@@ -1051,11 +1051,13 @@ void gdImageAABlend (gdImagePtr im)
        }
 }
 
+static void _gdImageFilledHRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color);
+
 static void gdImageHLine(gdImagePtr im, int y, int x1, int x2, int col)
 {
        if (im->thick > 1) {
                int thickhalf = im->thick >> 1;
-               gdImageFilledRectangle(im, x1, y - thickhalf, x2, y + im->thick - thickhalf - 1, col);
+               _gdImageFilledHRectangle(im, x1, y - thickhalf, x2, y + im->thick - thickhalf - 1, col);
        } else {
                if (x2 < x1) {
                        int t = x2;
@@ -2120,10 +2122,53 @@ void gdImageRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
        }
 }
 
-void gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
+static void _gdImageFilledHRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
 {
        int x, y;
 
+       if (x1 == x2 && y1 == y2) {
+               gdImageSetPixel(im, x1, y1, color);
+               return;
+       }
+
+       if (x1 > x2) {
+               x = x1;
+               x1 = x2;
+               x2 = x;
+       }
+
+       if (y1 > y2) {
+               y = y1;
+               y1 = y2;
+               y2 = y;
+       }
+
+       if (x1 < 0) {
+               x1 = 0;
+       }
+
+       if (x2 >= gdImageSX(im)) {
+               x2 = gdImageSX(im) - 1;
+       }
+
+       if (y1 < 0) {
+               y1 = 0;
+       }
+
+       if (y2 >= gdImageSY(im)) {
+               y2 = gdImageSY(im) - 1;
+       }
+
+       for (x = x1; (x <= x2); x++) {
+               for (y = y1; (y <= y2); y++) {
+                       gdImageSetPixel (im, x, y, color);
+               }
+       }
+}
+
+static void _gdImageFilledVRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
+{
+       int x, y;
 
        if (x1 == x2 && y1 == y2) {
                gdImageSetPixel(im, x1, y1, color);
@@ -2165,6 +2210,11 @@ void gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int
        }
 }
 
+void gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
+{
+       _gdImageFilledVRectangle(im, x1, y1, x2, y2, color);
+}
+
 void gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h)
 {
        int c;
diff --git a/ext/gd/tests/bug43475.phpt b/ext/gd/tests/bug43475.phpt
new file mode 100644 (file)
index 0000000..b29b980
--- /dev/null
@@ -0,0 +1,59 @@
+--TEST--
+Bug #43475 (Thick styled lines have scrambled patterns)
+--SKIPIF--
+<?php
+       if (!extension_loaded('gd')) die("skip gd extension not available\n");
+?>
+--FILE--
+<?php
+require_once __DIR__ . '/similarity.inc';
+
+function setStyleAndThickness($im, $color, $thickness)
+{
+       $style = array();
+       $i = 0;
+       while ($i < 16 * $thickness) {
+               $style[$i++] = $color;
+       }
+       while ($i < 20 * $thickness) {
+               $style[$i++] = IMG_COLOR_TRANSPARENT;
+       }
+       while ($i < 28 * $thickness) {
+               $style[$i++] = $color;
+       }
+       while ($i < 32 * $thickness) {
+               $style[$i++] = IMG_COLOR_TRANSPARENT;
+       }
+       imagesetstyle($im, $style);
+       imagesetthickness($im, $thickness);
+}
+
+$im = imagecreate(800, 800);
+imagecolorallocate($im, 255, 255, 255);
+$black = imagecolorallocate($im, 0, 0, 0);
+
+setStyleAndThickness($im, $black, 1);
+imageline($im,  50, 250, 550, 250, IMG_COLOR_STYLED);
+imageline($im, 550, 250, 550, 750, IMG_COLOR_STYLED);
+imageline($im, 550, 750,  50, 250, IMG_COLOR_STYLED);
+
+setStyleAndThickness($im, $black, 2);
+imageline($im, 100, 200, 600, 200, IMG_COLOR_STYLED);
+imageline($im, 600, 200, 600, 700, IMG_COLOR_STYLED);
+imageline($im, 600, 700, 100, 200, IMG_COLOR_STYLED);
+
+setStyleAndThickness($im, $black, 4);
+imageline($im, 150, 150, 650, 150, IMG_COLOR_STYLED);
+imageline($im, 650, 150, 650, 650, IMG_COLOR_STYLED);
+imageline($im, 650, 650, 150, 150, IMG_COLOR_STYLED);
+
+setStyleAndThickness($im, $black, 6);
+imageline($im, 200, 100, 700, 100, IMG_COLOR_STYLED);
+imageline($im, 700, 100, 700, 600, IMG_COLOR_STYLED);
+imageline($im, 700, 600, 200, 100, IMG_COLOR_STYLED);
+
+$ex = imagecreatefrompng(__DIR__ . '/bug43475.png');
+var_dump(calc_image_dissimilarity($ex, $im) < 1e-5);
+?>
+--EXPECT--
+bool(true)
diff --git a/ext/gd/tests/bug43475.png b/ext/gd/tests/bug43475.png
new file mode 100644 (file)
index 0000000..774270f
Binary files /dev/null and b/ext/gd/tests/bug43475.png differ