Icon is a form of icons for system icons, software icons, and so on, with the extension *.icon, *.ico. The most common software or icons on the Windows desktop are usually in icon format.
Icon file format is simple, including the header segment, image data header, image data segment.
File header:
The file header is 6 bytes and is defined as follows:
123456 |
type
ICONDIR =
packed
record
idReserved:
SmallInt
;
// Reserved
idType:
SmallInt
;
// Resource type
idCount:
SmallInt
;
// Image Count
end
;
// 6 bytes
|
Idcount marks the number of images contained in the file.
Image Data Header segment:
Immediately after the file header is the image Data header section, it holds the file each image width, height, color number, data segment offset and other information, size of * idcount. It is an array of 16 bytes per item of data, defined as follows:
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 W Planes:smallint; Color Planes (-xhotspot [cursor]) wbitcount:smallint;//Bits per pixel (-yhotspot [cursor]) DwB Ytesinres:integer; How many bytes in this resource? Dwimageoffset:integer; Where in the file is this image? End bytes
After reading the image data header, you can know the size of each icon in the file, the number of color bits, and directly according to the data segment offset, read the image data segment. The offset of the image data is calculated from the beginning of the file.
Image Data segment:
The image data is the DIB data of multiple images and is positioned according to the offset of the data header segment. After locating, read the BiH information. From the BiH information, to determine the number of colors more than 8 bits, remember the XOR palette data (less than 8 bits of the non-existent XOR palette, contains only a mask palette). After reading the XOR palette, initialize the image Dib header, and then read the DIB data in the file.
The following is a look at the implementation of the Load code: (Note: This sample code, only load the ICO file the highest number of color bits, the largest one)
Related definitions:
Type dibbppcts = (bpp_01 = 1, bpp_04 = 4, bpp_08 = 8, bpp_16 = +, bpp_24 = 32, bpp_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..] 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 =, Color_argb = 32);
Load code:
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].bwidt h = 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 is the image data of an icon in the icons file, the code is as follows:
{Dibitem}procedure dibitem.clone (var todib:dibitem); var apal:tbytes;begin if M_hdib <> 0 THEN BEGIN TODIB.C Reate (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 +) 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 +) div.) * 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 = and begin for J: = 1 to H does begin for I: = 0 to W-1 does 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].RGBR Eserved + 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].rgb Reserved)) 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;
Display of Icon:
The Tyxdicon in this example inherits from Ticon, which is itself a graphic, so you can overload the draw implementation display directly.
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) + () and not) 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//Draw Mask layer M_uDIBData.ANDDIB.Stretch (BUFFERDC, Rect.left, rect.tOP, W, H, 0, 0, m_uDIBData.XORDIB.Width, M_uDIBData.XORDIB.Height, srccopy); Save Transparent Area information Buf: = GetMemory (bytesperrow*h); CopyMemory (Buf, Bufferbits, bytesperrow*h); Draw the actual image M_uDIBData.XORDIB.Stretch (BUFFERDC, Rect.left, Rect.top, W, H, 0, 0, M_uDIBData.XORDIB.Width, M_udibdata. Xordib. Height, srccopy); Apply Mask pbyte (ImageData): = Pbyte (bufferbits); Alphasource: = Buf; for J: = 1 to H does begin for I: = 0 to W-1 does begin if (Alphasource[i].rgbblue = 0) and (ALPHASOURCE[I].RGBG Reen = 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;
The main areas of special handling in the display are the transparent channel icons that distinguish whether they are 32-bit. With no transparent channels, the mask layer is used for transparent processing.
Http://www.cnblogs.com/yangyxd/articles/3984901.html
Icon File parsing