Recent

Author Topic: BGRABitmap center and scale question  (Read 12969 times)

scons

  • Full Member
  • ***
  • Posts: 141
BGRABitmap center and scale question
« on: September 01, 2016, 12:15:05 am »
Hello,

I am trying to scale and center a drawing, but I can not seem to get it right unfortunatley.

I am loading data from a file to convert to a drawing (shown on a Tpanel), most of the time the drawings are a lot bigger then my panel, so it draws beyond the canvas.

So I want to rescale the drawing and center it on the panel.

To center I tried this:

Code: Pascal  [Select][+][-]
  1.     Panel1.Canvas.Clear();
  2.     bmp := TBGRABitmap.Create(Panel1.ClientWidth, Panel1.ClientHeight, BGRAWhite);
  3.  
  4.     bmp.Canvas2D.fontRenderer := TBGRAVectorizedFontRenderer.Create;
  5.     bmp.Canvas2D.font := '20px Arial';
  6.     bmp.Canvas2D.fillStyle(VGARed);
  7.     bmp.Canvas2D.textBaseline := 'bottom';
  8.  
  9.     c := ColorToBGRA(ColorToRGB(clWindowText));
  10.     bmp.JoinStyle := pjsRound;
  11.     boxX := (Panel1.ClientWidth) div 2;
  12.     boxY := (Panel1.ClientHeight) div 2;
  13.  
  14. {do some drawing}
  15.  
  16.       bmp.LineCap := pecSquare;
  17.       bmp.PenStyle := psSolid;
  18.  
  19.       bmp.DrawPolylineAntialias([PointF(abs(varX2) +10, 50),
  20.                                  PointF(abs(varX2) +10 + varX1 + varX2, 50),
  21.                                  PointF(abs(varX2) +10 + varX1 + 2*varX2, 50 + VarY1),
  22.                                  PointF(abs(varX2) +10 + varX2, 50 + varY1),
  23.                                  PointF(abs(varX2) +10, 50)], c, 3);
  24.  
  25.       bmp.DrawPolylineAntialias([PointF(abs(varX2) +10 + varX3, 50 + FlensX),
  26.                                  PointF(abs(varX2) +10 + varX1 + varX2 +varX3, 50 + FlensX)], c, 3);
  27.       bmp.DrawPolylineAntialias([PointF(abs(varX2) +10 + varX2 - varX3, 50 + varY1 - FlensX),
  28.                                  PointF(abs(varX2) +10 + VarX1 + 2*varX2 - varX3, 50 + varY1 - FlensX)], c, 3);
  29.  
  30.       bmp.ArrowStartAsClassic;
  31.       bmp.ArrowEndAsClassic(False,False,1);
  32.       bmp.DrawPolylineAntialias([PointF(abs(varX2) +10 + varX2, 2*50 + varY1),
  33.                                  PointF(abs(varX2) +10 + varX1 + varX2, 2*50 + varY1)],VGARed,w);
  34.       bmp.Canvas2D.fillText(varX,10 + varX1/2 + varX2 + varX3,2*50 + varY1);
  35.       bmp.Draw(Panel1.Canvas, 0, 0, False);
  36.       bmp.Free;
  37.  

So instead of centering the drawing (on screen), it shows it in the right bottom corner. I guess it just put the  zeroX and Y coördinates to the center of the Canvas ?

If I can fix this I can start thinking of a function that scales my drawing so it fits the Canvas.

Also, when I resize my application window on runtime, everything dissapears ? If I grab a side of the window, drag it to half of the drawing and back to its original state, half the drawing is gone. What causes this problem ?

Thanks
Windows 10-64bit Lazarus 2.0.12 + FPC 3.2.0

lainz

  • Hero Member
  • *****
  • Posts: 4473
    • https://lainz.github.io/
Re: BGRABitmap center and scale question
« Reply #1 on: September 01, 2016, 12:47:17 am »
Dont draw in a regular panel use bgravirtualscreen instead.

There are a lot of examples on how to use it and it solves the resizing problems.

