php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #43475 Thick styled lines have scrambled patterns
Submitted: 2007-12-02 02:10 UTC Modified: 2016-06-15 16:14 UTC
Votes:4
Avg. Score:3.8 ± 1.3
Reproduced:4 of 4 (100.0%)
Same Version:1 (25.0%)
Same OS:2 (50.0%)
From: lb2048 at pobox dot com Assigned: cmb
Status: Closed Package: GD related
PHP Version: 5.2CVS-2008-10-30 OS: *
Private report: No CVE-ID:
 [2007-12-02 02:10 UTC] lb2048 at pobox dot com
Description:
------------
Styled lines with thickness greater than 1 are not drawn correctly.
The style pattern is not visible, and the lines have a 'scrambled' or 
'plaid' appearance.


Reproduce code:
---------------
<?php
$img = imagecreate(800,800);
$bg = ImageColorAllocate($img, 255, 255, 255);
$fg = ImageColorAllocate($img,   0,   0,   0);
$style = array(); # Make a pattern of 16 on, 4 off, 8 on, 4 off
for ($i = 0; $i < 16; $i++) $style[] = $fg;
for ($i = 0; $i <  4; $i++) $style[] = IMG_COLOR_TRANSPARENT; 
for ($i = 0; $i <  8; $i++) $style[] = $fg;
for ($i = 0; $i <  4; $i++) $style[] = IMG_COLOR_TRANSPARENT;
ImageSetStyle($img, $style);
ImageSetThickness($img, 1);
ImagePolygon($img,array(50,250,550,250,550,750),3,IMG_COLOR_STYLED);
ImageSetThickness($img, 2);
ImagePolygon($img,array(100,200,600,200,600,700),3,IMG_COLOR_STYLED);
ImageSetThickness($img, 4);
ImagePolygon($img,array(150,150,650,150,650,650),3,IMG_COLOR_STYLED);
ImageSetThickness($img, 6);
ImagePolygon($img,array(200,100,700,100, 700,600),3,IMG_COLOR_STYLED);
ImagePng($img);

Expected result:
----------------
The output of the script is a PNG file. The image should contain 4 triangles drawn with a styled line (16 pixels on, 4 off, 8 on, 4 off).  From lower left to upper right, the triangles are drawn with line thickness 1, 2, 4, and 6 respectively. The styled pattern should be visible in all of the triangles.


Actual result:
--------------
The triangle with thickness 1 is correctly drawn. The other triangles are not correctly drawn with the desired line style, although the diagonal part of the thickness 2 triangle looks correct. The other lines appear to have a 'plaid' pattern. Using a 4x screen magnifier, I can see that the multiple parallel lines which make up the thick lines each have the correct style, but the patterns in these lines are offset relative to each other, so the overall appearance does not reflect the desired style.


Patches

PHP-code_to_patch_bug_43475.txt (last revision 2010-08-06 13:57 UTC) by php at imperium dot be)

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2008-10-24 16:01 UTC] jani@php.net
Please try using this CVS snapshot:

  http://snaps.php.net/php5.2-latest.tar.gz
 
For Windows:

  http://windows.php.net/snapshots/

And use the bundled GD library!
 [2008-10-27 01:50 UTC] lbayuk at pobox dot com
I tried php5.2-200810262330 (PHP 5.2.7RC3-dev), using bundled gd.
There is no difference. The problem is still there, and the image is
the same as in 5.2.6.
 [2008-10-30 17:03 UTC] jani@php.net
Assigned to the GD maintainer.
 [2010-08-02 21:55 UTC] php at imperium dot be
Lines *do* have the expected style, *EXCEPT* when they are at a 0 or 180 degree angle (e.g. x1==x2).  That is where the 'bug' is at.  This is probably because imageline tries to be more efficient than it should be, drawing a fast rectangle instead of a thick line.

In any case, the style pattern is applied towards the flow of the line instead of linear.  This is the correct approach imho and should not be changed.  To achieve the same style pattern with a line twice as thick you should double your imagesetstyle as well.  E.G. in your test case, 16+4+8+4 for thickness 1 would become 32+8+16+8 for thickness 2.

When you adjust your test case like this, you will see that all works as expected except for horizontal lines.  Thus, GD maintainer, please adjust the inner workings of imageline so it won't paint a rectangle instead of a thick line (at least not for thickness>1 or when using styled lines).

jacQues
 [2010-08-03 03:51 UTC] lbayuk at pobox dot com
OK, thanks, now I understand what it is doing.  It is applying the pixels from the style across the width of the line first, then along the length second. But I don't agree that it is working correctly. I think the width and style should be independent, and I think the current behavior may be unintentional.  Because gdImageSetPixel increments the style pointer for every pixel, then the order in which the higher-level drawing routines put down the pixels makes a difference in how the pattern is applied. Surely this cannot be useful.

