- procedure ReadIcon(Stream: TStream; var Icon: HICON; ImageCount: Integer;
- StartOffset: Integer; const RequestedSize: TPoint; var IconSize: TPoint);
- type
- PIconRecArray = ^TIconRecArray;
- TIconRecArray = array[0..300] of TIconRec;
- var
- List: PIconRecArray;
- HeaderLen, Length: Integer;
- BitsPerPixel: Word;
- Colors, BestColor, C1, N, Index: Integer;
- DC: HDC;
- BI: PBitmapInfoHeader;
- ResData: Pointer;
- XorBits, AndBits: HBITMAP;
- XorInfo, AndInfo: Windows.TBitmap;
- XorMem, AndMem: Pointer;
- XorLen, AndLen: Integer;
- (*
- var
- P: PChar;
- begin
- P := Pointer(Integer((Stream as TCustomMemoryStream).Memory) + Stream.Position);
- // N := LookupIconIdFromDirectoryEx(Pointer(P), True, 0, 0, LR_DEFAULTCOLOR);
- Icon := GDICheck(CreateIconFromResourceEx(
- Pointer(P + PIconRec(P)^.DIBOffset - StartOffset),
- PIconRec(P)^.DIBSize, True, $00030000, 0, 0, LR_DEFAULTCOLOR));
- end;
- *)
- function AdjustColor(I: Integer): Integer;
- begin
- if I = 0 then
- Result := MaxInt
- else
- Result := I;
- end;
- function BetterSize(const Old, New: TIconRec): Boolean;
- var
- NewX, NewY, OldX, OldY: Integer;
- begin
- NewX := New.Width - IconSize.X;
- NewY := New.Height - IconSize.Y;
- OldX := Old.Width - IconSize.X;
- OldY := Old.Height - IconSize.Y;
- Result := (Abs(NewX) <= Abs(OldX)) and ((NewX <= 0) or (NewX <= OldX)) and
- (Abs(NewY) <= Abs(OldY)) and ((NewY <= 0) or (NewY <= OldY));
- end;
- begin
- HeaderLen := SizeOf(TIconRec) * ImageCount;
- List := AllocMem(HeaderLen);
- try
- Stream.Read(List^, HeaderLen);
- if (RequestedSize.X or RequestedSize.Y) = 0 then
- begin
- IconSize.X := GetSystemMetrics(SM_CXICON);
- IconSize.Y := GetSystemMetrics(SM_CYICON);
- end
- else
- IconSize := RequestedSize;
- DC := GetDC(0);
- if DC = 0 then OutOfResources;
- try
- BitsPerPixel := GetDeviceCaps(DC, PLANES) * GetDeviceCaps(DC, BITSPIXEL);
- if BitsPerPixel > 8 then
- Colors := MaxInt
- else
- Colors := 1 shl BitsPerPixel;
- finally
- ReleaseDC(0, DC);
- end;
- { Find the image that most closely matches (<=) the current screen color
- depth and the requested image size. }
- Index := 0;
- BestColor := AdjustColor(List^[0].Colors);
- for N := 1 to ImageCount-1 do
- begin
- C1 := AdjustColor(List^[N].Colors);
- if (C1 <= Colors) and (C1 >= BestColor) and
- BetterSize(List^[Index], List^[N]) then
- begin
- Index := N;
- BestColor := C1;
- end;
- end;
- { the following code determines which image most closely matches the
- current device. It is not meant to absolutely match Windows
- (known broken) algorithm }
- (* C2 := 0;
- for N := 0 to ImageCount - 1 do
- begin
- C1 := List^[N].Colors;
- if C1 = Colors then
- begin
- Index := N;
- if (IconSize.X = List^[N].Width) and (IconSize.Y = List^[N].Height) then
- Break; // exact match on size and color
- end
- else if Index = -1 then
- begin // take the first icon with fewer colors than screen
- if C1 <= Colors then
- begin
- Index := N;
- C2 := C1;
- end;
- end
- else if C1 > C2 then // take icon with more colors than first match
- Index := N;
- end;
- if Index = -1 then Index := 0;
- *)
- with List^[Index] do
- begin
- IconSize.X := Width;
- IconSize.Y := Height;
- BI := AllocMem(DIBSize);
- try
- Stream.Seek(DIBOffset - (HeaderLen + StartOffset), 1);
- Stream.Read(BI^, DIBSize);
- TwoBitsFromDIB(BI^, XorBits, AndBits, IconSize);
- GetObject(AndBits, SizeOf(Windows.TBitmap), @AndInfo);
- GetObject(XorBits, SizeOf(Windows.TBitmap), @XorInfo);
- with AndInfo do
- AndLen := bmWidthBytes * bmHeight * bmPlanes;
- with XorInfo do
- XorLen := bmWidthBytes * bmHeight * bmPlanes;
- Length := AndLen + XorLen;
- ResData := AllocMem(Length);
- try
- AndMem := ResData;
- with AndInfo do
- XorMem := Pointer(Longint(ResData) + AndLen);
- GetBitmapBits(AndBits, AndLen, AndMem);
- GetBitmapBits(XorBits, XorLen, XorMem);
- DeleteObject(XorBits);
- DeleteObject(AndBits);
- Icon := CreateIcon(HInstance, IconSize.X, IconSize.Y,
- XorInfo.bmPlanes, XorInfo.bmBitsPixel, AndMem, XorMem);
- if Icon = 0 then GDIError;
- finally
- FreeMem(ResData, Length);
- end;
- finally
- FreeMem(BI, DIBSize);
- end;
- end;
- finally
- FreeMem(List, HeaderLen);
- end;
- end;