circular

  • Hero Member
  • *****
  • Posts: 4224
    • Personal webpage
Re: BGRABitmap center and scale question
« Reply #2 on: September 01, 2016, 08:20:17 am »
@lainz: Using a BGRAVirtualScreen would make it cross-platform, however I understand that the problem scons is highlighting is about scaling the drawing.

@scons: I don't see where you use boxX and boxY.

I would suggest to do everything with Canvas2D because it provides translate and scale functions:
Code: [Select]
bmp.Canvas2D.save;
bmp.Canvas2D.translate(boxX,boxY);
bmp.Canvas2D.scale(...);
...
bmp.Canvas2D.restore;[/bmp]
Conscience is the debugger of the mind

scons

  • Full Member
  • ***
  • Posts: 141
Re: BGRABitmap center and scale question
« Reply #3 on: September 01, 2016, 11:54:59 am »
@ lainz & circular

Both thanks guys, I will try the provided solutions.
Windows 10-64bit Lazarus 2.0.12 + FPC 3.2.0

scons

  • Full Member
  • ***
  • Posts: 141
Re: BGRABitmap center and scale question
« Reply #4 on: September 01, 2016, 11:21:13 pm »
I would suggest to do everything with Canvas2D because it provides translate and scale functions:
Code: [Select]
bmp.Canvas2D.save;
bmp.Canvas2D.translate(boxX,boxY);
bmp.Canvas2D.scale(...);
...
bmp.Canvas2D.restore;[/bmp]

These have no effect whatsover. But I'm probably doing something wrong.

Code: Pascal  [Select][+][-]
  1.       { draw measure lines }
  2.       bmp.ArrowStartAsClassic;
  3.       bmp.ArrowEndAsClassic(False,False,1);
  4.       bmp.DrawPolylineAntialias([PointF(abs(varX2) + varX2, 50 + varY1),
  5.                                  PointF(abs(varX2) + varX1 + varX2, 50 + varY1)],VGARed,w);
  6.       bmp.Canvas2D.fillText(varX,10 + varX1/2 + varX2 + varX3,50 + varY1);
  7.  
  8.       bmp.Canvas2D.translate(boxX,boxY);
  9.       bmp.Canvas2D.save;
  10.       bmp.Canvas2D.scale(0.2);
  11.       bmp.Draw(Panel1.Canvas,0,0);
  12.       bmp.Canvas2D.restore;
  13.       bmp.Free;
  14.  
Windows 10-64bit Lazarus 2.0.12 + FPC 3.2.0

lainz

  • Hero Member
  • *****
  • Posts: 4473
    • https://lainz.github.io/
Re: BGRABitmap center and scale question
« Reply #5 on: September 02, 2016, 12:04:37 am »
Without a code to test I think no one can help you.

scons

  • Full Member
  • ***
  • Posts: 141
Re: BGRABitmap center and scale question
« Reply #6 on: September 02, 2016, 12:37:40 am »
Without a code to test I think no one can help you.

Thanks for jumping in but I have to correct myself !!!!

I just found out I have to recode my lines from bmp.DrawPolylineAntialias... to bmp.Canvas2D.lineto ...

Oh boy, what a learning curve ...
Windows 10-64bit Lazarus 2.0.12 + FPC 3.2.0

scons

  • Full Member
  • ***
  • Posts: 141
Re: BGRABitmap center and scale question
« Reply #7 on: September 02, 2016, 05:33:28 pm »
owkay, made a bit progress, but now I'm stuck again.

This is what I have so far :

