Browse Source

Third approach.

Keep TBitmapImage using TBitmap only (so no use of pngimage or WIC stuff there) but convert any TPngImage to TBitmap when assigning it to the TBitmapImage using a single simple Assign call in TBitmapImageImplementation.SetGraphic.

Setup uses pngimage in Setup.MainFunc to load any PNG, but no WIC stuff. ISCmplr has no extra uses at all. So no extra run-time dependencies.

Also means run-time support for PNG. (Did not yet add stuff to make it visible to [Code].)

The builtin images are now PNG so Compil32 actually decreased in size.

The only downside is the extra size of pngimage code in Setup but thats only a few kb which is well worth having PNG support. Not only is PNG support by many more tools, also it has no annoying AlphaFormat to set.

Using TBitmapImage or TBitmapButton design-time doesnt really work for transparent images because both AlphaFormat and Graphic are missing in the list of published properties. Not sure how to fix, but also doesnt matter for us.
Martijn Laan 3 weeks ago
parent
commit
4c783a234e

+ 9 - 0
Components/BitmapButton.pas

@@ -9,6 +9,8 @@ unit BitmapButton;
   A TImage-like component for bitmaps without the TPicture bloat and
   which is actually a button with a focus rectangle when focused - in
   other words: an accessible TImage
+
+  Also supports other TGraphic types which can be assigned to a TBitmap, like TPngImage
   
   Make sure to set the Caption property, even if it isn't visible
 
@@ -29,6 +31,7 @@ type
     procedure SetBackColor(Value: TColor);
     procedure SetBitmap(Value: TBitmap);
     procedure SetCenter(Value: Boolean);
+    procedure SetGraphic(Value: TGraphic);
     procedure SetReplaceColor(Value: TColor);
     procedure SetReplaceWithColor(Value: TColor);
     procedure SetStretch(Value: Boolean);
@@ -44,6 +47,7 @@ type
     constructor Create(AOwner: TComponent); override;
     destructor Destroy; override;
     function InitializeFromIcon(const Instance: HINST; const Name: PChar; const BkColor: TColor; const AscendingTrySizes: array of Integer): Boolean;
+    property Graphic: TGraphic write SetGraphic;
   published
     property Align;
     property Anchors;
@@ -128,6 +132,11 @@ begin
   FImpl.SetCenter(Self, Value);
 end;
 
+procedure TBitmapButton.SetGraphic(Value: TGraphic);
+begin
+  FImpl.SetGraphic(Value);
+end;
+
 procedure TBitmapButton.SetReplaceColor(Value: TColor);
 begin
   FImpl.SetReplaceColor(Self, Value);

+ 16 - 1
Components/BitmapImage.pas

@@ -7,6 +7,8 @@ unit BitmapImage;
   For conditions of distribution and use, see LICENSE.TXT.
 
   A TImage-like component for bitmaps without the TPicture bloat
+  
+  Also supports other TGraphic types which can be assigned to a TBitmap, like TPngImage
 
   Also see TBitmapButton which is the TWinControl version
 }
@@ -43,6 +45,7 @@ type
     procedure SetBackColor(Sender: TObject; Value: TColor);
     procedure SetBitmap(Value: TBitmap);
     procedure SetCenter(Sender: TObject; Value: Boolean);
+    procedure SetGraphic(Value: TGraphic);
     procedure SetReplaceColor(Sender: TObject; Value: TColor);
     procedure SetReplaceWithColor(Sender: TObject; Value: TColor);
     procedure SetStretch(Sender: TObject; Value: Boolean);
@@ -56,6 +59,7 @@ type
     procedure SetBackColor(Value: TColor);
     procedure SetBitmap(Value: TBitmap);
     procedure SetCenter(Value: Boolean);
+    procedure SetGraphic(Value: TGraphic);
     procedure SetReplaceColor(Value: TColor);
     procedure SetReplaceWithColor(Value: TColor);
     procedure SetStretch(Value: Boolean);
@@ -67,17 +71,18 @@ type
     constructor Create(AOwner: TComponent); override;
     destructor Destroy; override;
     function InitializeFromIcon(const Instance: HINST; const Name: PChar; const BkColor: TColor; const AscendingTrySizes: array of Integer): Boolean;
