【问题标题】:Load MultiFrame Icons加载多帧图标
【发布时间】:2012-03-21 13:27:07
【问题描述】:

有人知道可以读取多帧图标的类吗?上网搜了一下,没有任何信息。

我尝试使用 Alan Peter Stotz 的 IconTools 2.0,它将图标正确加载到列表中,但 8 位和 4 位图标的位深度返回为 0。32 位和 24 位图标框架的位深度是但是,返回正确。

查看时图标本身看起来是正确的......只是提到的位的位深度是错误的。

编辑 #2 根据 TLama 的评论,这里有一些未经测试的代码:

function NumberOfIcons ( AFileName: string ): integer;
var
  iNumberOfIcons: Integer;
begin

  iNumberOfIcons := ExtractIcon ( hInstance, PChar ( AFilename ), UINT ( -1 ) );
  Result := iNumberOfIcons;

end;

function ExtractAnIcon ( AFilename: string; AIndex: integer ): TBitmap;
var
  icoHandle: HIcon;
  iBitmap: TBitmap;
  iIcon: TIcon;
  iNumberOfIcons, i: Integer;
begin

  Result := nil;

  iBitmap := TBitMap.Create;

  iIcon := TIcon.Create;
  try

    // Get the number of Icons
    iNumberOfIcons := ExtractIcon ( hInstance, PChar ( AFilename ), UINT ( -1 ) );

    // Extract the icon frame
    icoHandle := ExtractIcon ( hInstance, PChar ( AFileName ), AIndex );
    iIcon.Handle := icoHandle;
    iBitmap.Width := iIcon.Width;
    iBitmap.Height := iIcon.Height;
    // Draw the icon on your bitmap
    DrawIcon ( iBitmap.Canvas.Handle, 0, 0, iIcon.Handle );    
    Result := iBitmap;

  finally
    iIcon.Free;
  end;

end;

function PixelFormatToBitDepth ( APixelFormat: TPixelFormat ): integer;
// Convert TPixelFormat to integer
begin

  Result := -1;
  case APixelFormat of
    pf32Bit:
      Result := 32;
    pf24bit:
      Result := 24;
    pf8bit:
      Result := 8;
    pf4Bit:
      Result := 4;
    pf1bit:
      Result := 1;
  end;

end;

我在正确的轨道上吗?在我的测试中,我现在得到 1 个图标,但 NumberOfIcons 函数返回 1?

编辑#3 根据帮助文件“如果文件是.ICO文件,ExtractIcon的返回值为1”。那么有什么方法可以获取ico文件中图标的个数呢?

【问题讨论】:

  • 您打算进一步编辑它们还是只想在程序中使用它们?如果是后者,则更容易将它们链接为资源并使用资源 API 来获取正确版本的图标。
  • @David... 我正在尝试在加载位图的 ImageEditor 中使用它们,因此一旦获得图标,我需要将其转换为位图,然后获取其宽度和高度以及位深度。我正在尝试根据 TLamas 评论使用 ExtractIcon 来执行此操作。我将未经测试的代码添加为编辑。
  • @Bill,Delphi 附带的 ImageEditor ?如果是这样,那么试着忘记它。我有一个很好的经验,例如使用 IcoFX(也有它的便携式版本),它允许您将图标导出为多种格式(包括 *.bmp)。但是你不需要在资源文件中只使用位图,你可以使用任何文件类型,你只需要自己编译资源文件。
  • 好吧,我会阅读 Graphics.pas 中读取 .ico 文件的代码。这很全面。 MS 的主要文档来源在这里:msdn.microsoft.com/en-us/library/ms997538.aspx
  • @user539484 是的,我知道该代码的作用。但它提供了一些有用的想法,如何实现所需要的。因此链接到实际文档。阅读 Graphics.pas 中的 Delphi 代码可能更容易阅读抽象的 MS 文档,反之亦然。这当然是我的经验。

标签: delphi icons delphi-2010


【解决方案1】:

这是一个小代码示例:

uses ShellApi;

