Recent

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

J-G

  • Hero Member
  • *****
  • Posts: 953
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: 953
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: 5154
  • 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
- Runtime generating/showing a progress form when loading data
- 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: 3197
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;
  3.       Radius1 = 140;
  4.       Radius2=135;
  5.       Radius3=120;
  6.       Radius4 = 50;
  7.       Radius5 = 40;
  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);
  16. tmp.EllipseAntialias(Center.X, Center.y,Radius1,Radius1,cssOrange,2,cssGray);
  17. tmp.EllipseAntialias(Center.X, Center.y,Radius2,Radius2,cssGreen,4,cssGray);
  18.  
  19. tmp.EllipseAntialias(Center.X, Center.y,Radius3,Radius3,CSSDarkGreen,2,cssGreen);
  20. tmp.EllipseAntialias(Center.X, Center.y,Radius4,Radius4,cssBlack,2,cssGray);
  21. tmp.EllipseAntialias(Center.X, Center.y,Radius5,Radius5,cssBlack,2,csswhite);
  22.  
  23. tmp.FillRectAntialias(Center.x-5,Center.y-radius5-5, Center.x+5,Center.y-radius5+2, cssWhite);
  24.  
  25. tmp.Draw(Image2.Canvas,0,0,false);
  26. tmp.free;
  27. end;
  28.  

Change the size and the radiuses to your need.
Change the colors to your needs.

Done.

Winni

J-G

  • Hero Member
  • *****
  • Posts: 953
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: 953
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
- Runtime generating/showing a progress form when loading data
- 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. :o  -  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: 3197
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: 953
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: 4468
    • https://lainz.github.io/
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.

Josh

  • Hero Member
  • *****
  • Posts: 1274
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: 1274
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: 953
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  ;D


« 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: 3197
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

BGRADefaultBitmap

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

Winni

J-G

  • Hero Member
  • *****
  • Posts: 953
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.

The BGRADefaultBitmap brings up "There is currently no text in this page." ??

[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: 3197
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

Change  the heightWidth and the radius to your needs.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button3Click(Sender: TObject);
  2. const Deg2Rad = pi/180;
  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);
  16.    radius := 130;
  17.    delta := 15;
  18.    step := 360/numOfteeth/2;
  19.    angle := 0;
  20.    setLength(poly,numOfteeth*2);
  21.    while angle < 360 do
  22.      begin
  23.      math.sincos(angle*Deg2Rad,sinus,cosinus);
  24.      poly[i] := PointF ((radius+delta)*cosinus, (radius+delta)*sinus)+ center;
  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 »

 

TinyPortal © 2005-2018