icon是一种图标格式,用于系统图标、软件图标等,这种图标扩展名为*.icon、*.ico。常见的软件或windows桌面上的那些图标一般都是ICON格式的。

ICON文件格式比较简单,包含文件头段、图像数据头段、图像数据段。

文件头:
文件头为6个字节,定义如下:

1
2
3
4
5
6
type
  ICONDIR = packed record
    idReserved: SmallInt// Reserved
    idType: SmallInt// Resource type
    idCount: SmallInt// Image Count
  end// 6 bytes

idCount标记了文件中包含的图像数量。

图像数据头段:

紧接着文件头的就是图像数据头段了,它存放着文件中每个图像宽度、高度、颜色数量、数据段的偏移等信息,大小为16 * idCount。它是一个数组,每项数据16字节,定义如下:

type
ICONDIRENTRY = packed record
bWidth: Byte; // Width of the image
bHeight: Byte; // Height of the image (2 * Height)
bColorCount: Byte; // Number of colors in image (0 when >= 8 bpp)
bReserved: Byte; // Reserved
wPlanes: SmallInt; // Color Planes (-> xHotspot [Cursor])
wBitCount: SmallInt; // Bits per pixel (-> yHotspot [Cursor])
dwBytesInRes: Integer; // How many bytes in this resource?
dwImageOffset: Integer; // Where in the file is this image?
end; // 16 bytes

读取完图像数据头段后,就可以知道文件中每个图标的大小,颜色位数了,同时直接根据数据段的偏移,读取图像数据段。图像数据的偏移是从文件最开始算起的。

图像数据段:

图像数据为多个图像的DIB数据,根据数据头段的偏移来定位。定位后,读取BIH信息。从BIH信息中,判断颜色位数大于8位的,记取XOR调色盘数据(小于8位的不存在XOR调色盘,只包含有一个MASK调色盘)。读取完XOR调色盘后,初始化图像DIB头,然后在文件中读取DIB数据。

下面来看看实现的加载代码:(注意:本示例代码,只加载ICO文件中颜色位数最高,最大的一个)

相关定义:

type
dibBPPCts = (bpp_01 = 1, bpp_04 = 4, bpp_08 = 8, bpp_16 = 16, bpp_24 = 24,
bpp_32 = 32); DIBItem = packed record
private
function GetBPP: dibBPPCts;
function GetBytesPerScanline: Integer;
function GetHeight: Integer;
function GetWidth: Integer;
function GetSize: Integer;
public
m_uBIH: BITMAPINFOHEADER;
m_hDC: Integer;
m_hDIB: Integer;
m_hOldDIB: Integer;
m_lpBits: Pointer;
m_lpBitsSize: Integer; function Create(NewWidth, NewHeight: Integer; NewBPP: dibBPPCts): Boolean;
procedure Free();
procedure Clone(var toDIB: DIBItem); procedure GetPalette(var Palette: TBytes);
procedure SetPalette(Palette: TBytes); function Stretch(dc: HDC; x, y, w, h, xSrc, ySrc, wSrc, hSrc: Integer;
rop: Cardinal): Integer;
function Stretch32(dc: HDC; BufferBits: Pointer; BytesPerRow, x, y, w, h, xSrc, ySrc, wSrc, hSrc: Integer): Integer; property Width: Integer read GetWidth;
property Height: Integer read GetHeight;
property BPP: dibBPPCts read GetBPP;
property BytesPerScanline: Integer read GetBytesPerScanline;
property Size: Integer read GetSize;
end; DIBDATA = packed record
XORDIB: DIBItem; // XOR DIB section
ANDDIB: DIBItem; // AND DIB section
end; type
BITMAPINFO_001 = packed record
bmiHeader: BITMAPINFOHEADER;
bmiColors: array [0 .. 7] of Byte;
end; BITMAPINFO_004 = packed record
bmiHeader: BITMAPINFOHEADER;
bmiColors: array [0 .. 63] of Byte;
end; BITMAPINFO_008 = packed record
bmiHeader: BITMAPINFOHEADER;
bmiColors: array [0 .. 1023] of Byte;
end; BITMAPINFO_RGB = packed record
bmiHeader: BITMAPINFOHEADER;
end; type
icoBPPCts = (Colors_002 = 1, Colors_016 = 4, Colors_256 = 8, Color_True = 24,
Color_ARGB = 32);

