View Issue Details

IDProjectCategoryView StatusLast Update
0022646LazarusLCLpublic2017-09-25 12:10
ReporterДмитрийAssigned ToBart Broersma 
PrioritynormalSeveritymajorReproducibilityalways
Status resolvedResolutionfixed 
Product Version1.1 (SVN)Product Build 
Target Version1.6.2Fixed in Version1.6.2 
Summary0022646: Draw line at Pen.Style: = psPattern and Pen.width: = 1.
DescriptionIf you use Pen.style: = psPattern along with Pen.width: = 1, we obtain a one-pixel line in black, regardless of the previously set color.
If you put Pen.Width: => 1, all works correctly.

sample code:
var
   PenPattern:TPenPattern;
begin
 with buffer.Canvas do
 begin
  Pen.Mode:=pmCopy;
  Pen.Width:=1;
  Pen.Color:=clRed;
  SetLength(PenPattern, 4);
  PenPattern[0]:=10;
  PenPattern[1]:=5;
  PenPattern[2]:=2;
  PenPattern[3]:=5;
  pen.Style:=psPattern;
  Pen.SetPattern(PenPattern);
  LineTo(0,0,100,100);
 end;
end;
TagsNo tags attached.
Fixed in Revisionr53046
LazTarget1.6.2
WidgetsetWin32/Win64
Attached Files

Relationships

related to 0032465 closedZeljan Rikalo Graphic inconsistency Canvas.Pen 

Activities

wp

2016-09-11 00:41

developer  

Canvas-PenPattern.zip (2,002 bytes)

wp

2016-09-11 00:43

developer   ~0094568

The attached demo (Canvas_PenPattern) verifies the reported issue (Win 10, Laz trunk, FPC 3.0) But it shows also that the pattern and color are drawn correctly if the Cosmetic flag of the Pen is turned off.

Bart Broersma

2016-09-11 13:00

developer   ~0094576

Last edited: 2016-09-11 13:16

View 2 revisions

In
procedure TPen.ReferenceNeeded;
...
  IsGeometric := (Width > 1) or not Cosmetic;

This is the line that causes this behaviour.

