【问题标题】:TPicture Width and Height reported incorrectly for .ico files (Delphi 7).ico 文件的 TPicture Width 和 Height 报告不正确 (Delphi 7)
【发布时间】:2020-07-18 16:09:59
【问题描述】:

使用 Delphi 7。我有一个简单的例程成功加载 .bmp.emf.wmf.ico.jpg 文件(代码如下)。我的问题是每个.ico(图标)文件总是将TImage.TPicture.WidthTImage.TPicture.Height 报告为“32”。所有图标都是 32 位的,里面只有一个页面。实际大小无关紧要(我尝试过 16x16、32x32、64x64 和 128x128)。

如果我手动将TImage.WidthTImage.Width 设置为我知道图标的大小,则图像可以很好地显示。所有其他文件类型都正确报告大小。

为什么.ico 文件有问题,我该如何纠正或解决该问题。

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;

更新 1

作为测试,我将文件加载为TIcon,但结果是一样的。

ico: TIcon;
// ...
ico := TIcon.Create();
ico.LoadFromFile(openPictureDlg.FileName);
testWidth := ico.Width;   // Still 32, regardless of the actual size
testHeight := ico.Height;
ico.Free();

更新 2

查看接受的答案。基本上有两种方法可以获得正确的大小(a)加载图标,分配给 TBitmap,并读取位图大小或(b)读取图标标题,字节 7 和 8 是宽度/高度。后者在我的测试中要快约 20 倍,代码如下:

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;

【问题讨论】:

  • (我相信您会在实际应用程序中使用try..finally 来保护您的对象。)
  • 是的,只是去掉了一些代码以获得最少的样本! :o)
  • 阿兰:好! :)
  • FWIW,我无法在 Delphi 10.3.2 中使用 a simple 48×48 px icon 重现该问题。
  • 仅供参考,您不需要单独列出 JPG 文件。加载 JPG 文件名时,TPicture.LoadFromFile() 将在内部使用 TJPEGImage

标签: image delphi icons delphi-7


【解决方案1】:

一种解决方法是自己解析 ICO 文件,这相当简单:https://en.wikipedia.org/wiki/ICO_(file_format) - 这样您就可以轻松了解每个条目的尺寸。在最简单的情况下(只有一张图片)文件的前 6 个字节必须是#0#0#1#0#1#0,第 7 和第 8 个字节是宽度和高度。

【讨论】:

  • 太好了,谢谢!学到了一些新东西,因为为图像/宽度保留了 1 个字节,所以图标尺寸限制为 256x256(0 表示 256)。将查看该文章并尝试一下,谢谢!
  • 您将无法向我展示尺寸大于 256x256 的 ICO。
  • 效果很好!只需使用TFileStream 读取前八个字节。第 7 和第 8 个字节分别是宽度和高度(0 表示 256)。
猜你喜欢
  • 2011-04-23
  • 2012-10-28
  • 1970-01-01
  • 2015-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多