加载代码:

procedure TYxdIcon.LoadFromStream(Stream: TStream);
var
nImg: Integer;
begin
// Get icon header
Fillchar(m_uDir, sizeof(m_uDir), 0);
Stream.Read(m_uDir, sizeof(m_uDir)); // Get icon entries
SetLength(m_uDirEntry, m_uDir.idCount);
Stream.Read(m_uDirEntry[0], sizeof(ICONDIRENTRY) * m_uDir.idCount); // Initialize arrays and monochrome palette
//SetLength(m_OrderKey, m_uDir.idCount);
//SetLength(m_uDIBData, m_uDir.idCount);
//SetLength(m_DIBData, m_uDir.idCount);
SetLength(aPalAND, 8);
FillChar(aPalAND[0], SizeOf(aPalAND), 0);
aPalAND[4] := $FF;
aPalAND[5] := $FF;
aPalAND[6] := $FF; // Get images
nMaxIndex := -1;
nMaxW := 0;
for nImg := 0 to m_uDir.idCount - 1 do begin
if (m_uDirEntry[nImg].bWidth > nMaxW) or
((m_uDirEntry[nImg].bWidth = nMaxW) and (m_uDirEntry[nImg].bColorCount = 0)) then begin
nMaxW := m_uDirEntry[nImg].bWidth;
nMaxIndex := nImg;
end;
end; if nMaxIndex > -1 then begin
// Move to begin of image data
Stream.Position := m_uDirEntry[nMaxIndex].dwImageOffset;
// Load BITMAPINFOHEADER
Stream.Read(uBIH, SizeOf(uBIH));
// Load XOR palette [?] (<= 8 bpp)
if uBIH.biBitCount <= 8 then begin
SetLength(aPalXOR, 4 * Trunc(Power(2, uBIH.biBitCount)));
Stream.Read(aPalXOR[0], Length(aPalXOR));
end; // Inititalize XOR DIB
FillChar(m_uDIBData, SizeOf(m_uDIBData), 0);
m_uDIBData.XORDIB.Create(uBIH.biWidth, uBIH.biHeight div 2, dibBPPCts(ubih.biBitCount));
if uBIH.biBitCount <= 8 then
m_uDIBData.XORDIB.SetPalette(aPalXOR); // Inititalize AND DIB
m_uDIBData.ANDDIB.Create(uBIH.biWidth, uBIH.biHeight div 2, bpp_01);
m_uDIBData.ANDDIB.SetPalette(aPalAND); // Read DIB bits
m_uDIBData.XORDIB.m_lpBits := GetMemory(m_uDIBData.XORDIB.Size);
m_uDIBData.ANDDIB.m_lpBits := GetMemory(m_uDIBData.ANDDIB.Size);
Stream.Read(m_uDIBData.XORDIB.m_lpBits^, m_uDIBData.XORDIB.Size);
Stream.Read(m_uDIBData.ANDDIB.m_lpBits^, m_uDIBData.ANDDIB.Size); m_OrderKey := IntToHex(uBIH.biWidth, 3) + IntToHex(uBIH.biHeight div 2, 3) +
IntToHex(uBIH.biBitCount, 2);
end;
Changed(Self);
end;

DIBItem 就是ICON文件中一个图标的图像数据,代码如下:

{ DIBItem }

