Bookstore

 Computer Math and Games in Pascal (preview) Lazarus Handbook

Author Topic: Building a composite image  (Read 3277 times)

J-G

• Hero Member
• Posts: 939
Building a composite image
« on: June 10, 2022, 06:24:00 pm »
As a different approach to my question in the general [Graphic] forum (Trapping non-available resource), I'm looking at using some feature of BGRA..... to combine 4 images into one.

The issue is that I need an image which is variable in size but certain elements need to remain at a constant size and others vary according to the overall size but at a constant difference to each other !!!    Phew !! that took some working out.

Full picture - - -  Gears,  these images must retain a centre portion which is always the same but three other parts which must be scaled. Of the four images attached, the 'OD' would be the first to be sized and added, then the 'PCD' which would be 10px smaller, then the 'Root' a further 11px smaller and finally the centre which would remain at its original size.   I'm sure you can see why a single image 'scaled' can't be used.

A number (Tooth count) would also be added but that would be trivial if the basic 'build' could be achieved.

I could position the four separate images I suppose but there could be up to 6 gears to draw and I suspect that placing a single image would be more efficient.

« Last Edit: June 10, 2022, 06:26:17 pm by J-G »
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0
Win 7 Ult 64

J-G

• Hero Member
• Posts: 939
Re: Building a composite image
« Reply #1 on: June 10, 2022, 06:35:50 pm »
Since I could only add 4 images to my original post, here is a finished composite image to give you a full picture of what I'm trying to achieve.
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0
Win 7 Ult 64

Handoko

• Hero Member
• Posts: 4768
• My goal: build my own game engine using Lazarus
Re: Building a composite image
« Reply #2 on: June 10, 2022, 07:53:08 pm »
Maybe you can find something useful on my previous project - CATWW:
https://forum.lazarus.freepascal.org/index.php/topic,50989

The newest version 0.3 (see the image below), which has not been published, has improved further. But you still may find many useful techniques in the version 0.2, like:
- Image caching for performance improvement, multires version
- BGRABitmap translate, resize, rotate, flip, resample, composition

Unfortunately the code is moderately optimized, it is a bit hard for novices to understand.

For your information, BGRABitmap is not fully hardware accelerated. If you want to do some real-time animations using it, you really need to do plenty of optimizations and/or image caching.
« Last Edit: June 10, 2022, 07:56:04 pm by Handoko »

winni

• Hero Member
• Posts: 3192
Re: Building a composite image
« Reply #3 on: June 10, 2022, 08:48:05 pm »
Hi!

You need only one BGRAbitmap.

And a lot of Ellipses.

Code: Pascal  [Select][+][-]
1. procedure TForm1.Button3Click(Sender: TObject);
2. const HeightWidth = 300;
8. var  tmp  : TBGRABitmap;
9.      Center: TPointF;
10. begin
11. Image2.Canvas.Brush.Color := clWhite;
12. Image2.Canvas.Fillrect(0,0,Image2.width, Image2.height);
13.
14. tmp := TBGRAbitmap.create(HeightWidth,HeightWidth);
15. center := PointF (HeightWidth/2, HeightWidth/2);
18.
22.
24.
25. tmp.Draw(Image2.Canvas,0,0,false);
26. tmp.free;
27. end;
28.

Change the colors to your needs.

Done.

Winni

J-G

• Hero Member
• Posts: 939
Re: Building a composite image
« Reply #4 on: June 10, 2022, 10:30:56 pm »
Hi Winni,

That looks interesting and I think I understand the logic, I can certainly see how I can pass the value of the OD (Radius1) from which the PCD & Root values can be deduced. Radius4 & Radius5 will always be the same so they can be set as 'Const'.  I don't understand how the 'keyway' is created, though that may be down to the use of a bitmap image as the 'starting point' of Image2.

The more important issue though is that the final image MUST be transparrent - including the centre bore with keyway. If this can be done using 'ReplaceTransparent(clRed);' and 'TransparentColor:=clRed;'  just before .Draw....  then the concept could have 'legs'.

Using Centre.X & .Y would be a benefit as I currently have to calculate the 'Top' & 'Left' positions before passing them to the 'Rotate' proc.   Although I use my 'Rotate' proc to draw the gears, in actual fact I only rotate one of them and that is a simple 45° CCW so that the Tooth count can be seen - it's not a full animation. The main reason for the 'Rotate' proc is to correctly position the image of the Gear Carrier, it just happens to be an easy way to process a transparent image.

If I can get this to work then the question about an image not being in the 'Resource' goes away, since an image of all posible 109 Gears can be created 'on the fly'.

FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0
Win 7 Ult 64

J-G

• Hero Member
• Posts: 939
Re: Building a composite image
« Reply #5 on: June 11, 2022, 12:58:45 am »
Maybe you can find something useful on my previous project - CATWW:
Thanks Handoko, I've had a quick look but naturally I will need to spend some time to fully understand what techniques may be useful. - 'Resize' will certainly be one but it may be 'Composition' that will deliver what I need  -  that is if 'Composition' means adding images together.

Quote from: Handoko
The newest version 0.3 (see the image below), which has not been published, has improved further. But you still may find many useful techniques in the version 0.2, like:
- Image caching for performance improvement, multires version
- BGRABitmap translate, resize, rotate, flip, resample, composition

Unfortunately the code is moderately optimized, it is a bit hard for novices to understand.

For your information, BGRABitmap is not fully hardware accelerated. If you want to do some real-time animations using it, you really need to do plenty of optimizations and/or image caching.
I'm not too concerned about 'Real-Time' animation in this case - I have been in the past, witness the attached ScreenGrab which shows two of the time-pieces that I wrote in 2016/19 - they are both 'Transparent' but use bitmaps created in CorelDRAW! rather than the 'ellipses' suggested by @Winni

This program will not have the gears 'animated', they will just be shown in the correct location relative to each other. If I wanted animation I would want the images to include the correct number of teeth and for them to 'mesh' correctly and I suspect that would demand that I would have to draw all 108 separate gears.   -  it may even yet come to that!

FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0
Win 7 Ult 64

winni

• Hero Member
• Posts: 3192
Re: Building a composite image
« Reply #6 on: June 11, 2022, 01:17:05 am »
Hi!

There are a lot of overloaded versions of TBGRAbitmap.create.

This one creates a transparent bitmap:

Code: Pascal  [Select][+][-]
1. MyBmp := TBGRAbitmap.create (w,h);
2.

A lot of your questions to BGRAbitmap is already anwered in the tutorial. Read it slow and not only once:

https://wiki.freepascal.org/BGRABitmap_tutorial

Winni
« Last Edit: June 11, 2022, 01:19:08 am by winni »

J-G

• Hero Member
• Posts: 939
Re: Building a composite image
« Reply #7 on: June 11, 2022, 03:03:27 am »
There are a lot of overloaded versions of TBGRAbitmap.create.

A lot of your questions to BGRAbitmap is already anwered in the tutorial. Read it slow and not only once:

I have quite a few BGRA Tutorials open on a permanent basis and am constantly referring to them, though I will admit that the TChart one did not strike me as being useful in this particular instance

I've started a new project to better understand the facilities in BGRA.....  but I've come up against a brick wall very quickly. I've put 'BGRABitmap' in the [Uses], specified a couple of 'Constants' and a few 'Vars' , created a TEdit and its associated 'OnEditingDone' event. This ought to be a simple initial test but it refuses to compile, reporting that it can't find BGRABitmap ???

I've checked [Package][OPM] and can confirm the BGRABitmap & BGRABitmapTypes are 'Installed', and I've compared the 'Paths' in this and the 'Gears' Project and they are identical. The issue can't be a mis-spelling, the entry in the 'Uses' is a Copy'n'Paste from the 'Gears' program.

I'm either tired or baffled but I can't see why    - -  It can't be the former, I've only done 18½ hours coding today    -  much of that has been asking and aswering questions though!

Since it is < 60 lines, here's the complete code :
Code: Pascal  [Select][+][-]
1. unit ShowGears;
2. {\$mode objfpc}{\$H+}
3. interface
4. uses
5.   Classes, SysUtils, Forms, Controls, Graphics,
6.   Dialogs, StdCtrls, BGRABitmap, BGRABitmapTypes;
7.
8. type
9.   { TForm1 }
10.   TForm1 = class(TForm)
11.     NoOfTeeth : TEdit;
12.     procedure FormCreate(Sender: TObject);
13.     procedure NoOfTeethEditingDone(Sender: TObject);
14.   private
15.
16.   public
17.
18.   end;
19.
20. var
21.   Form1: TForm1;
22.
23. implementation
24.
25. {\$R *.lfm}
26.
27. Const
28.   DP : word = 20;
29.   M  : single = 25.4;
30. Var
31. { TForm1 }
32.   OD,
33.   PCD,
34.   Root   : word;
35.   DM     : single;
36.   tmp    : TBGRABitmap;
37.   Centre : TPointF;
38.   T      : byte;
39.
40. procedure TForm1.FormCreate(Sender: TObject);
41. begin
42.   Width  := 600;
43.   Height := 600;
44.   DM     := 1 / DP;
45. end;
46.
47. procedure TForm1.NoOfTeethEditingDone(Sender: TObject);
48. begin
49.   T  := StrToInt(NoOfTeeth.Caption);
50.   OD := Round(T * DM * M);
51.   OD := OD + OD Mod 2;
52.
53.   tmp := TBGRABitmap.Create(OD,OD);
54. end;
55. end.
« Last Edit: June 11, 2022, 03:08:06 am by J-G »
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0
Win 7 Ult 64

