ICO 實為多圖像容器,結構:
idReserved=0, idType=1 (圖標), idCount (圖像數)。bWidth, bHeight (0=256), bColorCount (0=256+), bReserved=0, wPlanes, wBitCount (色深), dwBytesInRes, dwImageOffset。BITMAPINFOHEADER),但 biHeight = 2×實際高度(含 XOR 與 AND 遮罩),biBitCount=24 真彩色無調色盤。procedure Pic2BMP(Picture: TPicture);
var Bmp: TBitmap;
begin
if not (Picture.Graphic is TBitmap) then
begin
Bmp := TBitmap.Create;
try Bmp.Width := Picture.Width; Bmp.Height := Picture.Height;
Bmp.Canvas.Draw(0, 0, Picture.Graphic);
Picture.Graphic := Bmp;
finally Bmp.Free; end;
end;
end;
procedure PicToMiniature(Src, Dst: TBitmap; W, H: Integer);
var Tmp: TBitmap;
begin
Tmp := TBitmap.Create;
try Tmp.Assign(Src); Tmp.Width := Min(W,255); Tmp.Height := Min(H,255);
Tmp.PixelFormat := pf24bit;
Tmp.Canvas.StretchDraw(Rect(0,0,Tmp.Width,Tmp.Height), Src);
Dst.Assign(Tmp);
finally Tmp.Free; end;
end;
function MakeICOHead(const Mem: TStream): Boolean;
var BMPH: TBitmapFileHeader; BMPInfo: TBitmapInfoHeader; Sz: DWORD;
begin
Result := False;
Mem.Position := 0;
Mem.Read(BMPH, SizeOf(BMPH)); Mem.Read(BMPInfo, SizeOf(BMPInfo));
if (BMPInfo.biCompression = BI_RGB) and (BMPInfo.biWidth <= 255) and (BMPInfo.biHeight <= 255) then
begin
with IconDir.idEntries do
begin
bWidth := Byte(BMPInfo.biWidth); bHeight := Byte(BMPInfo.biHeight);
wBitCount := 24; wPlanes := 1;
Sz := (Mem.Size - SizeOf(BMPH)) * 2 + SizeOf(BMPInfo); // *2 含 AND 遮罩
dwBytesInRes := Sz; dwImageOffset := SizeOf(ICONDIR);
end;
Result := True;
end;
end;
function MakeICOData(const Mem: TStream): Boolean;
var M1, M2: TMemoryStream; BMPInfo: TBitmapInfoHeader;
begin
Result := False;
M1 := TMemoryStream.Create; M2 := TMemoryStream.Create;
try
M1.SetSize(Mem.Size - SizeOf(TBitmapFileHeader));
Mem.Position := SizeOf(TBitmapFileHeader);
M1.CopyFrom(Mem, M1.Size); // 複製 BMPInfo + 像素資料
M1.Position := 0; M1.Read(BMPInfo, SizeOf(BMPInfo));
BMPInfo.biHeight := BMPInfo.biHeight * 2; // 雙倍高度含遮罩
BMPInfo.biSizeImage := M1.Size * 2;
M1.Position := 0; M1.Write(BMPInfo, SizeOf(BMPInfo));
M2.SetSize(M1.Size - SizeOf(BMPInfo)); // 遮罩區填 0 (白色透明)
FillChar(M2.Memory^, M2.Size, 0);
Mem.Size := 0;
Mem.Write(IconDir, SizeOf(ICONDIR));
Mem.Write(M1.Memory^, M1.Size);
Mem.Write(M2.Memory^, M2.Size);
Result := True;
finally M1.Free; M2.Free; end;
end;
Mem.SaveToFile('output.ico')。重複上述流程產生 16×16、32×32、48×48、256×256 等多組 ICONDIRENTRY 與圖像資料,依序寫入同一檔案,Windows 會自動選取最適合解析度顯示。