+    property Graphic: TGraphic write SetGraphic;
   published
     property Align;
     property Anchors;
     property AutoSize: Boolean read FImpl.AutoSize write SetAutoSize default False;
     property BackColor: TColor read FImpl.BackColor write SetBackColor default clBtnFace;
+    property Bitmap: TBitmap read FImpl.Bitmap write SetBitmap;
     property Center: Boolean read FImpl.Center write SetCenter default False;
     property DragCursor;
     property DragMode;
     property Enabled;
     property ParentShowHint;
-    property Bitmap: TBitmap read FImpl.Bitmap write SetBitmap;
     property PopupMenu;
     property ShowHint;
     property Stretch: Boolean read FImpl.Stretch write SetStretch default False;
@@ -209,6 +214,11 @@ begin
   end;
 end;
 
+procedure TBitmapImageImplementation.SetGraphic(Value: TGraphic);
+begin
+  Bitmap.Assign(Value);
+end;
+
 procedure TBitmapImageImplementation.SetReplaceColor(Sender: TObject; Value: TColor);
 begin
   if ReplaceColor <> Value then begin
@@ -351,6 +361,11 @@ begin
   FImpl.SetCenter(Self, Value);
 end;
 
+procedure TBitmapImage.SetGraphic(Value: TGraphic);
+begin
+  FImpl.SetGraphic(Value);
+end;
+
 procedure TBitmapImage.SetReplaceColor(Value: TColor);
 begin
   FImpl.SetReplaceColor(Self, Value);

+ 14 - 14
ISHelp/isetup.xml

@@ -5456,10 +5456,10 @@ DiskSliceSize=736000000
 <setuptopic directive="WizardImageFile">
 <setupdefault><i>(blank)</i></setupdefault>
 <body>
-<p>Specifies the name(s) of the bitmap file(s) to display on the left side of the <i>Welcome</i> and <i>Setup Completed</i> wizard pages. Wildcards are supported and the files(s) must be located in your installation's <link topic="sourcedirectorynotes">source directory</link> when running the compiler, unless a fully qualified pathname is specified or the pathname is prefixed by "compiler:", in which case it looks for the file in the compiler directory.</p>
-<p>Supports transparent bitmaps, see <link topic="setup_wizardimagealphaformat">WizardImageAlphaFormat</link> for more information.</p>
-<p>The size of the area in which the image is displayed depends on the system's DPI setting and whether the default <link topic="langoptionssection">font settings</link> are being used. At standard DPI with the default font settings, the size of the area is 164x314 pixels. At 200% DPI, the width and height will be roughly double that. In all cases, an aspect ratio of 164:314 is maintained. The specified bitmap should have the same aspect ratio.</p>
-<p>Any size of bitmap may be used; by default, bitmaps that are too small or too large to fit in the image area will be stretched or shrunk. Specifying a bitmap larger than 164x314 is recommended to avoid the image looking blurry on higher-DPI systems. The size of the default built-in image is 240x459.</p>
+<p>Specifies the name(s) of the image file(s) to display on the left side of the <i>Welcome</i> and <i>Setup Completed</i> wizard pages. Wildcards are supported and the files(s) must be located in your installation's <link topic="sourcedirectorynotes">source directory</link> when running the compiler, unless a fully qualified pathname is specified or the pathname is prefixed by "compiler:", in which case it looks for the file in the compiler directory.</p>
+<p>Supports .bmp and .png images, including those with transparency. Even transparent .bmp files are supported, see <link topic="setup_wizardimagealphaformat">WizardImageAlphaFormat</link> for more information.</p>
+<p>The size of the area in which the image is displayed depends on the system's DPI setting and whether the default <link topic="langoptionssection">font settings</link> are being used. At standard DPI with the default font settings, the size of the area is 164x314 pixels. At 200% DPI, the width and height will be roughly double that. In all cases, an aspect ratio of 164:314 is maintained. The specified image should have the same aspect ratio.</p>
+<p>Any size of image may be used; by default, images that are too small or too large to fit in the image area will be stretched or shrunk. Specifying an image larger than 164x314 is recommended to avoid the image looking blurry on higher-DPI systems. The size of the default built-in image is 240x459.</p>
 <p>If a single larger-sized image does not produce a satisfactory result across different DPI settings, multiple files may be specified, separated by commas. In that case, Setup will automatically select the one that best matches the size of the image area. Assuming the default font settings are being used, the size of the image area at various DPI settings is:</p>
 <table>
 <tr><td>100%</td><td>164x314</td></tr>
