Icon converts to image?

  • Thread starter Thread starter yxq
  • Start date Start date
Y

yxq

Hello
The icons with the alpha channel are supported in WindowsXP. If use the
System.Drawing.Bitmap.ToBitmap on the icon handle(ico.ToBitmap), the alpha
channel won't be preserved, resulting in an ugly black border where the
alpha area. But if the icons with the alpha channel must be show in a
picuturebox, how to do?
Picturebox1.Image=???

The article
http://www.vbaccelerator.com/home/NET/Code/Libraries/Shell_Projects/Getting_
File_Icons_Using_The_Shell/article.asp


Thanks
 
Your best bet is to use DrawIcon on the Picturebox's Graphics Object.

If you really want an Alpha Image:
First of all you need to extract the hBitmap from the Icon and use that to
create your bitmap.
When you create a new bitmap, from existing data, it has an RGB format. The
Alpha channel is not recognised even though the BitmapData does contain it.
To overcome this you must create a second blank bitmap with the ARGB format
and copy the bits to it.
The following code shows how to do this: (note: this will produce a blank
bitmap if the image does not have an Alpha channel)

*****************************************
Imports System.Drawing.Imaging
Imports System.Runtime.InteropServices

Public Class Form1
Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "
...
Code Ommitted
...
#End Region

#Region " Win32 API "

Private Structure ICONINFO
Dim fIcon As Boolean
Dim xHotspot As Integer
Dim yHotspot As Integer
Dim hbmMask As IntPtr 'hBitmap
Dim hbmColor As IntPtr 'hBitmap
End Structure

<DllImport("user32", _
CallingConvention:=CallingConvention.Cdecl)> _
Private Shared Function GetIconInfo( _
ByVal hIcon As IntPtr, _
ByRef piconinfo As ICONINFO) _
As Boolean
End Function

#End Region

Private Sub Form1_Load(ByVal sender As System.Object,
ByVal e As System.EventArgs) _
Handles MyBase.Load

Dim ico As New Icon("MyPath\MyIcon.ico")
Dim ii As New ICONINFO
GetIconInfo(ico.Handle, ii)
Dim bmp As Bitmap = Bitmap.FromHbitmap(ii.hbmColor)
PictureBox1.Image = New Bitmap(FixAlphaBitmap(bmp))

End Sub

Private Function FixAlphaBitmap(ByRef bmSource As Bitmap) _
As Bitmap

'WARNING! This function will fail if the passed bitmap is
'not of the correct Pixelformat.
Dim bmData(1) As Imaging.BitmapData
Dim bmBounds As New Rectangle(0, 0, _
bmSource.Width, _
bmSource.Height)

Dim bmArray((bmSource.Width * bmSource.Height) - 1) _
As Integer

bmData(0) = bmSource.LockBits(bmBounds, _
ImageLockMode.ReadOnly, _
bmSource.PixelFormat)

Dim dstBitmap As New Bitmap(bmData(0).Width, _
bmData(0).Height, _
bmData(0).Stride, _
PixelFormat.Format32bppArgb, _
bmData(0).Scan0)

bmData(1) = dstBitmap.LockBits(bmBounds, _
ImageLockMode.WriteOnly, _
dstBitmap.PixelFormat)

Marshal.StructureToPtr(bmData(0).Scan0, _
bmData(1).Scan0, _
True)

bmSource.UnlockBits(bmData(0))
dstBitmap.UnlockBits(bmData(1))

Return dstBitmap

End Function

End Class

*****************************************

HTH

Mick
 
Hello
Thank you, it works well!
But if i use API PickIconDlg and ExtractIcon to get icon from *.dll files,
how to know whether the icons have Alpha channel? It does not work when the
icons have no Alpha channel. if the icons have no Alpha channel, i can use
"ico.Tobitmap".

Thanks
 
I haven't worked that one out yet.
I think, but have not confirmed, that the Bitmap returned, when there is no
Alpha channel, is not actually blank, it's just fully Transparent.
I am no expert in Bitmap structures so it took me a while to come up with
that solution. However, I would expect that you need to get the Bitmap
Header and check for it there.
I suppose you could loop through the BitmapData bits and check the Alpha bit
for each Color. If all Alpha Bits are zero then there is no Alpha Channel,
so return the original bitmap. I'll look into that and let you know if I can
get it to work.
 