Code: Pascal  [Select][+][-]
  1.     Val(varX, numX, error);
  2.     Val(varY, numY, error);
  3.     varX1 := numX;
  4.     varY1 := numY;
  5.     BGRAVirtualScreen1.Canvas.Clear();
  6.     boxX := (ClientWidth) div 4;
  7.     boxY := (ClientHeight) div 4;
  8.     bmp :=  TBGRABitmap.Create(BGRAVirtualScreen1.ClientWidth, BGRAVirtualScreen1.ClientHeight, BGRA(0,0,0,0));
  9.     tmp :=  TBGRABitmap.Create(BGRAVirtualScreen1.ClientWidth, BGRAVirtualScreen1.ClientHeight, BGRAWhite);
  10.     ctx := bmp.Canvas2D;
  11.     ttx := tmp.Canvas2D;
  12.     ctx.save();
  13.     ttx.save();
  14.     ctx.translate(boxX, boxY);
  15.     ttx.translate(boxX, boxY);
  16.     ttx.fontRenderer := TBGRAVectorizedFontRenderer.Create; //here we supply an adequate font renderer
  17.     ttx.font := '20px Calibri';
  18.     ttx.textBaseline := 'bottom';
  19.     ttx.textalign := 'center';
  20.     ctx.antialiasing := True;
  21.     ctx.lineWidth:=1;
  22.     ctx.scale(1, 1);
  23.     ttx.scale(1, 1);
  24.     ctx.pixelCenteredCoordinates := True;
  25.     ctx.StrokeStyle(clBlack);
  26.  
  27. ...
  28.  
  29.                 Val(sX, holX, error);
  30.                 Val(sY, holY, error);
  31.                 holY := varY1 - holY;
  32.                 Val(sline.ValueFromIndex[3], radX, error);
  33.                 radX1 := radX / 2;
  34.  
  35.                
  36.                 p2 := TBGRAPath.Create;
  37.                 p2.arc(abs(varX2) + holX + varX2, holY, radX1, degtorad(0), degtorad(360));
  38.                 p2.closePath();
  39.                 p2.copyTo(ctx);
  40.                 ctx.moveTo(abs(varX2) + holX + varX2, holY - RadX/2 - 5);
  41.                 ctx.lineTo(abs(varX2) + holX + varX2, varY1 + 105);
  42.                 ttx.fillStyle(VGARed);
  43.                 varM := varX2 + single(holX) + varX2;
  44.                 ttx.fillText(FloatToStrF(varM,ffFixed,10,2), abs(varX2) + holX + varX2, varY1 + 90);
  45.                 ttx.rotate(degtorad(90));
  46.                 ttx.fill();
  47.                ctx.moveTo(abs(varX2) + varX2 - 5, varY1 + 100);
  48.                ctx.lineTo(abs(varX2) + varX1 + varX2 + 5, varY1 + 100);
  49.  
  50.       ctx.fillStyle(BGRA(127, 130, 204, 255));
  51.       {draw outline}
  52.       p1 := TBGRAPath.Create;
  53.       p1.lineTo(abs(varX2), 0);
  54.       p1.lineTo(abs(varX2) + varX1 + varX2, 0);
  55.       p1.lineTo(abs(varX2) + varX1 + 2*varX2, VarY1);
  56.       p1.lineTo(abs(varX2) + varX2, varY1);
  57.       p1.lineTo(abs(varX2), 0);
  58.       p1.closePath();
  59.       p1.copyTo(ctx);
  60.       ctx.fill();
  61.      
  62.  
  63.       {draw flange thickness}
  64.       p3 := TBGRAPath.Create;
  65.       p3.lineTo(abs(varX2) + varX3, FlensX);
  66.       p3.lineTo(abs(varX2) + varX1 + varX2 +varX3, FlensX);
  67.       p3.closePath();
  68.       p3.copyTo(ctx);
  69.  
  70.       p4 := TBGRAPath.Create;
  71.       p4.lineTo(abs(varX2) + varX2 - varX3, varY1 - FlensX);
  72.       p4.lineTo(abs(varX2) + VarX1 + 2*varX2 - varX3, varY1 - FlensX);
  73.       p4.closePath();
  74.       p4.copyTo(ctx);
  75.       ctx.stroke();
  76.  
  77.       { draw measure lines }
  78.       ctx.moveTo(abs(varX2) + varX2 - 5, varY1 + 100+50);
  79.       ctx.lineTo(abs(varX2) + varX1 + varX2 + 5, varY1 + 100+50);
  80.       ctx.moveTo(abs(varX2) + varX2, varY1 + 5);
  81.       ctx.lineTo(abs(varX2) + varX2 , varY1 + 100+55);
  82.       ctx.moveTo(abs(varX2) + varX1 + varX2 , varY1 + 5);
  83.       ctx.lineTo(abs(varX2) + varX1 + varX2 , varY1 + 100+55);
  84.       ctx.stroke();
  85.       ctx.fillStyle(VGARed);
  86.       ctx.fillText(varX, (abs(varX2) + varX1 + varX2)/2, varY1 + 100+50);
  87.       ctx.fillText('Calibri', (abs(varX2) + varX1 + varX2)/2, 100 + varY1);
  88.       ctx.fill();
  89.  
  90.       bmp.Draw(tmp.Canvas, 0, 0, True);
  91.       bmp.Draw(BGRAVirtualScreen1.Canvas, 0, 0, True);
  92.       tmp.Free;
  93.       bmp.Free;
  94.  
  95.  