@@ -5484,10 +5484,10 @@ DiskSliceSize=736000000
 <setuptopic directive="WizardSmallImageFile">
 <setupdefault><i>(blank)</i></setupdefault>
 <body>
-<p>Specifies the name(s) of the bitmap file(s) to display in the upper right corner of the wizard. Wildcards are supported and the file(s) must be located in your installation's <link topic="sourcedirectorynotes">source directory</link> when running the compiler, unless a fully qualified pathname is specified or the pathname is prefixed by "compiler:", in which case it looks for the file in the compiler directory.</p>
-<p>Supports transparent bitmaps, see <link topic="setup_wizardimagealphaformat">WizardImageAlphaFormat</link> for more information.</p>
-<p>The size of the area in which the image is displayed depends on the system's DPI setting and whether the default <link topic="langoptionssection">font settings</link> are being used. At standard DPI with the default font settings, the size of the area is 58x58 pixels. At 200% DPI, the width and height will be roughly double that. In all cases, the area is square; thus, the specified bitmap should be square as well.</p>
-<p>Any size of bitmap may be used; by default, bitmaps that are too small or too large to fit in the image area will be stretched or shrunk. Specifying a bitmap larger than 58x58 is recommended to avoid the image looking blurry on higher-DPI systems. The size of the default built-in image is 147x147.</p>
+<p>Specifies the name(s) of the image file(s) to display in the upper right corner of the wizard. Wildcards are supported and the file(s) must be located in your installation's <link topic="sourcedirectorynotes">source directory</link> when running the compiler, unless a fully qualified pathname is specified or the pathname is prefixed by "compiler:", in which case it looks for the file in the compiler directory.</p>
+<p>Supports .bmp and .png images, including those with transparency. Even transparent .bmp files are supported, see <link topic="setup_wizardimagealphaformat">WizardImageAlphaFormat</link> for more information.</p>
+<p>The size of the area in which the image is displayed depends on the system's DPI setting and whether the default <link topic="langoptionssection">font settings</link> are being used. At standard DPI with the default font settings, the size of the area is 58x58 pixels. At 200% DPI, the width and height will be roughly double that. In all cases, the area is square; thus, the specified image should be square as well.</p>
+<p>Any size of image may be used; by default, images that are too small or too large to fit in the image area will be stretched or shrunk. Specifying an image larger than 58x58 is recommended to avoid the image looking blurry on higher-DPI systems. The size of the default built-in image is 147x147.</p>
 <p>If a single larger-sized image does not produce a satisfactory result across different DPI settings, multiple files may be specified, separated by commas. In that case, Setup will automatically select the one that best matches the size of the image area. Assuming the default font settings are being used, the size of the image area at various DPI settings is:</p>
 <table>
 <tr><td>100%</td><td>58x58</td></tr>
@@ -5499,7 +5499,7 @@ DiskSliceSize=736000000
 <tr><td>250%</td><td>147x147</td></tr>
 </table>
 <p>(You may notice that the size at 200% is not exactly double the 100% size. This is because the scaling factor is based on the dimensions of the font that a DPI setting uses, not the DPI itself.)</p>
-<p>Backward compatibility note: If a single bitmap smaller than 58x58 is specified, the bitmap will not be stretched to fill the entire image area; instead, it will be centered.</p>
+<p>Backward compatibility note: If a single image smaller than 58x58 is specified, the image will not be stretched to fill the entire image area; instead, it will be centered.</p>
 <p>If this directive is not specified or is blank, a single built-in 147x147 wizard image will be used, by default stretched or shrunk if the image is larger or smaller than required.</p>
 <p>To use the old default wizard images set this directive to <tt>compiler:WizClassicSmallImage.bmp</tt>.</p>
 <example><pre>WizardSmallImageFile=mysmallimage.bmp,mysmallimage2.bmp</pre></example>
@@ -5527,11 +5527,11 @@ DiskSliceSize=736000000
 <setupvalid><tt>none</tt>, <tt>defined</tt>, <tt>premultiplied</tt></setupvalid>
 <setupdefault><tt>none</tt></setupdefault>
 <body>
