1

I'm trying to draw some custom shapes on the canvas of a TImage, but the output ends up on the TImage parent form's canvas instead. It appears I have to convert my points from local to absolute to make this work, but that causes problems too. See example:

  • Does anyone know why Image.Canvas.DrawArc (etc) draws relative to the parent form instead of relative to the Image?
  • If I go through the trouble of .LocalToAbsolute... why does the arc look so different?

The project is simple: Firemonkey HD form with TPanel in the middle and TImage inside the TPanel (aligned to client). The button just executes the code.

Here's the code:

    unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, 
  FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls,
  FMX.Objects;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Panel1: TPanel;
    Image1: TImage;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}


procedure TForm1.Button1Click(Sender: TObject);
begin
  Image1.Canvas.BeginScene;

  {Trying to draw arc and line on Image's canvas - Doesn't work; it draws to Form's canvas instead}
  Image1.Canvas.DrawArc(PointF(0,0), PointF(10, 10), 0.0, 45.0, 1.0);
  Image1.Canvas.DrawLine(PointF(0.0, 0.0), PointF(100, 100), 1.0);

  {Trying to draw arc and line on Image's canvas - This works; by why should such steps be necessary and why is the arc so different?}
  Image1.Canvas.DrawArc(Image1.LocalToAbsolute(PointF(0,0)), Image1.LocalToAbsolute(PointF(10, 10)), 0.0, 45.0, 1.0);
  Image1.Canvas.DrawLine(Image1.LocalToAbsolute(PointF(0.0, 0.0)), Image1.LocalToAbsolute(PointF(100, 100)), 1.0);

  Image1.Canvas.EndScene;
end;

end.
Sir Rufo
  • 18,395
  • 2
  • 39
  • 73
Jeffam70
  • 11
  • 1
  • 3
  • Please include the generic `delphi` tag to your delphi related questions – Sir Rufo Jul 15 '14 at 23:16
  • Don't have XE6, but in XE5 you must draw in the image bitmap's canvas, i.e. Image1.Bitmap.Canvas.DrawArc(PointF(0,0), PointF(10, 10), 0.0, 145.0, 1.0); – LHristov Jul 16 '14 at 03:53
  • @SirRufo Thanks for the tips! I'll do that next time. – Jeffam70 Jul 16 '14 at 21:14
  • @LHristov Thanks. I tried that just now, but it didn't solve the problem. I changed the code (between BeginScene and EndScene) to be `Image1.Bitmap.Canvas.DrawArc(PointF(0,0), PointF(10, 10), 0.0, 145.0, 1.0);` `Image1.Bitmap.Canvas.DrawLine(PointF(0.0, 0.0), PointF(100, 100), 1.0);` The first doesn't seem to do anything at all, and the second causes an exception with an attempt to access address 0x00000000. – Jeffam70 Jul 16 '14 at 21:14
  • I'll add an answer with your code modified – LHristov Jul 17 '14 at 05:15

2 Answers2

0

As I mentioned before, this is for XE5. Here is you code:

procedure TForm3.Button1Click(Sender: TObject);
begin
  Image1.Bitmap.Canvas.BeginScene;

  {Trying to draw arc and line on Image's canvas - Doesn't work; it draws to Form's canvas instead}
  Image1.Bitmap.Canvas.DrawArc(PointF(0,0), PointF(10, 10), 0.0, 145.0, 1.0);
  Image1.Bitmap.Canvas.DrawLine(PointF(0.0, 0.0), PointF(200, 200), 1.0);

  {Trying to draw arc and line on Image's canvas - This works; by why should such steps be necessary and why is the arc so different?}
  Image1.Bitmap.Canvas.DrawArc(Image1.LocalToAbsolute(PointF(0,0)), Image1.LocalToAbsolute(PointF(10, 10)), 0.0, 45.0, 1.0);
  Image1.Bitmap.Canvas.DrawLine(Image1.LocalToAbsolute(PointF(0.0, 0.0)), Image1.LocalToAbsolute(PointF(100, 100)), 1.0);

  Image1.Bitmap.Canvas.EndScene;

end;

procedure TForm3.FormCreate(Sender: TObject);
begin
  Image1.Bitmap:=TBitmap.Create(trunc(image1.Width),trunc(image1.Height));
end;

You didn't paste bitmap's creation procedure.

LHristov
  • 1,103
  • 7
  • 16
  • Setting Image1.Bitmap internally calls Bitmap.Assign. Therefore you'd leak a TBitmap. – Sebastian Z Jul 18 '14 at 16:50
  • Well, I feel stupid for not creating the bitmap. Oops! But, either they changed something in XE6, or I'm doing something wrong still because there is no visible display from my code with the modifications you made. I'll try to back up and run in XE5 to confirm. – Jeffam70 Jul 19 '14 at 01:32
  • @Sebastian Z: Yes, but then Image1.Bitmap.SetSize is required as drawing on 0x0 bitmap throws an exception – LHristov Jul 20 '14 at 10:26
0

Well i've had some problems with this too and you should use a Bitmap as @LHristov said. The only thing is that there is a bug that doesn't set the bitmap size correctly and the fix for this is as follows:

procedure TForm3.FormCreate(Sender: TObject);
begin
  bitmap := TBitmap.Create;
  bitmap.SetSize(round(Image1.Width), round(Image1.Height));
  Image1.MultiResBitmap.Bitmaps[1].Assign(bit);
  Image1.Bitmap := Image1.MultiResBitmap.Bitmaps[1];
  Image1.Bitmap.Clear(TAlphaColorRec.White);
end;

procedure TForm3.Button1Click(Sender: TObject);
begin
  Image1.Bitmap.Canvas.BeginScene;

  Image1.Bitmap.Canvas.DrawArc(PointF(0,0), PointF(10, 10), 0.0, 145.0, 1.0);
  Image1.Bitmap.Canvas.DrawLine(PointF(0.0, 0.0), PointF(200, 200), 1.0);

  Image1.Bitmap.Canvas.DrawArc(Image1.LocalToAbsolute(PointF(0,0)), Image1.LocalToAbsolute(PointF(10, 10)), 0.0, 45.0, 1.0);
  Image1.Bitmap.Canvas.DrawLine(Image1.LocalToAbsolute(PointF(0.0, 0.0)), Image1.LocalToAbsolute(PointF(100, 100)), 1.0);

  Image1.Bitmap.Canvas.EndScene;

end;

Hope this solves it for you!

Remi
  • 1,289
  • 1
  • 18
  • 52