![]() Home |
Icons To File Unit You can Create an Icon File in any Color Depth Version 1.2 For Delphi 4, 5, and 6 |
![]() Home |
| Why use the IconsToFile.pas? ? To Save 256 Color and FullColor Icons to File or Stream. When you use the Delphi Graphics.pas TIcon.SaveToFile( ) method, the Icon file saved to disk will be in Four Bit (16 Color) Color Depth. So if you save a 256 color or Full color Icon to a TIcon 16 color Icon File it will NOT look like the Full Color Icon. Using the functions in IconsToFile.pas will allow you to save Icons to file in one of Five Color Bit Counts. The Six Function in IconsToFile.pas are -
To find out what the functions in IconsToFile.pas do and how to use them, look at the help page for the Icons to File Unit - - help page for the Icons to File Unit You can download the ZIP file, with the IconsToFile.pas and the Icons To File Help.html files in it here - - ZIP file with IconsToFile.pas |
| This is the Code for the IconsToFile.pas Unit, it has Three Functions that can allow you to save Icons to file in different Color Depths (pixel Bit Counts). One function to Convert a 32 bit Icon to a 24 bit Icon file. A function to test the Icons in an Array of TMutiIcon for duplicates to be used in an IconsToStream( ). And a utility function to get a 48x48 size Icon hamdle. |
unit IconsToFile;
// version 1.2
interface
uses Classes;
type
TBitCount = (BitC1, BitC4, BitC8, BitC24, BitC32);
{use the TBitCount to set the Color Depth (number of Colors)
in your saved Icon file}
PMutiIcon = ^TMutiIcon;
TMutiIcon = Record
hIcon: Cardinal;
BitCount: TBitCount;
end;
{you need to use this TMutiIcon as an Array in the IconsToStream
function, setting the hIcon and it's Bit Count for each Icon in the file}
{ALL of these Icon To File functions will save an Icon to File AND
it will OVERWRITE an existing file WITHOUT prompting or warning}
function hIconToFile(FileName: String; hIcon: Cardinal;
iconBitCount: TBitCount): Integer;
{the hIconToFile fuction
This has a TBitCount parameter, which you set to have this Icon saved in that
color Bit Count (Color Depth). There is no visuall difference in the BitC24
and BitC32 icons except in Windows XP, and then ONLY if Alpha channel shadow
information is included, but win XP will automatically produce the shadow
from any color depth if it is not there}
function autoIconToFile(FileName: String; hIcon: Cardinal): Integer;
{the autoIconToFile function
No TBitCount parameter is in this function. This will attempt to Automatically
calculate a Bit Count, Color Depth, for the hIcon. (a Save Icon for Dumbys)
A Black and White Icon will be BitC1, a standard 16 color or less will be
a BitC4, if the Icon has less than 236 colors plus the 20 standard windows
colors it will be BitC8 with an optimized palette,
more than 236 colors will be BitC24 (Full Color)}
function Icon32To24File(FileName: String; hIcon: Cardinal): Integer;
{the Icon32To24File function is only useful in windows XP or newer
systems, that support 32 bit Icons. If you convert a 32 alpha blend
to 24 bit icon, with the hIconToFile function, it will not look correct.
This Icon32To24File function will try and convert the 32 bit alpha blended
icon to a 24 bit NON-blended icon and take out the areas that are
alpha-blended and appear as black areas if you convert with another function.
This is based on the Microsoft methods of 32 bit icon alpha-blend icon shadow
and may NOT work very well on 32 bit Icons that are NOT done by the
Microsoft methods}
function IconsToStream(Stream: TStream; aryMutiIcon: Array of TMutiIcon;
NumIcons: Byte = 1): Integer;
{IconsToStream is included for building a standard windows "Multi" Icon file
AND to use the VCL "Stream" type. A Standard windows Icon file should have
9 icons in it, a 32x32 and a 16x16 SIXTEEN color-BitC4, a 32x32 and
a 16x16 256 Color-BitC8, and a 32x32 and a 16x16 FullColor-BitC24,
and a 48x48 and a 32x32 and a 16x16 32BIT Full Color-BitC32 (for win XP)}
function TestMultiIcons(aryMutiIcon: Array of TMutiIcon; NumIcons: Byte): Cardinal;
{I took this TestMultiIcons out of the IconsToStream, you can save any combination
of hIcons in the IconsToStream fuction, correct or incorrect combinations,
but if you want to test and see if there are any duplicate size and Bit Count,
use this TestMultiIcons fuction, if the result is Zero, all are OK}
function Get48hIcon(FileName: String; icoIndex: Integer = 0): Integer;
{This is a utility function, to get a 48x48 pixel Icon Handle from an
Icon File. It uses the IExtractIcon COM Interface to get the 48x48
Icon Handle, so it can also get an Icon handle from a windows program
executable file (.EXE with an Icon bitmap in the file) or a windows
library file (.DLL with an Icon bitmap in the file). icoIndex must be
Zero for an Icon File (.ICO) }
implementation
uses Windows, ShlObj;
type
PIconCurHeader = ^TIconCurHeader;
TIconCurHeader = packed record
wReserved: Word;
wType: Word;
wCount: Word;
end; // file header for Icon and Cursor
PIconSpec = ^TIconSpec;
TIconSpec = packed record
bWidth: Byte;
bHeight: Byte;
wColors: Word;
wReserved1: Word;
wReserved2: Word;
iDIBSize: Integer;
iDIBOffset: Integer;
end; // Specifications for each individual Icon in file
TMulti = Record
Width: Integer;
BitCount: TBitCount;
end;
const
Zero = 0;
One = 1;
Two = 2;
Four = 4;
n16 = 16;
green = $FF00;
white = $FFFFFF;
AryWinColor: Array[Zero..9] of Cardinal =($F0FBFF,$A4A0A0,$808080,MaxByte,
green,$00FFFF,$FF0000,$FF00FF,$FFFF00,white);
{AryPalColor has a "One Size Fits All" array of palette
colors for the 8 bit bitmaps, similar to the 256 color
Netscape web palette, but with wider range of colors}
AryPalColor: Array[Byte] of Cardinal =(Zero,$800000,$008000,$808000,
$000080,$800080,$008080,$C0C0C0,$C0DCC0,$A6CAF0,$D4F0FF,$B1E2FF,$8ED4FF,
$6BC6FF,$48B8FF,$00ACFF,$009FEE,$0092DC,$007AB9,$006296,$004A73,$003250,
$D4E3FF,$B1C7FF,$8EABFF,$6B8FFF,$4A79FF,$0069FF,$0058EE,$0049DC,$003DB9,
$003196,$002573,$001950,$D4D4FF,$B1B1FF,$8E8EFF,$6B6BFF,$4848FF,$0000EE,
$0000DE,$0000CC,$0000B6,$000098,$00007A,$000058,$E3D4FF,$C7B1FF,$AB8EFF,
$8F6BFF,$784AFF,$7600FF,$6F00EE,$6000D6,$3D00B9,$310096,$250073,$190050,
$F0D4FF,$E2B1FF,$D48EFF,$C66BFF,$B848FF,$AC00FF,$9F00EE,$9200DC,$7A00B9,
$620096,$4A0073,$320050,$FFD4FF,$FFB1FF,$FF8EFF,$FF6BFF,$FF48FF,$EE00EE,
$DE00DE,$CC00CC,$B600B6,$980098,$790079,$490049,$FFD4F0,$FFB1E2,$FF8ED4,
$FF6BC6,$FF48B8,$FF00AA,$EE009F,$DC0092,$B9007A,$960062,$73004A,$500032,
$FFD4E3,$FFB1C7,$FF8EAB,$FF6B8F,$FF4873,$FF0066,$EE0059,$DC0049,$B9003D,
$960031,$730025,$500019,$FFD4D4,$FFB1B1,$FF8E8E,$FF6B6B,$FF4848,$EF0000,
$DE0000,$CC0000,$B80000,$9F0000,$7C0000,$580000,$FFE3D4,$FFC7B1,$FFAB8E,
$FF8F6B,$FF7348,$FF6600,$EE5800,$DC4900,$B93D00,$963100,$732500,$501900,
$FFF0D4,$FFE2B1,$FFD48E,$FFC66B,$FFBA48,$FFB100,$EEA300,$DC9200,$B97A00,
$966200,$734A00,$503200,$FFFFD4,$FFFFB1,$FFFF8E,$FFFF6B,$FFFF48,$EEEE00,
$DEDE00,$CCCC00,$B6B600,$989800,$747400,$484800,$F0FFD4,$E2FFB1,$D4FF8E,
$C6FF6B,$B8FF48,$AAFF00,$9FED00,$92DC00,$7AB900,$629600,$4A7300,$325000,
$E3FFD4,$C7FFB1,$ABFF8E,$8FFF6B,$73FF48,$66FF00,$58EE00,$49DC00,$3DB900,
$319600,$257300,$194C00,$D4FFD4,$B1FFB1,$8EFF8E,$6BFF6B,$48FF48,$00EF00,
$00DC00,$00C900,$00B000,$009400,$007600,$005200,$D4FFE3,$B1FFC7,$8EFFAB,
$6BFF8F,$48FF73,$00FF66,$00EB5A,$00DC49,$00B93D,$009631,$007325,$005019,
$D4FFF0,$B1FFE2,$8EFFD4,$6BFFC6,$48FFB8,$00FFAA,$00EAA0,$00DC92,$00B97A,
$009662,$00734A,$005032,$D4FFFF,$B1FFFF,$8EFFFF,$6BFFFF,$48FFFF,$00EEEE,
$00DEDE,$00CCCC,$00B6B6,$009898,$007979,$004A4A,$F2F2F2,$E6E6E6,$DADADA,
$CECECE,$C2C2C2,$B6B6B6,$AAAAAA,$9E9E9E,$929292,$868686,$7A7A7A,$6E6E6E,
$626262,$565656,$4A4A4A,$3E3E3E,$323232,$262626,$1A1A1A,$0E0E0E,$FFFBF0,
$A0A0A4,$808080,$FF0000,green,$FFFF00,MaxByte,$FF00FF,$00FFFF, white);
function DoDib(hBmp: Cardinal; var pBits: Pointer; var DC1: Cardinal;
var sSize: Cardinal): Cardinal;
var
BmpInfo1: TBitmapInfo;
tBmp1: tagBitmap;
inDC: Cardinal;
begin
{this function creates a 32 Bit Bitmap, with a Copy of the
Color Icon on it, for scanline testing of the pBits}
Result := Zero;
sSize := Zero;
if GetObject(hBmp, SizeOf(tBmp1), @tBmp1) = Zero then Exit;
ZeroMemory(@BmpInfo1, sizeOf(BmpInfo1));
sSize := (tBmp1.bmWidth * tBmp1.bmHeight)-One;
with BmpInfo1.bmiHeader do
begin
biSize := sizeOf(BmpInfo1.bmiHeader);
biWidth := tBmp1.bmWidth;
biHeight := tBmp1.bmHeight;
biPlanes := One;
biBitCount := 32;
biCompression := BI_RGB;
biSizeImage := (biWidth shl Two) * biHeight;
end;
pBits := nil;
DC1 := CreateCompatibleDC(Zero);
Result := CreateDIBSection(DC1, BmpInfo1, DIB_RGB_COLORS, pBits, Zero, Zero);
if Result = Zero then
begin
DeleteDC(DC1);
Exit;
end;
SelectObject(DC1, Result);
inDC := CreateCompatibleDC(Zero);
SelectObject(inDC, hBmp);
if not BitBlt(DC1, Zero, Zero, tBmp1.bmWidth, tBmp1.bmHeight, inDC,
Zero,Zero, SRCCOPY) then
begin
DeleteDC(DC1);
DeleteObject(Result);
Result := Zero;
end;
DeleteDC(inDC);
end;
function SetInfo(var BmpInfoHead: TBitmapInfoHeader; Width, Height: Integer;
BitCnt: TBitCount): Cardinal;
begin
{this function fills the Bitmap headers (TBitmapInfoHeader) with
the correct information for that bitmap}
ZeroMemory(@BmpInfoHead, sizeof(BmpInfoHead));
with BmpInfoHead do
begin
biSize := SizeOf(TBitmapInfoHeader);
biWidth := Width;
biHeight := Height;
biPlanes := One;
biClrUsed := Zero;
case BitCnt of
BitC1:
begin
biBitCount := One;
biClrUsed := Two;
end;
BitC4:
begin
biBitCount := Four;
biClrUsed := n16;
end;
BitC8:
begin
biBitCount := 8;
biClrUsed := 256;
end;
BitC32: biBitCount := 32;
else biBitCount := 24;
end; // case
biClrImportant := biClrUsed;
biSizeImage := ((biWidth * biBitCount) + 31) and not 31;
biSizeImage := Integer((biSizeImage shr 3)) * Abs(biHeight);
Result := SizeOf(TBitmapInfoHeader);
if biBitCount < 9 then
Result := Result + (biClrUsed shl Two);
end; // with BmpInfo.bmiHeader
end;
function Do1BitDib(var hBmp: HBITMAP): Cardinal;
const
AryColor: Array[Zero..One] of Cardinal = (Zero, white);
var
BmpInfo1: TBitmapInfoHeader;
pBits: Pointer;
DC1, HeaderSize, hNewBmp, inDC, outDC: Cardinal;
tBmp1: tagBitmap;
PntBmpInfo: Pointer;
begin
{ since a black and white, One Bit Icon has only One Bitmap,
instead of Two, this function creates two One Bit DIBs and
copys the upper and lower halves to the new DIBs}
Result := Zero;
ZeroMemory(@BmpInfo1, sizeOf(BmpInfo1));
if GetObject(hBmp, SizeOf(tBmp1), @tBmp1) = Zero then Exit;
tBmp1.bmHeight := tBmp1.bmHeight shr One;
HeaderSize := SetInfo(BmpInfo1, tBmp1.bmWidth, tBmp1.bmHeight, BitC1);
if HeaderSize = Zero then Exit;
GetMem(PntBmpInfo, HeaderSize);
CopyMemory(PntBmpInfo, @BmpInfo1, SizeOf(BmpInfo1));
CopyMemory(@TBitmapInfo(PntBmpInfo^).bmiColors, @AryColor[Zero], 8);
pBits := nil;
DC1 := CreateCompatibleDC(Zero);
try
Result := CreateDIBSection(DC1, TBitmapInfo(PntBmpInfo^),
DIB_RGB_COLORS, pBits, Zero, Zero);
if Result = Zero then Exit;
hNewBmp := CreateDIBSection(DC1, TBitmapInfo(PntBmpInfo^),
DIB_RGB_COLORS, pBits, Zero, Zero);
if hNewBmp = Zero then
begin
DeleteObject(Result);
Result := Zero;
Exit;
end;
SelectObject(DC1, Result);
inDC := CreateCompatibleDC(Zero);
outDC := CreateCompatibleDC(Zero);
try
SelectObject(outDC, hNewBmp);
SelectObject(inDC, hBmp);
BitBlt(outDC, Zero, Zero, tBmp1.bmWidth, tBmp1.bmHeight, inDC,
Zero, Zero, SRCCOPY);
BitBlt(DC1, Zero, Zero, tBmp1.bmWidth, tBmp1.bmHeight, inDC,
Zero, tBmp1.bmHeight, SRCCOPY);
finally
DeleteDC(inDC);
DeleteObject(hBmp);
DeleteDC(outDC);
end;
hBmp := hNewBmp;
finally
FreeMem(PntBmpInfo);
DeleteDC(DC1);
end;
end;
function GetInfoAndBits(hBitmap: Cardinal; var PntBmpInfo: Pointer;
var PntBits: Pointer; BitCount: TBitCount; var hBmp8: Cardinal): Cardinal;
var
HeaderSize, cDC1, inDC: Cardinal;
BmpInfo1: TBitmapInfoHeader;
tBmp1: tagBitmap;
begin
{this fuction will set the TBitmapInfo with the info used to save a Bitmap file,
saved as an Icon in this case, and create the memory block PntBmpInfo and copy
the TBitmapInfo into it. If the Bit Count is BitC8 then a New Bitmap is Created,
with the color Palete from the AryEPalColor. If not then the Icon Bitmap
info is retrived with GetDIBits}
Result := Zero;
{if this function returns zero, it has FAILED to get needed parameters}
if GetObject(hBitmap, SizeOf(tBmp1), @tBmp1) = Zero then Exit;
HeaderSize := SetInfo(BmpInfo1, tBmp1.bmWidth, tBmp1.bmHeight, BitCount);
GetMem(PntBmpInfo, HeaderSize);
CopyMemory(PntBmpInfo, @BmpInfo1, SizeOf(BmpInfo1));
hBmp8 := Zero;
cDC1 := CreateCompatibleDC(Zero);
try
if BitCount = BitC8 then
begin
CopyMemory(@TBitmapInfo(PntBmpInfo^).bmiColors, @AryPalColor[Zero], 1024);
hBmp8 := CreateDIBSection(cDC1, TBitmapInfo(PntBmpInfo^),
DIB_RGB_COLORS, PntBits, Zero, Zero);
if hBmp8 = Zero then
begin
Exit;
end else
Result := HeaderSize;
SelectObject(cDC1, hBmp8);
inDC := CreateCompatibleDC(Zero);
GdiFlush;
SelectObject(inDC, hBitmap);
if not BitBlt(cDC1, Zero, Zero, tBmp1.bmWidth, tBmp1.bmHeight,
inDC, Zero, Zero, SRCCOPY) then Result := Zero;
DeleteDC(inDC);
end else
begin
GetMem(PntBits, BmpInfo1.biSizeImage);
if GetDIBits(cDC1, hBitmap, Zero, abs(BmpInfo1.biHeight), PntBits,
TBitmapInfo(PntBmpInfo^), DIB_RGB_COLORS) <> Zero then Result := HeaderSize;
end;
finally
DeleteDC(cDC1);
end;
end;
function WriteToFile(FileName: Pchar; PcInfo, PcBits, PmBits: Pointer;
CHeaderSize, monoImgSize: Cardinal): Integer;
var
hFile1, BytesWrite: Cardinal;
IconCurHd: TIconCurHeader;
IconSpec: TIconSpec;
Total: Cardinal;
procedure BadWrite;
begin
Result := -7;
CloseHandle(hFile1);
DeleteFile(FileName);
end;
begin
{this function writes the Icon Header, the Icon specifications,
color Bitmap specifications, and memory Blocks (Pointers) to an Icon file}
Result := -5;
if (PcInfo = nil) or (PcBits = nil) or (PmBits = nil) then Exit;
IconCurHd.wReserved := Zero;
IconCurHd.wType := One;
IconCurHd.wCount := One;
ZeroMemory(@IconSpec, SizeOf(IconSpec));
with IconSpec, PBitmapInfo(PcInfo).bmiHeader do
begin
bWidth := biWidth;
bHeight := biHeight;
wColors := biBitCount;
iDIBOffset := SizeOf(IconCurHd) + SizeOf(IconSpec);
iDIBSize := CHeaderSize + biSizeImage + monoImgSize;
biHeight := bHeight shl One;
end;
hFile1 := CreateFile(FileName,GENERIC_WRITE,FILE_SHARE_READ,nil,
CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN,Zero);
if hFile1 = INVALID_HANDLE_VALUE then
begin
Result := -6;
Exit;
end;
try
if not WriteFile(hFile1, IconCurHd, SizeOf(IconCurHd), BytesWrite, nil) then
begin
BadWrite;
Exit;
end;
Total := BytesWrite;
if not WriteFile(hFile1, IconSpec, SizeOf(IconSpec), BytesWrite, nil) then
begin
BadWrite;
Exit;
end;
Total := Total+BytesWrite;
if Not WriteFile(hFile1,PcInfo^, CHeaderSize, BytesWrite, nil) then
begin
BadWrite;
Exit;
end;
Total := Total+BytesWrite;
if not WriteFile(hFile1,PcBits^, PBitmapInfo(PcInfo).bmiHeader.biSizeImage,
BytesWrite, nil) then
begin
BadWrite;
Exit;
end;
Total := Total+BytesWrite;
if not WriteFile(hFile1,PmBits^, monoImgSize, BytesWrite, nil) then
begin
BadWrite;
Exit;
end;
Total := Total+BytesWrite;
Result := Total;
finally
CloseHandle(hFile1);
end;
end;
function hIconToFile(FileName: String; hIcon: Cardinal;
iconBitCount: TBitCount): Integer;
var
cIHeaderSize, mIHeaderSize, hBmp8bit, zip: Cardinal;
IconInfo: TIconInfo;
PcBits, PcInfo, PmBits, PmInfo: Pointer;
begin
{this function will use an Icon Handle to get the information and Bytes needed
to make and Icon file, and then create and write that file as the SaveFileName}
Result := -One;
if Length(FileName) < Four then Exit;
if not GetIconInfo(hIcon, IconInfo) then
begin
Result := -2;
Exit;
end;
if IconInfo.hbmColor < 33 then
begin
if IconInfo.hbmMask > 32 then
IconInfo.hbmColor := Do1BitDib(IconInfo.hbmMask);
if IconInfo.hbmColor < 33 then
begin
Result := -3;
Exit;
end;
end;
try
PcInfo := nil;
PcBits := nil;
PmInfo := nil;
PmBits := nil;
hBmp8bit := Zero;
cIHeaderSize := GetInfoAndBits(IconInfo.hbmColor, PcInfo, PcBits,
iconBitCount, hBmp8bit);
mIHeaderSize := GetInfoAndBits(IconInfo.hbmMask, PmInfo, PmBits, BitC1, zip);
try
if (cIHeaderSize = Zero) or (mIHeaderSize = Zero) then
begin
Result := -4;
Exit;
end;
Result := WriteToFile(@FileName[One], PcInfo, PcBits, PmBits, cIHeaderSize,
PBitmapInfo(PmInfo).bmiHeader.biSizeImage);
finally
if hBmp8bit <> Zero then
DeleteObject(hBmp8bit);
if iconBitCount <> BitC8 then
if PcBits <> nil then
FreeMem(PcBits);
if PmBits <> nil then
FreeMem(PmBits);
if PcInfo <> nil then
FreeMem(PcInfo);
if PmInfo <> nil then
FreeMem(PmInfo);
end;
finally
DeleteObject(IconInfo.hbmMask);
DeleteObject(IconInfo.hbmColor);
end;
end;
function TestMultiIcons(aryMutiIcon: Array of TMutiIcon; NumIcons: Byte): Cardinal;
var
IconInfo: TIconInfo;
tBmp1: tagBitmap;
AryMulti: Array[Zero..20] of TMulti;
MultiNum: Integer;
i, j: Cardinal;
InIt: Boolean;
begin
{this fuction will loop through all the hIcons in an Array and test and see if
the Icon handles are valid and if there are any duplicate Icon Sizes with the
same Color Bit Count, if there is a duplicate, then the Result's bit is set for
the index of that duplicate}
Result := 900000000;
if (NumIcons < One) or (NumIcons > 15) then Exit;
if High(aryMutiIcon) < NumIcons-One then
begin
Result := 900000001;
Exit;
end;
MultiNum := Zero;
Result := Zero;
AryMulti[Zero].Width := -24000;
for i := Zero to NumIcons - One do
begin
if not GetIconInfo(aryMutiIcon[i].hIcon, IconInfo) then
begin
Result := 1000000000 + i;
Exit;
end;
try
if IconInfo.hbmColor < 33 then
begin
if IconInfo.hbmMask > 32 then
IconInfo.hbmColor := Do1BitDib(IconInfo.hbmMask);
if IconInfo.hbmColor < 33 then
begin
Result := 1000000100 + i;;
Exit;
end;
end;
if GetObject(IconInfo.hbmColor, SizeOf(tBmp1), @tBmp1) = Zero then
begin
Result := 1000000200 + i;
Exit;
end;
finally
DeleteObject(IconInfo.hbmColor);
DeleteObject(IconInfo.hbmMask);
end;
if (tBmp1.bmWidth <> tBmp1.bmHeight) then
begin
Result := 2000000000+ i;
Exit;
end;
case tBmp1.bmWidth of
n16: ;
32: ;
48: ;
else begin
Result := 2000000000+ i;
Exit;
end;
end;
case tBmp1.bmHeight of
n16: ;
32: ;
48: ;
else begin
Result := 2000000000+ i;
Exit;
end;
end;
InIt := False;
for j := Zero to MultiNum do
if(AryMulti[j].Width = tBmp1.bmWidth) and
(AryMulti[j].BitCount = aryMutiIcon[i].BitCount) then
begin
InIt := True;
Break;
end;
if InIt Then
begin
Result := Result or One shl i;
Continue;
end;
Inc(MultiNum);
AryMulti[MultiNum].Width := tBmp1.bmWidth;
AryMulti[MultiNum].BitCount := aryMutiIcon[i].BitCount;
end;
end;
function IconsToStream(Stream: TStream; aryMutiIcon: Array of TMutiIcon;
NumIcons: Byte = One): Integer;
var
i, cIHeaderSize, mIHeaderSize, hBmp8bit, EndPos, StartoF, zip: Cardinal;
IconInfo: TIconInfo;
PcBits, PcInfo, PmBits, PmInfo, Pstorage: Pointer;
IconCurHd: TIconCurHeader;
IconSpec: TIconSpec;
begin
{this function uses the VCL Stream type and can put more than
one hIcon in the file. A standard window Icon file is suppose to have an Icon
for each color depth in 32x32 and 16x16,
and win XP adds the 48x48 and the 32 bit}
Result := -One;
if (not Assigned(Stream)) then Exit;
if NumIcons = Zero then
begin
Result := -2;
Exit;
end;
if NumIcons > 15 then
begin
Result := -3;
Exit;
end;
if High(aryMutiIcon) < NumIcons-One then
begin
Result := -4;
Exit;
end;
IconCurHd.wReserved := Zero;
IconCurHd.wType := One;
IconCurHd.wCount := NumIcons;
EndPos := Zero;
Pstorage := nil;
try
for i := Zero to NumIcons - One do
begin // for loop
if not GetIconInfo(aryMutiIcon[i].hIcon, IconInfo) then
begin
Result := -5;
Exit;
end;
try
if IconInfo.hbmColor < 33 then
begin
if IconInfo.hbmMask > 32 then
IconInfo.hbmColor := Do1BitDib(IconInfo.hbmMask);
if IconInfo.hbmColor < 33 then
begin
Result := -6;
Exit;
end;
end;
PcInfo := nil;
PcBits := nil;
PmInfo := nil;
PmBits := nil;
hBmp8bit := Zero;
cIHeaderSize := GetInfoAndBits(IconInfo.hbmColor, PcInfo, PcBits,
aryMutiIcon[i].BitCount, hBmp8bit);
mIHeaderSize := GetInfoAndBits(IconInfo.hbmMask, PmInfo, PmBits, BitC1, zip);
try
if (cIHeaderSize = Zero) or (mIHeaderSize = Zero) then
begin
Result := -7;
Exit;
end;
ZeroMemory(@IconSpec, SizeOf(IconSpec));
with IconSpec, PBitmapInfo(PcInfo).bmiHeader do
begin
bWidth := biWidth;
bHeight := biHeight;
wColors := biBitCount;
iDIBOffset := SizeOf(IconCurHd) + SizeOf(IconSpec);
iDIBSize := cIHeaderSize + biSizeImage+ PBitmapInfo(PmInfo).bmiHeader.biSizeImage;
biHeight := bHeight shl One;
end;
if i = Zero then
begin
EndPos := SizeOf(IconCurHd)+ (NumIcons * SizeOf(IconSpec))+ cIHeaderSize+
PBitmapInfo(PcInfo).bmiHeader.biSizeImage +
PBitmapInfo(PmInfo).bmiHeader.biSizeImage;
ReAllocMem(Pstorage, EndPos);
CopyMemory(PStorage, @IconCurHd, SizeOf(IconCurHd));
StartoF := SizeOf(IconCurHd) + (NumIcons * SizeOf(IconSpec));
end else
begin
StartoF := EndPos;
EndPos := EndPos + cIHeaderSize + PBitmapInfo(PcInfo).bmiHeader.biSizeImage +
PBitmapInfo(PmInfo).bmiHeader.biSizeImage;
ReAllocMem(Pstorage, EndPos);
end;
CopyMemory(Pointer(Cardinal(PStorage)+StartoF), PcInfo, cIHeaderSize);
CopyMemory(Pointer(Cardinal(PStorage)+StartoF+cIHeaderSize), PcBits,
PBitmapInfo(PcInfo).bmiHeader.biSizeImage);
CopyMemory(Pointer(Cardinal(PStorage)+StartoF+cIHeaderSize+
PBitmapInfo(PcInfo).bmiHeader.biSizeImage), PmBits,
PBitmapInfo(PmInfo).bmiHeader.biSizeImage);
with IconSpec, PBitmapInfo(PcInfo).bmiHeader do
begin
bWidth := biWidth;
bHeight := biHeight shr One;
wColors := biPlanes * biBitCount;
iDIBSize := cIHeaderSize + biSizeImage +
PBitmapInfo(PmInfo).bmiHeader.biSizeImage;
iDIBOffset := StartoF;
end;
CopyMemory(Pointer(Cardinal(PStorage)+SizeOf(IconCurHd) +
((i) * SizeOf(IconSpec))), @IconSpec, SizeOf(IconSpec));
finally
if hBmp8bit <> Zero then
DeleteObject(hBmp8bit);
if (PcBits <> nil) and (aryMutiIcon[i].BitCount <> BitC8) then
FreeMem(PcBits);
if PmBits <> nil then
FreeMem(PmBits);
if PcInfo <> nil then
FreeMem(PcInfo);
if PmInfo <> nil then
FreeMem(PmInfo);
end;
finally
DeleteObject(IconInfo.hbmColor);
DeleteObject(IconInfo.hbmMask);
end;
end; // for loop
Result := Stream.Write(Pstorage^, EndPos);
if Cardinal(Result) <> EndPos then
Result := -Result;
finally
if Pstorage <> nil then
FreeMem(Pstorage);
end;
end;
{this autoIconToFile is for those who have little or no Idea
of Bit Counts and just want to have a single Icon in a file
that preserves it's visual appearence, beyond the four bit
Icon that Delphi TIcon does}
function autoIconToFile(FileName: String; hIcon: Cardinal): Integer;
var
cIHeaderSize, mIHeaderSize, h8bitBmp, zip: Cardinal;
IconInfo: TIconInfo;
PcBits, PcInfo, PmBits, PmInfo: Pointer;
autoBitCnt: TBitCount;
AryColor: Array[Zero..265] of Cardinal;
// - - - - - - - - - - - - - - - - - - - -
{this function determines if there are less than 236 colors beside the
20 standard windows colors, and then will create an optimized pallete, with
all of the icons colors, if there are more colors then the result is 238,
which will result in a Full Color BitC24 Icon file}
function GetNumColors(hBitmap: Cardinal): TBitCount;
var
pBits, pScan: Pointer;
BmpDC, hBmp32, scanS, ReC: Cardinal;
i, j: Integer;
isThere: Boolean;
begin
Result := BitC4;
{this function will create a 32 bit Bitmap and copy the Color
Icon bitmap on it. Then test it's pixel colors for Black and White,
and then the standard 16, four bit, colors, and if there is a color
that is not in the standard 16, then it Returns BitC8. If there are
more than 236 colors then it returns BitC24, if it detects any alpha
channel data it will return BitC32}
CopyMemory(@AryColor[Zero], @AryWinColor[Zero], SizeOf(AryWinColor));
for i := 0 to MaxByte do
begin
ReC := AryPalColor[i];
AryColor[i+10] := (ReC shr n16) or (ReC and green) or ((ReC and MaxByte) shl n16);
end;
hBmp32 := DoDib(hBitMap, pBits, BmpDC, scanS);
if (hBmp32 = Zero) or (pBits = nil) then Exit;
try
Result := BitC1;
ReC := Zero;
pScan := Pointer(Cardinal(pBits) - Four);
for i := Zero to scanS do
begin
Inc(Cardinal(pScan), Four);
if (Cardinal(pScan^) = white) or
(Cardinal(pScan^) = Zero) then Continue;
if (Cardinal(pScan^) > white) then
begin
Result := BitC32;
Break;
end;
if Result = BitC1 then
Result := BitC4;
if not ((Cardinal(pScan^) = MaxByte) or
(Cardinal(pScan^) = green) or
(Cardinal(pScan^) = $FF0000) or
(Cardinal(pScan^) = $00FFFF) or
(Cardinal(pScan^) = $FFFF00) or
(Cardinal(pScan^) = $FF00FF) or
(Cardinal(pScan^) = $808080) or
(Cardinal(pScan^) = $C0C0C0) or
(Cardinal(pScan^) = $000080) or
(Cardinal(pScan^) = $008000) or
(Cardinal(pScan^) = $800000) or
(Cardinal(pScan^) = $008080) or
(Cardinal(pScan^) = $808000) or
(Cardinal(pScan^) = $800080))
then
begin
if Result = BitC4 then
Result := BitC8;
isThere := False;
for j := Zero to ReC+19 do
begin
if Cardinal(pScan^) = AryColor[j] then
begin
isThere := True;
Break;
end;
end;
if not isThere then
begin
if ReC < 236 then
AryColor[ReC+20] := Cardinal(pScan^);
Inc(ReC);
end;
if ReC = 238 then
begin
Result := BitC24;
Break;
end;
end;
end;
finally
DeleteDC(BmpDC);
DeleteObject(hBmp32);
end;
end;
// - - - - - - - - - - - - - -
function autoInfoAndBits(hBitmap: Cardinal; var PntBmpInfo: Pointer;
var PntBits: Pointer): Cardinal;
var
HeaderSize, cDC1, inDC: Cardinal;
DibSec: TDIBSection;
BmpInfo1: TBitmapInfoHeader;
i: Integer;
begin
{this function will get the TBitmapInfo info and pBits for the Icon Bitmap
and do an 8 Bit Count bitmap for an 8 bit Icon, with an optimized pallete}
Result := Zero;
DibSec.dsbmih.biSize := Zero;
if GetObject(hBitmap, SizeOf(DibSec), @DibSec) = Zero then
begin
MessageBox(Zero, 'GetObject did NOT work', 'ERROR GetObject', MB_ICONERROR);
Exit;
end;
autoBitCnt := GetNumColors(hBitmap);
HeaderSize := SetInfo(BmpInfo1, DibSec.dsBm.bmWidth, DibSec.dsBm.bmHeight, autoBitCnt);
GetMem(PntBmpInfo, HeaderSize);
CopyMemory(PntBmpInfo, @BmpInfo1, SizeOf(BmpInfo1));
h8bitBmp := Zero;
cDC1 := CreateCompatibleDC(Zero);
try
if autoBitCnt = BitC8 then
begin
for i := Zero to MaxByte do
begin
inDC := AryColor[i+10];
TBitmapInfo(PntBmpInfo^).bmiColors[i] := tagRGBQUAD((inDC shr n16) or
(inDC and green) or ((inDC and MaxByte) shl n16));
end;
h8bitBmp := CreateDIBSection(cDC1, TBitmapInfo(PntBmpInfo^),
DIB_RGB_COLORS, PntBits, Zero, Zero);
if h8bitBmp = Zero then Exit else
Result := HeaderSize;
SelectObject(cDC1, h8bitBmp);
inDC := CreateCompatibleDC(Zero);
GdiFlush;
SelectObject(inDC, hBitmap);
if not BitBlt(cDC1, Zero, Zero, DibSec.dsBm.bmWidth, DibSec.dsBm.bmHeight, inDC,
Zero, Zero, SRCCOPY) then Result := Zero;
DeleteDC(inDC);
end else // = BitC8
begin
GetMem(PntBits, BmpInfo1.biSizeImage);
if GetDIBits(cDC1, hBitmap, Zero, abs(BmpInfo1.biHeight), PntBits,
TBitmapInfo(PntBmpInfo^), DIB_RGB_COLORS) <> Zero then Result := HeaderSize;
end;
finally
DeleteDC(cDC1);
end;
end;
// - - - - - - - - - - - - - - - - - -
begin // autoIconToFile / / / / / / / / / / / / / / / / / / / / / / /
Result := -One;
if Length(FileName) < Four then Exit;
if not GetIconInfo(hIcon, IconInfo) then
begin
Result := -2;
Exit;
end;
if IconInfo.hbmColor < 33 then
begin
if IconInfo.hbmMask > 32 then
IconInfo.hbmColor := Do1BitDib(IconInfo.hbmMask);
if IconInfo.hbmColor < 33 then
begin
Result := -3;
Exit;
end;
end;
try
PcInfo := nil;
PcBits := nil;
PmInfo := nil;
PmBits := nil;
h8bitBmp := Zero;
cIHeaderSize := autoInfoAndBits(IconInfo.hbmColor, PcInfo, PcBits);
mIHeaderSize := GetInfoAndBits(IconInfo.hbmMask, PmInfo, PmBits, BitC1, zip);
try
if (cIHeaderSize = Zero) or (mIHeaderSize = Zero) then
begin
Result := -4;
Exit;
end;
Result := WriteToFile(@FileName[One], PcInfo, PcBits, PmBits, cIHeaderSize,
PBitmapInfo(PmInfo).bmiHeader.biSizeImage);
finally
if h8bitBmp <> Zero then
DeleteObject(h8bitBmp);
if (PcBits <> nil) and (autoBitCnt <> BitC8) then
FreeMem(PcBits);
if PmBits <> nil then
FreeMem(PmBits);
if PcInfo <> nil then
FreeMem(PcInfo);
if PmInfo <> nil then
FreeMem(PmInfo);
end;
finally
DeleteObject(IconInfo.hbmMask);
DeleteObject(IconInfo.hbmColor);
end;
end;
{the Icon32To24File fuction makes a copy of the icon's color bitmap
and scans the alpha channel for values that would be blended in 32 bit
and converts these to the Mask Bitmap additions, to make the mask
bitmap mask area smaller, reducing the Black areas around the 24
bit icon.}
function Icon32To24File(FileName: String; hIcon: Cardinal): Integer;
const
AryColor: Array[Zero..One] of Cardinal = (Zero, white);
var
IconInfo: TIconInfo;
BmpInfo1: TBitmapInfo;
tBmp1: tagBitmap;
pBits, pScan, pMBits, pCBits, PntBmpInfo: Pointer;
DC1, iClDC, mDC, n1DC, n2DC, aBmp, sSize,
nColBmp, nMonBmp, monoImgSize, B1: Cardinal;
i: Integer;
begin
Result := -One;
if Length(FileName) < Four then Exit;
if not GetIconInfo(hIcon, IconInfo) then
begin
Result := -2;
Exit;
end;
try
if IconInfo.hbmColor < 33 then
begin
Result := -3;
Exit;
end;
if GetObject(IconInfo.hbmColor, SizeOf(tBmp1), @tBmp1) = Zero then
begin
Result := -4;
Exit;
end;
if tBmp1.bmBitsPixel <> 32 then
begin
Result := -8;
Exit;
end;
ZeroMemory(@BmpInfo1, sizeOf(BmpInfo1));
sSize := (tBmp1.bmWidth * tBmp1.bmHeight)-One;
with BmpInfo1.bmiHeader do
begin
biSize := sizeOf(BmpInfo1.bmiHeader);
biWidth := tBmp1.bmWidth;
biHeight := tBmp1.bmHeight;
biPlanes := One;
biBitCount := 32;
biCompression := BI_RGB;
biSizeImage := (biWidth shl Two) * biHeight;
end;
pBits := nil;
DC1 := CreateCompatibleDC(Zero);
aBmp := CreateDIBSection(DC1, BmpInfo1, DIB_RGB_COLORS, pBits, Zero, Zero);
try
SelectObject(DC1, aBmp);
iClDC := CreateCompatibleDC(Zero);
SelectObject(iClDC, IconInfo.hbmColor);
BitBlt(DC1, Zero, Zero, tBmp1.bmWidth, tBmp1.bmHeight, iClDC,
Zero,Zero, SRCCOPY);
pScan := Pointer(Cardinal(pBits) - Four);
for i := Zero to Ssize do
begin
Inc(Cardinal(pScan), Four);
B1 := Cardinal(pScan^) shr 24;
if (Cardinal(pScan^) > white) then
begin
if B1 < 116 then
Cardinal(pScan^) := white else
Cardinal(pScan^) := Zero;
end else Cardinal(pScan^) := Zero;
end;
mDC := CreateCompatibleDC(Zero);
SelectObject(mDC, IconInfo.hbmMask);
BitBlt(mDC, Zero, Zero, tBmp1.bmWidth, tBmp1.bmHeight, DC1,
Zero,Zero, SRCPAINT);
finally
DeleteDC(DC1);
DeleteObject(aBmp);
end;
with BmpInfo1.bmiHeader do
begin
biBitCount := One;
biClrUsed := Two;
biClrImportant := Two;
biSizeImage := ((biWidth * biBitCount) + 31) and not 31;
biSizeImage := Integer((biSizeImage shr 3)) * Abs(biHeight);
monoImgSize := biSizeImage;
end;
GetMem(PntBmpInfo, SizeOf(TBitmapInfoHeader) + 8);
try
CopyMemory(PntBmpInfo, @BmpInfo1.bmiHeader, SizeOf(BmpInfo1.bmiHeader));
CopyMemory(@TBitmapInfo(PntBmpInfo^).bmiColors, @AryColor[Zero], 8);
pMbits := nil;
n1DC := CreateCompatibleDC(Zero);
nMonBmp := CreateDIBSection(n1DC, TBitmapInfo(PntBmpInfo^),
DIB_RGB_COLORS, pMbits, Zero, Zero);
finally
FreeMem(PntBmpInfo);
end;
if nMonBmp = Zero then
begin
Result := -9;
DeleteDC(iClDC);
DeleteDC(n1DC);
DeleteDC(mDC);
Exit;
end;
SelectObject(n1DC, nMonBmp);
BitBlt(n1DC, Zero, Zero, tBmp1.bmWidth, tBmp1.bmHeight, mDC,
Zero,Zero, SRCCOPY);
DeleteDC(n1DC);
with BmpInfo1.bmiHeader do
begin
biBitCount := 24;
biClrUsed := Zero;
biClrImportant := Zero;
biSizeImage := ((biWidth * biBitCount) + 31) and not 31;
biSizeImage := Integer((biSizeImage shr 3)) * Abs(biHeight);
end;
pCbits := nil;
n2DC := CreateCompatibleDC(Zero);
nColBmp := CreateDIBSection(n2DC, BmpInfo1, DIB_RGB_COLORS, pCbits, Zero, Zero);
if nColBmp = Zero then
begin
Result := -9;
DeleteDC(iClDC);
DeleteDC(n2DC);
DeleteObject(nMonBmp);
Exit;
end;
SelectObject(n2DC, nColBmp);
BitBlt(n2DC, Zero, Zero, tBmp1.bmWidth, tBmp1.bmHeight, iClDC,
Zero,Zero, SRCCOPY);
BitBlt(mDC, Zero, Zero, tBmp1.bmWidth, tBmp1.bmHeight, n2DC,
Zero,Zero, DSTINVERT);
BitBlt(n2DC, Zero, Zero, tBmp1.bmWidth, tBmp1.bmHeight, mDC,
Zero,Zero, SRCAND);
DeleteDC(mDC);
DeleteDC(iClDC);
DeleteDC(n2DC);
finally
DeleteObject(IconInfo.hbmMask);
DeleteObject(IconInfo.hbmColor);
end;
Result := WriteToFile(@FileName[One], @BmpInfo1, pCBits, pMBits,
SizeOf(TBitmapInfoHeader), monoImgSize);
DeleteObject(nMonBmp);
DeleteObject(nColBmp);
end;
function Get48hIcon(FileName: String; icoIndex: Integer = Zero): Integer;
var
DeskTopISF: IShellFolder;
IExIcon: IExtractIcon;
PathPidl: PItemIDList;
hIconL, hIconS: HIcon;
begin
{this function uses the IExtractIcon to get a 48x48 icon Handle from a file
that Has the Icon Bitmaps in it, like an Icon File (.ICO), an executable
(.EXE) and a library (.DLL) }
Result := Zero;
if SHGetDesktopFolder(DeskTopISF) <> NOERROR then
Exit;
PathPidl := nil;
if DeskTopISF.GetUIObjectOf(Zero, One, PathPidl, IID_IExtractIconA,
nil, IExIcon) <> NOERROR then
Exit;
if (IExIcon.Extract(PChar(FileName), icoIndex, hIconL, hIconS,
48 or (n16 shl n16)) = NOERROR) and (hIconL <> Zero) then
Result := hIconL;
DestroyIcon(hIconS);
end;
end. |

H O M E 