-<p>If set to <tt>none</tt>, the default, any wizard image which is a 32-bit bitmap file should not have an alpha channel.</p>
-<p>If set to <tt>premultiplied</tt>, any wizard image which is a 32-bit bitmap file should have its red, green and blue channel values premultiplied with the alpha channel value.</p>
-<p>If set to <tt>defined</tt>, any wizard image which is a 32-bit bitmap file should not have its red, green and blue channel values premultiplied with the alpha channel value.</p>
-<p>This directive has no effect for a wizard image which is not a 32-bit bitmap file.</p>
-<p>To create transparent 32-bit bitmaps compatible with Inno Setup, you can use Paint.NET, a free image editor. Open your transparent image in Paint.NET, save it as a 32-bit .bmp file, and then set this directive to <tt>defined</tt>. These files may appear large, but Inno Setup compresses them using LZMA, which typically achieves better compression ratios than, for example, PNG compression.</p>
+<p>If set to <tt>none</tt>, the default, any wizard image which is a 32-bit .bmp file should not have an alpha channel.</p>
+<p>If set to <tt>premultiplied</tt>, any wizard image which is a 32-bit .bmp file should have its red, green and blue channel values premultiplied with the alpha channel value.</p>
+<p>If set to <tt>defined</tt>, any wizard image which is a 32-bit .bmp file should not have its red, green and blue channel values premultiplied with the alpha channel value.</p>
+<p>This directive has no effect for a wizard image which is not a 32-bit .bmp file.</p>
+<p>To create transparent .bmp files compatible with Inno Setup, you can use Paint.NET, a free image editor. Open your transparent image in Paint.NET, save it as a 32-bit .bmp file, and then set this directive to <tt>defined</tt>. These files may appear large, but Inno Setup compresses them using LZMA, which typically achieves better compression ratios than, for example, PNG compression.</p>
 <p><b>See also:</b><br/>
 <link topic="setup_wizardimagefile">WizardImageFile</link><br/>
 <link topic="setup_wizardsmallimagefile">WizardSmallImageFile</link></p>

BIN
Projects/Res/ISCmplr.images.res


+ 54 - 18
Projects/Src/Compiler.SetupCompiler.pas

@@ -65,6 +65,15 @@ type
   TPrecompiledFile = (pfSetupE32, pfSetupLdrE32, pfIs7zDll, pfIsbunzipDll, pfIsunzlibDll, pfIslzmaExe);
   TPrecompiledFiles = set of TPrecompiledFile;
 
+  TWizardImage = class
+    Stream: TCustomMemoryStream;
+    Format: TWizardImageGraphicFormat;
+    constructor Create(const AStream: TCustomMemoryStream; const AFormat: TWizardImageGraphicFormat);
+    destructor Destroy; override;
+  end;
+
+  TWizardImages = TObjectList<TWizardImage>;
+
   TSetupCompiler = class
   private
     ScriptFiles: TStringList;
@@ -261,8 +270,8 @@ type
     procedure WriteDebugEntry(Kind: TDebugEntryKind; Index: Integer; StepOutMarker: Boolean = False);
     procedure WriteCompiledCodeText(const CompiledCodeText: Ansistring);
     procedure WriteCompiledCodeDebugInfo(const CompiledCodeDebugInfo: AnsiString);
-    function CreateMemoryStreamsFromFiles(const ADirectiveName, AFiles: String): TObjectList<TCustomMemoryStream>;
-    function CreateMemoryStreamsFromResources(const AResourceNamesPrefixes, AResourceNamesPostfixes: array of String): TObjectList<TCustomMemoryStream>;
+    function CreateWizardImagesFromFiles(const ADirectiveName, AFiles: String): TWizardImages;
+    function CreateWizardImagesFromResources(const AResourceNamesPrefixes, AResourceNamesPostfixes: array of String): TWizardImages;
     procedure VerificationError(const AError: TVerificationError;
       const AFilename: String; const ASigFilename: String = '');
   public
@@ -378,6 +387,21 @@ begin
   Result := False;
 end;
 
+{ TWizardImage }
+
+constructor TWizardImage.Create(const AStream: TCustomMemoryStream; const AFormat: TWizardImageGraphicFormat);
+begin
+  inherited Create;
+  Stream := AStream;
+  Format := AFormat;
+end;
+
+destructor TWizardImage.Destroy;
+begin
+  Stream.Free;
+  inherited;
+end;
+
 { TSetupCompiler }
 
 constructor TSetupCompiler.Create(AOwner: TComponent);
@@ -475,12 +499,14 @@ begin
   inherited Destroy;
 end;
 
