Transparent .png images

Just starting out? Need help? Post your questions and find answers here.
MikeB
Enthusiast
Enthusiast
Posts: 183
Joined: Sun Apr 27, 2003 8:39 pm
Location: Cornwall UK

Transparent .png images

Post by MikeB »

I have a piece of code that I have cobbled together from bits on the forum that shows images with a transparent background that I have used as backround pictures (fancy icons really) to run odds and ends. It may not be great programming and I don't fully understand it but it works!

Code: Select all

;
;  Saved as Garfield StarterPicture.exe
;
Define.l MonitorX, MonitorY
Define.s MyFile$ = "C:\Users\Whatever"
If ReadFile(1, MyFile$)
	MonitorX = ReadLong(1)
	MonitorY = ReadLong(1)
	CloseFile(1)
Else
	MonitorX = 1280
	MonitorY = 948
EndIf
UsePNGImageDecoder()
Procedure.l Exist(File$)                 ;- Check a drive + file exists, without system requesters etc. 
	Protected EFlag.l, OldErrorMode.l, Junk.l 
	OldErrorMode = SetErrorMode_(1)   ; Turn off screen error messages 
	If GetFileAttributes_(@File$)=-1  ; Get file butes.  -1 = fail 
		Junk.l=GetLastError_()          ; Get last error, to flush system 
		SetLastError_(0)                ; Set error to zero 
		EFlag.l = 0                     ; Return value to flag FAIL 
	Else 
		EFlag.l = 1                    ; Return value to flag a PASS 
	EndIf 
	SetErrorMode_(OldErrorMode)       ; Reset the error flags 
	ProcedureReturn EFlag 