As an example, the problem you found with horizontal and vertical lines. If the width is > 1, these are optimized as filled rectangles. But filled rectangles with IMG_COLOR_STYLED are unpredictable, because the result depends on the remainder when dividing the rectangle width by the style array size. (Try drawing 2 filled rectangles with an IMG_COLOR_STYLED pattern, where 1 rectangle is 1 pixel wider than the other. They will look very different.)

I would like to hear what the PHP GD maintainer thinks about this.

(FYI, now using PHP-5.3.3 with same results)
 [2015-05-07 18:09 UTC] cmb@php.net
-Status: Assigned +Status: Open -Type: Bug +Type: Documentation Problem -Assigned To: pajoye +Assigned To:
 [2015-05-07 18:09 UTC] cmb@php.net
> Lines *do* have the expected style, *EXCEPT* when they are at a
> 0 or 180 degree angle (e.g. x1==x2).

This issue seems to have been fixed in the meantime, see
<http://imgur.com/AIn9RLh>.

> I think the width and style should be independent, and I think
> the current behavior may be unintentional.

Even if it had been unintentional, changing it now would be a
massive BC break. However, I believe the behavior is intentional,
because as it is you can apply 2D styles instead of 1D styles
only. If you have the need for linear styles, you can use a
function such as ImageStyleThicken() contributed by jacQues.

All in all, this issue seems to be a documentation problem. The
imagesetstyle man page should be improved to document how the
function works for thick lines, and probably a respective example
should be added.
 [2015-05-08 00:05 UTC] lb2048 at pobox dot com
-: lbayuk at pobox dot com +: lb2048 at pobox dot com
 [2015-05-08 00:05 UTC] lb2048 at pobox dot com
I agree that changing the way it works would be bad, and the way it works should be better documented.

I do not agree that the issue raised by "jacQues" has been fixed. After replicating my pattern bits by the line thickness, as stated in that comment, I do see reasonable thick styled lines, except for horizontal lines.  Horizontal thick lines patterns look scrambled to me.  (jacQues said in 2010 that vertical lines were also bad. I don't see that now - my vertical lines seem OK.)

Now using php-5.6.8; same results with php-5.5.24.
 [2015-06-11 12:53 UTC] cmb@php.net
-Status: Open +Status: Suspended -Type: Documentation Problem +Type: Bug
 [2015-06-11 12:53 UTC] cmb@php.net
Sorry for the late reply.

> Horizontal thick lines patterns look scrambled to me.

Indeed! I had a closer look at the issue, and found that
horizontal and vertical lines do call gdImageFilledRectangle when
the thickness is greater than 1 for performance reasons.

The relevant code of gdImageFilledRectangle[1] loops over the x
and y coordinates, and calls gdImageSetPixel which iterates over
the style pattern[2]. As is, this works fine for vertical lines,
but not for horizontal lines. Swapping the for loops in
gdImageFilledRectangle will make horizontal lines look fine, but
will break vertical lines.

I'm not sure (yet) how to solve this issue, but anyhow, this is an
issue that should preferably be fixed upstream in libgd. I'll file
a bug report there later, and switch this ticket to "suspended"
until a resolution is found.

[1] <https://github.com/php/php-src/blob/PHP-5.6.9/ext/gd/libgd/gd.c#L2145-L2149>
[2] <https://github.com/php/php-src/blob/PHP-5.6.9/ext/gd/libgd/gd.c#L724-L735>
 [2015-06-11 17:15 UTC] cmb@php.net
-Assigned To: +Assigned To: cmb
 [2015-06-11 17:15 UTC] cmb@php.net
I have filed a ticket against libgd now.

I've noticed a minor issue wrt. to jacQues' ImageStyleThicken()
function: it only works correctly for even thickness values,
because libgd rounds odd thickness values to the next smaller even
value.
 [2015-06-11 17:15 UTC] cmb@php.net
The libgd ticket: <https://github.com/libgd/libgd/issues/167>.
 [2016-06-15 16:14 UTC] cmb@php.net
-Status: Suspended +Status: Open
 [2016-06-15 16:14 UTC] cmb@php.net
The bug has been fixed in libgd, so I'm reopening.
 [2016-06-16 12:23 UTC] cmb@php.net
Automatic comment on behalf of cmb
Revision: http://git.php.net/?p=php-src.git;a=commit;h=8aa511f1fc8123bba6107fa856b0b6bf298de87c
Log: Fix #43475: Styled thick horizontal lines are scrambled
 [2016-06-16 12:23 UTC] cmb@php.net
-Status: Assigned +Status: Closed
 [2016-06-22 05:58 UTC] krakjoe@php.net
Automatic comment on behalf of cmb
Revision: http://git.php.net/?p=php-src.git;a=commit;h=8aa511f1fc8123bba6107fa856b0b6bf298de87c
Log: Fix #43475: Styled thick horizontal lines are scrambled
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Wed Feb 22 20:01:42 2017 UTC