lainz

• Hero Member
• Posts: 4079
Re: Building a composite image
« Reply #8 on: June 11, 2022, 07:00:54 am »
Open the bgrabitmap package and add use, add to project. Done. Now you can use bgrabitmap.
lainz.github.io

Josh

• Hero Member
• Posts: 1040
Re: Building a composite image
« Reply #9 on: June 11, 2022, 08:00:15 am »
or add the requirement in project inspecter

The best way to get accurate information on the forum is to post something wrong and wait for corrections.

Josh

• Hero Member
• Posts: 1040
Re: Building a composite image
« Reply #10 on: June 11, 2022, 08:31:27 am »
and Lainz method
The best way to get accurate information on the forum is to post something wrong and wait for corrections.

J-G

• Hero Member
• Posts: 939
Re: Building a composite image
« Reply #11 on: June 11, 2022, 09:25:53 am »
@Josh & @Lainz  !!!

Thanks -- I don't recall ever having to manually [add] a package using the Project Inspector ??

@Josh, your explicit instructions realy were useful in my bleery-eyed just awake state!

All sorted now - well the test project compiled

« Last Edit: June 11, 2022, 09:28:47 am by J-G »
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0
Win 7 Ult 64

winni

• Hero Member
• Posts: 3192
Re: Building a composite image
« Reply #12 on: June 11, 2022, 02:50:12 pm »
Hi!

If you want to learn about BGRAbitmap then have a long look at the unit

There are a lot of comments and the very rich basic abilities of BGRA are defined here.

Winni

J-G

• Hero Member
• Posts: 939
Re: Building a composite image
« Reply #13 on: June 11, 2022, 03:42:50 pm »
Hi Winni,

There is a very old addage that states that if you give a man a fish you can feed him for a day but give him a Fishing Rod and you'll feed him for life      I thank you for the gift of a Rod!

I've spent the past 6 hours massaging the test project  line by line with reference to your last posting which used  tmp.EllipseAntialias . . . .  starting with a simple circle in a black square, moving to a white and then transparent square, adding other circles with differing body and outline colours and a transparent hole in the centre !  -  I haven't yet discovered how you included the keyway

Determining the size of some circles and whether or not to include them was essentially a trivial matter.

