Recent

Author Topic: How to install image library for freepascal on linux?  (Read 12156 times)

barracuda

  • Full Member
  • ***
  • Posts: 133
Re: How to install image library for freepascal on linux?
« Reply #60 on: August 18, 2023, 10:03:33 am »
Now I have tested your programs. Thank you. Now I see that the function ChangeColor may not be declared. Interesting. I thought functions must be declared or have return type. I see one problem. This is logical and can be expected with semitransparent background. Can we detect the average lightness of the background? While we are in the loop, there could be one more function to detect it the background of image under the rectangle of edit control is dark or light. So we would have some options what to do with the colors. Because if the area is really black we don't need to add extra background to the edit control. We just set the text color to black. If the average color in area is white, we can set the text to black. But if there is low contrast, then we could add the background color to the edit box, and choose the color depending if it is darker or lighter.

Handoko

  • Hero Member
  • *****
  • Posts: 5524
  • My goal: build my own game engine using Lazarus
Re: How to install image library for freepascal on linux?
« Reply #61 on: August 18, 2023, 10:58:46 am »
Can we detect the average lightness of the background? While we are in the loop, there could be one more function to detect it the background of image under the rectangle of edit control is dark or light.

Sure we can.

That code works by doing 2 main loops. The first is looping the Y coordinate of the pixels (see line #92), by using the ScanLine[Y] command you set the pointer to point to the first left most pixel. The result there then added with X multiple by 3 or 4, depends on the pixel format of the image.

The second is looping the X coordinate of the pixels (see line #105). So now the Data24bit^ or Data32bit^ (depends on the pixel format) will point to the pixel information.

By setting the pointer to point to the correct X, Y position, now you can read the pixel information, which are the values of red, green, blue and alpha (transparency) of the pixel. And if you modify the value, for example by adding it with 128 (as shown in the demo, line 74), it will increase the brightness of the pixel. That's how it draws a semi transparent rectangle.

So if you do the looping from top to bottom and left to right of all the pixels, and averaging all the r, g, b values you can get the global lightness of the image.

... expected with semitransparent background.

For detecting semi transparent pixel, you can learn from this demo:
https://forum.lazarus.freepascal.org/index.php/topic,37242.msg488758.html#msg488758

---

Basically, the method I used is relatively simple. But the hardest part is, we need to deal with the pixel format. Each image file format (jpg, png, bmp, etc) has different pixel formats. And Linux and Windows handle pixel format a bit differently.

barracuda

  • Full Member
  • ***
  • Posts: 133
Re: How to install image library for freepascal on linux?
« Reply #62 on: August 18, 2023, 11:15:31 am »
My try to get the avarage intensity (of grayscale bitmap under the edit control). Please check if I do it correctly.
Code: Pascal  [Select][+][-]
  1. procedure TForm1.GetAvgIntensity;
  2. const
  3.   BoxWidth  = 100;
  4.   BoxHeight = 20;
  5. var
  6.   ScanData:  Pointer;
  7.   Data24bit: PRGBTriple absolute ScanData;
  8.   Data32bit: PRGBQuad   absolute ScanData;
  9.   X, Y:       Integer;
  10.   temp: Integer;
  11. begin
  12.   temp := 125;
  13.   AvgInt := 125;
  14.   for Y := Clickable.Top to Clickable.Bottom do
  15.   begin
  16. {$ifdef Windows}
  17.   case Image1.Picture.Bitmap.PixelFormat of
  18.     pf24bit:
  19.       ScanData := Image1.Picture.Bitmap.ScanLine[Y] + Clickable.Left * 3;
  20.     pf32bit:
  21.       ScanData := Image1.Picture.Bitmap.ScanLine[Y] + Clickable.Left * 3;
  22.   end;
  23. {$endif}
  24. {$ifdef Linux}
  25.     ScanData := Image1.Picture.Bitmap.ScanLine[Y] + Clickable.Left * 4;
  26. {$endif}
  27.     for X:= 0 to Clickable.Width do
  28.     begin
  29.       case Image1.Picture.Bitmap.PixelFormat of
  30.         pf24bit:
  31.           begin
  32.             temp := round(Data24bit^.rgbtRed + Data24bit^.rgbtGreen + Data24bit^.rgbtBlue) div 3;
  33.             AvgInt := (AvgInt+temp) div 2;
  34. {$ifdef Windows}
  35.             Inc(ScanData, 3);
  36. {$endif}
  37. {$ifdef Linux}
  38.             Inc(ScanData, 4);
  39. {$endif}
  40.           end;
  41.         pf32bit:
  42.           begin
  43.             temp := round(Data24bit^.rgbtRed + Data24bit^.rgbtGreen + Data24bit^.rgbtBlue) div 3;
  44.             AvgInt := (AvgInt+temp) div 2;
  45.             Inc(ScanData, 4);
  46.           end;
  47.       end;
  48.     end;
  49.   end;
  50. end;
  51.  
« Last Edit: August 18, 2023, 12:20:13 pm by barracuda »

Handoko

  • Hero Member
  • *****
  • Posts: 5524
  • My goal: build my own game engine using Lazarus
Re: How to install image library for freepascal on linux?
« Reply #63 on: August 18, 2023, 11:55:03 am »
Your code has some issues:

Line 14, you should loop from 0 to the height of the image.
Line 16..24, no need to include the clickable because you start from left most position.
Line 27, you should loop from 0 to the width of the image.
And you average calculation is incorrect.

Handoko

  • Hero Member
  • *****
  • Posts: 5524
  • My goal: build my own game engine using Lazarus
Re: How to install image library for freepascal on linux?
« Reply #64 on: August 18, 2023, 11:58:32 am »
I modified your code and added it to this demo.

This demo is quickly tested on Linux only. It may have bugs.

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, ExtCtrls, StdCtrls, LCLType;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Button1: TButton;
  16.     Edit1: TEdit;
  17.     Image1: TImage;
  18.     procedure Button1Click(Sender: TObject);
  19.     procedure Edit1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  20.     procedure FormCreate(Sender: TObject);
  21.     procedure Image1DblClick(Sender: TObject);
  22.   private
  23.     Title: string;
  24.     Clickable: TRect;
  25.     procedure LoadImage;
  26.     procedure CalculateClickable;
  27.     procedure DrawCenterRectangle;
  28.     procedure WriteCenterText;
  29.     procedure GetAvgIntensity;
  30.   end;
  31.  
  32. var
  33.   Form1: TForm1;
  34.  
  35. implementation
  36.  
  37. {$R *.lfm}
  38.  
  39. { TForm1 }
  40.  
  41. procedure TForm1.LoadImage;
  42. const
  43.   ImageFile = 'img.png';
  44. var
  45.   Tmp: TPicture;
  46. begin
  47.   Image1.SetBounds(0, 0, Width, Height);
  48.   Tmp := TPicture.Create;
  49.   try
  50.     Tmp.LoadFromFile(ImageFile);
  51.     Image1.Canvas.StretchDraw(ClientRect, Tmp.Bitmap);
  52.   finally
  53.     Tmp.Free;
  54.   end;
  55. end;
  56.  
  57. procedure TForm1.CalculateClickable;
  58. var
  59.   W, H: Integer;
  60. begin
  61.   Image1.Canvas.GetTextSize(Title, W, H);
  62.   Clickable.Left   := (Width - W)  div 2;
  63.   Clickable.Top    := (Height - H) div 2;
  64.   Clickable.Width  := W;
  65.   Clickable.Height := H;
  66.   Clickable.Inflate(2, 0);
  67. end;
  68.  
  69. procedure ChangeColor(var Data: Byte);
  70. const
  71.   Shift = 128; // 50% white
  72. var
  73.   Temp: Integer;
  74. begin
  75.   Temp := Data + Shift;
  76.   if (Temp > 255) then Temp := 255
  77.     else
  78.       if (Temp < 0) then Temp := 0;
  79.   Data := Temp;
  80. end;
  81.  
  82. procedure TForm1.DrawCenterRectangle;
  83. const
  84.   BoxWidth  = 100;
  85.   BoxHeight = 20;
  86. var
  87.   ScanData:  Pointer;
  88.   Data24bit: PRGBTriple absolute ScanData;
  89.   Data32bit: PRGBQuad   absolute ScanData;
  90.   X, Y:       Integer;
  91. begin
  92.   Image1.Picture.Bitmap.BeginUpdate;
  93.   for Y := Clickable.Top to Clickable.Bottom do
  94.   begin
  95. {$ifdef Windows}
  96.   case Image1.Picture.Bitmap.PixelFormat of
  97.     pf24bit:
  98.       ScanData := Image1.Picture.Bitmap.ScanLine[Y] + Clickable.Left * 3;
  99.     pf32bit:
  100.       ScanData := Image1.Picture.Bitmap.ScanLine[Y] + Clickable.Left * 3;
  101.   end;
  102. {$endif}
  103. {$ifdef Linux}
  104.     ScanData := Image1.Picture.Bitmap.ScanLine[Y] + Clickable.Left * 4;
  105. {$endif}
  106.     for X:= 0 to Clickable.Width do
  107.     begin
  108.       case Image1.Picture.Bitmap.PixelFormat of
  109.         pf24bit:
  110.           begin
  111.             begin
  112.               ChangeColor(Data24bit^.rgbtRed);
  113.               ChangeColor(Data24bit^.rgbtGreen);
  114.               ChangeColor(Data24bit^.rgbtBlue);
  115.             end;
  116. {$ifdef Windows}
  117.             Inc(ScanData, 3);
  118. {$endif}
  119. {$ifdef Linux}
  120.             Inc(ScanData, 4);
  121. {$endif}
  122.           end;
  123.         pf32bit:
  124.           begin
  125.             begin
  126.               ChangeColor(Data32bit^.rgbRed);
  127.               ChangeColor(Data32bit^.rgbGreen);
  128.               ChangeColor(Data32bit^.rgbBlue);
  129.             end;
  130.             Inc(ScanData, 4);
  131.           end;
  132.       end;
  133.     end;
  134.   end;
  135.   Image1.Picture.Bitmap.EndUpdate;
  136. end;
  137.  
  138. procedure TForm1.WriteCenterText;
  139. begin
  140.   Image1.Canvas.Brush.Style := bsClear;
  141.   Image1.Canvas.Font.Color  := clBlack;
  142.   Image1.Canvas.TextOut(Clickable.Left+2, Clickable.Top, Title);
  143. end;
  144.  
  145. procedure TForm1.GetAvgIntensity;
  146. var
  147.   ScanData:  Pointer;
  148.   Data24bit: PRGBTriple absolute ScanData;
  149.   Data32bit: PRGBQuad   absolute ScanData;
  150.   X, Y:      Integer;
  151.   AvgInt:    Integer;
  152.   Total:     Integer;
  153.   Temp:      Integer;
  154. begin
  155.   Total := 0;
  156.   for Y := 0 to Image1.Picture.Bitmap.Height-1 do
  157.   begin
  158.     ScanData := Image1.Picture.Bitmap.ScanLine[Y];
  159.     for X:= 0 to Image1.Picture.Bitmap.Width-1 do
  160.     begin
  161.       case Image1.Picture.Bitmap.PixelFormat of
  162.         pf24bit:
  163.           begin
  164.             Temp  := (Data24bit^.rgbtRed + Data24bit^.rgbtGreen + Data24bit^.rgbtBlue) div 3;
  165.             Total := Total + Temp;
  166. {$ifdef Windows}
  167.             Inc(ScanData, 3);
  168. {$endif}
  169. {$ifdef Linux}
  170.             Inc(ScanData, 4);
  171. {$endif}
  172.           end;
  173.         pf32bit:
  174.           begin
  175.             Temp  := (Data32bit^.rgbRed + Data32bit^.rgbGreen + Data32bit^.rgbBlue) div 3;
  176.             Total := Total + Temp;
  177.             Inc(ScanData, 4);
  178.           end;
  179.       end;
  180.     end;
  181.   end;
  182.   AvgInt  := Round(Total/(Image1.Picture.Bitmap.Width*Image1.Picture.Bitmap.Height));
  183.   Caption := AvgInt.ToString;
  184. end;
  185.  
  186. procedure TForm1.Button1Click(Sender: TObject);
  187. begin
  188.   LoadImage;
  189.   CalculateClickable;
  190.   DrawCenterRectangle;
  191.   WriteCenterText;
  192.   GetAvgIntensity;
  193. end;
  194.  
  195. procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState
  196.   );
  197. begin
  198.   case Key of
  199.     VK_ESCAPE:
  200.       begin
  201.         Button1.Visible := True;
  202.         Edit1.Visible   := False;
  203.       end;
  204.     VK_RETURN:
  205.       begin
  206.         if Edit1.Text <> '' then
  207.         begin
  208.           Title := Edit1.Text;
  209.           CalculateClickable;
  210.           LoadImage;
  211.           CalculateClickable;
  212.           DrawCenterRectangle;
  213.           WriteCenterText;
  214.         end;
  215.         Button1.Visible := True;
  216.         Edit1.Visible   := False;
  217.       end;
  218.   end;
  219. end;
  220.  
  221. procedure TForm1.FormCreate(Sender: TObject);
  222. begin
  223.   Title         := 'Double click here';
  224.   Edit1.Visible := False;
  225. end;
  226.  
  227. procedure TForm1.Image1DblClick(Sender: TObject);
  228. var
  229.   MouseXY: TPoint;
  230. begin
  231.   MouseXY := ScreenToClient(Mouse.CursorPos);
  232.   if not(Clickable.Contains(MouseXY)) then Exit;
  233.   Button1.Visible := False;
  234.   Edit1.Left      := Clickable.Left;
  235.   Edit1.Top       := Clickable.Top;
  236.   Edit1.Width     := Clickable.Width;
  237.   Edit1.Text      := Title;
  238.   Edit1.Visible   := True;
  239.   Edit1.SetFocus;
  240.   Edit1.SelectAll;
  241. end;
  242.  
  243. end.

The result is shown on the titlebar. As you can see from the screenshot below, the value is 65, which means the picture is relatively dark. The values can start from 0 to 255. Value of 128 means 50% brightness.
« Last Edit: August 18, 2023, 12:43:04 pm by Handoko »

barracuda

  • Full Member
  • ***
  • Posts: 133
Re: How to install image library for freepascal on linux?
« Reply #65 on: August 18, 2023, 12:05:12 pm »
No no no. We don't want avg intensity from all the image but only from the area where the text will be present.

Handoko

  • Hero Member
  • *****
  • Posts: 5524
  • My goal: build my own game engine using Lazarus
Re: How to install image library for freepascal on linux?
« Reply #66 on: August 18, 2023, 12:07:13 pm »
Then, you put the Clickable area calculation back to the code.

For the average calculation, it will be easier done by totaling all the values then divided by the count of total pixels. In my case:
Avg = Total / (...bitmap.Width * ...bitmap.Height)

You need to change the width and height.
« Last Edit: August 18, 2023, 12:18:17 pm by Handoko »

barracuda

  • Full Member
  • ***
  • Posts: 133
Re: How to install image library for freepascal on linux?
« Reply #67 on: August 18, 2023, 12:19:07 pm »
Then the avg. intensity should be
// begin of loop
sum := sum + Data24bit^.rgbtRed + Data24bit^.rgbtGreen + Data24bit^.rgbtBlue;
// end of loop
avg := sum div ( (Clickable.Width div Clickable.Height) div 3);

I modified my previous description. I don't speak about color.
« Last Edit: August 18, 2023, 12:20:39 pm by barracuda »

Handoko

  • Hero Member
  • *****
  • Posts: 5524
  • My goal: build my own game engine using Lazarus
Re: How to install image library for freepascal on linux?
« Reply #68 on: August 18, 2023, 12:46:00 pm »
Oops, I forgot to mention the pixel color need to be divided by 3, but it's already done in the code:

Temp  := (Data24bit^.rgbtRed + Data24bit^.rgbtGreen + Data24bit^.rgbtBlue) div 3;
Temp  := (Data32bit^.rgbRed + Data32bit^.rgbGreen + Data32bit^.rgbBlue) div 3;

barracuda

  • Full Member
  • ***
  • Posts: 133
Re: How to install image library for freepascal on linux?
« Reply #69 on: August 18, 2023, 01:47:32 pm »
I have prepared this so far...

Code: Pascal  [Select][+][-]
  1. type
  2.   TColIndicator = (very_dark, medium_dark, normal_intensity, medium_light, very_light);
  3.  
  4.   private
  5.     AvgInt: Integer;
  6.     FontColor, BgColor: TColor;
  7.     ColIndicator: TColIndicator;
  8.     procedure GetAvgIntensity;
  9.     procedure SetColors;
  10.  
  11. procedure TForm1.GetAvgIntensity;
  12. const
  13.   BoxWidth  = 100;
  14.   BoxHeight = 20;
  15. var
  16.   ScanData:  Pointer;
  17.   Data24bit: PRGBTriple absolute ScanData;
  18.   Data32bit: PRGBQuad   absolute ScanData;
  19.   X, Y:       Integer;
  20.   sum: Integer;
  21. begin
  22.   for Y := Clickable.Top to Clickable.Bottom do
  23.   begin
  24. {$ifdef Windows}
  25.   case Image1.Picture.Bitmap.PixelFormat of
  26.     pf24bit:
  27.       ScanData := Image1.Picture.Bitmap.ScanLine[Y] + Clickable.Left * 3;
  28.     pf32bit:
  29.       ScanData := Image1.Picture.Bitmap.ScanLine[Y] + Clickable.Left * 3;
  30.   end;
  31. {$endif}
  32. {$ifdef Linux}
  33.     ScanData := Image1.Picture.Bitmap.ScanLine[Y] + Clickable.Left * 4;
  34. {$endif}
  35.     for X:= 0 to Clickable.Width do
  36.     begin
  37.       case Image1.Picture.Bitmap.PixelFormat of
  38.         pf24bit:
  39.           begin
  40.             sum := sum + Data24bit^.rgbtRed + Data24bit^.rgbtGreen + Data24bit^.rgbtBlue;
  41. {$ifdef Windows}
  42.             Inc(ScanData, 3);
  43. {$endif}
  44. {$ifdef Linux}
  45.             Inc(ScanData, 4);
  46. {$endif}
  47.           end;
  48.         pf32bit:
  49.           begin
  50.             sum := sum + Data24bit^.rgbtRed + Data24bit^.rgbtGreen + Data24bit^.rgbtBlue;
  51.             Inc(ScanData, 4);
  52.           end;
  53.       end;
  54.     end;
  55.   end;
  56.   AvgInt := sum div ( (Clickable.Width div Clickable.Height) div 3);
  57. end;
  58.  
  59. procedure TForm1.SetColors;
  60. begin
  61.   if AvgInt<64) then
  62.     begin
  63.       ColIndicator:=very_dark;
  64.       FontColor:=White;
  65.     end
  66.   else if AvgInt<100 then
  67.      begin
  68.        ColIndicator:=medium_dark;
  69.        FontColor:=White;
  70.        BgColor:=Black;
  71.      end
  72.   else if AvgInt>190 then
  73.     begin
  74.       ColIndicator:=very_light;
  75.       FontColor:=Black;
  76.     end
  77.   else if AvgInt>154 then
  78.     begin
  79.       ColIndicator:=medium_light;
  80.       FontColor:=Black;
  81.       BgColor:=White;
  82.     end
  83.   else
  84.     begin
  85.       ColIndicator:=normal_intensity;
  86.       FontColor:=Black;
  87.       BgColor:=White;
  88.     end;
  89. end;
  90.  
  91. procedure TForm1.Button1Click(Sender: TObject);
  92. begin
  93.   LoadImage;
  94.   CalculateClickable;
  95.   GetAvgIntensity;
  96.   SetColors;
  97.   DrawCenterRectangle;
  98.   WriteCenterText;
  99. end;
  100.  