procedure DIBItem.Clone(var toDIB: DIBItem);
var
aPal: TBytes;
begin
if m_hDIB <> 0 then begin
toDIB.Create(m_uBIH.biWidth, m_uBIH.biHeight, dibBPPCts(m_uBIH.biBitCount));
if m_lpBits <> nil then begin
toDIB.m_lpBits := GetMemory(Size);
CopyMemory(toDIB.m_lpBits, m_lpBits, Size);
end else
toDIB.m_lpBits := nil;
if (m_uBIH.biBitCount <= 8) then begin
SetLength(aPal, 4 * Trunc(Power(2, m_uBIH.biBitCount)) - 1);
GetPalette(aPal);
toDIB.SetPalette(aPal);
end;
end;
end; function DIBItem.Create(NewWidth, NewHeight: Integer;
NewBPP: dibBPPCts): Boolean;
var
BI_001: BITMAPINFO_001;
BI_004: BITMAPINFO_004;
BI_008: BITMAPINFO_008;
BI_RGB: BITMAPINFO_RGB;
begin
Free(); // Define DIB header
m_uBIH.biSize := SizeOf(m_uBIH);
m_uBIH.biPlanes := 1;
m_uBIH.biBitCount := Integer(NewBPP);
m_uBIH.biWidth := NewWidth;
m_uBIH.biHeight := NewHeight;
m_uBIH.biSizeImage := 4 * ((m_uBIH.biWidth * m_uBIH.biBitCount + 31) div 32) * m_uBIH.biHeight;
case NewBPP of
bpp_01: BI_001.bmiHeader := m_uBIH;
bpp_04: BI_004.bmiHeader := m_uBIH;
bpp_08: BI_008.bmiHeader := m_uBIH;
else
BI_RGB.bmiHeader := m_uBIH
end; // Create DIB and select into a DC
m_hDC := CreateCompatibleDC(0);
if m_hDC <> 0 then begin
case NewBPP of
bpp_01: m_hDIB := CreateDIBSection(m_hDC, pBitmapInfo(@BI_001)^, DIB_RGB_COLORS, m_lpBits, 0, 0);
bpp_04: m_hDIB := CreateDIBSection(m_hDC, pBitmapInfo(@BI_004)^, DIB_RGB_COLORS, m_lpBits, 0, 0);
bpp_08: m_hDIB := CreateDIBSection(m_hDC, pBitmapInfo(@BI_008)^, DIB_RGB_COLORS, m_lpBits, 0, 0);
else
m_hDIB := CreateDIBSection(m_hDC, pBitmapInfo(@BI_RGB)^, DIB_RGB_COLORS, m_lpBits, 0, 0);
end;
if m_hDIB <> 0 then
m_hOldDIB := SelectObject(m_hDC, m_hDIB)
else
Free;
end;
Result := m_hDIB <> 0;
end; procedure DIBItem.Free;
begin
if m_hDC <> 0 then begin
if m_hDIB <> 0 then begin
SelectObject(m_hDC, m_hOldDIB);
DeleteObject(m_hDIB);
end;
DeleteDC(m_hDC);
end;
if m_lpBits <> nil then begin
FreeMemory(m_lpBits);
m_lpBits := nil;
end;
FillChar(m_uBIH, SizeOf(m_uBIH), 0);
m_hDC := 0;
m_hDIB := 0;
m_hOldDIB := 0;
end; function DIBItem.GetBPP: dibBPPCts;
begin
Result := dibBPPCts(m_uBIH.biBitCount);
end; function DIBItem.GetBytesPerScanline: Integer;
begin
Result := ((m_uBIH.biWidth * m_uBIH.biBitCount + 31) div 32) * 4;
end; function DIBItem.GetHeight: Integer;
begin
Result := m_uBIH.biHeight;
end; procedure DIBItem.GetPalette(var Palette: TBytes);
begin
if m_hDIB <> 0 then
GetDIBColorTable(m_hDC, 0, Trunc(Power(2, m_uBIH.biBitCount)), Palette[Low(Palette)]);
end; function DIBItem.GetSize: Integer;
begin
Result := m_uBIH.biSizeImage;
end; function DIBItem.GetWidth: Integer;
begin
Result := m_uBIH.biWidth;
end; procedure DIBItem.SetPalette(Palette: TBytes);
begin
SetDIBColorTable(m_hDC, 0, (High(Palette) - Low(Palette) + 1) div 4, Palette[Low(Palette)])
end; function DIBItem.Stretch(dc: HDC; x, y, w, h, xSrc, ySrc, wSrc, hSrc: Integer;
rop: Cardinal): Integer;
var
b001: BITMAPINFO_001;
b004: BITMAPINFO_004;
b008: BITMAPINFO_008;
brgb: BITMAPINFO_RGB;
iLen: Integer;
lOldMode: Integer;
begin
Result := 0;
if m_hDIB = 0 then Exit;
lOldMode := SetStretchBltMode(dc, COLORONCOLOR);
iLen := Trunc(Power(2, m_uBIH.biBitCount));
case dibBPPCts(m_uBIH.biBitCount) of
bpp_01:
begin
b001.bmiHeader := m_uBIH;
GetDIBColorTable(m_hDC, 0, iLen, b001.bmiColors[0]);
StretchDIBits(dc, x, y, w, h, xSrc, ySrc, wsrc, hsrc, m_lpBits,
pBitmapinfo(@b001)^, DIB_RGB_COLORS, rop);
end;
bpp_04:
begin
b004.bmiHeader := m_uBIH;
GetDIBColorTable(m_hDC, 0, iLen, b004.bmiColors[0]);
StretchDIBits(dc, x, y, w, h, xSrc, ySrc, wsrc, hsrc, m_lpBits,
pBitmapinfo(@b004)^, DIB_RGB_COLORS, rop);
end;
bpp_08:
begin
b008.bmiHeader := m_uBIH;
GetDIBColorTable(m_hDC, 0, iLen, b008.bmiColors[0]);
StretchDIBits(dc, x, y, w, h, xSrc, ySrc, wsrc, hsrc, m_lpBits,
pBitmapinfo(@b008)^, DIB_RGB_COLORS, rop);
end;
else begin
brgb.bmiHeader := m_uBIH;
StretchDIBits(dc, x, y, w, h, xSrc, ySrc, wsrc, hsrc, m_lpBits,
pBitmapinfo(@brgb)^, DIB_RGB_COLORS, rop);
end;
end;
SetStretchBltMode(dc, lOldMode);
Result := 1;
end; function DIBItem.Stretch32(dc: HDC; BufferBits: Pointer; BytesPerRow, x, y, w, h, xSrc, ySrc, wSrc, hSrc: Integer): Integer;
var
i, i2, j, j2: Integer;
Stretch: Boolean;
FactorX, FactorY: Double;
ABytesPerScanline: Integer;
AlphaSource, ImageData: pPixelLine;
begin
Result := 0;
if (m_hDIB = 0) or (m_lpBits = nil) then Exit; Stretch := (W <> wSrc) or (H <> hSrc);
if Stretch then FactorX := W / wSrc else FactorX := 1;
if Stretch then FactorY := H / hSrc else FactorY := 1; AlphaSource := m_lpBits;
ABytesPerScanline := BytesPerScanline;
PByte(ImageData) := PByte(Integer(BufferBits) + BytesPerRow * (H - 1));
BufferBits := ImageData; if m_uBIH.biBitCount = 32 then begin FOR j := 1 TO H DO begin
FOR i := 0 TO W - 1 DO begin
if Stretch then i2 := trunc(i / FactorX) else i2 := i;
if (AlphaSource[i2].rgbReserved <> 0) then begin
if (AlphaSource[i2].rgbReserved = 255) then begin
ImageData[i] := AlphaSource[i2];
end else
with ImageData[i] do begin
rgbRed := ($7F + AlphaSource[i2].rgbRed * AlphaSource[i2].rgbReserved + rgbRed *
(not AlphaSource[i2].rgbReserved)) div $FF;
rgbGreen := ($7F + AlphaSource[i2].rgbGreen * AlphaSource[i2].rgbReserved +
rgbGreen * (not AlphaSource[i2].rgbReserved)) div $FF;
rgbBlue := ($7F + AlphaSource[i2].rgbBlue * AlphaSource[i2].rgbReserved + rgbBlue *
(not AlphaSource[i2].rgbReserved)) div $FF;
rgbReserved := not (($7F + (not rgbReserved) * (not AlphaSource[i2].rgbReserved)) div $FF);
end;
end;
end; {Move pointers}
PByte(ImageData) := PByte(Integer(BufferBits) - BytesPerRow * j);
if Stretch then j2 := trunc(j / FactorY) else j2 := j;
PByte(AlphaSource) := PByte(m_lpBits) + ABytesPerScanline * j2;
end
end;
Result := 1;
end;