EndProcedure 
;
Procedure Error(message.s, fatal.b)
	ErrorBuffer$ = Space(256)
	FormatMessage_(#FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError_(), 0, ErrorBuffer$, Len(ErrorBuffer$), 0)
	MessageRequester("Error", message+Chr(10)+Chr(10)+ErrorBuffer$, 0)
	If fatal
		End
	EndIf
EndProcedure
Global MDIFrame, MDIClient, hChild, hStatus, hToolBar, hMainMenu, hChildMenu, ActiveMDIChild
Global xPos, yPos, WindowWidth, WindowHeight, ChildNumber, ExtraWidth, ExtraHeight
Global hInstance
Global wc.WNDCLASSEX
Global ClassName$
Structure GdiplusStartupInput
	GdiplusVersion.l
	DebugEventCallback.l
	SuppressBackgroundThread.l
	SuppressExternalCodecs.l
EndStructure
Structure bsize
	width.l
	height.l
EndStructure
Structure bpoint
	x.l
	y.l
EndStructure
Structure ARGB
	blue.b
	green.b
	red.b
	alpha.b
EndStructure
Structure ImageItemInfo
	Clsid.CLSID         ; Codec identifier.
	FormatID.GUID       ; File format identifier. GUIDs that identify various file formats (ImageFormatBMP, ImageFormatEMF, And the like) are defined in Gdiplusimaging.h.
	CodecName.s         ; WCHAR * Pointer To a null-terminated string that contains the codec name.
	DllName.s           ; WCHAR * Pointer To a null-terminated string that contains the path name of the DLL in which the codec resides. If the codec is not in a DLL, this pointer is NULL.
	FormatDescription.s ; WCHAR * Pointer To a null-terminated string that contains the name of the file format used by the codec.
	FilenameExtension.s ; WCHAR * Pointer To a null-terminated string that contains all file-name extensions associated with the codec. The extensions are separated by semicolons.
	MimeType.s          ; WCHAR * Pointer To a null-terminated string that contains the mime type of the codec.
	Flags.l             ; DWORD  Combination of flags from the ImageCodecFlags enumeration.
	Version.l           ; DWORD  Integer that indicates the version of the codec.
	SigCount.l          ; DWORD  Integer that indicates the number of signatures used by the file format associated with the codec.
	SigSize.l           ; DWORD  Integer that indicates the number of bytes in each signature.
	SigPattern.l        ; BYTE * Pointer To an array of bytes that contains the pattern For each signature.
	SigMask.l           ; BYTE * Pointer To an array of bytes that contains the mask For each signature.
EndStructure
Global Gdiplus, gdiplusToken, bitmap, hbmReturn, encoderClsid
Global *GdiplusStartup, *GdipCreateBitmapFromFile, *GdipCreateHBITMAPFromBitmap, *GdipGetImageHeight, *GdipGetImageWidth, *GdiplusShutdown, *GdipSaveImageToFile, *GdipGetImageEncodersSize, *GdipGetImageEncoders, *GdipCreateBitmapFromHBITMAP
Procedure OpenImageFile(File$)
	result = 0
	If Gdiplus
		FileWSize = (Len(File$)*2)+2
		*FileW = CoTaskMemAlloc_(FileWSize)
		If *FileW
			If MultiByteToWideChar_(#CP_ACP, 0, File$, -1, *FileW, FileWSize)
				bitmap.l = 0
				CallFunctionFast(*GdipCreateBitmapFromFile, *FileW, @bitmap)
				If bitmap
					hbmReturn.l = 0
					CallFunctionFast(*GdipCreateHBITMAPFromBitmap, bitmap, @hbmReturn, 0)
				Else
					Error("GdipCreateBitmapFromFile() failed."+Chr(10)+File$+" is not a valid image file.", 0)
				EndIf
			EndIf
		Else
			SetLastError_(#ERROR_NOT_ENOUGH_MEMORY)
		EndIf
		CoTaskMemFree_(*FileW)
	EndIf
	ProcedureReturn hbmReturn
EndProcedure
CoInitialize_(#Null)
Gdiplus = OpenLibrary(0, "GDIPLUS.DLL")
If Gdiplus
	*GdiplusStartup = GetFunction(0, "GdiplusStartup")
	If *GdiplusStartup
		gdpsi.GdiplusStartupInput
		gdpsi\GdiplusVersion = 1
		gdpsi\DebugEventCallback = 0
		gdpsi\SuppressBackgroundThread = 0
		gdpsi\SuppressExternalCodecs = 0
		CallFunctionFast(*GdiplusStartup, @gdiplusToken, gdpsi, #Null)
		If gdiplusToken
			*GdipCreateBitmapFromFile = GetFunction(0, "GdipCreateBitmapFromFile")
			*GdipCreateHBITMAPFromBitmap = GetFunction(0, "GdipCreateHBITMAPFromBitmap")
			*GdipGetImageWidth = GetFunction(0, "GdipGetImageWidth")
			*GdipGetImageHeight = GetFunction(0, "GdipGetImageHeight")
			*GdipGetImageEncodersSize = GetFunction(0, "GdipGetImageEncodersSize")
			*GdipGetImageEncoders = GetFunction(0, "GdipGetImageEncoders")
			*GdipCreateBitmapFromHBITMAP = GetFunction(0, "GdipCreateBitmapFromHBITMAP")
			*GdipSaveImageToFile = GetFunction(0, "GdipSaveImageToFile")
			*GdiplusShutdown = GetFunction(0, "GdiplusShutdown")
		Else
			Gdiplus = 0
		EndIf
	Else
		Gdiplus = 0
	EndIf
Else
	Gdiplus = 0
EndIf
File$ = "C:\Users\Something.png"
LoadImage(1, File$)
Myimwid = ImageWidth(1)
Myimht = ImageHeight(1)
FreeImage(1)
bitmap1 = OpenImageFile(File$)
hwnd=OpenWindow(0, MonitorX, MonitorY, Myimwid, Myimht, "Monitor Offulator", #PB_Window_BorderLess|#PB_Window_Invisible)
SetWindowLong_(hwnd,#GWL_EXSTYLE,#WS_EX_TOOLWINDOW)  ; this bit stops the window appearing on the toolbar if called before the window is visible
ShowWindow_(WindowID(0),#SW_SHOW)  ; make the window visible and it will / won't be on the toolbar depending on OnTopFlag
SetWindowLong_(WindowID(0), #GWL_EXSTYLE, GetWindowLong_(WindowID(0),#GWL_EXSTYLE)|$00080000)
AddKeyboardShortcut(0, #PB_Shortcut_Escape, 1)
If CreatePopupMenu(1)
	;  whatever
EndIf
width1.l=0
screenDc=GetDC_(#Null)
memDc=CreateCompatibleDC_(screenDc)
oldbitmap=SelectObject_(memDc, bitmap1)
GetObject_(bitmap1,SizeOf(BITMAP),bmInfo.BITMAP)
bitmapsize.bsize
bitmapsize\width=bmInfo\bmWidth
bitmapsize\height=bmInfo\bmHeight
pointsource.bpoint
pointsource\x=0
pointsource\y=0
ExamineDesktops()
topPos.bpoint   ;  this is where the image appears on the screen
topPos\x= MonitorX
topPos\y= MonitorY
BlendFunc.blendfunction
BlendFunc\blendop=0
BlendFunc\blendflags=0
BlendFunc\sourceconstantalpha=255
BlendFunc\alphaformat=1
UpdateLayeredWindow_(WindowID(0), screenDc, topPos, bitmapsize, memDc, pointsource, 0, BlendFunc, 2)
ReleaseDC_(#Null,screenDc)
SelectObject_(memDc,oldbitmap)
DeleteObject_(hbitmap)
DeleteDC_(memDc)
SetWindowPos_(WindowID(0),#HWND_BOTTOM,0,0,0,0,#SWP_NOMOVE|#SWP_NOSIZE)
;
Repeat
	Select WaitWindowEvent()
	Case #WM_LBUTTONDOWN
		ReleaseCapture_()
		SendMessage_(WindowID(0), #WM_NCLBUTTONDOWN, #HTCAPTION, 0)
		SetWindowPos_(WindowID(0),#HWND_BOTTOM,0,0,0,0,#SWP_NOMOVE|#SWP_NOSIZE)
	Case #WM_RBUTTONDOWN       ; right mouse button was clicked =>
		DisplayPopupMenu(1, WindowID(0))  ; now display the popup-menu
		SetWindowPos_(WindowID(0),#HWND_BOTTOM,0,0,0,0,#SWP_NOMOVE|#SWP_NOSIZE)
	Case #PB_Event_Menu        ; an item of the popup-menu was clicked
		Select EventMenu()     
			; do whatever
		EndSelect
	EndSelect
ForEver
;
;
The question is - Is there a way of making a suitable modification to this or is there a better way to show a series of same sized images to make a simple animation?

Obviously the requirements are using a borderless window that stays behind all other windows, that can be moved, has a transparent background, utilises a menu and does not suck up too much CPU time. Or to put it another way exactly what I have but allowing changing the image every few seconds, I'm not after 30fps !

P.S. the bit at the start MonitorX & MonitorY is because one of the menu items is to save the screen position. Another being to close the prog if required as well as the bits it is actually designed for.
Mike.
(I'm never going to catch up with the improvements to this program)
MikeB
Enthusiast
Enthusiast
Posts: 183
Joined: Sun Apr 27, 2003 8:39 pm
Location: Cornwall UK

Post by MikeB »

I think I have found the answer to my own question.

Code: Select all

;
UsePNGImageDecoder()
Global Dim	File$(13)
Global Dim bitmap.l(13)
;
Procedure Error(message.s, fatal.b)
	ErrorBuffer$ = Space(256)
	FormatMessage_(#FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError_(), 0, ErrorBuffer$, Len(ErrorBuffer$), 0)
	MessageRequester("Error", message+Chr(10)+Chr(10)+ErrorBuffer$, 0)
	If fatal
		End
	EndIf
EndProcedure
Global MDIFrame, MDIClient, hChild, hStatus, hToolBar, hMainMenu, hChildMenu, ActiveMDIChild
Global xPos, yPos, WindowWidth, WindowHeight, ChildNumber, ExtraWidth, ExtraHeight
Global hInstance
Global wc.WNDCLASSEX
Global ClassName$
Structure GdiplusStartupInput
	GdiplusVersion.l
	DebugEventCallback.l
	SuppressBackgroundThread.l
	SuppressExternalCodecs.l
EndStructure
Structure bsize
	width.l
	height.l
EndStructure
Structure bpoint
	x.l
	y.l
EndStructure
Structure ARGB
	blue.b
	green.b
	red.b
	alpha.b
EndStructure
Structure ImageItemInfo
	Clsid.CLSID         ; Codec identifier.
	FormatID.GUID       ; File format identifier. GUIDs that identify various file formats (ImageFormatBMP, ImageFormatEMF, And the like) are defined in Gdiplusimaging.h.
	CodecName.s         ; WCHAR * Pointer To a null-terminated string that contains the codec name.
	DllName.s           ; WCHAR * Pointer To a null-terminated string that contains the path name of the DLL in which the codec resides. If the codec is not in a DLL, this pointer is NULL.
	FormatDescription.s ; WCHAR * Pointer To a null-terminated string that contains the name of the file format used by the codec.
	FilenameExtension.s ; WCHAR * Pointer To a null-terminated string that contains all file-name extensions associated with the codec. The extensions are separated by semicolons.
	MimeType.s          ; WCHAR * Pointer To a null-terminated string that contains the mime type of the codec.
	Flags.l             ; DWORD  Combination of flags from the ImageCodecFlags enumeration.
	Version.l           ; DWORD  Integer that indicates the version of the codec.
	SigCount.l          ; DWORD  Integer that indicates the number of signatures used by the file format associated with the codec.
	SigSize.l           ; DWORD  Integer that indicates the number of bytes in each signature.
	SigPattern.l        ; BYTE * Pointer To an array of bytes that contains the pattern For each signature.
	SigMask.l           ; BYTE * Pointer To an array of bytes that contains the mask For each signature.
EndStructure
Global Gdiplus, gdiplusToken, bitmap, hbmReturn, encoderClsid
Global *GdiplusStartup, *GdipCreateBitmapFromFile, *GdipCreateHBITMAPFromBitmap, *GdipGetImageHeight, *GdipGetImageWidth, *GdiplusShutdown, *GdipSaveImageToFile, *GdipGetImageEncodersSize, *GdipGetImageEncoders, *GdipCreateBitmapFromHBITMAP
Procedure OpenImageFile(File$)
	result = 0
	If Gdiplus
		FileWSize = (Len(File$)*2)+2
		*FileW = CoTaskMemAlloc_(FileWSize)
		If *FileW
			If MultiByteToWideChar_(#CP_ACP, 0, File$, -1, *FileW, FileWSize)
				bitmap.l = 0
				CallFunctionFast(*GdipCreateBitmapFromFile, *FileW, @bitmap)
				If bitmap
					hbmReturn.l = 0
					CallFunctionFast(*GdipCreateHBITMAPFromBitmap, bitmap, @hbmReturn, 0)
				Else
					Error("GdipCreateBitmapFromFile() failed."+Chr(10)+File$+" is not a valid image file.", 0)
				EndIf
			EndIf
		Else
			SetLastError_(#ERROR_NOT_ENOUGH_MEMORY)
		EndIf
		CoTaskMemFree_(*FileW)
	EndIf
	ProcedureReturn hbmReturn
EndProcedure
;
Procedure WibbleImage()
	Repeat
		k = Random(12)+1
		MyDelay = Random(1500) + 500
		Delay(MyDelay)
		screenDc=GetDC_(#Null)
		memDc=CreateCompatibleDC_(screenDc)
		oldbitmap=SelectObject_(memDc, bitmap(k))
		GetObject_(bitmap(k),SizeOf(BITMAP),bmInfo.BITMAP)
		bitmapsize.bsize
		bitmapsize\width=bmInfo\bmWidth
		bitmapsize\height=bmInfo\bmHeight
		pointsource.bpoint
		pointsource\x=0
		pointsource\y=0
		BlendFunc.blendfunction
		BlendFunc\blendop=0
		BlendFunc\blendflags=0
		BlendFunc\sourceconstantalpha=255
		BlendFunc\alphaformat=1
		UpdateLayeredWindow_(WindowID(0), screenDc, topPos, bitmapsize, memDc, pointsource, 0, BlendFunc, 2)
		ReleaseDC_(#Null,screenDc)
		SelectObject_(memDc,oldbitmap)
		DeleteObject_(hbitmap)
		DeleteDC_(memDc)
	ForEver
EndProcedure
;
CoInitialize_(#Null)
Gdiplus = OpenLibrary(0, "GDIPLUS.DLL")
If Gdiplus
	*GdiplusStartup = GetFunction(0, "GdiplusStartup")
	If *GdiplusStartup
		gdpsi.GdiplusStartupInput
		gdpsi\GdiplusVersion = 1
		gdpsi\DebugEventCallback = 0
		gdpsi\SuppressBackgroundThread = 0
		gdpsi\SuppressExternalCodecs = 0
		CallFunctionFast(*GdiplusStartup, @gdiplusToken, gdpsi, #Null)
		If gdiplusToken
			*GdipCreateBitmapFromFile = GetFunction(0, "GdipCreateBitmapFromFile")
			*GdipCreateHBITMAPFromBitmap = GetFunction(0, "GdipCreateHBITMAPFromBitmap")
			*GdipGetImageWidth = GetFunction(0, "GdipGetImageWidth")
			*GdipGetImageHeight = GetFunction(0, "GdipGetImageHeight")
			*GdipGetImageEncodersSize = GetFunction(0, "GdipGetImageEncodersSize")
			*GdipGetImageEncoders = GetFunction(0, "GdipGetImageEncoders")
			*GdipCreateBitmapFromHBITMAP = GetFunction(0, "GdipCreateBitmapFromHBITMAP")
			*GdipSaveImageToFile = GetFunction(0, "GdipSaveImageToFile")
			*GdiplusShutdown = GetFunction(0, "GdiplusShutdown")
		Else
			Gdiplus = 0
		EndIf
	Else
		Gdiplus = 0
	EndIf
Else
	Gdiplus = 0
EndIf
;
;
For k = 1 To 13
	File$(k) = "C:\Users\Whatever\"+Str(k)+".png"
	;Debug File$(k)
Next
LoadImage(1, File$(1))
Myimwid = ImageWidth(1)
Myimht = ImageHeight(1)
FreeImage(1)
For k = 1 To 13
	bitmap(k) = OpenImageFile(File$(k))
	;Debug bitmap(k)
Next
hwnd=OpenWindow(0,400,400,Myimwid, Myimht,"alpha",#PB_Window_BorderLess)
StickyWindow(0, 1)
SetWindowLong_(WindowID(0),#GWL_EXSTYLE,GetWindowLong_(WindowID(0),#GWL_EXSTYLE)|$00080000)
AddKeyboardShortcut(0, #PB_Shortcut_Escape, 1)
width1.l=0
screenDc=GetDC_(#Null)
memDc=CreateCompatibleDC_(screenDc)
oldbitmap=SelectObject_(memDc, bitmap(1))
GetObject_(bitmap(1),SizeOf(BITMAP),bmInfo.BITMAP)
bitmapsize.bsize
bitmapsize\width=bmInfo\bmWidth
bitmapsize\height=bmInfo\bmHeight
pointsource.bpoint
pointsource\x=0
pointsource\y=0
ExamineDesktops()
topPos.bpoint   ;  this is where the image appears on the screen
topPos\x= (DesktopWidth(0)-Myimwid)/2
topPos\y= (DesktopHeight(0)-Myimht)/2
BlendFunc.blendfunction
BlendFunc\blendop=0
BlendFunc\blendflags=0
BlendFunc\sourceconstantalpha=255
BlendFunc\alphaformat=1
UpdateLayeredWindow_(WindowID(0), screenDc, topPos, bitmapsize, memDc, pointsource, 0, BlendFunc, 2)
ReleaseDC_(#Null,screenDc)
SelectObject_(memDc,oldbitmap)
DeleteObject_(hbitmap)
DeleteDC_(memDc)
;Debug "#1"
;
;
CreateThread(@WibbleImage(), 1)
;
;
;
Repeat
	ev=WaitWindowEvent()
	If ev=#WM_LBUTTONDOWN
		ReleaseCapture_()
		SendMessage_(WindowID(0), #WM_NCLBUTTONDOWN, #HTCAPTION, 0)
	EndIf
Until ev= #PB_Event_Menu
This appears to work although it is obviously not finished as it is also supposed to do something from a menu and save the screen position etc., but it looks as though it is a success.

My worry was that it might start eating memory but it appears to be OK, if anyone spots a problem I will be greatful to hear about it.
Mike.
(I'm never going to catch up with the improvements to this program)
eJan
Enthusiast
Enthusiast
Posts: 366
Joined: Sun May 21, 2006 11:22 pm
Location: Sankt Veit am Flaum

Post by eJan »

MikeB
Enthusiast
Enthusiast
Posts: 183
Joined: Sun Apr 27, 2003 8:39 pm
Location: Cornwall UK

Post by MikeB »

eJan wrote:Here's shorter one by netmaestro:
http://www.purebasic.fr/english/viewtop ... 814#211814
Thanks for that, it is rather shorter but it leaves me with the problem of animating it and by the time I have sorted out how to get it working for an animation it probably will be nearly as long!

The one I have seems to work OK and can easily be modified for different numbers of frames and whatever I want on the menu. So being too lazy to start over again I think I will leave my animated Garfield as he is. After all it's just a bit of decoration really, the added menu is just a convenience.
Mike.
(I'm never going to catch up with the improvements to this program)
Post Reply