Recent

Author Topic: fpGUI:How to add image for fpgbutton  (Read 2402 times)

lazpas

  • Jr. Member
  • **
  • Posts: 86
fpGUI:How to add image for fpgbutton
« on: April 10, 2024, 01:12:33 pm »
How do I associate a custom image for fpgbutton?

Thanks for help.

Graham1

  • Jr. Member
  • **
  • Posts: 64
Re: fpGUI:How to add image for fpgbutton
« Reply #1 on: July 25, 2024, 02:35:30 am »
Sorry for such a late reply.

I think you need to start by using the imageconvert tool in FPGUI to change your BMP (not PNG) image file into data, for example:

Code: Pascal  [Select][+][-]
  1. const
  2.   newimg_rotate: array[0..821] of byte = (
  3.      $42,$4D,$36,$03,$00,$00,$00,$00,$00,$00,$36,$00,$00,$00,$28,$00,$00,
  4.      $00,$10,$00,$00,$00,$10,$00,$00,$00,$01,$00,$18,$00,$00,$00,$00,$00,
  5.      $00,$03,$00,$00,$C4,$0E,$00,$00,$C4,$0E,$00,$00,$00,$00,$00,$00,$00,
  6.      $00,$00,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,
  7.      $FF,$CC,$CC,$CC,$27,$27,$27,$05,$05,$05,$8C,$8C,$8C,$FF,$FF,$FF,$A8,
  8.      $A8,$A8,$DA,$DA,$DA,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,
  9.      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$A8,$A8,$A8,$DA,$DA,$DA,$B4,$B4,
  10.      $B4,$05,$05,$05,$1C,$1C,$1C,$9F,$9F,$9F,$CC,$CC,$CC,$00,$00,$00,$05,
  11.      $05,$05,$9F,$9F,$9F,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,
  12.      $FF,$FF,$FF,$75,$75,$75,$00,$00,$00,$53,$53,$53,$FF,$FF,$FF,$FF,$FF,
  13.      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$89,$89,$89,$0C,$0C,$0C,$75,
  14.      $75,$75,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,
  15.      $0C,$0C,$0C,$13,$13,$13,$D4,$D4,$D4,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,
  16.      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$F9,$F9,$F9,$FF,$FF,$FF,$96,
  17.      $96,$96,$D4,$D4,$D4,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$D0,$D0,$D0,
  18.      $DE,$DE,$DE,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,
  19.      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$DA,$DA,$DA,$00,$00,$00,$32,
  20.      $32,$32,$FF,$FF,$FF,$E9,$E9,$E9,$4A,$4A,$4A,$B8,$B8,$B8,$FF,$FF,$FF,
  21.      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,
  22.      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$2E,$2E,$2E,$00,$00,$00,$E9,
  23.      $E9,$E9,$A8,$A8,$A8,$00,$00,$00,$73,$73,$73,$FF,$FF,$FF,$FF,$FF,$FF,
  24.      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,
  25.      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$CC,$CC,$CC,$9A,$9A,$9A,$FF,$FF,$FF,$9A,
  26.      $9A,$9A,$00,$00,$00,$84,$84,$84,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,
  27.      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,
  28.      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$B0,$B0,$B0,$00,
  29.      $00,$00,$66,$66,$66,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,
  30.      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,
  31.      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$E7,$E7,$E7,$00,$00,$00,$1C,
  32.      $1C,$1C,$F9,$F9,$F9,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,
  33.      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$DE,$DE,
  34.      $DE,$BC,$BC,$BC,$E1,$E1,$E1,$FF,$FF,$FF,$4A,$4A,$4A,$00,$00,$00,$89,
  35.      $89,$89,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$F9,$F9,$F9,
  36.      $72,$72,$72,$4A,$4A,$4A,$27,$27,$27,$05,$05,$05,$00,$00,$00,$00,$00,
  37.      $00,$B4,$B4,$B4,$FF,$FF,$FF,$D4,$D4,$D4,$05,$05,$05,$05,$05,$05,$9F,
  38.      $9F,$9F,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$53,$53,$53,
  39.      $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$21,$21,$21,$FF,$FF,
  40.      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$A8,$A8,$A8,$05,$05,$05,$00,$00,$00,$4A,
  41.      $4A,$4A,$B0,$B0,$B0,$E1,$E1,$E1,$DE,$DE,$DE,$9F,$9F,$9F,$00,$00,$00,
  42.      $00,$00,$00,$00,$00,$00,$00,$00,$00,$89,$89,$89,$FF,$FF,$FF,$FF,$FF,
  43.      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$BC,$BC,$BC,$21,$21,$21,$00,$00,$00,$00,
  44.      $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  45.      $00,$00,$00,$05,$05,$05,$EC,$EC,$EC,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,
  46.      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$F9,$F9,$F9,$A8,$A8,$A8,$60,$60,$60,$3D,
  47.      $3D,$3D,$3D,$3D,$3D,$60,$60,$60,$A8,$A8,$A8,$7B,$7B,$7B,$00,$00,$00,
  48.      $60,$60,$60,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,
  49.      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,
  50.      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$4A,$4A,$4A,$CC,$CC,$CC,
  51.      $FF,$FF,$FF,$FF,$FF,$FF);