-function TSetupCompiler.CreateMemoryStreamsFromFiles(const ADirectiveName, AFiles: String): TObjectList<TCustomMemoryStream>;
+function TSetupCompiler.CreateWizardImagesFromFiles(const ADirectiveName, AFiles: String): TWizardImages;
 
   procedure AddFile(const Filename: String);
+  const
+    Formats: array [Boolean] of TWizardImageGraphicFormat = (gfBitmap, gfPng);
   begin
     AddStatus(Format(SCompilerStatusReadingInFile, [FileName]));
-    Result.Add(CreateMemoryStreamFromFile(FileName));
+    Result.Add(TWizardImage.Create(CreateMemoryStreamFromFile(FileName),  Formats[SameText(PathExtractExt(Filename), '.png')]));
   end;
 
 var
@@ -490,7 +516,7 @@ var
   H: THandle;
   FindData: TWin32FindData;
 begin
-  Result := TObjectList<TCustomMemoryStream>.Create;
+  Result := TWizardImages.Create;
   try
     { In older versions only one file could be listed and comma's could be used so
       before treating AFiles as a list, first check if it's actually a single file
@@ -532,15 +558,15 @@ begin
   end;
 end;
 
-function TSetupCompiler.CreateMemoryStreamsFromResources(const AResourceNamesPrefixes, AResourceNamesPostfixes: array of String): TObjectList<TCustomMemoryStream>;
+function TSetupCompiler.CreateWizardImagesFromResources(const AResourceNamesPrefixes, AResourceNamesPostfixes: array of String): TWizardImages;
 var
   I, J: Integer;
 begin
-  Result := TObjectList<TCustomMemoryStream>.Create;
+  Result := TWizardImages.Create;
   try
     for I := 0 to Length(AResourceNamesPrefixes)-1 do
       for J := 0 to Length(AResourceNamesPostfixes)-1 do
-        Result.Add(TResourceStream.Create(HInstance, AResourceNamesPrefixes[I]+AResourceNamesPostfixes[J], RT_RCDATA));
+        Result.Add(TWizardImage.Create(TResourceStream.Create(HInstance, AResourceNamesPrefixes[I]+AResourceNamesPostfixes[J], RT_RCDATA), gfPng));
   except
     Result.Free;
     raise;
@@ -6860,14 +6886,14 @@ var
   SetupFile: TFile;
   ExeFile: TFile;
   LicenseText, InfoBeforeText, InfoAfterText: AnsiString;
-  WizardImages, WizardSmallImages: TObjectList<TCustomMemoryStream>;
+  WizardImages, WizardSmallImages: TWizardImages;
   DecompressorDLL, SevenZipDLL: TMemoryStream;
 
   SizeOfExe, SizeOfHeaders: Int64;
 
   function WriteSetup0(const F: TFile): Int64;
 
-    procedure WriteStream(Stream: TCustomMemoryStream; W: TCompressedBlockWriter);
+    procedure WriteStream(const Stream: TCustomMemoryStream; const W: TCompressedBlockWriter);
     var
       Size: Longint;
     begin
@@ -6876,6 +6902,12 @@ var
       W.Write(Stream.Memory^, Size);
     end;
 
+    procedure WriteWizardImage(const WizardImage: TWizardImage; const W: TCompressedBlockWriter);
+    begin
+      W.Write(WizardImage.Format, SizeOf(TWizardImageGraphicFormat));
+      WriteStream(WizardImage.Stream, W);
+    end;
+
   var
     J: Integer;
     W: TCompressedBlockWriter;
@@ -6970,10 +7002,10 @@ var
 
       W.Write(WizardImages.Count, SizeOf(Integer));
       for J := 0 to WizardImages.Count-1 do
-        WriteStream(WizardImages[J], W);
+        WriteWizardImage(WizardImages[J], W);
       W.Write(WizardSmallImages.Count, SizeOf(Integer));
       for J := 0 to WizardSmallImages.Count-1 do
-        WriteStream(WizardSmallImages[J], W);
+        WriteWizardImage(WizardSmallImages[J], W);
       if SetupHeader.CompressMethod in [cmZip, cmBzip] then
         WriteStream(DecompressorDLL, W);
       if SetupHeader.SevenZipLibraryName <> '' then
@@ -7995,9 +8027,11 @@ begin
         WarningsList.Add(Format(SCompilerWizImageRenamed, [WizardImageFile, 'compiler:WizClassicImage.bmp']));
         WizardImageFile := 'compiler:WizClassicImage.bmp';
       end;
-      WizardImages := CreateMemoryStreamsFromFiles('WizardImageFile', WizardImageFile)
-    end else
-      WizardImages := CreateMemoryStreamsFromResources(['WizardImage'], ['150']);
+      WizardImages := CreateWizardImagesFromFiles('WizardImageFile', WizardImageFile)
+    end else begin
+      WizardImages := CreateWizardImagesFromResources(['WizardImage'], ['150']);
+      Include(SetupHeader.Options, shUsesBuiltinWizardImages);
+    end;
     LineNumber := SetupDirectiveLines[ssWizardSmallImageFile];
     AddStatus(Format(SCompilerStatusReadingFile, ['WizardSmallImageFile']));
     if WizardSmallImageFile <> '' then begin
@@ -8005,9 +8039,11 @@ begin
         WarningsList.Add(Format(SCompilerWizImageRenamed, [WizardSmallImageFile, 'compiler:WizClassicSmallImage.bmp']));
         WizardSmallImageFile := 'compiler:WizClassicSmallImage.bmp';
       end;
-      WizardSmallImages := CreateMemoryStreamsFromFiles('WizardSmallImage', WizardSmallImageFile)
-    end else
-      WizardSmallImages := CreateMemoryStreamsFromResources(['WizardSmallImage'], ['250']);
+      WizardSmallImages := CreateWizardImagesFromFiles('WizardSmallImage', WizardSmallImageFile)
+    end else begin
+      WizardSmallImages := CreateWizardImagesFromResources(['WizardSmallImage'], ['250']);
+      Include(SetupHeader.Options, shUsesBuiltinSmallWizardImages);
+    end;
     LineNumber := 0;
 
     { Prepare Setup executable & signed uninstaller data }

+ 17 - 15
Projects/Src/Setup.MainFunc.pas

@@ -12,7 +12,7 @@ unit Setup.MainFunc;
 interface
 
 uses
-  Windows, SysUtils, Messages, Classes, Graphics, Controls, Forms, Dialogs,
+  Windows, SysUtils, Messages, Classes, Graphics, Controls, Forms, Dialogs, Generics.Collections,
   StdCtrls, Shared.Struct, Shared.DebugStruct, Shared.CommonFunc.Vcl, Shared.CommonFunc,
   Shared.SetupTypes, Setup.ScriptRunner, RestartManager;
 
@@ -25,6 +25,8 @@ type
     sfFonts, sfAppData, sfDocs, sfTemplates,                                  //
     sfFavorites, sfLocalAppData, sfUserProgramFiles, sfUserCommonFiles, sfUserSavedGames); //these only have user versions
 