Handoko

  • Hero Member
  • *****
  • Posts: 5524
  • My goal: build my own game engine using Lazarus
Re: How to install image library for freepascal on linux?
« Reply #70 on: August 18, 2023, 02:04:58 pm »
That seems good. But maybe you miss it, I ever mentioned there was a mistake in my code. In your code above, in GetAvgIntensity line #29, that should be:

ScanData := Image1.Picture.Bitmap.ScanLine[Y] + Clickable.Left * 4;

For pf32bit, it should be 4 bytes. That's why it should be multiplied by 4.
For pf24bit, it should be 3 bytes. That's why it should be multiplied by 3.
(But things go weird, on Linux it should always be 4)

barracuda

  • Full Member
  • ***
  • Posts: 133
Re: How to install image library for freepascal on linux?
« Reply #71 on: August 18, 2023, 02:48:25 pm »
Why linux reads 4 bytes with pf24bit format?

Handoko

  • Hero Member
  • *****
  • Posts: 5524
  • My goal: build my own game engine using Lazarus
Re: How to install image library for freepascal on linux?
« Reply #72 on: August 18, 2023, 02:55:31 pm »
I don't know.

But I tested several times and I found, in Linux:
- It normally will read 3 bytes for pf24bit format
- But if the image is StretchDrawed, it will store/read 4 bytes for pf24bit format