ICON的显示:

本示例中的TYxdIcon继承自TIcon,本身就是一个Graphic了,所以可以直接重载Draw实现显示。

type
TYxdIcon = class(TIcon)
private
m_uDir: ICONDIR; // Icon file header
m_uDirEntry: array of ICONDIRENTRY; // Icon image headers
m_OrderKey: string; // Image format key
aPalXOR: TBytes;
aPalAND: TBytes;
nMaxW: Byte;
nMaxIndex: Integer;
uBIH: BITMAPINFOHEADER; BufferDC: HDC;
OldBufferBitmap, BufferBitmap: HBitmap;
LastW, LastH: Integer;
FUseBuffer: Boolean;
protected
m_uDIBData: DIBDATA; // Icon data (DIBs)
function GetEmpty: Boolean; override;
function GetHeight: Integer; override;
function GetWidth: Integer; override;
procedure Draw(ACanvas: TCanvas; const Rect: TRect); override;
function GetSupportsPartialTransparency: Boolean; override;
public
constructor Create; override;
destructor Destroy; override;
procedure Assign(Source: TPersistent); override;
procedure LoadFromStream(Stream: TStream); override;
procedure SaveToStream(Stream: TStream); override;
property UseBuffer: Boolean read FUseBuffer write FUseBuffer;
end;
procedure TYxdIcon.Draw(ACanvas: TCanvas; const Rect: TRect);
var
BitmapInfo: TBitmapInfo;
BufferBits, Buf: Pointer;
AlphaSource, ImageData: pPixelLine;
W, H: Integer;
BytesPerRow: Integer;
I, J: Integer;
begin
W := Rect.Right - Rect.Left;
H := Rect.Bottom - Rect.Top; BitmapInfo := GetBitmapInfoHeader(W, H);
BufferDC := CreateCompatibleDC(0);
if (BufferDC = 0) then Exit; BytesPerRow := (((BitmapInfo.bmiHeader.biBitCount * W) + 31) and
not 31) div 8; BufferBitmap := CreateDIBSection(BufferDC, pBitmapInfo(@BitmapInfo)^,
DIB_RGB_COLORS, BufferBits, 0, 0);
OldBufferBitmap := SelectObject(BufferDC, BufferBitmap);
BitBlt(BufferDC, 0, 0, W, H, ACanvas.Handle, Rect.Left, Rect.Top, SRCCOPY); if m_uDIBData.XORDIB.BPP = bpp_32 then begin
m_uDIBData.XORDIB.Stretch32(BufferDC, BufferBits, BytesPerRow, Rect.Left, Rect.Top,
W, H, 0, 0, m_uDIBData.XORDIB.Width, m_uDIBData.XORDIB.Height);
end else begin
// 画 Mask 层
m_uDIBData.ANDDIB.Stretch(BufferDC, Rect.Left, Rect.Top, W, H, 0, 0,
m_uDIBData.XORDIB.Width, m_uDIBData.XORDIB.Height, SRCCOPY); // 保存透明区域信息
Buf := GetMemory(BytesPerRow*H);
CopyMemory(Buf, BufferBits, BytesPerRow*H); // 画实际图像
m_uDIBData.XORDIB.Stretch(BufferDC, Rect.Left, Rect.Top, W, H, 0, 0,
m_uDIBData.XORDIB.Width, m_uDIBData.XORDIB.Height, SRCCOPY); // 应用 Mask
PByte(ImageData) := PByte(BufferBits);
AlphaSource := Buf;
FOR j := 1 TO H DO begin
FOR i := 0 TO W - 1 DO begin
if (AlphaSource[i].rgbBlue = 0) and (AlphaSource[i].rgbGreen = 0) and (AlphaSource[i].rgbRed = 0) then begin
ImageData[i].rgbReserved := $ff;
end else
ImageData[i].rgbReserved := 0;
end;
{Move pointers}
inc(PByte(AlphaSource), BytesPerRow);
inc(PByte(ImageData), BytesPerRow);
end;
FreeMemory(Buf);
end; TYxdCanvas(ACanvas).RequiredState([csHandleValid]);
BitBlt(ACanvas.Handle, Rect.Left, Rect.Top, W, H, BufferDC, 0, 0, SRCCOPY); SelectObject(BufferDC, OldBufferBitmap);
DeleteObject(BufferBitmap);
DeleteDC(BufferDC);
BufferBitmap := 0;
end;