+  TWizardImages = TObjectList<TGraphic>;
+
 const
   EntryStrings: array[TEntryType] of Integer = (SetupLanguageEntryStrings,
     SetupCustomMessageEntryStrings, SetupPermissionEntryStrings,
@@ -109,8 +111,8 @@ var
   SetupHeader: TSetupHeader;
   LangOptions: TSetupLanguageEntry;
   Entries: array[TEntryType] of TList;
-  WizardImages: TList;
-  WizardSmallImages: TList;
+  WizardImages: TWizardImages;
+  WizardSmallImages: TWizardImages;
   CloseApplicationsFilterList, CloseApplicationsFilterExcludesList: TStringList;
   ISSigAvailableKeys: TArrayOfECDSAKey;
 
@@ -238,7 +240,7 @@ function IsWindows11: Boolean;
 implementation
 
 uses
-  ShellAPI, ShlObj, StrUtils, ActiveX, RegStr, ChaCha20, ECDSA, ISSigFunc,
+  ShellAPI, ShlObj, StrUtils, ActiveX, RegStr, Imaging.pngimage, ChaCha20, ECDSA, ISSigFunc,
   SetupLdrAndSetup.Messages, Shared.SetupMessageIDs, Setup.DownloadFileFunc, Setup.ExtractFileFunc,
   SetupLdrAndSetup.InstFunc, Setup.InstFunc, SetupLdrAndSetup.RedirFunc, PathFunc,
   Compression.Base, Compression.Zlib, Compression.bzlib, Compression.LZMADecompressor,
@@ -2636,14 +2638,20 @@ var
     end;
   end;
 
-  function ReadWizardImage(const Reader: TCompressedBlockReader): TBitmap;
+  function ReadWizardImage(const Reader: TCompressedBlockReader): TGraphic;
   begin
+    var Format: TWizardImageGraphicFormat;
+    Reader.Read(Format, SizeOf(TWizardImageGraphicFormat));
+
     const MemStream = TMemoryStream.Create;
     try
       ReadFileIntoStream(Reader, MemStream);
       MemStream.Seek(0, soFromBeginning);
-      Result := TBitmap.Create;
-      Result.AlphaFormat := TAlphaFormat(SetupHeader.WizardImageAlphaFormat);
+      if Format = gfBitmap then begin
+        Result := TBitmap.Create;
+        TBitmap(Result).AlphaFormat := TAlphaFormat(SetupHeader.WizardImageAlphaFormat);
+      end else
+        Result := TPngImage.Create;
       Result.LoadFromStream(MemStream);
     finally
       MemStream.Free;
@@ -3966,14 +3974,8 @@ begin
 end;
 
 procedure FreeWizardImages;
-var
-  I: Integer;
 begin
-  for I := WizardImages.Count-1 downto 0 do
-    TBitmap(WizardImages[I]).Free;
   FreeAndNil(WizardImages);
-  for I := WizardSmallImages.Count-1 downto 0 do
-    TBitmap(WizardSmallImages[I]).Free;
   FreeAndNil(WizardSmallImages);
 end;
 
@@ -3992,8 +3994,8 @@ initialization
   DeleteDirsAfterInstallList := TStringList.Create;
   CloseApplicationsFilterList := TStringList.Create;
   CloseApplicationsFilterExcludesList := TStringList.Create;
-  WizardImages := TList.Create;
-  WizardSmallImages := TList.Create;
+  WizardImages := TWizardImages.Create;
+  WizardSmallImages := TWizardImages.Create;
   SHGetKnownFolderPathFunc := GetProcAddress(SafeLoadLibrary(AddBackslash(GetSystemDir) + shell32,
     SEM_NOOPENFILEERRORBOX), 'SHGetKnownFolderPath');
 

+ 13 - 6
Projects/Src/Setup.WizardForm.pas

@@ -733,7 +733,7 @@ constructor TWizardForm.Create(AOwner: TComponent);
   using the FormCreate event, because if an exception is raised in FormCreate
   it's not propagated out. }
 
-  function SelectBestImage(WizardImages: TList; TargetWidth, TargetHeight: Integer): TBitmap;
+  function SelectBestImage(WizardImages: TWizardImages; TargetWidth, TargetHeight: Integer): TGraphic;
   var
     TargetArea, Difference, SmallestDifference, I: Integer;
   begin
@@ -743,7 +743,7 @@ constructor TWizardForm.Create(AOwner: TComponent);
       SmallestDifference := -1;
       Result := nil;
       for I := 0 to WizardImages.Count-1 do begin
-        Difference := Abs(TargetArea-TBitmap(WizardImages[I]).Width*TBitmap(WizardImages[I]).Height);
+        Difference := Abs(TargetArea-WizardImages[I].Width*WizardImages[I].Height);
         if (SmallestDifference = -1) or (Difference < SmallestDifference) then begin
           Result := WizardImages[I];
           SmallestDifference := Difference;
@@ -854,8 +854,8 @@ begin
         (such as 55x55 or 32x32) and WizardImageStretch=yes.
       - Otherwise, it's unclear what size/shape the user prefers for the
         control. Keep the default control size. }
