I just want to draw a vertical dotted thick line on a layer in ImgView32. I also want my line to be thicker so I draw multiple lines close to one another, because the Canvas.Pen.Width has no effect on the LineTo methods. So my code is as follows:
procedure TMainForm.PaintDottedHandler(Sender: TObject;Buffer: TBitmap32);
var
Cx, Cy,raza: Single;
W2, H2: Single;
I,J: Integer;
points:TArrayOfFloatPoint;
Center, Radius:TFloatPoint;
const
CScale = 1 / 200;
begin
if Sender is TPositionedLayer then
with TPositionedLayer(Sender).GetAdjustedLocation do
begin
W2 := (Right - Left) * 0.5;
H2 := (Bottom - Top) * 0.5;
Cx := Left + W2;
Cy := Top + H2;
W2 := W2 * CScale;
H2 := H2 * CScale;
Buffer.PenColor := clRed32;
Buffer.MoveToF(Cx-2,Top);
Buffer.LineToFSP(Cx-2 , Bottom);
Buffer.MoveToF(Cx-1,Top);
Buffer.LineToFSP(Cx-1 , Bottom);
Buffer.MoveToF(Cx,Top);
Buffer.LineToFSP(Cx , Bottom);
Buffer.MoveToF(Cx+1,Top);
Buffer.LineToFSP(Cx+1 , Bottom);
Buffer.MoveToF(Cx+2,Top);
Buffer.LineToFSP(Cx+2 , Bottom);
end;
end;
So the line is intended to be placed in the middle of the new layer. I add the layer using this:
procedure TMainForm.DottedLine1Click(Sender: TObject);
var
L: TPositionedLayer;
begin
L := CreatePositionedLayer;
L.OnPaint := PaintDottedHandler;
L.Tag := 2;
Selection := L;
end;
For the rest of the code just add my code to the Layers example and you will be able to reproduce my problem.
As far as I read, in order to draw a dotted line there are multiple aprroaches, like Stipple with LineToFSP (used in my code) or PolyPolygonFS with a BuildDashedLine points. But I cannot seem to make any of them to work corectly. Actually the second approach does not do anything... so I stick with my first approach. So it seems like everytime it starts drawing a line it's random the way the dotted line starts. So it's either a pixel, or an empty one. So when I resize the layer the line transforms like in the following images:
And in fact all I want to achieve is this:
And of course I want the line to be drawn again when resizing the layer without distorting it (that's why I use the onPaint handler approach). If I just draw a simple line on a layer (using Bitmap.Canvas) and then resize the layer, then the line would get distorted just like stretching a jpeg, so I want to avoid that.
So please tell me how to draw a thick dotted line on a layer in ImgView32 (TGraphics32)
EDIT
After trying the code from the answers I made it work. However there is a side-effect to this layer: when resizing the layer (using the mouse), at some widths the color of the dotted line is dimmed and blurred like bellow:
Before resizing After resizing (sometimes).
You can reproduce this yourself using the same code.
EDIT
There is another problem with this special layer: saving it to file... I tried to save it as a transparent PNG using 2 approaches but I keep getting a corrupted file. Even if I try to save the layer as Bitmap the same corruption occurs. Please check out this question too:
Graphics32 - saving transparent drawing layer to png
As @SpeedFreak mentioned you need to reset StrippleCounter
before each line draw call. You also need to setup up a proper line pattern for your line. This could be done by SetStripple
method. The trick is to set up this pattern correctly for the width of your line. If your line is 5 pixels wide then you need a pattern that will consist of 5 black pixels and 5 white pixels.
Try this out, I've removed unnecessary code (updated):
procedure TMainForm.PaintDottedHandler(Sender: TObject; Buffer: TBitmap32);
var
R: TRect;
Cx: Integer;
begin
if Sender is TPositionedLayer then
begin
// Five black pixels, five white pixels since width of the line is 5px
Buffer.SetStipple([clBlack32, clBlack32, clBlack32, clBlack32, clBlack32,
clWhite32, clWhite32, clWhite32, clWhite32, clWhite32]);
// We mest operate on integer values to avoid blurred line.
R := MakeRect(TPositionedLayer(Sender).GetAdjustedLocation);
Cx := R.Left + (R.Right - R.Left) div 2;
Buffer.StippleCounter := 0;
Buffer.MoveToF(Cx-2, R.Top);
Buffer.LineToFSP(Cx-2 , R.Bottom);
Buffer.StippleCounter := 0;
Buffer.MoveToF(Cx-1, R.Top);
Buffer.LineToFSP(Cx-1 , R.Bottom);
Buffer.StippleCounter := 0;
Buffer.MoveToF(Cx, R.Top);
Buffer.LineToFSP(Cx , R.Bottom);
Buffer.StippleCounter := 0;
Buffer.MoveToF(Cx+1, R.Top);
Buffer.LineToFSP(Cx+1 , R.Bottom);
Buffer.StippleCounter := 0;
Buffer.MoveToF(Cx+2, R.Top);
Buffer.LineToFSP(Cx+2 , R.Bottom);
end;
end;
And the result should be like on the picture:
The reason for which you've got "blurred" line from time to time when resizing layer is because you were operating on floating point values for drawing the line. You need to use integer values. I am guessing that in some cases drawing engine decided to draw a blurred pixel when your line was filling only the part of that pixel.
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With