Then when you create your button you can use:

Code: Pascal  [Select][+][-]
  1.   fpgImages.AddMaskedBMP(
  2.      'newimg.rotate',
  3.      @newimg_rotate,
  4.      sizeof(newimg_rotate), 0,0);
  5.  
  6.   MyButton := TfpgButton.Create(Self);
  7.   with MyButton do
  8.   begin
  9.     Name := 'MyButton';
  10.     Left := 10;
  11.     Top := 10;
  12.     Width := 24;
  13.     Height := 24;
  14.     Text := '';
  15.     ImageName:='newimg.rotate';
  16.     ShowImage := True;
  17.     ImageLayout:=ilImagetop;
  18.   end;
  19.  
« Last Edit: July 28, 2024, 12:51:57 am by Graham1 »
Windows 10/11 Home 64-bit (and Linux because I have to)
Lazarus 2.0.12 / FPC 3.2.0 (because libQt5pas 1.2.6)
Linux Mint 20 (because GLIBC_2.31)

Graham1

  • Jr. Member
  • **
  • Posts: 64
Re: fpGUI:How to add image for fpgbutton
« Reply #2 on: July 27, 2024, 02:17:35 am »
The problem with the above method is that you need CONST data for every size of button image, regardless of whether you use it at runtime.

Here's another way to do it, using the BGRA package and a PNG file in Resources. Note that the mask for the PNG is the top left pixel, so it works best if that is the same colour as your button. I use a 128x128 PNG as that allows for most sized buttons. The PNG file can't have transparency.

Requires package BGRABitmapPack4fpGUI.

Code: Pascal  [Select][+][-]
  1. uses
  2.   Classes, SysUtils,
  3.   fpg_base, fpg_main, fpg_form, fpg_button,
  4.   BGRABitmapTypes, BGRABitmap;

Code: Pascal  [Select][+][-]
  1. // OLD VERSION - see the post below for an update
  2. procedure FPGAddMask(ResName:string; MaskId:string; siz:integer);
  3. var   ResPng        : TBGRABitmap;
  4.       WrkBmp        : TBGRABitmap;
  5.       ImgArr        : array of byte;
  6.       InStream      : TFileStream;
  7.       i, cnt        : integer;
  8.       b             : byte = 0;
  9. begin
  10.    ResPng:=TBGRABitmap.Create;
  11.    ResPng.LoadFromResource(ResName);
  12.  
  13.    WrkBmp:=TBGRABitmap.Create;
  14.    BGRAReplace(WrkBmp, ResPng.Resample(siz, siz, rmFineResample));
  15.  
  16.    WrkBmp.SaveToFile('tempwork.bmp');
  17.  
  18.    InStream := TFileStream.Create('tempwork.bmp', fmOpenRead);
  19.    try
  20.      InStream.Seek(0, soFromBeginning);
  21.      cnt:=InStream.Size;
  22.      ImgArr:=[];
  23.      setlength(ImgArr, cnt);
  24.      for i:=0 to cnt-1 do begin
  25.        InStream.Read(b, 1);
  26.        ImgArr[i]:=b;
  27.      end;
  28.    finally
  29.      InStream.Free;
  30.    end;
  31.  
  32.    DeleteFile('tempwork.bmp');
  33.  
  34.    fpgImages.AddMaskedBMP(
  35.       MaskId,
  36.       @ImgArr[0],
  37.       cnt, 0,0);
  38.  
  39.    ResPng.Free;
  40.    WrkBmp.Free;
  41.  
  42. end;

Code: Pascal  [Select][+][-]
  1.   FPGAddMask('PNG_RES_NAME','myImgId',16);
  2.  
  3.   MyButton := TfpgButton.Create(Self);
  4.   with MyButton do
  5.   begin
  6.     Name := 'MyButton';
  7.     Left := 10;
  8.     Top := 10;
  9.     Width := 24;
  10.     Height := 24;
  11.     Text := '';
  12.     ImageMargin=1;
  13.     ImageName:='myImgId';
  14.     ShowImage := True;
  15.     ImageLayout:=ilImagetop;
  16.   end;