-    var NewWidth := TBitmap(WizardSmallImages[0]).Width;
-    var NewHeight := TBitmap(WizardSmallImages[0]).Height;
+    var NewWidth := WizardSmallImages[0].Width;
+    var NewHeight := WizardSmallImages[0].Height;
     if (WizardSmallImages.Count > 1) or
        (NewWidth > 58) or
        (NewHeight > 58) then begin
@@ -880,18 +880,25 @@ begin
   end;
 
   { Initialize images }
-  WizardBitmapImage.Bitmap := SelectBestImage(WizardImages, WizardBitmapImage.Width, WizardBitmapImage.Height);
+  WizardBitmapImage.Graphic := SelectBestImage(WizardImages, WizardBitmapImage.Width, WizardBitmapImage.Height);
   WizardBitmapImage.Center := True;
   WizardBitmapImage.Stretch := (shWizardImageStretch in SetupHeader.Options);
   WizardBitmapImage2.Bitmap := WizardBitmapImage.Bitmap;
   WizardBitmapImage2.Center := True;
   WizardBitmapImage2.Stretch := (shWizardImageStretch in SetupHeader.Options);
-  WizardSmallBitmapImage.Bitmap := SelectBestImage(WizardSmallImages, WizardSmallBitmapImage.Width, WizardSmallBitmapImage.Height);
+  WizardSmallBitmapImage.Graphic := SelectBestImage(WizardSmallImages, WizardSmallBitmapImage.Width, WizardSmallBitmapImage.Height);
   WizardSmallBitmapImage.Stretch := (shWizardImageStretch in SetupHeader.Options);
   SelectDirBitmapImage.InitializeFromIcon(HInstance, 'Z_DIRICON', SelectDirPage.Color, [32, 48, 64]); {don't localize}
   SelectGroupBitmapImage.InitializeFromIcon(HInstance, 'Z_GROUPICON', SelectProgramGroupPage.Color, [32, 48, 64]); {don't localize}
   PreparingErrorBitmapImage.InitializeFromIcon(HInstance, 'Z_STOPICON', PreparingPage.Color, [16, 24, 32]); {don't localize}
 
+  if shUsesBuiltinWizardImages in SetupHeader.Options then begin
+    WizardBitmapImage.BackColor := $F9F3E8; { Bluish Gray }
+    WizardBitmapImage2.BackColor := WizardBitmapImage.BackColor;
+  end;
+  if shUsesBuiltinSmallWizardImages in SetupHeader.Options then
+    WizardSmallBitmapImage.BackColor := clNone;
+
   { Initialize wpWelcome page }
   RegisterExistingPage(wpWelcome, WelcomePage, nil, '', '');
   WelcomeLabel1.Caption := ExpandSetupMessage(msgWelcomeLabel1) + SNewLine;

+ 3 - 1
Projects/Src/Shared.Struct.pas

@@ -64,7 +64,8 @@ type
     shSignedUninstaller, shUsePreviousLanguage, shDisableWelcomePage,
     shCloseApplications, shRestartApplications, shAllowNetworkDrive,
     shForceCloseApplications, shAppNameHasConsts, shUsePreviousPrivileges,
-    shWizardResizable, shUninstallLogging);
+    shWizardResizable, shUninstallLogging, shUsesBuiltinWizardImages,
+    shUsesBuiltinSmallWizardImages);
   TSetupLanguageDetectionMethod = (ldUILanguage, ldLocale, ldNone);
   TSetupCompressMethod = (cmStored, cmZip, cmBzip, cmLZMA, cmLZMA2);
   TSetupKDFSalt = array[0..15] of Byte;
@@ -94,6 +95,7 @@ type
     BaseNonce: TSetupEncryptionNonce;
     PasswordTest: Integer;
   end;
+  TWizardImageGraphicFormat = (gfBitmap, gfPng);
 
 const
   SetupHeaderStrings = 34;

+ 2 - 1
whatsnew.htm

@@ -50,7 +50,8 @@ For conditions of distribution and use, see <a href="files/is/license.txt">LICEN
     The default disk slice size is still <tt>2100000000</tt>, which is almost 2 GB. To update, you can simply set <tt>[Setup]</tt> section directive <tt>DiskSliceSize</tt> to <tt>max</tt>.</li>
 <li>All download functionality now supports TLS 1.3 when available. Support for TLS 1.0 and 1.1 has been removed on all versions of Windows.</li>
 <li>Archive extraction now supports the RAR5 format.</li>
-<li>Improved support for stretching 32-bit bitmaps with transparency.</li>
+<li>Added support for .png files to <tt>[Setup]</tt> section directives <tt>WizardImageFile</tt> and <tt>WizardSmallImageFile</tt>.</li>
+<li>Improved support for stretching 32-bit .bmp files with transparency.</li>
 <li>Compiler IDE: Added new <i>Automatically reload files</i> and <i>Allow Undo after reload</i> options. Both are enabled by default, consistent with most other modern editors, and improving integration with tools like Claude Code.</li>
 <li>Pascal Scripting: Added new <tt>LogFmt</tt> support function.</li>
 </ul>