That's why you can see I used many conditional compiler directives in the demos to make to code work correctly on both Windows and Linux.

If you can afford it, you should buy a new computer so you will have both Windows and Linux computers to test your programs. Or at least you should have a good computer with plenty of RAM so you can run tests on virtual machines.
« Last Edit: August 18, 2023, 03:00:44 pm by Handoko »

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: How to install image library for freepascal on linux?
« Reply #73 on: August 18, 2023, 04:09:57 pm »
Handoko, I have two thinkings about your drawn color calculated rectangle:

both have in common:
get absolute screen coordinates from your calculated destination rectangle
(ClientToScreen)
prepare to make a snapshot of that small area

Idea 1:
grayscale it and paint text over

Idea 2:
inverse it and paint text over

apply the small bitmap onto the image, done

(both ways can be done via the canvas copymode IIRC)

Additional, stop using SetBounds() and just activate from image alClient alignment and stretch property.
On windows your current way will come more and more worse when you change window size, and at a certain size (ie: maximized) your code break with access violations.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

barracuda

  • Full Member
  • ***
  • Posts: 133
Re: How to install image library for freepascal on linux?
« Reply #74 on: August 18, 2023, 05:26:08 pm »
Now it can detect the color and the program decides wheather to use background color and what color to use.

Now please advice, how to get 1st argument of program or how to parse arguments.
I have a script in bash which will send list of files like "file 1.jpg" "bla bla.jpg" "next file of mine.jpg" This is ordered list and I need to move it to TStringList.

So I will call the program like so:

One set of images:
project1.exe "file 1.jpg" "bla bla.jpg" "next file of mine.jpg" &
Second set of images:
project1.exe "very dark 1.jpg" "darker 2.jpg" "normal brightness 3.jpg" "lighter 4.jpg" "very light 5.jpg" &

For testing purposes we may have like 5 files of img1.png to img5.png with different level of brightness.

I have another idea. May be good to create an icon on the left, which will represent the first set of images. Let's say the icon could be like 64x64px. And after the second call it will create next icon under the first icon, so we have two icons with - two TStrings of list. So acctually this would need and array of TString list. Icon should be created from the first image. And the image is always square, so we expect that there will be enough room on the left side and right side for the icons.

And I expect the icons should be clickable like buttons are so when we will click one icon, we will watch only that set of images.

Notice that the main point is that the program is called from script which defines the order of images. The program does not do any filtering.
« Last Edit: August 18, 2023, 05:32:07 pm by barracuda »

 

TinyPortal © 2005-2018