But now I have a question. How can I create the byte array without writing the image to a temporary file on disk first? It slows things down using the HDD and I think it's an ugly way of doing it. I tried to find the source code for SaveToFile but it seems to be buried in classes of classes.
« Last Edit: July 27, 2024, 03:07:37 am by Graham1 »
Windows 10/11 Home 64-bit (and Linux because I have to)
Lazarus 2.0.12 / FPC 3.2.0 (because libQt5pas 1.2.6)
Linux Mint 20 (because GLIBC_2.31)

TRon

  • Hero Member
  • *****
  • Posts: 3136
Re: fpGUI:How to add image for fpgbutton
« Reply #3 on: July 27, 2024, 02:29:57 am »
But now I have a question. How can I create the byte array without writing the image to a temporary file on disk first?
Usually by using SaveToStream, for example writing to a (temp) MemoryStream. TMemoryStream has a pointer to its memory that can be used.
All software is open source (as long as you can read assembler)

Graham1

  • Jr. Member
  • **
  • Posts: 64
Re: fpGUI:How to add image for fpgbutton
« Reply #4 on: July 27, 2024, 03:06:18 am »
Usually by using SaveToStream, for example writing to a (temp) MemoryStream. TMemoryStream has a pointer to its memory that can be used.

Thank you! I didn't know about TMemoryStream but that was the solution, although I'm not sure about the "pointer to its memory" bit. Now I have the following and it works fine.

Code: Pascal  [Select][+][-]
  1. procedure FPGAddMask(ResName:string; MaskId:string; siz:integer);
  2. var   ResPng        : TBGRABitmap;
  3.       WrkStream     : TMemoryStream;
  4.       ImgArr        : array of byte;
  5.       i, cnt        : integer;
  6.       b             : byte = 0;
  7. begin
  8.    ResPng:=TBGRABitmap.Create;
  9.    ResPng.LoadFromResource(ResName);
  10.    BGRAReplace(ResPng, ResPng.Resample(siz, siz, rmFineResample));
  11.  
  12.    WrkStream:=TMemoryStream.Create;
  13.    ResPng.SaveToStreamAs(WrkStream, ifBmp);
  14.  
  15.    try
  16.      WrkStream.Seek(0, soFromBeginning);
  17.      cnt:=WrkStream.Size;
  18.      ImgArr:=[];
  19.      setlength(ImgArr, cnt);
  20.      for i:=0 to cnt-1 do begin
  21.        WrkStream.Read(b, 1);
  22.        ImgArr[i]:=b;
  23.      end;
  24.    finally
  25.      WrkStream.Free;
  26.    end;
  27.  
  28.    fpgImages.AddMaskedBMP(
  29.       MaskId,
  30.       @ImgArr[0],
  31.       cnt, 0,0);
  32.  
  33.    ResPng.Free;
  34.  
  35. end;

Thank you again.
Windows 10/11 Home 64-bit (and Linux because I have to)
Lazarus 2.0.12 / FPC 3.2.0 (because libQt5pas 1.2.6)
Linux Mint 20 (because GLIBC_2.31)

TRon

  • Hero Member
  • *****
  • Posts: 3136
Re: fpGUI:How to add image for fpgbutton
« Reply #5 on: July 27, 2024, 03:14:12 am »
Thank you!
You're welcome... and tbh you did all the work so you can thank yourself as well  :)

Quote
I didn't know about TMemoryStream but that was the solution, although I'm not sure about the "pointer to its memory" bit.
If I understood the code and fpGUI correctly you could skip reading the data from the stream into the array, e.g.

Code: Pascal  [Select][+][-]
  1. procedure FPGAddMask(ResName:string; MaskId:string; siz:integer);
  2. var   ResPng        : TBGRABitmap;
  3.       WrkStream     : TMemoryStream;
  4.       ImgArr        : array of byte;
  5.       i, cnt        : integer;
  6.       b             : byte = 0;
  7. begin
  8.    ResPng:=TBGRABitmap.Create;
  9.    ResPng.LoadFromResource(ResName);
  10.    BGRAReplace(ResPng, ResPng.Resample(siz, siz, rmFineResample));
  11.  
  12.    WrkStream:=TMemoryStream.Create;
  13.    ResPng.SaveToStreamAs(WrkStream, ifBmp);
  14.  
  15. //   try
  16. //     WrkStream.Seek(0, soFromBeginning);
  17. //     cnt:=WrkStream.Size;
  18. //     ImgArr:=[];
  19. //     setlength(ImgArr, cnt);
  20. //     for i:=0 to cnt-1 do begin
  21. //       WrkStream.Read(b, 1);
  22. //       ImgArr[i]:=b;
  23. //     end;
  24. //   finally
  25. //     WrkStream.Free;
  26. //   end;
  27.  
  28.    fpgImages.AddMaskedBMP(
  29.       MaskId,
  30.       WrkStream.Memory,  // it might be that fpGUI wants that memory pointer being cast as an array of bytes, IDK
  31.       WrkStream.Size, 0,0);
  32.  
  33.    ResPng.Free;
  34.   WrkStream.Free;
  35. end;
  36.  

