Drawing on an Image

Find TImage under the Additional component tab. You will notice that we needed to change very little code from that used in Drawing on a Canvas. We call the paint procedure when the form is created and when it is resized. Unlike the PaintBox demonstration on the previous page, the graphic displays if you minimise then restore the form and it scales appropriately when you resize the form. (For fast rendering to a TImage and for the transformations usually necessary for motion graphics you can use a TGLCanvas as demonstrated in our Box2D examples).

The Pascal and code of the form follow the screenshot.

Output after resizing the form

Output after resizing the form

Pascal Code of Unit

unit uImageDemo;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls;

type

  TForm1 = class(TForm)
    Image1: TImage;
    procedure FormCreate(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure Image1Paint(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1Paint(Sender);
end;

procedure TForm1.FormResize(Sender: TObject);
begin
  Image1Paint(Sender);
end;

procedure TForm1.Image1Paint(Sender: TObject);
const
  HB = 10;     // Horizontal border
  VB = 10;     // Vertical border
var
  MaxWidth, MaxHeight, MaxX, MaxY, Col1, Col2, Col3, Row1, Row2, Row3,
  X, Y, CellWidth, CellHeight, CentreX, CentreY, Radius: integer;
  PentagonPoints: array[1 .. 6] of TPoint;
  TrianglePoints: array[1 .. 4] of TPoint;

  procedure RenderRow1;
  begin
    with Image1.Canvas do
      begin
        //  Red rectangle
        pen.Color := clRed;
        rectangle(HB , VB, Col1 - HB, Row1 - VB);
        //  Yellow filled rectangle
        brush.Color := clYellow;
        rectangle(Col1 + HB, VB, Col2 - HB, Row1 - VB);
        //  Green circle needs bounding square
        pen.Color := clGreen;
        brush.Color := clBtnFace;
        CentreX := (Col2 + Col3) div 2;
        CentreY := Row1 div 2;
        CellWidth := Col1 - 2 * HB;
        CellHeight := Row1 - 2 * VB;
        if CellWidth < CellHeight then
          Radius := CellWidth div 2
        else
          Radius := CellHeight div 2;
        ellipse(CentreX - Radius, CentreY - Radius,  CentreX + Radius, CentreY + Radius);
        //  Blue filled ellipse needs bounding rectangle
        pen.Color := clBlue;
        brush.Color := clBlue;
        ellipse(Col3 + 2 * HB, VB, MaxX - 2 * HB, Row1 - VB);
      end;
  end;

  procedure RenderRow2;
  begin
    with Image1.Canvas do
      begin
        //  Aqua line (solid)
        pen.Color := clAqua;
        pen.width := 4;
        moveTo(HB, Row1 + VB);
        lineTo (Col1 - HB, Row2 - VB);
        //  Teal dashed line
        moveTo( Col1 + HB, Row2 - VB);
        pen.Width := 1;
        pen.Style := psDash;
        pen.Color:= clTeal;
        lineTo(Col2 - HB, Row1 + VB);
        //  BtnFace ellipse with light grey outline
        pen.Color := clLtGray;
        pen.Style := psSolid;
        brush.Color := clBtnFace;
        Ellipse(Col2 + 2 * HB, Row1 + VB, Col3 - 2 * HB, Row2 - VB);
        //Purple filled circle
        pen.Color := clPurple;
        brush.Color := clPurple;
        CentreX := (Col3 + MaxX) div 2;
        CentreY := (Row1 + Row2) div 2;
        ellipse(CentreX - Radius, CentreY - Radius,  CentreX + Radius, CentreY + Radius);
      end;
  end;

  procedure RenderRow3;
  begin
    with Image1.Canvas do
      begin
        //  Three quarters of lime ellipse
        pen.Color := clLime;
        brush.Color := clLime;
        pie(HB, Row2 + VB, Col1-HB, Row3 - VB, HB + Row1 div 2, Row2 + VB,
           Row2 + VB + Row1 div 2, Row2 + VB + Row1 div 2);
        //  Dark grey rounded rectangle
        pen.Color := clDkGray;
        brush.Color := clDkGray;
        roundRect(Col1 + 2 * HB, Row2 + VB, Col2 - 2 * HB, Row3 - VB, 20, 20);
        //Fuchsia  pentagon
        pen.color := clFuchsia;
        PentagonPoints[1] := Point((Col3 + Col2) DIV 2,Row2 + VB);
        PentagonPoints[2] := Point(Col3 - HB,(Row2 + Row3) DIV 2);
        PentagonPoints[3] := Point(Col3 - (Col1 DIV 3), Row3 - VB);
        PentagonPoints[4] := Point(Col2 + (Col1 DIV 3), Row3 - VB);
        PentagonPoints[5] := Point(Col2 +  HB,(Row2 + Row3) DIV 2);
        PentagonPoints[6] := PentagonPoints[1];
        polyline(PentagonPoints);
        //  Red filled triangle
        pen.Color := clRed;
        brush.Color := clRed;
        TrianglePoints[1] := Point((Col3 + MaxX) DIV 2, Row2 + VB);
        TrianglePoints[2] := Point(MaxX - HB, Row3 - VB);
        TrianglePoints[3] := Point(Col3 + HB, Row3 - VB);
        TrianglePoints[4] := TrianglePoints[1];
        polygon(TrianglePoints);
      end;
  end;

  procedure RenderRow4;
  var
    Count: integer;
  begin
    with Image1.Canvas do
      begin
        //  Navy arc of ellipse
        pen.Color := clNavy;
        arc(HB, Row3 + VB, Col1 - HB, MaxY - VB,
            HB + Row1 div 2, Row3 + VB, HB, Row3 + VB + Row1 div 2);
        //Blue text
        font.Color := clBlue;
        font.Size := 10;
        TextOut(col1 + HB, (Row3 + MaxY) DIV 2, 'pp4s.co.uk');
        //  Maroon curve
        pen.Color := clMaroon;
        brush.Color := clMaroon;
        Count := 0;
        X := Col2 + HB;
        Y := Row3 + VB;
        while (X <= Col3) and (Y <= MaxY) do
          begin
            Rectangle(X - 1, Y - 1, X + 1, Y + 1);
            inc(Count);
            X := Col2 + HB + (Count * MaxX ) DIV 40;
            Y := Row3 + VB + (Count * Count * MaxY) DIV 150;
          end;
        pen.Color := clNavy;
        brush.Color := clSilver;
        Chord(HB + Col3, VB + Row3, MaxX - HB, MaxY - VB,
              HB + Col3, VB + Row3, MaxX - HB, MaxY - VB);
      end;
  end;

begin
  Image1.Width := Form1.ClientWidth;
  Image1.Height := Form1.ClientHeight;
  Image1.Canvas.Brush.Color := clWhite;
  Image1.Canvas.rectangle(0, 0, Image1.ClientWidth, Image1.ClientHeight);
  MaxWidth := Image1.ClientWidth;
  MaxHeight := Image1.ClientHeight;
  Col1 := MaxWidth DIV 4;  //  End of column
  Col2 := MaxWidth DIV 2;
  Col3 := Col1 + Col2;
  Row1 := MaxHeight DIV 4;   //  End of row
  Row2 := MaxHeight DIV 2;
  Row3 := Row1 + Row2;
  MaxX := MaxWidth;
  MaxY := MaxHeight;
  RenderRow1;
  RenderRow2;
  RenderRow3;
  RenderRow4;
end;

end.

Code of Form

object Form1: TForm1
  Left = 522
  Height = 450
  Top = 94
  Width = 450
  Caption = 'Image Demo'
  ClientHeight = 450
  ClientWidth = 450
  OnCreate = FormCreate
  OnResize = FormResize
  LCLVersion = '1.2.4.0'
  object Image1: TImage
    Left = 0
    Height = 450
    Top = 0
    Width = 450
    OnPaint = Image1Paint
  end
end    

Gradient Fill

Replace the rectangle code at the start of procedure RenderRow1 with the following to output rectangles with horizontal and vertical gradient painting.

  procedure RenderRow1;
  var
    Rect: TRect;
  begin
    Rect.Left := HB;
    Rect.Top := VB;
    Rect.Right := Col1 - HB;
    Rect.Bottom := Row1 - VB;

    with Image1.Canvas do
      begin
        // rectangle with horizontal gradient fill
        GradientFill(Rect, clRed, clGreen, gdHorizontal);
        // rectangle with vertical gradient fill
        Rect.Left:= Rect.Left + Col1;
        Rect.Right:= Rect.Right + Col1;
        GradientFill(Rect, clWhite, clGreen, gdVertical);        

Programming - a skill for life!

Using widgets (such as list boxes, combo boxes, string grids, DBgrids, charts and maps) and drawing on the canvas