How do I make a PNG resource?
Asked Answered
S

4

40

I've got a form with a large TImage on it as a background. Problem is, this is stored directly in the DFM as a bitmap, which takes up about 3 MB. The original PNG file is ~250K. I'd like to try to reduce bloat by embedding the PNG in a resource, and then having the form load it during OnCreate. I can do that now that Delphi 2009 includes PNG support, except I don't quite know how to build a resource file with a PNG in it. Anyone know how that's done?

Shipp answered 20/7, 2009 at 12:51 Comment(0)
O
61

Example text file (named myres.rc):

MYPNG RCDATA mypng.png

Added to project:

{$R 'myres.res' 'myres.rc'}

Example of loading at runtime:

uses
  PngImage;

var
  Png: TPngImage;
begin
  Png := TPngImage.Create;
  try
    Png.LoadFromResourceName(HInstance, 'MYPNG');
    Image1.Picture.Graphic := Png; // Image1: TImage on the form
  finally
    Png.Free;
  end;
end;
Odontalgia answered 20/7, 2009 at 13:20 Comment(5)
Is RCDATA really the most specific resource type available for that graphic type? There's no RT_PNG, for instance?Anchylose
Good question, Rob. My currently installed Platform SDK is for Windows Server 2003 R2, and I couldn't find a PNG-specific constant in WinUser.h. I'm not sure, though. It might be declared somewhere else, perhaps in a later version of the Platform SDK.Odontalgia
LoadFromResourceName specifically looks for a resource of type RCDATA.Shipp
You can also include the resource in your MSBuild process: tondrej.blogspot.com/2016/08/…Odontalgia
It seems that for a .DLL project the auto .rc file compilation doesn't work?Clementineclementis
S
2

For those who use C++ Builder this code works for me :

In the ResourceTest.rc file

IMG_BMP BITMAP "Ressources\\myimage.bmp";
IMG_PNG RCDATA "Ressources\\myimage.png";

In the ResourceTest.rh file

#ifndef ResourceTestRH
#define ResourceTestRH

#define IMG_BMP "IMG_BMP"
#define IMG_PNG "IMG_PNG"

#endif

In the ResourceTest.cpp file

#include "pngimage.hpp"

// Loading bmp image from resource
Graphics::TBitmap *bmpImage = new Graphics::TBitmap();
bmpImage->LoadFromResourceName((int)HInstance, IMG_BMP);

// Loading png image from resource
TPngImage *pngImage = new TPngImage();
pngImage->LoadFromResourceName((int)HInstance, IMG_PNG);
Strike answered 16/9, 2011 at 12:56 Comment(0)
L
1

If you're using Delphi 2009, TImage should store your PNG file as a PNG into the DFM file. The DFM will be larger because the binary content of the Picture.Data property of the TImage object is encoded in the DFM as hexadecimal text. But when the DFM is compiled into your EXE, it is compiled into a binary resource. Your image should then take up the same space inside the form's RCDATA resource as storing the PNG in its own RCDATA resource would.

I just tested this by opening one of my own Delphi 2009 DFM files that have a TImage component with a PNG image loaded at design time in a text editor, copying the contents of the Picture.Data property and pasting them into a hex editor. The hex editor shows me that the Picture.Data property stores an actual PNG file prefixed with 10 bytes. The first byte is $09 and the next 9 bytes spell TPngImage. If I delete those 10 bytes and save the file in the hex editor, I get a proper PNG file.

So if you're using Delphi 2009, simply load the PNG image into a TImage component at design time.

Lesley answered 21/8, 2009 at 5:46 Comment(2)
Interesting, but what about the case where an image gets reused on multiple forms? Is Delphi smart enough to store only one copy, or does it store the image n times, where n is the number of TImage components with that image loaded? :)Heddy
Each TImage component stores its image independent of any other TImage instances. So if you load the same image into n instances of TImage, the same image is stored n times. One way to solve this is to use form inheritance. Create a base form with the TImage and load the image into it. Then derive all forms that need to have the same TImage from that form. Any properties that are not changed in descendant forms are only stored in the DFM of the ancestor form. That includes the picture data of a TImage.Lesley
V
1

When using Resource Hacker, PNG images are added with 'PNG' ResType rather than common RT_RCDATA.

A TPngImage Class Helper gives a simple solution for this issue :

Type
  TPngImageHelper = Class Helper For Vcl.Imaging.pngimage.TPngImage
    Procedure LoadFromRHResourceName(Instance: HInst; Const Name: String);
  End;

...

Procedure TPngImageHelper.LoadFromRHResourceName(Instance: HInst; Const Name: String);
Var
  rs: TResourceStream;
Begin
  rs := TResourceStream.Create(Instance, PChar(Name), 'PNG');
  Try
    LoadFromStream(rs);
  Finally
    rs.Free;
  End;
End;

With a simple use:

var
  pngInfo: TPngImage;
begin
  pngInfo := TPngImage.Create;
  try
    pngInfo.LoadFromRHResourceName(HInstance, 'MY_IMAGE.PNG');
    Image1.Picture.Graphic:= pngInfo;
  finally
    pngInfo.Free;
  end;
end;
Vaporish answered 7/4, 2018 at 19:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.