Recent

Author Topic: [Solved] Storing image resources in a separate unit  (Read 1747 times)

heebiejeebies

  • Full Member
  • ***
  • Posts: 129
[Solved] Storing image resources in a separate unit
« on: April 06, 2024, 01:39:03 am »
Hi all,

I previously posted a question about why the IDE was running slowly when editing my gigantic main unit.  Although there were a number of excellent suggestions, nothing seems to have helped.  So at this point I have to conclude that the file is too large and I should try moving some of the image resources to a separate unit.   The way I've been doing this is to create a TPicture in a new unit called SharedResource and then assign the image from the SharedResource unit to a blank TImage in my main unit at runtime. 

Code: Pascal  [Select][+][-]
  1. BlankCanvas.Picture := SharedResource.MyPicture.Picture;

This works, but there's a weird bug.  If the image gets assigned again then it loses antialiasing.  Looks fine the first time, but when the code runs again, no antialiasing.  At least I think that's what's happening as the edges of the image, where the image proper meets the transparent background, look jagged.  I've tried qualifying it with "If BlankCanvas.Picture <> SharedResource.MyPicture.Picture then .... " to stop the code from ever running twice but this does not work.  Nor does manually setting antialising options.  Any ideas?  Am I even approaching this the right way?

Thanks for your help   :)
« Last Edit: April 09, 2024, 10:43:36 am by heebiejeebies »
Fedora 38/Lazarus 2.2.4- FPC 3.3.1

lainz

  • Hero Member
  • *****
  • Posts: 4593
  • Web, Desktop & Android developer
    • https://lainz.github.io/
Re: Storing image resources in a separate unit
« Reply #1 on: April 06, 2024, 01:59:39 am »
There is Project > Project Options > Resources.

How to load from resource: I don't know, maybe other knows.

Handoko

  • Hero Member
  • *****
  • Posts: 5290
  • My goal: build my own game engine using Lazarus
Re: Storing image resources in a separate unit
« Reply #2 on: April 06, 2024, 04:17:05 am »
Loading image from resources is easy. You can find a demo in the link below "Load and show image from Resource Stream" in the File Handling category:

https://wiki.freepascal.org/Portal:HowTo_Demos#File_handling

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: Storing image resources in a separate unit
« Reply #3 on: April 06, 2024, 02:03:48 pm »
There are several ways to integrate images into an application to be used at runtime.
I would say it depend on usage to choose what fit best.
If its just a few images that needs to be computed very fast, either store them in a TImageList or link them as an array of byte into your code (as data.inc file for example) or the traditional resourcestream way.
(For resourcestreams I personal prefer to write a small script that includes everything, it compiles and link in automatic when building the binary,
the benefit is that you can have the script open within IDE to quick modify something
the disavantage, you can not use the resources menu from IDE.)
When its a big collection I would think about a different approach that would use external data, two things popping up fast on that matter, either archive them (.zip exemplary) or put them into a database, at runtime the data must be extracted to be used, some archive libraries offer for such suppose to extract direct into a stream that you can use within your app to not need to write data first to disk.
At the end all approaches do the same, difference is memory consumption vs execution speed vs maintain/updating.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

Handoko

  • Hero Member
  • *****
  • Posts: 5290
  • My goal: build my own game engine using Lazarus
