2

I need to draw rotated bitmap on an another bitmap's canvas (main Bitmap). But i have no idea how.

I tried to rotate bitmap with TBitMap.Rotate method and then draw it on main BitMap with TCanvas.DrawBitmap method, but it takes a lot of time (i need to draw ~100 same Bitmaps with different angles):

  1. resize BMP
  2. rotate BMP
  3. draw on another canvas

How to immediately draw rotated bitmap without 1 and 2 steps?

Example:

var
  Form1: TForm1;
  MainBMP: TBitMap;
  SomeItem: TBitMap;
  buffBMP: TBitMap;

implementation

{$R *.fmx}


procedure TForm1.FormCreate(Sender: TObject);
begin
  MainBMP := TBitMap.Create;
  MainBMP.SetSize(screen.Width, screen.Height);
  SomeItem := TBitMap.Create;
  SomeItem.SetSize(50, 50);
  with SomeItem.Canvas do
  begin
    BeginScene;
    FillRect(rectF(0, 0, 50, 50), 5, 20, allCorners, 1);
    EndScene;
  end;
  buffBMP := TBitMap.Create;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
  i: integer;
  rect, sizeRect: TRectF;
begin
  MainBMP.Canvas.BeginScene;
  MainBMP.Canvas.Clear($FF777777);
  for i := 1 to 10000 do
  begin
    buffBMP.Assign(SomeItem);
    buffBMP.Rotate(random(360));
    sizeRect := rectF(0, 0, buffBMP.Width, buffBMP.Height);
    rect := sizeRect;
    rect.Offset(random(1200), random(600));
    MainBMP.Canvas.DrawBitmap(buffBMP, sizeRect, rect, 1);
  end;
  MainBMP.Canvas.EndScene;
  Form1.Canvas.BeginScene;
  Form1.Canvas.DrawBitmap(MainBMP, ClientRect, ClientRect, 1);
  Form1.Canvas.EndScene;
end;

without

buffBMP.Rotate(random(360));

it takes 16-32 ms. With this method: ~8500 ms

I'm searching for some method like

TCanvas.DrawBitmap(const ABitmap: TBitmap; const SrcRect, DstRect: TRectF; const AOpacity: Single; const HighSpeed: Boolean);

but with added Angle: single parametr

Android. FMX.

Thanks.

  • Here are bitmap rotation examples using scanline http://www.efg2.com/Lab/ImageProcessing/Unit7.TXT – Jasper Schellingerhout Aug 11 '15 at 20:18
  • @JasperSchellingerhout it is only 180, 90 and 270. I need to rotate on fractional angles like 12.5, 186.23 and etc. – Vlad Romanovsky Aug 11 '15 at 21:22
  • what speed do you need and what resolution and bitdepth are the images? what is the bottleneck? resize of target image should be fast rotation is just copying pixels + rotation transformation which needs: 1x `cos`,1x `sin` 4x `*` and 2x `+/-` in FPU then 2 conversions to `int` that should be fast enough (if you also use bilinear filtering it is a bit slower but not much) you should loop through all destination pixels not the source ones to avoid holes in output. – Spektre Aug 12 '15 at 07:06
  • You can significantly speed this up with minimizing ScanLine[] calls to minimum also see [Graphics::TBitmap](http://stackoverflow.com/a/21699076/2521214) Also I hope you are resizing both x,y axises at once not one by one ... – Spektre Aug 12 '15 at 07:07
  • @Spektre post updated – Vlad Romanovsky Aug 12 '15 at 14:14
  • @VladRomanovsky You forget to add: What resolution of images you use? What speed you need (on which HW as you are adding Android to OP) do yo need opacity? Why are you drawing/rotating 10000 times? some kind of effect? In that case may be OpenGL will be much better as the GPU is exactly for this kind of stuff CPU+GDI is too slow for such transfere speeds ... for example 256x256x32bit image * 10000 = ~2.44GB per frame not counting transferes related with processing ... + the code for rotation and combining images (GPU's have native HW support for all of this) – Spektre Aug 13 '15 at 06:40
  • @Spektre images less then 256x256 (128x74, 256x200, 10x30 and etc.). Android snapdragon 801, adreno 330, 2gb ram, 1920x1080. Game :D. 10000 just for test. I need more than 800 and less then 3000 with perfect fps (30). – Vlad Romanovsky Aug 13 '15 at 10:41

1 Answers1

2

You should use a transformation Matrix instead of the Rotate method on the bitmap.

Such could look like:

procedure TForm1.Timer1Timer(Sender: TObject);
var
  I: Integer;
  R: TRectF;
  SaveMatrix: TMatrix;
  Matrix: TMatrix;
begin
  MainBMP.Canvas.BeginScene;
  MainBMP.Canvas.Clear($FF777777);
  SaveMatrix := MainBmp.Canvas.Matrix;
  for I := 1 to 1000 do
  begin
    BuffBMP.Assign(SomeItem);
    R := RectF(0, 0, BuffBMP.Width, BuffBMP.Height);
    Matrix := CreateRotationMatrix(DegToRad(Random(360)));
    Matrix.m31 := Random(1200);
    Matrix.m32 := Random(600);
    MainBMP.Canvas.SetMatrix(Matrix);
    MainBMP.Canvas.DrawBitmap(buffBMP, R, R, 1, True);
  end;
  MainBMP.Canvas.SetMatrix(SaveMatrix);
  MainBMP.Canvas.EndScene;
  Canvas.BeginScene;
  Canvas.DrawBitmap(MainBMP, ClientRect, ClientRect, 1);
  Canvas.EndScene;
end;
NGLN
  • 43,011
  • 8
  • 105
  • 200