Well it seems that the returned blank bitmap is indeed blank not just
transparent.
Looping through the Bitmap bits does not offer any help.
The only solution I can think of is to get the information from the Icon
File itself. I found some details on Icon File structure at this address:
<http://www.iconolog.net/info/icoFormat.html>
Now all that remains is to set up a BinaryFileReader to extract the relevant
data. That VBAccelerator example you looked at does that, but I am having
trouble following it to get the Info I want, so I will write my own routine
based on the information from the iconolog.net link above. I'm fitting this
in with other stuff so if you find a solution before me I would appreciate
the feedback.

p.s. Whilst playing around I discovered that you do not need that
Marshal.StructureToPtr() call or to lock/unlock the dstBitmap. When we
created dstBitmap we set its bits to the address of bmSource's bits with the
Scan0 IntPtr, so both bitmaps occupy the same memory. FixAlphaBitmap now
becomes:

Private Function FixAlphaBitmap(ByRef bmSource As Bitmap) _
As Bitmap

'WARNING! This function will fail if the passed bitmap is
'not of the correct Pixelformat.
Dim bmData As Imaging.BitmapData
Dim bmBounds As New Rectangle(0, 0, _
bmSource.Width, _
bmSource.Height)

bmData = bmSource.LockBits(bmBounds, _
ImageLockMode.ReadOnly, _
bmSource.PixelFormat)

Dim dstBitmap As New Bitmap(bmData.Width, _
bmData.Height, _
bmData.Stride, _
PixelFormat.Format32bppArgb, _
bmData.Scan0)

bmSource.UnlockBits(bmData)

Return dstBitmap

End Function

Mick
 
Well that turned out to be pretty simple.
If GetIconBitsPerPixel returns less than 32 then use Icon.ToBitmap

**** Code Starts ************************************
#Region " IconStructureInfo "

'Icon File Structure Info courtesy of:
'http://www.iconolog.net/info/icoFormat.html

Private Structure ICONFILE
Dim Reserved As Short
Dim ResourceType As Short
Dim IconCount As Short
Dim IconDir() As ICONENTRY
Dim IconData() As IconData
End Structure

Private Structure ICONENTRY
Dim Width As Byte
Dim Height As Byte
Dim NumColors As Byte
Dim Reserved As Byte
Dim NumPlanes As Short
Dim BitsPerPixel As Short
Dim DataSize As Integer
Dim DataOffset As Integer
End Structure

Private Structure ICONDATA
Dim header As BITMAPINFOHEADER
Dim Palette() As PALETTEENTRY
Dim XorMap() As Byte
Dim AndMap() As Byte
End Structure

Private Structure BITMAPINFOHEADER '40 bytes
Dim biSize As Integer
Dim biWidth As Integer
Dim biHeight As Integer
Dim biPlanes As Short
Dim biBitCount As Short
Dim biCompression As Integer
Dim biSizeImage As Integer
Dim biXPelsPerMeter As Integer
Dim biYPelsPerMeter As Integer
Dim biClrUsed As Integer
Dim biClrImportant As Integer
End Structure

Private Structure PALETTEENTRY
Dim peRed As Byte
Dim peGreen As Byte
Dim peBlue As Byte
Dim peFlags As Byte
End Structure

#End Region

Private Function GetIconBitsPerPixel(ByVal iconfile As String) _
As Integer

Dim fs As New IO.FileStream(iconfile, IO.FileMode.Open)
Dim BR As New IO.BinaryReader(fs)
Dim iFile As New ICONFILE

iFile.Reserved = BR.ReadInt16
iFile.ResourceType = BR.ReadInt16
iFile.IconCount = BR.ReadInt16

ReDim iFile.IconDir(iFile.IconCount)
Dim id(iFile.IconCount) As ICONENTRY

Dim MaxColors As Integer = 0

For i As Integer = 1 To iFile.IconCount
id(i).Width = BR.ReadByte
id(i).Height = BR.ReadByte
id(i).NumColors = BR.ReadByte
id(i).Reserved = BR.ReadByte
id(i).NumPlanes = BR.ReadInt16
id(i).BitsPerPixel = BR.ReadInt16
id(i).DataSize = BR.ReadInt32
id(i).DataOffset = BR.ReadInt32
If id(i).BitsPerPixel > MaxColors Then
MaxColors = id(i).BitsPerPixel
End If
Next

fs.Close()
BR.Close()

If iFile.ResourceType = 1 Then
Return MaxColors
End If

End Function

**** Code Ends *************************************

Mick
 
Back
Top