Re: Storing image resources in a separate unit
« Reply #4 on: April 06, 2024, 04:55:30 pm »
You're right, there are many ways to integrate images into a program.
I like to try doing thing in different ways. I wrote myself a module and tool to convert images into Pascal includable text files, so images can be included in compile time. It works similar to BASIC's Data and Read commands, I was a fan of BASIC.
For my game engine, I wrote myself a module to store all kinds of data. I can throw pictures, audio and binary files or whatever into a single file. Basically, it is a kind of noSQL database, lol. Then the data can be merged into the end of the program binary. At runtime, the program will automatically locate the data correctly. I do it because I want to distribute my game as a single program file. It works, tested on WinXP and Win7. It may not work on Win10 due to security issue. But I haven't tried because I later found myself busy doing other things.

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: Storing image resources in a separate unit
« Reply #5 on: April 06, 2024, 08:18:30 pm »
I wrote myself a module and tool to convert images into Pascal includable text files, so images can be included in compile time. It works similar to BASIC's Data and Read commands, I was a fan of BASIC.
Maybe we've done same thing just different way's.
Here is my contribution to include whatever as a const, non optimized but it's working for me good.
Also included is a simple read-back method.
Code: Pascal  [Select][+][-]
  1. program bintoinc;
  2.  
  3. {$APPTYPE console}
  4.  
  5. uses
  6.   SysUtils, Classes;
  7.  
  8. {$R *.res}
  9.  
  10. function CreateStringListFromConst(const ABytes: array of byte): TStrings;
  11.   function ConstToBytes(const ABytes: array of byte): TBytes;
  12.   var
  13.     i: Integer;
  14.   begin
  15.     SetLength(Result, High(ABytes));
  16.     for i := 0 to High(ABytes) do
  17.       Result[i] := ABytes[i];
  18.   end;
  19. var
  20.   bytes: TBytes;
  21.   stream: TStream;
  22. begin
  23.   if High(ABytes) <= 0 then
  24.     Exit;
  25.   Result := TStringList.Create;
  26.   bytes := ConstToBytes(ABytes);
  27.   stream := TBytesStream.Create(bytes);
  28.   try
  29.     Result.LoadFromStream(stream);
  30.   finally
  31.     stream.Free;
  32.   end;
  33. end;
  34.  
  35. function Bin2Inc(const AInputFile: String; const AOutputFile: string = ''): Boolean;
  36.   function FileToBytes(const AFilename: string): TBytes;
  37.   var
  38.     FileStream: TFileStream;
  39.   begin
  40.     FileStream := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite);
  41.     try
  42.       SetLength(Result, FileStream.Size);
  43.       FileStream.ReadBuffer(Result[0], FileStream.Size);
  44.     finally
  45.       FileStream.Free;
  46.     end;
  47.   end;
  48. var
  49.   bytes: TBytes;
  50.   sl: TStrings;
  51.   s: AnsiString;
  52.   i: Integer;
  53.   cnt: Integer;
  54. begin
  55.   Result := False;
  56.   if (not FileExists(AInputFile)) then
  57.     Exit;
  58.   bytes := FileToBytes(AInputFile);
  59.   if High(bytes) = 0 then
  60.     Exit;
  61.   sl := TStringList.Create;
  62.   try
  63.     cnt := 0;
  64.     s := '';
  65.     sl.Add('const ' + Copy(ExtractFilename(AInputFile), 1, Length(ExtractFilename(AInputFile)) - Length(ExtractFileExt(AInputFile))) + ': array[0..' + IntToStr(High(bytes)) + '] of byte = (');
  66.     for i := 0 to High(bytes) do
  67.       begin
  68.         if cnt < 85 then
  69.           begin
  70.             if i = High(bytes) then
  71.               s := s + ' $' + IntToHex(bytes[i], 2) + ');'
  72.             else
  73.               s := s + ' $' + IntToHex(bytes[i], 2) + ',';
  74.             Inc(cnt, 1);
  75.           end;
  76.         if cnt = 85 then
  77.           begin
  78.             sl.Add(s);
  79.             cnt := 0;
  80.             s := '';
  81.           end;
  82.       end;
  83.     if (s <> '') then
  84.       sl.Add(s);
  85.     if (AOutputFile = '') then
  86.       sl.SaveToFile(ChangeFileExt(AInputFile, '.inc'))
  87.     else
  88.       sl.SaveToFile(AOutputFile);
  89.   finally
  90.     sl.Free;
  91.   end;
  92. end;
  93.  
  94. begin
  95.   if ParamCount > 0 then
  96.     Bin2Inc(ParamStr(1));
  97.   ReadLn;
  98. end.
Very simple done, not much info spoken lol.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

heebiejeebies

  • Full Member
  • ***
  • Posts: 129
Re: Storing image resources in a separate unit
« Reply #6 on: April 09, 2024, 10:43:20 am »
Thanks everyone!  :D I'm assuming you didn't write that last bit all for me KodeZwerg but thanks for the excellent responses ! :D  And lainz/Handoko.  Seems I can store a PNG as an RCDATA resource and load it as many times as I want without the antialiasing getting all weird and creepy.  WOOO  :D
Fedora 38/Lazarus 2.2.4- FPC 3.3.1

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11732
  • FPC developer.
Re: [Solved] Storing image resources in a separate unit
« Reply #7 on: April 09, 2024, 10:59:04 am »
The attempt I did in 1998 to create .INCs is included in FPC as data2inc :-)

And there is a bin2obj.exe included (which is a misnomer as it generates inc files)

 

TinyPortal © 2005-2018