The main image is show OK, so that was an achievement for me.

ctx. ... is the drawing
ttx. ... is the text and some lines I would like to see in another color

Things that still goes wrong:

  • changing from a TPanel to a VirtualScreen didn't cure the erasing of the image problem when resizing my runtime window
  • I can not merge the to bitmaps together
  • when I change the color of a line, all the lines change from color, I inly want some lines to change color
  • when I tried a gradient color on top of another, I only saw the gradient
  • the inner circle has to be white, my mask attemp did not really work, everything was black except the circles ...
  • turning text (rotating) although this could be ok but I can not see the text anymore because of the merging problem

Things I still want to implement/change:

  • add a gradient color at the top and bottom, something 'shadowish'
  • add save button
  • add print button
  • select a circle from the image and look at it's coördinates
  • mouse zooming and panning in the VirtualScreen

So what I would like to learn now is, in short, how mix & match different colours, merging these together. maybe layers works better on a Canvas2D ?
Windows 10-64bit Lazarus 2.0.12 + FPC 3.2.0

circular

  • Hero Member
  • *****
  • Posts: 4224
    • Personal webpage
Re: BGRABitmap center and scale question
« Reply #8 on: September 02, 2016, 05:50:34 pm »
Hello scons!

Do you need to have a separate image for the text? It would be simpler to use the same canvas.

To change the line color, you need to call strokeStyle each time you change it, before you call stroke().

You need to call beginPath each time you start a shape.

You don't need to use TBGRAPath to add a path, you can call directly the functions of Canvas2d.

Regards
Conscience is the debugger of the mind

scons

  • Full Member
  • ***
  • Posts: 141
Re: BGRABitmap center and scale question
« Reply #9 on: September 02, 2016, 10:06:18 pm »
Allrighty, recoded the whole part we are getting back on track. Thanks for the tips  Circular. Things are making sense, step by step  ::)

3 questions :

- can someone please explain to me why the drawing dissapears when you resize the form on runtime ? I still am missing something there. (drop the textfile in the listbox on the left)
- is there a way to get the image centered on the screen after it is drawn ? I never know how big it will be so I need to find a way to get the whole image and the do the scaling.
- how can turn the text 90 degrees ? what is the selector ?
« Last Edit: September 02, 2016, 10:07:54 pm by scons »
Windows 10-64bit Lazarus 2.0.12 + FPC 3.2.0

lainz

  • Hero Member
  • *****
  • Posts: 4473
    • https://lainz.github.io/
Re: BGRABitmap center and scale question
« Reply #10 on: September 02, 2016, 10:25:09 pm »
1) It disapears because you don't used the OnRedraw event

Code: Pascal  [Select][+][-]
  1. procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);
  2. begin
  3.   // Draw only here using Bitmap.something , it then is drawn automatically to the control itself
  4. end;  

