Search code examples
androiddelphifiremonkeydelphi-10-seattle

Draw text on image


I'm trying to draw text on image using the below code :

procedure TfMain.TextToImage(const AText: string; const AImage: TImage);
begin
  if NOT Assigned(AImage) then Exit;    
  AImage.Canvas.BeginScene;
  AImage.Canvas.Font.Size    := 18;
  AImage.Canvas.Font.Family  := 'Arial';
  AImage.Canvas.Fill.Color   := TAlphaColorRec.Dodgerblue;
  AImage.Canvas.Font.Style   := [TFontStyle.fsbold];
  AImage.Canvas.FillText( AImage.AbsoluteRect,
                          AText,
                          False,
                          1,
                          [TFillTextFlag.RightToLeft],
                          TTextAlign.taCenter,
                          TTextAlign.taCenter);
  AImage.Canvas.EndScene;
end;

Q: Why the above procedure works on Windows but not in android ?


Solution

  • Try to draw directly on the TBitmap of the timage instead of the Canvas of the TImage.

    You need also to create a bitmap of your image before you try to access it:

    AImage.Bitmap := TBitmap.Create(Round(AImage.Width), Round(AImage.Height));
    

    So the correct code will be something like this:

    procedure TfMain.TextToImage(const AText: string; const AImage: TImage);
    begin
      if NOT Assigned(AImage) then Exit;
      AImage.Bitmap := TBitmap.Create(Round(AImage.Width), Round(AImage.Height));
      AImage.Bitmap.Canvas.BeginScene;
      try
        //....
        // Use AImage.Bitmap.Canvas as needed
        AImage.Bitmap.Canvas.FillText( AImage.AbsoluteRect,
                                AText,
                                False,
                                1,
                                [],
                                TTextAlign.Center,
                                TTextAlign.Center);
      finally
        AImage.Bitmap.Canvas.EndScene;
      end;
    end;
    

    From the TImage.Paint event code you will see:

    procedure TImage.Paint;
    var
      R: TRectF;
    begin
      if (csDesigning in ComponentState) and not Locked and not FInPaintTo then
      begin
        R := LocalRect;
        InflateRect(R, -0.5, -0.5);
        Canvas.DrawDashRect(R, 0, 0, AllCorners, AbsoluteOpacity, $A0909090);
      end;
    
      UpdateCurrentBitmap;
      if FCurrentBitmap <> nil then
        DrawBitmap(Canvas, LocalRect, FCurrentBitmap, AbsoluteOpacity);
    end;
    

    So no matter what you will paint on the canvas, on the next repaint it will draw again the full bitmap erasing what you already done.

    If you don't want to touch the bitmap than you need to override the OnPaint event of theTImage and call function TextToImage(const AText: string; const AImage: TImage);