显示中主要特别处理的地方就是区分是否为32位的带透明通道图标。不带透明通道的,使用MASK层进行透明处理。

http://www.cnblogs.com/yangyxd/articles/3984901.html

ICON图标文件解析的更多相关文章

  1. C#icon图标文件转Image

    Icon icon = ICONHelper.GetFileIcon(filePath); MemoryStream mStream = new MemoryStream();//创建内存流 icon ...

  2. QT5.5.0版本添加icon图标步骤

    1.制作icon图标文件 可以进入这个网站在线制作:http://www.ico.la/ 2.创建资源文件:qrc文件 接着 添加2两项,先点击prefix,然后添加文件--->图标路径 3.可 ...

  3. QT5版本添加icon图标步骤

    QT5版本添加icon图标方法收藏 方法1: step1: 把要显示的图标文件,比如为1.ico文件放到工程v的根目录下 step2: 修改当前项目XXX.pro文件,在文件末尾添加如下内容(注意=的 ...

  4. IOS深入学习(1)之图标文件(icon files)

    1 前言 我相信大家在做IOS一定经常会跟图标文件(icon files)打交道,今天我们就来简单的学习一下iPhone和iPad程序中的icon files. 2 详述 除了iTunesArtwor ...

  5. C#之改变窗体icon图标、新建类文件、调用dll库

    一.改变窗体的图标 没有修改之前为: 修改之后为自己想要的图标: 需要在窗体Form1.cs属性里边添加icon图片文件: 二.新建cs类文件 如下图所示,新建一个类文件,我用于来调用库文件也可以来定 ...

  6. android基础知识13:AndroidManifest.xml文件解析

    注:本文转载于:http://blog.csdn.net/xianming01/article/details/7526987 AndroidManifest.xml文件解析. 1.重要性 Andro ...

  7. Android之AndroidManifest.xml文件解析

    转自:Android学习笔记之AndroidManifest.xml文件解析 一.关于AndroidManifest.xml AndroidManifest.xml 是每个android程序中必须的文 ...

  8. node文件中的package.json文件解析

    { "name":"myejsapp", "version":"0.0.0", "private": ...

  9. icon图标深入指南

    图标是网络上常用的元素. 它们是通用的,可以立即识别,可以非常吸引人,引起注意,并且(如果使用正确)可以提供出色的用户体验. 在网络上实现图标时,我们有很多选择: Icon Spritesheet – ...

随机推荐

  1. c++11: <thread>学习

    <thread>头文件中包含thread类与this_thread命名空间,下面逐一介绍. thread类 1. 构造函数 (1)默认构造函数 thread() noexcept; 默认构 ...

  2. hql中in的用法

    平时经常用Hibernate,由于习惯表间不建立关联,所以HQL查询时候经常要用in语句. 由于表间没有建立外键的关联关系所以使用in是最常见的代替使用对象po中的set. 但是在写hql时如果在ne ...

  3. VB生成xml

    Dim text As XmlText Dim doc As New XmlDocument '加入XML的声明段落 Dim node As XmlNode = doc.CreateXmlDeclar ...

  4. Mono For Android中AlarmManager的使用

    最近做了一个应用,要求如下: 程序运行之后的一段时间,分别触发3个不同的事件.当然很快就想到了Android中的AlarmManager和BroadcastReceiver.但是毕竟Mono环境和Ja ...

  5. Memcached简明介绍

    官网介绍:http://memcached.org/ Free & open source, high-performance, distributed memory object cachi ...

  6. InputStream和OutputStream

    1.在java中stream代表一种数据流(源),javaio的底层数据元,---(想像成水龙头) 2.任何有能力产生数据流(源)的javaio对象就可以看作是一个InputStream对象既然它能产 ...

  7. cdoj 791 Frozen Rose-Heads

    //本来想做白书上一题 结果发现又要二染色 又要dp的 想了两个小时没想通 然后做了个傻逼题安慰自己 解:不多说,就是递归到叶节点,然后回来的时候在解决子树和直接删边的代价中间取个最小值 #inclu ...

  8. 10-3[RF] feature selection

    main idea: 计算每一个feature的重要性,选取重要性前k的feature: 衡量一个feature重要的方式:如果一个feature重要,则在这个feature上加上noise,会对最后 ...

  9. Spring、Spring自动扫描和管理Bean

    Spring2.5为我们引入了组件自动扫描机制,它可以在类路径下寻找标记了@Component.@Service.@Controller.@Repository注解的类,并把这些类纳入到spring容 ...

  10. QT函数

    1 move 移动 2 resize 改变窗口大小 3 setNum 设置数字 4 setText 设置文本 5 setWindowTitle 设置窗口文本 6 show 弹出窗口 7 text 获取 ...