Skin window with PNG (Alpha channel support)

Share your advanced PureBasic knowledge/code with the community.
User avatar
Le Soldat Inconnu
Enthusiast
Enthusiast
Posts: 306
Joined: Wed Jul 09, 2003 11:33 am
Location: France

Skin window with PNG (Alpha channel support)

Post by Le Soldat Inconnu »

Hi,

A way to skin window with PNG and alpha channel support 8)

PB4.40 minimum require, you can try with 4.30 but I'm not sure

So, code is based on API "UpdateLayeredWindow" but not only.
Because Microsoft don't really know how to blend to color with transparency :shock:
So i add system to translate image to have the good display of image with alpha channel :D

it's do this finally :
Image
Window is green button, clean border, shadow, ... like if you draw PNG on another image with Photoshop :wink:

If some people can test this on 2000, XP, Vista, 7, thanks

Code: Select all

UsePNGImageDecoder()

Procedure SetLayeredWindow2(WindowID) ; Mettre l'attribut WS_EX_LAYERED à la fenêtre
	SetWindowLong_(WindowID, #GWL_EXSTYLE, GetWindowLong_(WindowID, #GWL_EXSTYLE) | #WS_EX_LAYERED) ; Mettre l'attribut WS_EX_LAYERED à la fenêtre
EndProcedure
Procedure AlphaImageWindow2(WindowID, ImageID, Alpha) ; Mettre une image PNG comme fond d'une fenêtre
  Protected Image_HDC, Image_Bitmap.BITMAP, Image_BitmapInfo.BITMAPINFO, ContextOffset.POINT, Blend.BLENDFUNCTION
	Protected xx, yy, x, y, Rouge, Vert, Bleu, AlphaChannel
	
	; Précalcul
	Protected Dim Echelle.f($FF)
	For x = 0 To $FF
		Echelle(x) = x / $FF
	Next
	
	; Chargement du HDC
	Image_HDC = CreateCompatibleDC_(#NULL)
  Image_Ancienne = SelectObject_(Image_HDC, ImageID)
	
	; Dimension de l'image
	GetObject_(ImageID, SizeOf(BITMAP), @Image_Bitmap)
	Image_BitmapInfo\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
	Image_BitmapInfo\bmiHeader\biWidth = Image_Bitmap\bmWidth
	Image_BitmapInfo\bmiHeader\biHeight = Image_Bitmap\bmHeight
	Image_BitmapInfo\bmiHeader\biPlanes = 1
	Image_BitmapInfo\bmiHeader\biBitCount = 32
	
	; Zone mémoire pour copier l'image
	xx = Image_Bitmap\bmWidth - 1
	yy = Image_Bitmap\bmHeight - 1
	Protected Dim Image.l(xx, yy)
	
	; Copie de l'image en mémoire
	GetDIBits_(Image_HDC, ImageID, 0, Image_Bitmap\bmHeight, @Image(), @Image_BitmapInfo, #DIB_RGB_COLORS)
	
	; Modification de l'image en mémoire
	For x = 0 To xx
		For y = 0 To yy
			Couleur = Image(x, y)
			AlphaChannel = Couleur >> 24 & $FF
			If AlphaChannel < $FF
				Rouge = (Couleur & $FF) * Echelle(AlphaChannel)
				Vert = (Couleur >> 8 & $FF) * Echelle(AlphaChannel)
				Bleu = (Couleur >> 16 & $FF) * Echelle(AlphaChannel)
				Image(x, y) = Rouge | Vert << 8 | Bleu << 16 | AlphaChannel << 24
			EndIf
		Next
	Next
	
	; Transfert de la mémoire dans la l'image de base
	SetDIBits_(Image_HDC, ImageID, 0, Image_Bitmap\bmHeight, @Image(), @Image_BitmapInfo, #DIB_RGB_COLORS)
	
	; L'image est mise en skin de la fenêtre
	Blend\SourceConstantAlpha = Alpha ; niveau de transparence
	Blend\AlphaFormat = 1 ; Support de la couche alpha
	Blend\BlendOp = 0
	Blend\BlendFlags = 0
	UpdateLayeredWindow_(WindowID, 0, 0, @Image_BitmapInfo + 4, Image_HDC, @ContextOffset, 0, @Blend, 2)
	
	; Fermeture du HDC
	SelectObject_(Image_HDC, Image_Ancienne)
	DeleteDC_(Image_HDC)
  
EndProcedure

Fichier.s = OpenFileRequester("Image", "", "PNG|*.png", 1)
If Fichier
  If LoadImage(0, Fichier)
		
		If OpenWindow(0, 0, 0, ImageWidth(0), ImageHeight(0), "Test", #PB_Window_BorderLess | #PB_Window_ScreenCentered | #PB_Window_Invisible)
			
			SetLayeredWindow2(WindowID(0))
			AlphaImageWindow2(WindowID(0), ImageID(0), 200)
			
			StickyWindow(0, 1)
			HideWindow(0, 0)
			
			Repeat
				Event = WaitWindowEvent()
				
				If Event = #WM_LBUTTONDOWN
					SendMessage_(WindowID(0), #WM_NCLBUTTONDOWN, #HTCAPTION, 0)
				EndIf
				
			Until Event = #PB_Event_CloseWindow
			
		EndIf
		
	EndIf
EndIf
LSI
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: Skin window with PNG (Alpha channel support)

Post by rsts »

Nice. Works fine on win 7 64 bit via PB 4.3 32 bit.

Thanks for sharing :)
User avatar
luis
Addict
Addict
Posts: 3895
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Skin window with PNG (Alpha channel support)

Post by luis »

Works on Windows XP SP3 with PB 4.31 x86.

Thanks :)
"Have you tried turning it off and on again ?"
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Skin window with PNG (Alpha channel support)

Post by netmaestro »

Looks nice, just bear in mind that you can't host gadgets on such a window. UpdateLayeredWindow won't support it.
BERESHEIT
User avatar
Le Soldat Inconnu
Enthusiast
Enthusiast
Posts: 306
Joined: Wed Jul 09, 2003 11:33 am
Location: France

Re: Skin window with PNG (Alpha channel support)

Post by Le Soldat Inconnu »

Yes, but if you draw your image with button and everythinks. you have window totally skined. After, you look where you click to run action :wink:

It's like this i use to do something like Dock
LSI
User avatar
Rook Zimbabwe
Addict
Addict
Posts: 4322
Joined: Tue Jan 02, 2007 8:16 pm
Location: Cypress TX
Contact:

Re: Skin window with PNG (Alpha channel support)

Post by Rook Zimbabwe »

I wish there was a way to do this in PB without having to use API calls!!! :mrgreen:
Binarily speaking... it takes 10 to Tango!!!

Image
http://www.bluemesapc.com/
User avatar
STARGÅTE
Addict
Addict
Posts: 2235
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: Skin window with PNG (Alpha channel support)

Post by STARGÅTE »

Thanks for sharing the code. :D
Was looking for something similar.

However, I have slightly reduced and simplified.

If the image is "right" created (all transparent colors are black or go to black), need not modify it and save time.
:arrow:

Code: Select all

Procedure WindowBackground(Window.i, Image.i, Transparency.a=255)
  Protected WindowID.i = WindowID(Window)
  Protected ImageID.i  = ImageID(Image)
  Protected HDC.i      = CreateCompatibleDC_(#Null)
  Protected Object.i   = SelectObject_(HDC, ImageID)
  Protected Size.Size  : Size\cx = ImageWidth(Image) : Size\cy = ImageHeight(Image)
  Protected Point.Point
  Protected Blend.BLENDFUNCTION : Blend\SourceConstantAlpha = Transparency : Blend\AlphaFormat = 1
  SetWindowLong_(WindowID, #GWL_EXSTYLE, GetWindowLong_(WindowID, #GWL_EXSTYLE) | #WS_EX_LAYERED)
  UpdateLayeredWindow_(WindowID, 0, 0, @Size, HDC, @Point, 0, @Blend, 2)
  SelectObject_(HDC, Object)
  DeleteDC_(HDC)
EndProcedure
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
User avatar
TomS
Enthusiast
Enthusiast
Posts: 342
Joined: Sun Mar 18, 2007 2:26 pm
Location: Munich, Germany

Re: Skin window with PNG (Alpha channel support)

Post by TomS »

STARGÅTE wrote:If the image is "right" created (all transparent colors are black or go to black), need not modify it and save time.
Example please?! First of all it's 24bit again and second: if "all transparent colors [...] go to black", than every color except white is transparent oO
User avatar
STARGÅTE
Addict
Addict
Posts: 2235
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: Skin window with PNG (Alpha channel support)

Post by STARGÅTE »

Code: Select all

Couleur = Image(x, y)
         AlphaChannel = Couleur >> 24 & $FF
         If AlphaChannel < $FF
            Rouge = (Couleur & $FF) * Echelle(AlphaChannel)
            Vert = (Couleur >> 8 & $FF) * Echelle(AlphaChannel)
            Bleu = (Couleur >> 16 & $FF) * Echelle(AlphaChannel)
            Image(x, y) = Rouge | Vert << 8 | Bleu << 16 | AlphaChannel << 24
         EndIf
if Alpha = 0 -> Color ist Black
If Color white and Alpha = 128 -> Color is Grey
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
Post Reply