Home |
Home |
|
Why use the IconsToFile.pas? ? To Save 256 Color and FullColor Icons to File or Stream. The Delphi Graphics.pas unit has a TIcon, and when you use it's SaveToFile( ) method, the Icon file it produces will be in Four Bit (16 Color) Color Depth. This is fine for icons that can be used in all of the 32 bit windows systems, however the more recent Windows Operating Systems can use 256 color, Full Color and windows XP and Newer systems have the 32 Bit Full Color Icons with alpha blending. 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. This IconsToFile.pas unit has three functions that can save Icons to File in five different Color Formats including 256 color, Full 24 Bit Color and Full 32 Bit Color. These functions in this IconsToFile.pas unit are -
PLEASE NOTE -When ALL of these Icon To File functions save an Icon to a File, it will OVERWRITE an existing File WITHOUT prompting or warning. There is a function that will convert a 32 bit alpha blend system Icon to a 24 bit Icon File without alpha blending, changing the color and mask bitbaps to more closely match how the Icon should look. This function is - Icon32To24File In Windows XP the 48x48 pixel size Icon is used in the default Explorer view, this 48x48 pixel size Icon was not used in the previous versions of windows enough to have an API function to get a 48x48 Icon Handle from an Icon File. I have included a helpful function that will get a 48x48 Icon from an Icon file. This function has nothing to do with saving an Icon to File. This function is - Get48hIcon Number of Colors in an Icon - Icon Files have Color Bitmaps that have a number of Colors they can display, determined by the Bit Count of this Bitmap. I will not attempt to explain the computer display pixel Bit Count definition and usage. I will use all of the following terms - "Color Format", "Color Depth", "Bit Count" and "Number of Colors" to refer to the Icon's Bitmap pixel definition Bit Count (which determines the number of Colors a Bitmap can use in it's pixels). If you are not familar with the Icon File's Bit Count, you should read the next section "Icons and their Color Format".
Icons and their Color Format With this IconsToFile Unit, you can choose the Bit Count for the Icon file,or you can use the autoIconToFile( ) which will scan the system Icon Bitmap and automaticaly choose a Color Format for the Icon. But you should keep in mind some factors especially for Icons in the windows XP system (or newer). Some Windows version Icon Information - The original Windows 95 will only show icons in Four Bit (16 color) , the Second Release of win 95 can only show icons in Eight Bit (256 color) or less (no full color icons). Windows 98 and newer will show full color (24 Bit) icons. Windows XP introduces the 32 Bit full Color Icon with alpha channel Background blending. This XP 32 Bit Icon will NOT display correctly in other systems that do not use 32 bit icons. The icon Colors will be correct, but there will be Dark areas around the icon display were the Blending (shadow) effect should be, but since they do not do the blending, all you'll get is black where the edge blending and background shadows should be. Saving a 32 Bit Icon to file, without alpha chanel blending, will give you the same visual display as a 24 Bit Icon, but a larger file size. What I am trying to say here is that only the Four Bit (16 color) icon is good in all of the windows systems. So if you save Icons to File to be used on a Windows version older than the one you are running, they may not display as they did in your system. This does not mean that you can save a full color (or 256 color) icon to 16 colors and it will look like the full color icon, it will not. To have an effective multi-system Icon File requires a "Muti-Icon" Icon file, with two four bit icons (one 16x16 and one 32x32), two eight bit Icons, two 24 bit Icons, and three 32 bit Icons (one 16x16, one 32x32, and one 48x48) with the alpha channel blending. I have included the BitC1 (two color bitmap) because you can have two color Icons, but this is no longer needed, because Black and White monitors are not used anymore. Why a Multi-Icon File? Whenever the Windows Operating System aquires (loads) an Icon into it's system Icon catch, it will scan the Icon file or resource in an .exe or .dll and pick the Icon that has a Color Bitmap with the same color depth (Bit Count) as the current screen (monitor) color depth (if the OS can use that Bit Count). If there is no Icon Bitmap that matches, it then searches for the closest lower bit count bitmap to create it's Icon, or use the only bitmap in a single Icon File. It will also "Create" any other size system Icons required, that are not in the Icon File or resource. TBitCount sets the Color Format In the hIconToFile( ) and the IconsToStream( ) functions, you will need to set the Bit Count for the file. Use the TBitCount to set the Color Depth (number of Colors, the Pixel Bit Count) in your saved Icon file. type TBitCount = (BitC1, BitC4, BitC8, BitC24, BitC32);The TBitCount Parameter should be set to the Bit Count that you want the Icon File to be saved as. There are NO guidelines I can give you for setting this parameter, since it depends on the version of windows you are using and the color information in the system's Icon Bitmap and which windows system version the Icon will be used. If BitC4 does not look right then try BitC8, and if that don't look right try BitC24, and if that don't look right, if you're in XP or newer then try the BitC32. You should not use the BitC32 unless there is alpha channel information in the Icon. If you do not know anything about the Color Format of icons then you can try the autoIconToFile( ) function. The Number after the BitC is the Bit Count. Here is a List of the Color Formats -
|
Icons To File Functions There are two Icon to File functions |
hIconToFile Function -
The hIconToFile( ) function will save an Icon (the Handle of a system icon in the hIcon1 parameter) as an Icon File with the Path and file Name of the FileName parameter. And you must have a TBitCount in the iconBitCount parameter, which will set the Color Format (Bit Count) of the Icon's Bitmap. Like all write to disk functions, the FileName must contain a valid Disk and path, or the function will fail. This function will fail if the hIcon1 parameter is not a valid system HICON handle. If you are using a Delphi TIcon then you can pass the TIcon.Handle as the hIcon1 parameter. The hIconToFile function looks like this - function hIconToFile(FileName: String; hIcon1: Cardinal; iconBitCount: TBitCount): Integer;hIconToFile function Result - The Result of this hIconToFile function is an Integer value, if the function is successful the Result will be a positive number Above zero, with the amount of bytes written to file. A 32x32 four bit Icon File will have 766 as the Result. If the function Fails to write an Icon to disk, then the Result will be a negative number in the list below -
You can see an example of code for hIconToFile in the code samples below, at this link - code for hIconToFile autoIconToFile Function - The autoIconToFile( ) function is like the hIconToFile( ) function, except there is No iconBitCount parameter. The FileName and hIcon1 parameters are like parameters in the hIconToFile function. The autoIconToFile( ) function will automaticaly try to determine a Color Format for that icon. If the icon only has black and white pixels it will be saved as a BitC1, , if the icon only uses the "standard four bit" 16 colors (VGA colors), then the icon will be saved as a BitC4. If the Icon has less than 237 colors plus the standard 20 windows colors in the windows SVGA palette, then it will be saved as a BitC8. A new pallete with All of the icon's colors is created and used for this BitC8 Icon File. . . And all Icons with more than 236 colors will be saved as a BitC24, unless there is any 32 bit Alpha Chanel information, in which case it will be saved as a BitC32. This may not be the original bit count of the Icon. This function will fail if the hIcon1 parameter is not a valid system HICON handle or the path in the Filename parameter is invalid. The autoIconToFile function looks like this - function autoIconToFile(FileName: String; hIcon1: Cardinal): Integer;autoIconToFile function Result - The Result of this autoIconToFile function is an Integer value, It is exactly the same as the hIconToFile function above, see the comments and List for the Result of the hIconToFile function. You can see an example of code for autoIconToFile in the code samples below, at this link - code for autoIconToFile |
IconsToStream Function Multi Icons to TStream |
IconsToStream Function - The IconsToStream function can save more than One Icon to a TStream, it uses the Delphi VCL TStream class as the reciever of the bytes for an Icon file. An array of TMutiIcon is used to define the icons that will be placed in the Stream. The TMutiIcon Record, used in this function, is defined as follows -
TMutiIcon = Record hIcon: Cardinal; BitCount: TBitCount; end;The TMutiIcon.hIcon is for the system Icon Handle, and the TMutiIcon.BitCount is a TBitCount that tells the function which color format to use for that hIcon. And by using an Array of TMutiIcon, it can put more than one icon in the Icon File. Many Icon files have several Icons in them, to use for the different size Icons displayed by the system (16x16, 32x32, 48x48 pixels) and the different Color Depths that your monitor can support (or the color depths that the system version can support), so there can be Four Bit, Eight Bit, 24 Bit and 32 Bit icons in the same Icon File. The system will automatically scan through a Multi-Icon file and get the first Icon in the file where the Color Format and size most closely matches it's system Icon requirements. The Stream parameter can be a TFileStream, TMemoryStream, or other TStream decendent that can be written to. The aryMutiIcon parameter is an Array of TMutiIcon, described above. The NumIcons parameter will set the number of Icons that will be read from the Array and placed into the Stream. This number must be equal to or less than the number of elements in the array. The Maximum number of Icons allowed in one stream write is 15. The IconsToStream function looks like this - function IconsToStream(Stream: TStream; aryMutiIcon: Array of TMutiIcon; NumIcons: Byte = 1): Integer;IconsToStream function Result - The Result of this IconsToStream function is an Integer value, if the function is successful the Result will be a positive number Above zero, with the amount of bytes written to the stream. A 32x32 four bit Icon File will have 766 as the Result. If the function Fails to write an Icon to stream, then the Result will be a negative number in the list below -
A multi-Icon file will usually have several icons of various sizes and color depths, so the system can get an Icon of the size needed (16x16, 32x32, 48x48) and a color depth (bit count) to match the number of colors in the computer Screen's color resolution. The IconsToStream function does NOT test or examine the icons in the aryMutiIcon paramter for duplicate Size and Bit Count, but this function will fail if Any of the TMutiIcon.hIcon is not a valid system HICON handle. There is a function to test the Array of TMutiIcon for duplicate Size and Bit Count, see the TestMultiIcons function below. You can see an example of code for IconsToStream in the code samples below, at this link - code for IconsToStream TestMultiIcons Function - This function will test the dimentions and color depth of the Icons in the aryMutiIcon parameter, to see if there are any duplicate icon types (same dimentions, and color depth). This fuction does NOT ever write to any file, it only tests the Icons in the array. This function is meant to be used with the IconsToStream function, to check the icons before they are saved to file. The TestMultiIcons function looks like this - function TestMultiIcons(aryMutiIcon: Array of TMutiIcon; NumIcons: Byte): Cardinal;The Result of the TestMultiIcons function is a Cardinal value. A function Result of Zero means that all of the icons are good and there are NO duplicates, if the Result value is above zero and below 100000 then there is at least one duplicate icon. This function will set a bit in the Cardinal Result for each duplicate Icon index. If the Result is two the second Icon (index one) is a duplicate. If the result is 4 then the third Icon (index 2) is a duplicate. If the result is 8 then the fourth Icon is a duplicate. If the result is six then the second and third Icons are duplicates. You can test the bit values of the result with a "if Result or 16 = Result then" test. the Result values are listed below -
You can see an example of code for TestMultiIcons in the code samples below, at this link - code for TestMultiIcons |
Icon32To24File Function To convert 32 bit alpha channel to 24 bit Icons |
Icon32To24File Function - The windows XP system introduced the 32 bit Icon with alpha channel blending. When you want to have an Icon file that will be used in a windows system that does NOT support 32 bit Icons, you might use the hIconToFile function with the BitC24. If you use the hIconToFile( ) function with a 32 bit hIcon with alpha channel blending and save it as a 24 bit Icon, it will NOT look like the 32 bit Icon, because all of the alpha blending information has been lost in the conversion. With the 32 bit alpha blending Icon, the Mask bitmap is not used, the alpha channel pixel information if used as the Mask. This Icon32To24File( ) Function will convert an alpha blend 32 bit Icon to a 24 bit Icon File. But it was designed to be used with the Microsoft Windows XP "shadowed" icons that came with that operating system. It attempts to read the alpha channel information and modifies the Mask and Color bitmaps for the 24 bit Icon, to better match the appearence of the 32 bit Icon. This will yield a 24 bit Icon that looks better than the hIconToFile( ) conversion, but will not have the edge and shadow blending of the original 32 bit Icon. There are a large number of icon alpha blending effects and options that the newer 32 bit Icon Editors can do, this function can NOT correctly translate 32 bit alpha channel blending for all of these effects and options. The Icon32To24File function looks like this - function Icon32To24File(FileName: String; hIcon: Cardinal): Integer;The FileName parameter needs to be a valid file name and file path. The hIcon needs to be a valid system Icon Handle, if it is not a valid system Icon handle , the function will fail. This does NOT test the Icon to see if it has alpha channel information, and will do the conversion even if there is NO Alpha channel information. The System Icon Color Bit Count is tested, and if the system Icons are not 32 bit then this function fails. Icon32To24File function Result - The Result of this Icon32To24File function is an Integer value, if the function is successful the Result will be a positive number Above zero, with the amount of bytes written to file. A 32x32 twenty four bit Icon File will have 3262 as the Result. If the function Fails to write an Icon to disk, then the Result will be a negative number in the list below -
You can see an example of code for Icon32To24File in the code samples below, at this link - code for Icon32To24File |
Get48hIcon Function To get a system Icon Handle for a 48x48 Icon from an Icon File, a Program file or .DLL library |
Get48hIcon Function - There are no API functions to get a 48x48 Icon Handle, and in Windows XP the 48 pixel icon size is the default, so I have a function to get a 48 Icon handle from an Icon File. This function can get an Icon handle from a file that has an Icon in it, which includes an Icon File (.ICO), a program executable that has an Icon in it (.EXE), a library file that has an Icon in it (.DLL) and an Icon library file (.ICL). . This function will Fail if the file does NOT have an Icon bitmap in it, it does NOT get the system default explorer's Icon for a file or file type. It is intended for Icon files, but will also work with other files that have the icon bitmats in them. The Get48hIcon function looks like this - function Get48hIcon(FileName: String; icoIndex: Integer = 0): Integer;The FileName parameter needs to be a valid file name and file path for an Icon file (or file with icon in it). The icoIndex is the index number of the Icon in the file, since an Icon File (.ICO) has only one icon in it, it must be Zero (the default) for all icon files. If you use a muti-Icon file, like an executable or .DLL, then you may include the index number of the icon you want to get the handle for. Get48hIcon function Result - The Result of this Get48hIcon function is an Integer value, which will be a system Icon Handle if the function is successful. If the function Fails, the Result is Zero. You should ALWAYS test for failure (result is equal to zero) of this function. If there is at least ONE Icon bitmap of any size in the file, this function will get a system generated 48x48 icon handle, even if the file does NOT have a 48x48 icon bitmap in it. |
You can see an example of code for Get48hIcon in the code samples below, at this link -
code for Get48hIcon
Code Samples |
procedure TForm1.autoIconToFileClick(Sender: TObject); begin if autoIconToFile('E:\aTest Icon.ico', Application.Icon.Handle) < 0 then ShowMessage('ERROR - autoIconToFile was NOT able to Write the Icon to disk file'); end; |
procedure TForm1.Icon2FileClick(Sender: TObject); var ShInfo1: TSHFILEINFO; hIcon1: Cardinal; Return: Integer; ReStr: String; begin Return := hIconToFile('E:\aTest1.ico', Application.Icon.Handle, BitC24); if Return < 0 then begin if Return = -1 then ReStr := 'ERROR - File name has less than 4 charaters' else if Return = -2 then ReStr := 'ERROR - hIcon is NOT a valid handle for an Icon' else if Return = -3 then ReStr := 'ERROR - could not get Icon''s Bitmap stuctures from the operating system' else if Return = -4 then ReStr := 'ERROR - Icon''s Bitmap pixel definition are Invalid' else if Return = -5 then ReStr := 'ERROR - Could not retrive system Bitmap Data' else if Return = -6 then ReStr := 'ERROR - Could not Create a file with the Path and file name' else if Return = -7 then ReStr := 'ERROR - Could not Write to disk, disk space unavailable or disk IO error' else ReStr := 'ERROR - Undetermined Error'; ShowMessage(ReStr); end else ShowMessage(IntToStr(Return)); {the next two hIconToFile show how to get and use system HICON with the hIconToFile function} SHGetFileInfo('C:\Windows\NotePad.exe', 0, ShInfo1, SizeOf(TSHFILEINFO), SHGFI_ICON); ShowMessage(IntToStr(hIconToFile('E:\New1.ico', ShInfo1.hIcon, BitC24))); if OpenPicDlg1.Execute then if UpperCase(ExtractFileExt(OpenPicDlg1.Filename)) = '.ICO' then begin hIcon1 := ExtractIcon(hInstance, PChar(OpenPicDlg1.Filename), 0); if hIcon1 > 0 then ShowMessage(IntToStr(hIconToFile('E:\Icon 8bit.ico', hIcon1, BitC8))); end; end; |
procedure TMainForm1.sbut_MultiIconClick(Sender: TObject); var aryMulIco: Array[0..0] of TMutiIcon; Return: Integer; FileStream1: TFileStream; begin aryMulIco[0].hIcon := Application.Icon.Handle; AryMulIco[0].BitCount := BitC4; FileStream1 := TFileStream.Create('E:\Multi Icon.ico', fmCreate or fmOpenWrite or fmShareDenyWrite); try Return := IconsToStream(FileStream1, aryMulIco); finally FileStream1.Free; end; ShowMessage('The Result of IconsToStream is '+IntToStr(Return)); end; |
procedure TMainForm1.sbut_MultiIconClick(Sender: TObject); var aryMulIco: Array[0..3] of TMutiIcon; ShInfo1: TSHFILEINFO; Return: Integer; MemStream1: TMemoryStream; begin aryMulIco[0].hIcon := Application.Icon.Handle; aryMulIco[0].BitCount := BitC4; SHGetFileInfo(PChar(ParamStr(0)), 0, ShInfo1, SizeOf(TSHFILEINFO), SHGFI_ICON or SHGFI_SMALLICON); {the SHGetFileInfo fuction with the SHGFI_SMALLICON flag set will get the handle of the Small Icon, 16x16} aryMulIco[1].hIcon := ShInfo1.hIcon; aryMulIco[1].BitCount := BitC4; aryMulIco[2].hIcon := Application.Icon.Handle; aryMulIco[2].BitCount := BitC8; aryMulIco[3].hIcon := ShInfo1.hIcon; aryMulIco[3].BitCount := BitC8; Return := 123; MemStream1 := TMemoryStream.Create; try MemStream1.Write(Return, SizeOf(Integer)); Return := IconsToStream(MemStream1, aryMulIco, 4); ShowMessage('MemStream size '+IntToStr(MemStream1.Size)+' Return '+IntToStr(Return)); finally MemStream1.Free; end; end; |
procedure TMainForm1.sbut_Icon32to24Click(Sender: TObject); var ShInfo1: TSHFILEINFO; begin SHGetFileInfo('C:\Program Files\Internet Explorer\IExplore.exe', 0, ShInfo1, SizeOf(TSHFILEINFO), SHGFI_ICON); ShowMessage(IntToStr(Icon32To24File('E:\Icon 32 to 24.ico', ShInfo1.hIcon))); end; |
procedure TMainForm1.sbut_Icon2File2Click(Sender: TObject); var hIcon1: Cardinal; AryMulIco: Array[0..9] of TMutiIcon; ShInfo1: TSHFILEINFO; Return: Cardinal; Str1: String; begin hIcon1 := Application.Icon.Handle; AryMulIco[0].hIcon := hIcon1; AryMulIco[0].BitCount := BitC8; AryMulIco[2].hIcon := hIcon1; //AryMulIco[2].BitCount := BitC4; AryMulIco[2].BitCount := BitC8; AryMulIco[4].hIcon := hIcon1; AryMulIco[4].BitCount := BitC1; AryMulIco[6].hIcon := hIcon1; AryMulIco[6].BitCount := BitC24; //AryMulIco[6].BitCount := BitC8; SHGetFileInfo(PChar(ParamStr(0)), 0, ShInfo1, SizeOf(TSHFILEINFO), SHGFI_ICON or SHGFI_SMALLICON); AryMulIco[1].hIcon := ShInfo1.hIcon; //AryMulIco[1].hIcon := hIcon1; AryMulIco[1].BitCount := BitC8; AryMulIco[3].hIcon := ShInfo1.hIcon; //AryMulIco[3].hIcon := 22; AryMulIco[3].BitCount := BitC4; AryMulIco[5].hIcon := ShInfo1.hIcon; AryMulIco[5].BitCount := BitC1; AryMulIco[7].hIcon := ShInfo1.hIcon; AryMulIco[7].BitCount := BitC4; //AryMulIco[7].BitCount := BitC24; Return := TestMultiIcons(AryMulIco, 8); if Return > 100000 then begin if Return < 900000000 then Str1 := 'ERROR - Undetermined Error' else if Return = 900000000 then Str1 := 'ERROR - the NumIcons is zero or above 15' else if Return = 900000001 then Str1 := 'ERROR - the NumIcons is higher than the number of elements in the MutiIcon Array' else if Return < 1000000100 then Str1 := 'ERROR - the Icon index '+IntToStr(Return - 1000000000)+ ', hIcon is NOT an ICON Handle' else if Return < 1000000200 then Str1 := 'ERROR - the Icon index '+IntToStr(Return - 1000000100)+ ', is a Two Color Icon without a bits Bitmap structure' else if Return < 1000000300 then Str1 := 'ERROR - the Icon index '+IntToStr(Return - 1000000200)+ ', the hIcon Bitmap will not get system Object information from GetObject( )' else if Return < 2000000100 then Str1 := 'ERROR - the Width and Height of Icon is Incorrect for a standard Icon, for icon index '+ IntToStr(Return - 2000000000) else Str1 :='ERROR - Undetermined Error'; end else // Return > 100000 if Return <> 0 then begin {you can use the test for a bit in the Result with a if Return and 2 <> 0 then The first bit will never be set, since there are no Icons before it} Str1 := 'Duplicate Icon Indexes are '; if Return and 2 <> 0 then Str1 := Str1+'1, '; if Return or 4 = Return then Str1 := Str1+'2, '; if Return or 8 = Return then Str1 := Str1+'3, '; if Return or 16 = Return then Str1 := Str1+'4, '; if Return or 32 = Return then Str1 := Str1+'5, '; if Return or 64 = Return then Str1 := Str1+'6, '; if Return or 128 = Return then Str1 := Str1+'7, '; if Return or 256 = Return then Str1 := Str1+'8, '; if Return or 512 = Return then Str1 := Str1+'9, '; if Return or 1024 = Return then Str1 := Str1+'10, '; if Return or 2048 = Return then Str1 := Str1+'11, '; if Return or 4096 = Return then Str1 := Str1+'12, '; if Return or 8192 = Return then Str1 := Str1+'13, '; if Return or 16384 = Return then Str1 := Str1+'14, '; if Return or 32768 = Return then Str1 := Str1+'15'; end else Str1 := 'All Icons are GOOD'; ShowMessage(Str1+' | '+IntToStr(Return)); end; |
procedure TMainForm1.sbut_Get48hIconClick(Sender: TObject); var Filename: String; hIcon48: Integer; begin FileName := 'C:\Icons\My Icon.ico'; hIcon48 := Get48hIcon(FileName); if hIcon48 <> 0 then DrawIconEx(Canvas.Handle,60,48, hIcon48, 0, 0, 0, 0, DI_NORMAL) else ShowMessage('FAILURE - Get48hIcon'); DestroyIcon(hIcon48); end; |
procedure TMainForm1.sbut_Get48hIconClick(Sender: TObject); var Filename: String; hIcon48: Integer; begin FileName := 'C:\Windows\Notepad.exe'; hIcon48 := Get48hIcon(FileName, 1); if hIcon48 <> 0 then DrawIconEx(Canvas.Handle,60,48, hIcon48, 0, 0, 0, 0, DI_NORMAL) else ShowMessage('FAILURE - Get48hIcon'); DestroyIcon(hIcon48); end; |