In the example it will set IsGeometric to False and sets elpWidth to 0.
Later on in the call to ExtCreatePen it uses elpWith (zero), but MS documentation says:
" If dwPenStyle is PS_COSMETIC, the width must be set to 1."
(https://msdn.microsoft.com/en-us/library/windows/desktop/dd162705(v=vs.85).aspx)

However, setting elpWidth to 1 (in this example) draws a line with a diiferent pattern (no dots, only dashes and "spaces").
See: pen-pattern-bug-1.png

Bart Broersma

2016-09-11 13:16

developer  

pen-pattern-bug-1.png (21,897 bytes)
pen-pattern-bug-1.png (21,897 bytes)

Bart Broersma

2016-09-11 13:55

developer   ~0094578

Last edited: 2016-09-11 14:09

View 2 revisions

Setting elpWith to 0 in the call to ExtCreatePen (when style = psPattern) will result in a failure: Handle = 0.
This explains why the line is drawn as solid black (a default Pen is created then).

Bart Broersma

2016-09-11 14:16

developer   ~0094580

Last edited: 2016-09-11 14:27

View 4 revisions

Setting elpWidth to 1 when IsGeometric is False will result in different lines being drawn (Pen.Width=1, Pen.Cosmetic=True than currently.
Probably very different from what users may have intended.
See file pen-pattern-bug-elpWidth-1.png for an example with Pen.Style:=psDahDot.

Note1 : ATM Cosmetic seems to have no influence on drawing at all.
Note 2: All testing done on Windows.
Note 3: I cannot test Delphi behaviour of Pen.Cosmetic, since my Delphi 7 does not have such a property (nor does it have psPattern).

Bart Broersma

2016-09-11 14:16

developer  

wp

2016-09-11 15:03

developer   ~0094587

Last edited: 2016-09-11 15:48

View 3 revisions

I recently got myself the new Delphi Berlin Starter while it was free. And even this latest version does not have a Pen.Cosmetic and a psPattern. However there's a

- psAlternate (Help file: "Paints only every second pixel. Only applicable for "cosmetic" pens. Only valid for pens created by the API function ExtCreatePen."

- psUserStyle: (Help file: "uses a style array provided by the user". Only valid for pens created by the API funtion "ExtCreatePen").

The help file, however, does not say how ExtCreatPen must be called to create a pen and how that user-defined style pattern must be set up.

There's also this hint for TPen.Style: "If the property Width is not 1, then no dotted or dashed lines can be painted." This shows again how advanced Lazarus is!

wp

2016-09-11 16:10

developer   ~0094589

Last edited: 2016-09-11 16:11

View 2 revisions

Now I found here (http://www.swissdelphicenter.ch/en/showcode.php?id=2332) how to use the psUserStyle:

<<< DELPHI CODE >>>
procedure TForm1.PaintBox1Paint(Sender: TObject);
const
  PenPattern: array[1..4] of DWORD = (10, 5, 2, 5);
var
  logBrush: TLogBrush;
begin
  with Paintbox1.Canvas do
  begin
    Pen.Width := RadioGroup1.ItemIndex + 1;
    Pen.Color := clRed;
    Pen.Style := TPenStyle(RadioGroup2.ItemIndex);
    if Pen.Style = psUserStyle then begin
      logBrush.lbStyle := BS_SOLID;
      logBrush.lbColor := Pen.Color;
      Pen.Handle := ExtCreatePen(PS_GEOMETRIC or PS_USERSTYLE,
                                  Pen.Width,
                                  logBrush,
                                  Length(PenPattern), @PenPattern);
    end;
    MoveTo(0,0);
    LineTo(100,100);
  end;
end;

The psUserStyle line paints the correct pattern for both linewidths. And, as written in the docs, the other pen styles are drawn only if pen width = 1 (otherwise solid).

Bart Broersma

2016-09-11 22:52

developer   ~0094598

IMO elpWidth should be set to 1 (not to zero) when IsGeometric is False, 0 is an invalid value, but this only shows if Style = psPattern (ExtCreatePen returns zero).
However, I am afraid people will start complaining because now the results of drawing with Pen.Width will be radically different (because Cosmetic is True by default).

wp

2016-09-11 23:26

developer   ~0094600

I agree and would not change anything. Probably the use of Cosmetic should be documented better. The current description in the docs completely misses its effect on patterns: "Pens can be Cosmetic and Geomeric. Cosmetic pens are always 1 pixel wide, while geometric pens can have any width. But width of geometric pens are defined in world units and thus depends on transforms (scaling, rotation, shear, reflection) applied to canvas. Operations with cosmetic pens are faster."

Bart Broersma

2016-09-12 00:19

developer   ~0094602

Last edited: 2016-09-12 00:23

View 2 revisions

This part obviously is wrong though:

    if IsGeometric then
      elpWidth := Width
    else
      elpWidth := 0;

Not only the MS docs for ExtCreatePen say so (as pointed out above), but alos the MS docs for ExtLogPen structure:
https://msdn.microsoft.com/en-us/library/windows/desktop/dd162711(v=vs.85).aspx

elpWidth
    The width of the pen. If the elpPenStyle member is PS_GEOMETRIC, this value is the width of the line in logical units. Otherwise, the lines are cosmetic and this value is 1, which indicates a line with a width of one pixel.

I attached an updated sample project that lets you easiy play with Pen.Style, Pen.Width and Pen.Cosmetic.

Change

    if IsGeometric then
      elpWidth := Width
    else
      elpWidth := 1; //change this line

and see the difference (keep Pen.Widht=1) for each Pen.Style with Cosmetic true/false.

Bart Broersma

2016-09-12 00:20

developer  

penpattern.zip (3,005 bytes)

wp

2016-09-12 18:11

developer  

wp

2016-09-12 18:16

developer   ~0094616

Last edited: 2016-09-12 18:18

View 2 revisions

The screenshot "pen-pattern current-left modified-right" was taken from two versions of Bart's demo. The left image uses the current version of the graphics unit - it shows the issue reported by the OP. For the right image I modified graphics as suggested by Bart - the image is much better than the left one: color is correct, even the dash-dot pattern is visible, it just looks as if some scaling factor is wrong. For the other pens, line widths and cosmetic on/off I don't see any difference. So, I think Bart's modification is good. At least for Windows, I still have to check Linux.

P.S. I added a horizontal and vertical line because I need the dotted lines with cosmetic off as "hair" pattern in FPSpreadsheet.

wp

2016-09-12 18:51

developer   ~0094617

OK - now I ran the test program under Linux Mint with gtk2 and qt widgetsets (and Bart's patch applied).

- qt: perfect, all pen styles render correctly at both line widths, with and without cosmetic, with and without Bart's modification.

- gtk2: The psPattern is correct with and without cosmetic, some shift in pattern origin though, but not serious in my eyes; no change if linewidth is increased if Cosmetic is off. The other patterns have similar painting issues as you, Bart, reported for Windows, and they don't even paint fine with Cosmetic=true. In general it looks as if the patterns are too short. There's no change when switching back to the unmodified graphics unit.

So, coming back to the original issue of this report, I think that Bart's solution does not degrade painting on Linux gtk2/qt.

Bart Broersma

2016-09-12 23:28

developer   ~0094618

I asked opinions on devel list.

wp

2016-09-13 01:10

developer   ~0094619

I don't understand your note above "ATM Cosmetic seems to have no influence on drawing at all."

In my obserations it does. For Windows, standard pens do paint correctly if Cosmetic is on. It Cosmetic is off they don't (I think they still do but the pattern lengths are too short which drops some pixels). This does not change when elpWidth is altered from 0 or 1.

The psPattern pen paints correctly if Cosmetic is off, and only if elWidth is 1. If (with elpWidth=1) Cosmetic is turned on the line also has the requested dash-dot pattern, but the segment lengths are too long. If elpWidth is 0 the pattern is only drawn correctly at all for Cosmetic = false (black solid line).

Bart Broersma

2016-09-13 13:26

developer   ~0094631

> I don't understand your note above "ATM Cosmetic seems to have no influence on drawing at all."

In my first test it did nothing, but later it clearly does. Conclusion: my test was wrong.

Bart Broersma

2016-09-14 13:12

developer  

Bart Broersma

2016-09-14 13:14

developer   ~0094648

Last edited: 2016-09-14 13:14

View 2 revisions

Attached pen-reference-comparison.png
It shows all patterns with Cometic True/False and with "elpWidth := 1" fix (Cosmetic = True, since it does not alter the behaviour for Cosmetic = False).

Bart Broersma

2016-09-28 08:50

developer   ~0094846

Please test and close if OK.

Issue History

Date Modified Username Field Change
2012-08-15 14:17 Дмитрий New Issue
2012-08-15 14:17 Дмитрий Widgetset => Win32/Win64
2016-09-11 00:41 wp File Added: Canvas-PenPattern.zip
2016-09-11 00:43 wp Note Added: 0094568
2016-09-11 13:00 Bart Broersma Note Added: 0094576
2016-09-11 13:05 Bart Broersma LazTarget => -
2016-09-11 13:05 Bart Broersma Status new => confirmed
2016-09-11 13:16 Bart Broersma File Added: pen-pattern-bug-1.png
2016-09-11 13:16 Bart Broersma Note Edited: 0094576 View Revisions
2016-09-11 13:55 Bart Broersma Note Added: 0094578
2016-09-11 14:09 Bart Broersma Note Edited: 0094578 View Revisions
2016-09-11 14:16 Bart Broersma Note Added: 0094580
2016-09-11 14:16 Bart Broersma File Added: pen-pattern-bug-elpWidth-1.png
2016-09-11 14:19 Bart Broersma Note Edited: 0094580 View Revisions
2016-09-11 14:27 Bart Broersma Note Edited: 0094580 View Revisions
2016-09-11 14:27 Bart Broersma Note Edited: 0094580 View Revisions
2016-09-11 15:03 wp Note Added: 0094587
2016-09-11 15:05 wp Note Edited: 0094587 View Revisions
2016-09-11 15:48 wp Note Edited: 0094587 View Revisions
2016-09-11 16:10 wp Note Added: 0094589
2016-09-11 16:11 wp Note Edited: 0094589 View Revisions
2016-09-11 22:52 Bart Broersma Note Added: 0094598
2016-09-11 23:26 wp Note Added: 0094600
2016-09-12 00:19 Bart Broersma Note Added: 0094602
2016-09-12 00:20 Bart Broersma File Added: penpattern.zip
2016-09-12 00:23 Bart Broersma Note Edited: 0094602 View Revisions
2016-09-12 18:11 wp File Added: pen-pattern current-left modified-right.png
2016-09-12 18:16 wp Note Added: 0094616
2016-09-12 18:18 wp Note Edited: 0094616 View Revisions
2016-09-12 18:51 wp Note Added: 0094617
2016-09-12 23:28 Bart Broersma Note Added: 0094618
2016-09-13 01:10 wp Note Added: 0094619
2016-09-13 13:26 Bart Broersma Note Added: 0094631
2016-09-14 13:12 Bart Broersma File Added: pen-reference-comparison.png
2016-09-14 13:14 Bart Broersma Note Added: 0094648
2016-09-14 13:14 Bart Broersma Note Edited: 0094648 View Revisions
2016-09-20 18:12 Bart Broersma Assigned To => Bart Broersma
2016-09-20 18:12 Bart Broersma Status confirmed => assigned
2016-09-28 08:50 Bart Broersma Fixed in Revision => r53046
2016-09-28 08:50 Bart Broersma LazTarget - => 1.6.2
2016-09-28 08:50 Bart Broersma Note Added: 0094846
2016-09-28 08:50 Bart Broersma Status assigned => resolved
2016-09-28 08:50 Bart Broersma Fixed in Version => 1.6.2
2016-09-28 08:50 Bart Broersma Resolution open => fixed
2016-09-28 08:50 Bart Broersma Target Version => 1.6.2
2017-09-25 12:10 Zeljan Rikalo Relationship added related to 0032465