Reputation: 6587
Using Delphi 7. I have a simple routine successfully loading .bmp
, .emf
, .wmf
, .ico
and .jpg
files (code given below). My problem is that every .ico
(Icon) file always reports TImage.TPicture.Width
and TImage.TPicture.Height
as "32". All icons are 32-bit with a single page inside. It doesn't matter what the actual size is (I have tried 16x16, 32x32, 64x64 and 128x128).
If I manually set TImage.Width
and TImage.Width
to what I know the icon size is, the image displays nicely. All the other file types report the size correctly.
Why is there a problem with .ico
files and how do I correct or workaround the problem.
procedure TfrmImageLoader.btnBrowseClick(Sender: TObject);
var
openPictureDlg: TOpenPictureDialog;
jpgImage: TJPEGImage;
testWidth, testHeight: Integer;
begin
// Browse for the image file
openPictureDlg := TOpenPictureDialog.Create(Self);
if (openPictureDlg.Execute) then
begin
// Check if file exists
if (FileExists(openPictureDlg.FileName)) then
begin
// Load the image into out image component
imgLoaded.Visible := False;
if (IsJPEG(openPictureDlg.FileName)) then
begin
jpgImage := TJPEGImage.Create();
jpgImage.LoadFromFile(openPictureDlg.FileName);
imgLoaded.Picture.Assign(jpgImage);
jpgImage.Free();
end
else
begin
imgLoaded.Picture.LoadFromFile(openPictureDlg.FileName);
end;
// Test width...here's the problem. Icons always report "32".
testWidth := m_imgLoaded.Picture.Width;
testHeight := m_imgLoaded.Picture.Height;
m_imgLoaded.Visible := True;
end
else
begin
// File does not exist
MessageDlg('File does not exist', mtWarning, [mbOK], 0);
end;
end;
// Clean up
openPictureDlg.Free();
end;
As a test, I loaded the file as a TIcon
, but the results are the same.
ico: TIcon;
// ...
ico := TIcon.Create();
ico.LoadFromFile(openPictureDlg.FileName);
testWidth := ico.Width; // Still 32, regardless of the actual size
testHeight := ico.Height;
ico.Free();
See the accepted answer. There are basically two ways to get the correct size (a) load the icon, assign to a TBitmap, and read the bitmap size or (b) read the icon header, bytes 7 & 8 are the width/height. The latter is ~20 times faster in my tests and the code is given below:
procedure GetTrueIconSize2(const cszIcon: String; var trueW: Integer; var trueH: Integer);
var
fs: TFileStream;
firstBytes: AnsiString;
begin
// The size of image/vnd.microsoft.icon MIME files (Windows icon) is in the header
// at bytes 7 & 8. A value of "0" means "256" (the largest icon size supported).
fs := TFileStream.Create(cszIcon, fmOpenRead);
try
SetLength(firstBytes, 8);
fs.Read(firstBytes[1], 8);
trueW := Integer(firstBytes[7]);
if (trueW = 0) then
trueW := 256;
trueH := Integer(firstBytes[8]);
if (trueH = 0) then
trueH := 256;
finally
fs.Free();
end;
end;
Upvotes: 2
Views: 259
Reputation: 6099
A workaround would be to parse ICO files yourself, which is rather trivial: https://en.wikipedia.org/wiki/ICO_(file_format) - that way you easily know the dimensions for each entry. In the most simple case (only one picture) the first 6 bytes of the file must be #0#0#1#0#1#0
and byte 7 and 8 are width and height.
Upvotes: 2