The one thing I haven't managed though is to prevent 'clipping' at the right & bottom (see the attached image)  -  I've tried all manner of 'adjustments' to both the TImage and the BGRABitmap, all without success - adding 1 or 2 px to OD or Sq (in the following code) just adds a black line at right & bottom.
Code: Pascal  [Select][+][-]
1. implementation
2. {\$R *.lfm}
3. Const
4.   DP : word = 20;
5.   M  : single = 25.4;
6.   Hue : Record
7.           one,
8.           two,
9.           three : TColor;
10.         end    = (one : \$00A9C6A8;two : \$00007500; three : \$00756060);
11.
12. Var
13. { TForm1 }
14.   OD,
15.   PCD,
16.   Root   : word;
17.   DM     : single;
18.   tmp    : TBGRABitmap;
19.   C      : TPointF;
20.   LS_Cen : TPointF;
21.   T,X,Y,
22.   Sq     : word;
23.   Fnt    : ShortInt;
24.
25. procedure TForm1.FormCreate(Sender: TObject);
26. begin
27.   Width  := 600;
28.   Height := 600;
29.   DM     := 1 / DP;
30.   LS_Cen.x:=400;
31.   LS_Cen.y:=400;
32.
33. end;
34.
35. procedure TForm1.NoOfTeethEditingDone(Sender: TObject);
36. Var
37.   R1,R2,R3,R4,R5 : word;
38. begin
39.   T  := StrToInt(NoOfTeeth.Caption);
40.   If T<20 then
41.     begin
42.       ShowMessage('Tooth Count too small');
43.       Exit;
44.     end;
45.   OD := Round(T * DM * M * 2);
46.   OD := OD + OD Mod 2;
47.   X  := OD div 2;
48.   Y  := X;
49.   R1 := X-4;
50.   R2 := X-9;
51.   R5 := 14;
52.   Sq := OD;
53.
54.   If T<50 then
55.     begin
56.       Fnt := -13;
57.       R3 := X-14;   // Outer Land
58.       R4 := 24;     // Centre Land
59.     end
60.   else
61.     begin
62.       Fnt := -16;
63.       R3 := X-22;
64.       R4 := 30;
65.     end;
66.
67.   tmp := TBGRABitmap.Create(OD,OD);
68.   tmp.ReplaceTransparent(clWhite);
69.
70.   with Image1 do
71.     begin
72.       Width  := Sq;           // needed to overide the size set at Design time
73.       Height := Sq;
74.
75.       Canvas.Brush.Color := clWhite;        // set to colour being used as 'transparent'
76.       Canvas.FillRect(0,0,Sq,Sq);
77.
78.       Picture.Clear;
79.       Picture.Bitmap.SetSize(Sq,Sq);
80.       Picture.Bitmap.TransparentColor:=clWhite;
81.       Transparent:=True;
82.
83.       Top    := Round(LS_Cen.y - Y);
84.       Left   := Round(LS_Cen.x - X);
85.     end;
86.
87.   C := PointF(X,Y);
88.
89.   tmp.EllipseAntialias(C.x,C.y, X, X,clRed, 1,Hue.one);      // OD
90.   tmp.EllipseAntialias(C.x,C.y,R1,R1,clGray,1,Hue.three);    // PCD
91.   tmp.EllipseAntialias(C.x,C.y,R2,R2,clLime,1,clNone);       // Root
92.   If T > 35 then
93.     begin
94.       tmp.EllipseAntialias(C.x,C.y,R3,R3,clGray,1,Hue.two);      // Outer Land
95.       tmp.EllipseAntialias(C.x,C.y,R4,R4,clGray,1,Hue.three);  // Centre Land
96.     end;
97.   tmp.EllipseAntialias(C.x,C.y,R5,R5,clGray,1,clWhite);      // Bore
98.
99.   tmp.FontHeight := Fnt;
100.   tmp.TextOut(C.x,C.y+R5,IntToStr(T),clSilver,taCenter);
101.
102.   tmp.Draw(Image1.Canvas,0,0,false);
103.   tmp.free;
104. end;
105. end.
106.

I still need to add the Tooth count as a Number which I may do using a TLabel with clNone as the body colour, but if there is some BGRA Text method which I've yet to discover which will do a better job I may switch to that.

I'd appreciate your opinion regarding how to stop the clipping - I'm sure it's a simple matter but is baffling me.

[EDIT] (16:20)
I've now found the BGRADefaultBitmap Unit !!
It came to the fore when I was looking to add 'Text' in the form of the Tooth Count and 'TextSize' expected a 'string' ???  -  I then found  .FontHeight. (the code above has been edited to reflect the new knowledge)
It seems that adding images is not allowed when 'Editing' a post
« Last Edit: June 11, 2022, 05:38:45 pm by J-G »
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0
Win 7 Ult 64

winni

• Hero Member
• Posts: 3192
Re: Building a composite image
« Reply #14 on: June 11, 2022, 06:13:37 pm »
Hi!

I made you a little demo for a gear wheel

You need the unit math for this demo:

Code: Pascal  [Select][+][-]
1. uses ......, math;
2.

The number of teeth is initialized in the var numOfTeeth
The amplitude around the circle is defined in the var delta

Code: Pascal  [Select][+][-]
1. procedure TForm1.Button3Click(Sender: TObject);
3. var radius, delta, step, angle : single;
4.     sinus, cosinus : single;
5.     heightWidth: integer=300;
6.     numOfteeth : integer= 60;
7.     tmp: TBGRAbitmap;
8.     center : TPointF;
9.     poly : ArrayOfTPointF;
10.
11. begin
12.    Image2.Canvas.Brush.color := clWhite;
13.    Image2.Canvas.Fillrect(0,0,image2.width, image2.height);
14.    center := PointF(heightWidth/2, heightWidth/2);
15.    tmp := TBGRAbitmap.create (heightWidth, heightWidth);
17.    delta := 15;
18.    step := 360/numOfteeth/2;
19.    angle := 0;
20.    setLength(poly,numOfteeth*2);
21.    while angle < 360 do
22.      begin
25.      angle := angle + step;
26.      delta := -delta;
27.      end;
28.    tmp.DrawPolygonAntialias(poly,cssred,2,csswhite);
29.    tmp.Draw(Image2.canvas,0,0,false);
30.    tmp.free;
31. end;
32.

Winni
« Last Edit: June 11, 2022, 06:16:50 pm by winni »