Viewing ICON files

BlitzPlus Forums/BlitzPlus Beginners Area/Viewing ICON files

SebHoll(Posted 2005) [#1]
Hi. I am making an app at the moment that involves the user choosing an icon file using the RequestFile() dialog box to be used in the app. However, I want the icon they selected to be diplayed in a Canvas but the LoadImage() command doesn't work with proper ICON files. However if I open JPEG or BMP, it displays it fine so I know it's not the programming. Is there another function or work around I could use because the program really wouldn't be that good without it. I would prefer it if I didn't have to use DLLs but if I do, could you tell me what I have to do. I am a newbie in the DLL field.

Thanks In Advance


Snarkbait(Posted 2005) [#2]
I can probably hack together a loader for you. Gimme a few hours.


Snarkbait(Posted 2005) [#3]
Oops, nevermind, instead of reinventing the wheel, I see you can use the FreeImage wrapper. Here: http://www.blitzcoder.com/cgi-bin/showcase/showcase_showentry.pl?id=snarty09252003024804&comments=no

put all the files in the 'decls' and 'data' folder in your blitzplus 'userlibs' directory. Not sure how it deals with .ico files with multiple images... I may still finish writing my own routine cuz I'm a file format geek like that.


SebHoll(Posted 2005) [#4]
That's great. However, I am making a program that involves reading & changing icons, and sometimes the icon is, an icon for an executable or DLL, like WINWORD.EXE. There isn't a winword.ico file so I need to somehow extract the icon in the resources of the executable. Any ideas

Thanks

Seb


MattVonFat(Posted 2005) [#5]
I don't know exactly which command it is but if you look at the Win API reference there is a command to get the icon from an executable.


Kev(Posted 2005) [#6]
seb, ExtractIconA found in 'shell32.dll'

checkout microsoft's msdn

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/resources/icons/iconreference/iconfunctions/extracticon.asp


SebHoll(Posted 2005) [#7]
How would I actually implement this function into Blitz+(Ie.e. declerations in UserLibs) and how would I use this to display an image?

Thanks for all you help

Seb


Kev(Posted 2005) [#8]
hi seb

heres .decls put this in your blitzplus userlibs folder


;
; Blitz Basic Plus Mixed decls.
;

.lib "kernel32.dll"
kernel32_GetModuleHandle%(lpModuleName%):"GetModuleHandleA" 

.lib "user32.dll"
user32_DestroyIcon%(hIcon%):"DestroyIcon"
user32_DrawIcon%(hdc%,x%,y%,hIcon%):"DrawIcon"
user32_GetDC%(hwnd%):"GetDC"


.lib "shell32.dll"
shell32_ExtractIcon%(hInst%,lpszExeFileName$,nIconIndex%):"ExtractIconA"



and an example that open the icon inside the exe then draws it on the window.


; open icon in exe file.
exe_icon = shell32_ExtractIcon(kernel32_GetModuleHandle(0),"test.exe",0)

; create window.
window = CreateWindow("test icon example",200,200,400,300,0,11) 

; get the windows device context
window_hdc = user32_GetDC(QueryObject(window,1))

; draw icon.
user32_DrawIcon window_hdc,100,10,exe_icon

; wait until the user closes one of the windows 
Repeat 
If WaitEvent()=$803 Then Exit 
Forever 

; free icon.
If exe_icon > 0 Then
	user32_DestroyIcon exe_icon
EndIf

End



kev


SebHoll(Posted 2005) [#9]
Cheers, thanks alot. By the way, what is the window device content. Also, when you compile your program, do you have to put any DLL files packaged with it.

Thanks for all your help

Seb

P.S: Will this work with normal icon files aswell? (*.ico)


SebHoll(Posted 2005) [#10]
Hi Again,
I have come accross a bit of a problem still. It draws the icon great (Thanks Kev) but I can't find a way to remove the icon off the screen. If you tell it to draw the icon again in the same place, the icon is drawn over it and you can see the previos icon underneath in the transparent parts. I tried DestroyImage but that just removes the icon from the memory but doesn't remove the icon drawn on the window. Any ideas???

Thanks

Seb

P.S: It works great with ICO files aswell. Thanks again, Kev. You've saved me a lot of late night hours.


Kev(Posted 2005) [#11]
Hi Seb

to remove the icon before redrawing a new one use a panel free it then recreate it. this works example below.


; open icon in exe file.
exe_icon = shell32_ExtractIcon(kernel32_GetModuleHandle(0),"test.exe",0)

; create window.
window = CreateWindow("test icon example",200,200,400,300,0,11) 

panel = CreatePanel(10,10,200,200,window)

; get the panels device context
window_hdc = user32_GetDC(QueryObject(panel ,1))

exe_icon_1 = shell32_ExtractIcon(kernel32_GetModuleHandle(0),"test2.exe",0)

; draw icon.
user32_DrawIcon window_hdc,100,10,exe_icon_1

MouseWait

FreeGadget panel
panel = CreatePanel(10,10,200,200,window)
; get the panels device context
window_hdc = user32_GetDC(QueryObject(panel ,1))

; draw icon.
user32_DrawIcon window_hdc,100,10,exe_icon

; wait until the user closes one of the windows 
Repeat 
If WaitEvent()=$803 Then Exit 
Forever 

; free icon.
If exe_icon > 0 Then
	user32_DestroyIcon exe_icon
EndIf

; free icon.
If exe_icon_1 > 0 Then
	user32_DestroyIcon exe_icon_1
EndIf

End


some information on device contexts found on msdn
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/devcons_0g6r.asp

kev


SebHoll(Posted 2005) [#12]
Thanks Once Again! - Finally though, one other thing. You know the declerations file you supplied, it declares the "ExtractIconA" function whereas on the MSDN it refers to it symply as "ExtractIcon". Is there any difference between these 2 commands and if so what difference is there.

Also, how do you specify a parameter as boolean in a decleration file. (Strings are specified using $, Integer with %, Floating Point with # Boolean ???) E.g. the RealDriveType function requires you to pass the drive number and also a reserved boolean value of 0. This value doesn't change. I have delcared it in the declarations file as:
.lib "shell32.dll"
DriveType%(DriveNumber%,0):"RealDriveType"

But it doesn't work. Blitz+ won't open with this command and it comes up with an error. I tried the following, which works:
.lib "shell32.dll"
DriveType%(DriveNumber%,Reserved%):"RealDriveType"

However, I don't know if I used the right variable type to specify a boolean value. (Are integar and boolean the same.) It just seems a bit pointless having to put a 0 every time the function is called when it's the same every time. Can it be done?

Hope you understand what I mean. More information on this can be found at this MSDN link.

Thanks

Seb


Snarkbait(Posted 2005) [#13]
Well, in case it still might be useful to you, here is a blitz include that will load most icons into an image you can use all the normal blitz image functions on, however it won't extract the icons from .exe files. This routine can also load the mask information from the icon file as an image.

A blitz plus example is included.

;loadICOfile.bb include
;
; for 4-bit,8-bit and 24-bit .ico files
; will load 16x16, 32x32 and 48x48 icon files
;
;
; by snarkbait snarkbait66@...
;



Dim pallette256(255,2)

Type icoinfo
Field bCount,bWidth,bHeight,bColorCount,bReserved,wPlanes,wBitCount,dwBytesInRes,dwImageOffset
End Type 

Global black = argb(0,0,0)
Global white = argb(255,255,255)

Function getICOinfo$(icon$)
	icofile = ReadFile(icon$)
	If Not icofile RuntimeError "file not found"
	; icon header
	idReserved = ReadShort(icofile) ;should be 0
	idType = ReadShort(icofile);should be 1
	If idType <> 1 RuntimeError "Not a valid .ico file"
	idCount = ReadShort(icofile) ; number of icons in file
	info$ = "Icon file has " + idCount + " icons."
	For iconcount = 1 To idCount
		bWidth = ReadByte(icofile)
		bHeight = ReadByte(icofile)
		bColorCount = ReadByte(icofile) ;# entries in pallette table
		bReserved = ReadByte(icofile) ; should be 0
		wPlanes = ReadShort(icofile) ;?
		wBitCount = ReadShort(icofile) ;bpp
		dwBytesInRes = ReadInt(icofile) ;total bytes of image including AND & XOR info
		dwImageOffset = ReadInt(icofile) ; offset to beginning of img data
		index$ = index$ + " Icon#" + iconcount + ":" + bWidth + "x" + bWidth + " - " + wBitCount + " bits per pixel   :"
	Next
	CloseFile icofile
	info$ = info$ + index$
	Return info$
End Function




Function loadICOimage(icon$,icoImageNumber = 1,returnMask = False)
	icofile = ReadFile(icon$)
	If Not icofile RuntimeError "file not found"
	; icon header
	idReserved = ReadShort(icofile) ;should be 0
	idType = ReadShort(icofile);should be 1
	If idType <> 1 RuntimeError "Not a valid .ico file"
	idCount = ReadShort(icofile) ; number of icons in file
	For iconcount = 1 To idCount
		;Icon Dir Entry
		ico.icoinfo = New icoinfo
		ico\bCount = iconcount
		ico\bWidth = ReadByte(icofile)
		ico\bHeight = ReadByte(icofile)
		ico\bColorCount = ReadByte(icofile) ;# entries in pallette table
		ico\bReserved = ReadByte(icofile) ; should be 0
		ico\wPlanes = ReadShort(icofile) ;?
		ico\wBitCount = ReadShort(icofile) ;bpp
		ico\dwBytesInRes = ReadInt(icofile) ;total bytes of image including AND & XOR info
		ico\dwImageOffset = ReadInt(icofile) ; offset to beginning of img data
	Next 
	
	; read image entries 
	For ico.icoinfo = Each icoinfo
		If ico\bCount = icoImageNumber	
			SeekFile(icofile,ico\dwImageOffset)
			biSize = ReadInt(icofile)
			biWidth = ReadInt(icofile)
			biHeight = ReadInt(icofile) ; x 2
			biPlanes = ReadShort(icofile)
			biBitCount = ReadShort(icofile)
			biCompression = ReadInt(icofile)
			biSizeimage = ReadInt(icofile)
			; go to bitmap info
			SeekFile(icofile,ico\dwImageOffset + biSize)
			
			Select biBitCount
			
			Case 4 ; 16-colour pallette
				; read pallette
				For color_value = 0 To 15
					For RGB = 0 To 2
						readval = ReadByte(icofile)
						pallette256(color_value,RGB) = readval 
					Next
					useless = ReadByte(icofile) ;reserved byte
				Next 
				If Not returnMask 
					newimage = CreateImage(biWidth,biHeight/2)
					SetBuffer ImageBuffer(newimage)
					LockBuffer
					For ycount = biHeight/2 To 1 Step -1
						For xcount = 1 To biWidth Step 2
							readval = ReadByte(icofile)
							leftbits = readval Shr 4
							rtbits = readval And $f
							WritePixelFast xcount - 1,ycount - 1,argb(pallette256(leftbits,2),pallette256(leftbits,1),pallette256(leftbits,0))
							WritePixelFast xcount,ycount - 1,argb(pallette256(rtbits,2),pallette256(rtbits,1),pallette256(rtbits,0))
						Next
					Next				
					UnlockBuffer 
				Else
					SeekFile(icofile,ico\dwImageOffset + biSize + (2^biBitCount * 4) + (biWidth ^ 2/2))
					newimage = CreateImage(biWidth,biHeight/2)
					SetBuffer ImageBuffer(newimage)
					LockBuffer
					If biWidth = 32
						For ycount = biHeight/2 To 1 Step -1
							For xcount = 0 To 3
								readval = ReadByte(icofile)
								xpos = 0
								For bits = 8 To 1 Step -1
									readbit = (readval And (2^bits - 1)) Shr (bits - 1)
									If readbit
										WritePixelFast (xcount * 8) + xpos,ycount - 1,white
									Else
										WritePixelFast (xcount * 8) + xpos,ycount - 1,black
									EndIf
									xpos = xpos + 1
								Next
							Next
						Next
					Else
						If biWidth = 16
							For ycount = biHeight/2 To 1 Step -1
								For xcount = 0 To 1
									readval = ReadByte(icofile)
									xpos = 0
									For bits = 8 To 1 Step -1
										readbit = (readval And (2^bits - 1)) Shr (bits - 1)
										If readbit
											WritePixelFast (xcount * 8) + xpos,ycount - 1,white
										Else
											WritePixelFast (xcount * 8) + xpos,ycount - 1,black
										EndIf
										xpos = xpos + 1
									Next
								Next
								skip = ReadShort(icofile)
							Next
						Else
							If biWidth = 48
								For ycount = biHeight/2 To 1 Step -1
									For xcount = 0 To 5
										readval = ReadByte(icofile)
										xpos = 0
										For bits = 8 To 1 Step -1
											readbit = (readval And (2^bits - 1)) Shr (bits - 1)
											If readbit
												WritePixelFast (xcount * 8) + xpos,ycount - 1,white
											Else
												WritePixelFast (xcount * 8) + xpos,ycount - 1,black
											EndIf
											xpos = xpos + 1
										Next
									Next
									skip = ReadShort(icofile)
								Next
							EndIf
						EndIf 
					EndIf
					UnlockBuffer
				EndIf 
				CloseFile icofile
				Return newimage
				
			Case 8
				;read pallette
				For color_value = 0 To 255
					For RGB = 0 To 2
						readval = ReadByte(icofile)
						pallette256(color_value,RGB) = readval 
					Next
					useless = ReadByte(icofile) ;reserved byte
				Next 
				
				;draw image
				If Not returnMask 
					newimage = CreateImage(biWidth,biHeight/2)
					SetBuffer ImageBuffer(newimage)
					LockBuffer
					For ycount = biHeight/2 To 1 Step -1
						For xcount = 1 To biWidth
							readval = ReadByte(icofile)
							WritePixelFast xcount - 1,ycount - 1,argb(pallette256(readval,2),pallette256(readval,1),pallette256(readval,0))
						Next
					Next				
					UnlockBuffer 
				;read AND mask
				Else
					SeekFile(icofile,ico\dwImageOffset + biSize + (2^biBitCount * 4) + (biWidth ^ 2))
					newimage = CreateImage(biWidth,biHeight/2)
					SetBuffer ImageBuffer(newimage)
					LockBuffer
					If biWidth = 32
						For ycount = biHeight/2 To 1 Step -1
							For xcount = 0 To 3
								readval = ReadByte(icofile)
								xpos = 0
								For bits = 8 To 1 Step -1
									readbit = (readval And (2^bits - 1)) Shr (bits - 1)
									If readbit
										WritePixelFast (xcount * 8) + xpos,ycount - 1,white
									Else
										WritePixelFast (xcount * 8) + xpos,ycount - 1,black
									EndIf
									xpos = xpos + 1
								Next
							Next
						Next
					Else
						If biWidth = 16
							For ycount = biHeight/2 To 1 Step -1
								For xcount = 0 To 1
									readval = ReadByte(icofile)
									xpos = 0
									For bits = 8 To 1 Step -1
										readbit = (readval And (2^bits - 1)) Shr (bits - 1)
										If readbit
											WritePixelFast (xcount * 8) + xpos,ycount - 1,white
										Else
											WritePixelFast (xcount * 8) + xpos,ycount - 1,black
										EndIf
										xpos = xpos + 1
									Next
								Next
								skip = ReadShort(icofile)
							Next
						Else
							If biWidth = 48
								For ycount = biHeight/2 To 1 Step -1
									For xcount = 0 To 5
										readval = ReadByte(icofile)
										xpos = 0
										For bits = 8 To 1 Step -1
											readbit = (readval And (2^bits - 1)) Shr (bits - 1)
											If readbit
												WritePixelFast (xcount * 8) + xpos,ycount - 1,white
											Else
												WritePixelFast (xcount * 8) + xpos,ycount - 1,black
											EndIf
											xpos = xpos + 1
										Next
									Next
									skip = ReadShort(icofile)
								Next
							EndIf
						EndIf 
					EndIf
					UnlockBuffer
				EndIf 
				CloseFile icofile
				Return newimage
	
			Case 24
				If Not returnmask
					newimage = CreateImage(biWidth,biHeight/2)
					SetBuffer ImageBuffer(newimage)
					LockBuffer
					For ycount = biHeight/2 To 1 Step -1
						For xcount = 1 To biWidth
							readblue = ReadByte(icofile)
							readgreen = ReadByte(icofile)
							readred = ReadByte(icofile)
							WritePixelFast xcount - 1,ycount - 1,argb(readred,readgreen,readblue)
						Next
					Next				
					UnlockBuffer 
				Else
					SeekFile(icofile,ico\dwImageOffset + biSize + (biWidth ^ 2 * 3))
					newimage = CreateImage(biWidth,biHeight/2)
					SetBuffer ImageBuffer(newimage)
					LockBuffer
					If biWidth = 32
						For ycount = biHeight/2 To 1 Step -1
							For xcount = 0 To 3
								readval = ReadByte(icofile)
								xpos = 0
								For bits = 8 To 1 Step -1
									readbit = (readval And (2^bits - 1)) Shr (bits - 1)
									If readbit
										WritePixelFast (xcount * 8) + xpos,ycount - 1,white
									Else
										WritePixelFast (xcount * 8) + xpos,ycount - 1,black
									EndIf
									xpos = xpos + 1
								Next
							Next
						Next
					Else
						If biWidth = 16
							For ycount = biHeight/2 To 1 Step -1
								For xcount = 0 To 1
									readval = ReadByte(icofile)
									xpos = 0
									For bits = 8 To 1 Step -1
										readbit = (readval And (2^bits - 1)) Shr (bits - 1)
										If readbit
											WritePixelFast (xcount * 8) + xpos,ycount - 1,white
										Else
											WritePixelFast (xcount * 8) + xpos,ycount - 1,black
										EndIf
										xpos = xpos + 1
									Next
								Next
								skip = ReadShort(icofile)
							Next
						Else
							If biWidth = 48
								For ycount = biHeight/2 To 1 Step -1
									For xcount = 0 To 5
										readval = ReadByte(icofile)
										xpos = 0
										For bits = 8 To 1 Step -1
											readbit = (readval And (2^bits - 1)) Shr (bits - 1)
											If readbit
												WritePixelFast (xcount * 8) + xpos,ycount - 1,white
											Else
												WritePixelFast (xcount * 8) + xpos,ycount - 1,black
											EndIf
											xpos = xpos + 1
										Next
									Next
									skip = ReadShort(icofile)
								Next
							EndIf
						EndIf 
							 
					EndIf
						 
					UnlockBuffer
				EndIf
				CloseFile icofile
				Return newimage
				
			End Select
		EndIf 
	Next 
End Function

Function argb(red,green,blue)
	Return (blue Or (green Shl 8) Or (red Shl 16) Or ($ff Shl 24))
End Function 


sample file (blitz plus)
Include "loadicofile.bb"

Global main = CreateWindow("ICO Loader",0,0,800,600,0,9)

this$ = RequestFile$("Open ICO Image","ico")

SetStatusText main,getICOinfo$(this$)

starttime# = MilliSecs()
convertedimage = loadicoimage(this$,1,False)
MidHandle convertedimage

;ScaleImage convertedimage,5,5
endtime# = MilliSecs() - starttime

canvas = CreateCanvas(100,100,200,200,main)
canvas2 = CreateCanvas(400,100,200,200,main)



SetBuffer CanvasBuffer(canvas)
ClsColor 128,128,128
Cls 

DrawBlock convertedimage,100,100
Text 0,0,"Time to load:" + endtime + " msecs"
FlipCanvas canvas

imagemask = loadicoimage(this$,1,True)
MidHandle imagemask
;ScaleImage imagemask,5,5
SetBuffer CanvasBuffer(canvas2)
ClsColor 128,128,128
Cls 

DrawBlock imagemask,100,100
Text 0,0,"Time to load:" + endtime + " msecs"
FlipCanvas canvas2

WaitKey()
End 




Kev(Posted 2005) [#14]
Seb

for example the declared function "ExtractIcon" is found within c header files. "ExtractIconA" or "ExtractIconEx" both these function calls can be found in "shell32.dll" the latter function enables extra params when making the call. in the blitz .decs we declare the function call.

i dont think boolean values are supported i use ('integar' %) for them.

Download ApiViewer for a good list of available api calls and what .dll these can be found in.

http://www.activevb.de/rubriken/apiviewer/index-apiviewereng.html

kev


SebHoll(Posted 2005) [#15]
Thanks for all your help. (Kev & Snarkbait). My program is running fine. Found a bug that I managed to fix myself (shock, shock, horror, horror). When you draw the image using Kev's method onto the window, then minimize the window, when the window is restored, the icon disappears. I got around this by including the AppResume event in the program loop, which when it is triggered, redraws the image(s) on the screen.

Snarkbait - I tried to follow your code through and succeeded mostly. - LOL. (I've made a Blitz Compression utility so my Bytes/Shorts/Integer stuff seems to be up to scratch). However, where did you manage to find the file structure of the ICON file. I used Wotsit's Format but it didn't have much stuff on it. Do you know of any other good websites?

Thanks for all your help

Seb

P.S: Thanks for telling me about that ApiViewer, it will come in very handy. :-)


Snarkbait(Posted 2005) [#16]
I used here:

http://www.awitness.org/delphi_pascal_tutorial/source2/icon_file_format.html

and here:
http://www.daubnet.com/formats/ICO.html

Nobody had info on the 24-bit icon (i was testing with the GLET one) so I figured that one out on my own.

Any part of my code you didn't get, let me know and I'll explain it... I didn't comment it enough lol.


Snarkbait(Posted 2005) [#17]
Seb: I put a better commented version in the code archives here:
http://www.blitzbasic.com/codearcs/codearcs.php?code=1358


Kev(Posted 2005) [#18]
hi seb,

ive uploaded this little file error.exe this returns information on errors returned by kernel32.dll GetLastError() this will help when debugging any api calls you make.

http://members.aol.com/kev12340poole/error.exe

kev