type
  TICONDIRENTRY = packed record
    bWidth: Byte;          // Width, in pixels, of the image
    bHeight: Byte;         // Height, in pixels, of the image
    bColorCount: Byte;     // Number of colors in image (0 if >=8bpp)
    bReserved: Byte;       // Reserved ( must be 0)
    wPlanes: Word;         // Color Planes
    wBitCount: Word;       // Bits per pixel
    dwBytesInRes: DWORD;   // How many bytes in this resource?
    dwImageOffset: DWORD;  // Where in the file is this image?
  end;

  TICONDIR = packed record
    idReserved: Word; // Reserved (must be 0)
    idType: Word;     // Resource Type (1 for icons)
    idCount: Word;    // How many images?
    idEntries: array [0..255] of TICONDIRENTRY;
  end;
  PICONDIR=^TICONDIR;

function GetIconsCount(const FileName: string): Word;
var
  Stream: TMemoryStream;
  IconDir: PICONDIR;
begin
  Result := 0;
  if ExtractIcon(hInstance, PChar(FileName), UINT(-1)) <> 0 then
  try
    Stream := TMemoryStream.Create;
    try
      Stream.LoadFromFile(FileName);
      IconDir := Stream.Memory;
      if IconDir.idType = 1 then
        Result := IconDir.idCount;
    finally
      Stream.Free;
    end;
  except
    // do not raise exceptions
  end;
end;

function ExtractIcons(const FileName: string; IconList: TList): Boolean;
var
  Stream: TMemoryStream;
  NewIconStream: TMemoryStream;
  IconDir: PICONDIR;
  NewIconDir: PICONDIR;
  Icon: TIcon;
  I: Integer;
begin
  Result := False;
  if ExtractIcon(hInstance, PChar(FileName), UINT(-1)) <> 0 then
  try
    Stream := TMemoryStream.Create;
    try
      Stream.LoadFromFile(FileName);
      IconDir := Stream.Memory;
      for I := 0 to IconDir.idCount-1 do
      begin
        NewIconStream := TMemoryStream.Create;
        try
          NewIconStream.Size := SizeOf(Word) * 3 + SizeOf(TICONDIRENTRY);
          NewIconStream.Position:= SizeOf(Word) * 3 + SizeOf(TICONDIRENTRY);

          NewIconDir := NewIconStream.memory;
          NewIconDir.idCount := 1;
          NewIconDir.idType := IconDir.idType;
          NewIconDir.idReserved := IconDir.idReserved;
          NewIconDir.idEntries[0] := IconDir.idEntries[I];
          NewIconDir.idEntries[0].dwImageOffset := NewIconStream.Size;

          Stream.Position := IconDir.idEntries[I].dwImageOffset;
          NewIconStream.CopyFrom(Stream, IconDir.idEntries[I].dwBytesInRes);
          NewIconStream.Position := 0;
          Icon := TIcon.Create;
          Icon.LoadFromStream(NewIconStream);
          IconList.Add(Icon);
        finally
          NewIconStream.Free;
        end;
        IconList.Add(Icon);
      end;
      Result := True;
    finally
      Stream.Free;
    end;
  except
    // do not raise exceptions
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  FileName: string;
  Icon: TIcon;
  List: TList;
  I: Integer;
begin
  FileName := 'c:\myicon.ico';
  List := TList.Create;
  try
    if ExtractIcons(FileName, List) then
    for I := 0 to List.Count - 1 do
    begin
      Icon := TIcon(List.Items[I]);
      DrawIcon(Form1.Canvas.Handle, 10, I * 40, Icon.Handle);
      Icon.Free;
    end;
  finally
    List.Free;
  end;
end;

【讨论】:

  • @Kobik...谢谢...我似乎在tkweb.eu/en/delphicomp/kicon.html 上也取得了一些成功。
  • @Bill, BTW KIcon 使用与上述相同的方法,即TKIcon.LoadFromStream->FIconCount := IH.idCount;
  • 嘿,有趣,从来不知道在所描述的情况下可以继续使用 ExctractIcon 。
猜你喜欢
  • 1970-01-01
  • 2012-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-10
  • 1970-01-01
  • 2013-03-13
  • 2023-03-13
相关资源
最近更新 更多