Perhaps you can make that work ?

PS: sorry I forgot to free the workstream but I assume you understand the idea. Added the missing free.
« Last Edit: July 27, 2024, 03:17:31 am by TRon »
All software is open source (as long as you can read assembler)

Graham1

  • Jr. Member
  • **
  • Posts: 64
Re: fpGUI:How to add image for fpgbutton
« Reply #6 on: July 27, 2024, 03:22:01 am »
Yes! That works and it's much cleaner. It looks like FPGUI isn't too bothered about what the data is as long as it's a list of bytes.

Thanks.
Windows 10/11 Home 64-bit (and Linux because I have to)
Lazarus 2.0.12 / FPC 3.2.0 (because libQt5pas 1.2.6)
Linux Mint 20 (because GLIBC_2.31)

TRon

  • Hero Member
  • *****
  • Posts: 3136
Re: fpGUI:How to add image for fpgbutton
« Reply #7 on: July 27, 2024, 03:36:07 am »
Yes! That works and it's much cleaner. It looks like FPGUI isn't too bothered about what the data is as long as it's a list of bytes.
Nice. Thank you for reporting back.

For reference, the Memory property is located in the TMemoryStream ancestor TCustomMemoryStream. The size property comes from the TMemoryStream ancestor TStream

Happy coding !

cleaned code:
Code: Pascal  [Select][+][-]
  1. procedure FPGAddMask(ResName:string; MaskId:string; siz:integer);
  2. var   ResPng        : TBGRABitmap;
  3.       WrkStream     : TMemoryStream;
  4. begin
  5.    ResPng:=TBGRABitmap.Create;
  6.    ResPng.LoadFromResource(ResName);
  7.    BGRAReplace(ResPng, ResPng.Resample(siz, siz, rmFineResample));
  8.  
  9.    WrkStream:=TMemoryStream.Create;
  10.    ResPng.SaveToStreamAs(WrkStream, ifBmp);
  11.    ResPng.Free;  // no need to keep the png alive after it was written to the stream
  12.  
  13.    fpgImages.AddMaskedBMP(
  14.       MaskId,
  15.       WrkStream.Memory,
  16.       WrkStream.Size, 0,0);
  17.  
  18.   WrkStream.Free;
  19. end;
  20.  
« Last Edit: July 27, 2024, 03:38:34 am by TRon »
All software is open source (as long as you can read assembler)

lazpas

  • Jr. Member
  • **
  • Posts: 86
Re: fpGUI:How to add image for fpgbutton
« Reply #8 on: July 27, 2024, 04:47:21 am »
Hello,Graham1

Thanks for help.

imageconvert for png picture not work. :(

I seem to have used the AddMaskedimage function to add the png image to the button, it worked, but there is a black background that cannot be removed. I will continue testing when the weather is cooler,BRGABitmap or other.
« Last Edit: July 27, 2024, 05:12:31 am by lazpas »

lazpas

  • Jr. Member
  • **
  • Posts: 86
Re: fpGUI:How to add image for fpgbutton
« Reply #9 on: July 27, 2024, 05:16:33 am »
Hello,TRon

Thanks for your code.

Graham1

  • Jr. Member
  • **
  • Posts: 64
Re: fpGUI:How to add image for fpgbutton
« Reply #10 on: July 28, 2024, 12:51:24 am »
Hi lazpas,

Yes, ImageConvert only works with BMP files, not PNG. I'll edit my first post above.

For the second method, using the resources, you can use a PNG file as my routine changes it to BMP when it saves it to the TMemoryStream. If you want to use a BMP in resources instead I think you need to include ".bmp" in the resource name when you call the LoadFromRource procedure.

For LCL the glyphs you use on buttons should be PNG files with a transparent background. But for FPGUI the images need to be masked BMP, meaning that the background colour is removed by FPGUI automatically. It decides what that background colour is by looking at the top left pixel. You cannot use a PNG file with any transparency as it will throw an exception.
Windows 10/11 Home 64-bit (and Linux because I have to)
Lazarus 2.0.12 / FPC 3.2.0 (because libQt5pas 1.2.6)
Linux Mint 20 (because GLIBC_2.31)

lazpas

  • Jr. Member
  • **
  • Posts: 86
Re: fpGUI:How to add image for fpgbutton
« Reply #11 on: July 28, 2024, 07:12:08 am »
Hi Graham1,

Thank you very much for your suggestion. I'll try your code.

Have a nice day.

 

TinyPortal © 2005-2018