So you change all the properties you need outside that event, for example in ListBox1Click, then when you're ready you can do:
Code: Pascal  [Select][+][-]
  1. BGRAVirtualScreen1.DiscardBitmap;

2) If in some way you can measure it and get the width and height you can: create a temporary bitmap with the width and height, then resample to fit and draw into the Bitmap, something like:

Code: Pascal  [Select][+][-]
  1. Temp: TBGRABitmpap;
  2. ...
  3. Temp := TBGRABitmap.Create(widthYouKnow, heightYouKnow);
  4. Temp.DrawHereEverything; // draw on it
  5. BGRAReplace(Temp, Temp.Resample(...)); // resample
  6.  
  7. Bitmap.PutImage(... ... Temp ... ...); // draw on control
  8.  
  9. Temp.Free; // free temp

3) I don't know, ask circular :)

circular

  • Hero Member
  • *****
  • Posts: 4224
    • Personal webpage
Re: BGRABitmap center and scale question
« Reply #11 on: September 02, 2016, 11:20:10 pm »
1) Agreed

2) Resampling would be slow but the thing here is more that the total size is not known at first. One way would be to go first through the points and determine the min-max and the transform

3) In Canvas2D, the rotate transform applies also to the text. So first call save() then rotate() then draw the text and then call restore()
Conscience is the debugger of the mind

scons

  • Full Member
  • ***
  • Posts: 141
Re: BGRABitmap center and scale question
« Reply #12 on: September 03, 2016, 12:54:24 am »
Thanks guys

Adding this right after the bmp.draw event
Code: Pascal  [Select][+][-]
  1.       bmp.Draw(BGRAVirtualScreen1.Canvas, 0, 0, True);
  2.       BGRAVirtualScreen1.Bitmap.PutImage(0,0,bmp,dmDrawWithTransparency);

and then this
Code: Pascal  [Select][+][-]
  1. procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);
  2. begin
  3.   Bitmap.PutImage(0, 0, bmp, dmDrawWithTransparency);
  4. end;

did solve the disapearing of the drawing on the window resize.
« Last Edit: September 03, 2016, 12:56:20 am by scons »
Windows 10-64bit Lazarus 2.0.12 + FPC 3.2.0

lainz

  • Hero Member
  • *****
  • Posts: 4473
    • https://lainz.github.io/
Re: BGRABitmap center and scale question
« Reply #13 on: September 03, 2016, 01:18:11 am »
Thanks guys

Adding this right after the bmp.draw event
Code: Pascal  [Select][+][-]
  1.       bmp.Draw(BGRAVirtualScreen1.Canvas, 0, 0, True);
  2.       BGRAVirtualScreen1.Bitmap.PutImage(0,0,bmp,dmDrawWithTransparency);

and then this
Code: Pascal  [Select][+][-]
  1. procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);
  2. begin
  3.   Bitmap.PutImage(0, 0, bmp, dmDrawWithTransparency);
  4. end;

did solve the disapearing of the drawing on the window resize.

Where you put this code:

Code: Pascal  [Select][+][-]
  1. bmp.Draw(BGRAVirtualScreen1.Canvas, 0, 0, True);
  2.       BGRAVirtualScreen1.Bitmap.PutImage(0,0,bmp,dmDrawWithTransparency);

Replace that code with:

Code: Pascal  [Select][+][-]
  1. BGRAVirtualScreen1.DiscardBitmap;

It will call the event and draw the bitmap, there is no need to draw on the canvas of the BGRAVirtualScreen, only draw on the event.

Code: Pascal  [Select][+][-]
  1. Bitmap.PutImage(0, 0, bmp, dmDrawWithTransparency);

This code is OK. However, maybe you can use dmSet since your bmp is fully opaque.

scons

  • Full Member
  • ***
  • Posts: 141
Re: BGRABitmap center and scale question
« Reply #14 on: September 03, 2016, 08:34:01 am »
Lainz if I do that, I get an empty screen.
Windows 10-64bit Lazarus 2.0.12 + FPC 3.2.0

 

TinyPortal © 2005-2018