Page 1 sur 2

Fenêtre avec skin au format PNG (support alpha)

Publié : jeu. 10/sept./2009 18:58
par Le Soldat Inconnu
Salut,

Je suis en train de refaire mon logiciel "PopupMenu Editeur" qui va s'appeler "Barre & Menu"

C'est une sorte de dock, un lanceur en gros.
Soit via une barre sur un bord de l'écran, soit via des menus qui s'ouvre un cliquant sur un raccourci.

Mon envie, c'est un skin qui supporte totalement le PNG.

Actuellement, je passe via un SetLayeredWindow_( pour rendre la couleur #FF00FF transparente.

Mais il n'y a pas de dégradé, cette méthode est basique, pixel affiché ou non, pas de gestion de la couche alpha.

Donc je penche sur ce code en C ici :
http://www.codeproject.com/KB/GDI-plus/ ... sharp.aspx
ou en VB ici : (c'est le même)
http://www.vbfrance.com/codes/FORM-GRAP ... 36788.aspx

C'est exactement ce que je recherche.

Visiblement, cela utilise la librairie GDI de crosoft

Si mon ami Denis peut me dire si ce genre de chose lui parle vu qu'il a beaucoup travailler sur GDI. Merci

Sinon, je vais essayer de traduire ce joli bazar mais le VB ou le C, pas trop ma tasse de thé.
Donc si des personnes sont intéressé par l'idée de fenêtre skinnable avec un PNG et support de la couche Alpha. Bienvenue.

Je compte essayer de faire une librairie pour PB en opensource.

Merci à tous ceux qui participeront :)

Re: Fenêtre avec skin au format PNG (support alpha)

Publié : jeu. 10/sept./2009 19:17
par Le Soldat Inconnu
Donc, j'ai continué mes investigations.

J'ai trouvé la fonction qui m'intéresse, elle s'appelle UpdateLayeredWindow

et voici une code d'un code trouvé sur le forum anglais
vous ouvrez une image PNG puis vous déplacer l'image en cliquant dessus.

Code : Tout sélectionner

    Global SD_Window = -1
    
    Procedure StopDrag()
      ReleaseCapture_()
      If IsWindow(SD_Window)
        CloseWindow(SD_Window)
      EndIf
    EndProcedure
    
    Procedure DragCallback(WindowID, message, wParam, lParam)
      Protected Result = #PB_ProcessPureBasicEvents
      Select message
        Case #WM_MOUSEMOVE
          SetWindowPos_(WindowID, #HWND_TOPMOST, DesktopMouseX(), DesktopMouseY(), 0, 0, #SWP_NOSIZE)
        Case #WM_LBUTTONUP
          StopDrag()
        Case #WM_CHAR
          If wParam = #ESC
            StopDrag()
          EndIf
      EndSelect
      ProcedureReturn Result
    EndProcedure
    
    Procedure StartDrag(Image)
      Protected BitmapInfo.BITMAP
      Protected ContextOffset.POINT
      Protected BlendMode.BLENDFUNCTION
      Protected hdc
      If IsWindow(SD_Window)
        CloseWindow(SD_Window)
      EndIf
      SD_Window = OpenWindow(#PB_Any, DesktopMouseX(), DesktopMouseY(), 20, 20, "", #PB_Window_BorderLess, WindowID(GetActiveWindow()))
      SetWindowLong_(WindowID(SD_Window), #GWL_EXSTYLE, GetWindowLong_(WindowID(SD_Window), #GWL_EXSTYLE) | #WS_EX_LAYERED)
      hdc = StartDrawing(ImageOutput(Image))
        GetObject_(ImageID(Image), SizeOf(BITMAP), @BitmapInfo)
        BlendMode\SourceConstantAlpha = 255
        BlendMode\AlphaFormat = 1
        UpdateLayeredWindow_(WindowID(SD_Window), 0, 0, @BitmapInfo+4, hdc, @ContextOffset, 0, @BlendMode, 2)
      StopDrawing()
      SetCapture_(WindowID(SD_Window))
      SetWindowCallback(@DragCallback(), SD_Window)
    EndProcedure
    
    UsePNGImageDecoder()
    fichier.s = OpenFileRequester("", "", "PNG|*.png", 1)
    If fichier
    OpenWindow(0, 0, 0, 512, 384, "", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
    CreateGadgetList(WindowID(0))
    LoadImage(0, fichier.s)
    ImageGadget(0, 10, 10, 0, 0, ImageID(0))
    
    Repeat
      Event = WaitWindowEvent()
      Select Event
        Case #PB_Event_Gadget
          Select EventGadget()
            Case 0
              Select EventType()
                Case 14002
                  StartDrag(0)
              EndSelect
          EndSelect
        Case #PB_Event_CloseWindow
          Break
      EndSelect
    ForEver
    
  EndIf
Donc ça avance :) je suis content, c'est bien plus simple que ce que je pensais

Re: Fenêtre avec skin au format PNG (support alpha)

Publié : jeu. 10/sept./2009 21:21
par Le Soldat Inconnu
La première version de la fonction qui va bien :)

Il faut que je fignole. Je veux passer l'image ID et pas l'identifiant PB à la procedure.

Donc petit travail sur CreateDC pour obtenir le HDC de l'image.

Code : Tout sélectionner

ProcedureDLL AlphaImageWindow(WindowID, Image, Alpha = 255)
  Protected Image_HDC, Image_BitmapInfo.BITMAPINFO, ContextOffset.POINT, Blend.BLENDFUNCTION
  SetWindowLong_(WindowID, #GWL_EXSTYLE, GetWindowLong_(WindowID, #GWL_EXSTYLE) | #WS_EX_LAYERED)
  
  Image_HDC = StartDrawing(ImageOutput(Image))
    GetObject_(ImageID(Image), SizeOf(BITMAP), @Image_BitmapInfo)
    Blend\SourceConstantAlpha = Alpha ; niveau de transparence
    Blend\AlphaFormat = 1 ; Support de la couche alpha
    UpdateLayeredWindow_(WindowID, 0, 0, @Image_BitmapInfo + 4, Image_HDC, @ContextOffset, 0, @Blend, 2)
  StopDrawing()
  
EndProcedure



UsePNGImageDecoder()

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)
      
      AlphaImageWindow(WindowID(0), 0)
      
      StickyWindow(0, 1)
      
      Repeat
        Event = WaitWindowEvent()
        
      Until Event = #PB_Event_CloseWindow
      
    EndIf
    
  EndIf
EndIf

Re: Fenêtre avec skin au format PNG (support alpha)

Publié : jeu. 10/sept./2009 21:57
par Le Soldat Inconnu
et voilà, c'est bon ;)


le code de ma librairie

Code : Tout sélectionner

ProcedureDLL SetLayeredWindow(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

ProcedureDLL SetLayeredWindowAttributes(WindowID.l, Alpha.l, Color.l) ; Transparence et forme de la fenêtre
  Protected Parametre.l
  If Alpha > 0
    Parametre | #LWA_ALPHA
  Else
    Alpha = 0
  EndIf
  If Color > 0
    Parametre | #LWA_COLORKEY
  Else
    Color = 0
  EndIf
  SetLayeredWindowAttributes_(WindowID, Color, Alpha, Parametre)
EndProcedure

ProcedureDLL SkinWindow(WindowID, ImageID) ; Mettre une forme sur une fenêtre a partir d'une image
  Protected bmi.BITMAPINFO, Region_Temp, Region_Totale, Largeur, Hauteur
  
  GetObject_(ImageID, SizeOf(BITMAP), @bm.BITMAP)
  
  bmi\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
  bmi\bmiHeader\biWidth = bm\bmWidth
  bmi\bmiHeader\biHeight = bm\bmHeight
  bmi\bmiHeader\biPlanes = 1
  bmi\bmiHeader\biBitCount = 32
  bmi\bmiHeader\biCompression = #BI_RGB
  
  Region_Totale = CreateRectRgn_(0, 0, bm\bmWidth, bm\bmHeight)
  
  mem = AllocateMemory(bm\bmWidth * bm\bmHeight * 4)
  If mem
    
    hdc = CreateCompatibleDC_(GetDC_(ImageID))
    If hdc
      GetDIBits_(hdc, ImageID, 0, bm\bmHeight, mem, @bmi, #DIB_RGB_COLORS) ; on envoie la liste dans l'image
      DeleteDC_(hdc)
    EndIf
    
    ; On convertit la liste dans le bon format
    Largeur = bm\bmWidth - 1
    Hauteur = bm\bmHeight - 1
    Point = mem
    For y1 = 0 To Hauteur
      For x1 = 0 To Largeur
        If PeekL(Point) = $FF00FF
          x2 = x1
          While x2 < Largeur And PeekL(Point + 4) = $FF00FF
            x2 + 1
            Point + 4
          Wend
          Region_Temp = CreateRectRgn_(x1, Hauteur - y1, x2 + 1, Hauteur - y1 + 1) ; On retire le point de la region
          CombineRgn_(Region_Totale, Region_Totale, Region_Temp, #RGN_DIFF)
          DeleteObject_(Region_Temp)
          x1 = x2
        EndIf
        Point + 4
      Next
    Next
    
    FreeMemory(mem)
  EndIf
  
  SetWindowRgn_(WindowID, Region_Totale, 1) ; On applique la region
  DeleteObject_(Region_Totale) ; On efface la region
  
EndProcedure

ProcedureDLL SkinWindow2(WindowID, ImageID, Couleur) ; Mettre une forme sur une fenêtre a partir d'une image
  Protected bmi.BITMAPINFO, Region_Temp, Region_Totale, Largeur, Hauteur
  
  GetObject_(ImageID, SizeOf(BITMAP), @bm.BITMAP)
  
  bmi\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
  bmi\bmiHeader\biWidth = bm\bmWidth
  bmi\bmiHeader\biHeight = bm\bmHeight
  bmi\bmiHeader\biPlanes = 1
  bmi\bmiHeader\biBitCount = 32
  bmi\bmiHeader\biCompression = #BI_RGB
  
  Region_Totale = CreateRectRgn_(0, 0, bm\bmWidth, bm\bmHeight)
  
  ; On inverse la couleur
  Couleur = ((Couleur & $0000FF) << 16) | (Couleur & $00FF00) | ((Couleur & $FF0000) >> 16)
  
  mem = AllocateMemory(bm\bmWidth * bm\bmHeight * 4)
  If mem
    
    hdc = CreateCompatibleDC_(GetDC_(ImageID))
    If hdc
      GetDIBits_(hdc, ImageID, 0, bm\bmHeight, mem, @bmi, #DIB_RGB_COLORS) ; on envoie la liste dans l'image
      DeleteDC_(hdc)
    EndIf
    
    ; On convertit la liste dans le bon format
    Largeur = bm\bmWidth - 1
    Hauteur = bm\bmHeight - 1
    Point = mem
    For y1 = 0 To Hauteur
      For x1 = 0 To Largeur
        If PeekL(Point) = Couleur
          x2 = x1
          While x2 < Largeur And PeekL(Point + 4) = Couleur
            x2 + 1
            Point + 4
          Wend
          Region_Temp = CreateRectRgn_(x1, Hauteur - y1, x2 + 1, Hauteur - y1 + 1) ; On retire le point de la region
          CombineRgn_(Region_Totale, Region_Totale, Region_Temp, #RGN_DIFF)
          DeleteObject_(Region_Temp)
          x1 = x2
        EndIf
        Point + 4
      Next
    Next
    
    FreeMemory(mem)
  EndIf
  
  SetWindowRgn_(WindowID, Region_Totale, 1) ; On applique la region
  DeleteObject_(Region_Totale) ; On efface la region
  
EndProcedure

ProcedureDLL AlphaImageWindow(WindowID, ImageID) ; Mettre une image PNG comme fond d'une fenêtre
  Protected Image_HDC, Image_Bitmap.BITMAP, ContextOffset.POINT, Blend.BLENDFUNCTION, Image
	
	; Dimension de l'image
	GetObject_(ImageID, SizeOf(BITMAP), @Image_Bitmap)
	
	Image = CreateImage(#PB_Any, Image_Bitmap\bmWidth, Image_Bitmap\bmHeight, 32)
	StartDrawing(ImageOutput(Image))
		DrawingMode(#PB_2DDrawing_AlphaBlend)
		DrawAlphaImage(ImageID, 0, 0)
		DrawingMode(#PB_2DDrawing_AlphaChannel)
		DrawAlphaImage(ImageID, 0, 0)
	StopDrawing()
	
	; Chargement du HDC
	Image_HDC = CreateCompatibleDC_(#NULL)
	Image_Ancienne = SelectObject_(Image_HDC, ImageID(Image))
	
	; L'image est mise en skin de la fenêtre
	Blend\SourceConstantAlpha = 255 ; niveau de transparence
	Blend\AlphaFormat = 1 ; Support de la couche alpha
	Blend\BlendOp = 0
	Blend\BlendFlags = 0
	UpdateLayeredWindow_(WindowID, 0, 0, @Image_Bitmap + 4, Image_HDC, @ContextOffset, 0, @Blend, 2)
	
	; Fermeture du HDC
	SelectObject_(Image_HDC, Image_Ancienne)
	DeleteDC_(Image_HDC)
	
	; Supression de l'image
	FreeImage(Image)
	
EndProcedure

ProcedureDLL AlphaImageWindow2(WindowID, ImageID, Alpha) ; Mettre une image PNG comme fond d'une fenêtre
  Protected Image_HDC, Image_Bitmap.BITMAP, ContextOffset.POINT, Blend.BLENDFUNCTION, Image
	
	; Dimension de l'image
	GetObject_(ImageID, SizeOf(BITMAP), @Image_Bitmap)
	
	Image = CreateImage(#PB_Any, Image_Bitmap\bmWidth, Image_Bitmap\bmHeight, 32)
	StartDrawing(ImageOutput(Image))
		DrawingMode(#PB_2DDrawing_AlphaBlend)
		DrawAlphaImage(ImageID, 0, 0)
		DrawingMode(#PB_2DDrawing_AlphaChannel)
		DrawAlphaImage(ImageID, 0, 0)
	StopDrawing()
	
	; Chargement du HDC
	Image_HDC = CreateCompatibleDC_(#NULL)
	Image_Ancienne = SelectObject_(Image_HDC, ImageID(Image))
	
	; 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_Bitmap + 4, Image_HDC, @ContextOffset, 0, @Blend, 2)
	
	; Fermeture du HDC
	SelectObject_(Image_HDC, Image_Ancienne)
	DeleteDC_(Image_HDC)
	
	; Supression de l'image
	FreeImage(Image)
	
EndProcedure
le code de l'exemple :

Code : Tout sélectionner

; PureBasic 4.40

UsePNGImageDecoder()

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)
      
			SetLayeredWindow(WindowID(0))
      AlphaImageWindow(WindowID(0), ImageID(0))
      
      StickyWindow(0, 1)
      
      Repeat
        Event = WaitWindowEvent()
        
      Until Event = #PB_Event_CloseWindow
      
    EndIf
    
  EndIf
EndIf
voici d'autres exemple pour cette lib

Code : Tout sélectionner

; Auteur : Le Soldat Inconnu
; Version de PB : 4
;
; Explication du programme :
; Pour doner une forme spéciale à une fenêtre



; Création de la fenêtre et de la GadgetList
If OpenWindow(0, 0, 0, 300, 300, "Skin", #PB_Window_BorderLess | #PB_Window_ScreenCentered) = 0
  End
EndIf
; La fenêtre doit obligatoirement être avec le style #PB_Window_BorderLess

SetWindowColor(0, RGB(255, 0, 0))

; On crée une image qui va servir de skin (elle doit avoir la taille de la fenêtre)
CreateImage(0, 300, 300)
StartDrawing(ImageOutput(0))
  ; La couleur mauve $FF00FF ou RGB(255, 0, 255) représente la partie transparente de la fenêtre
  Box(250, 0, 50, 30, $FF00FF)
  Circle(200, 200, 50, $FF00FF)
  Circle(250, 230, 50, $FF00FF)
  Ellipse(50, 120, 40, 20, $FF00FF)
  LineXY(50, 50, 250, 100, $FF00FF)
StopDrawing()

Temps = ElapsedMilliseconds()

SkinWindow(WindowID(0), ImageID(0))

Temps = (ElapsedMilliseconds() - Temps)

; On place un bouton pour quitter
ButtonGadget(0, 0, 0, 100, 25, "Quitter")
; On affichage le temps nécesssaire pour créer le masque
TextGadget(#PB_Any, 0, 25, 100, 15, Str(Temps) + " ms")

Repeat
  Event = WaitWindowEvent()
  
  If Event = #WM_LBUTTONDOWN
    SendMessage_(WindowID(0), #WM_NCLBUTTONDOWN, #HTCAPTION, 0)
  EndIf
  
  If Event = #PB_Event_Gadget
    Select EventGadget() ; boutons, zone de texte, ...
      Case 0 ; On quitte le programme
        Event = #PB_Event_CloseWindow
    EndSelect
  EndIf
  
Until Event = #PB_Event_CloseWindow

End

Code : Tout sélectionner

; Auteur : Le Soldat Inconnu
; Version de PB : 4
;
; Explication du programme :

; Création de la fenêtre et de la GadgetList
If OpenWindow(0, 0, 0, 300, 300, "Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget) = 0
  End
EndIf

; La couleur $FF00FF devient totalement transparente
; Donc si on dessine de la couleur $FF00FF sur la fenêtre, on fait des trous
; La valeur 200 est l'effet de transparence globale de la fenêtre, 0 donne invisible, et 255 complètement opaque
SetLayeredWindow(WindowID(0))
SetLayeredWindowAttributes(WindowID(0), 200, $FF00FF)

Repeat
  Event = WaitWindowEvent()
  
  Select Event
    Case #PB_Event_Menu
      Select EventMenu() ; Menus
          
      EndSelect
      
    Case #PB_Event_Gadget
      Select EventGadget() ; Gadgets
          
      EndSelect
      
    Case #WM_MOUSEMOVE
      StartDrawing(WindowOutput(0))
        Circle(WindowMouseX(0), WindowMouseY(0), 8, $FF00FF)
      StopDrawing()
  EndSelect
  
Until Event = #PB_Event_CloseWindow

End

Re: Fenêtre avec skin au format PNG (support alpha)

Publié : ven. 11/sept./2009 7:19
par Le Soldat Inconnu
Edition : cette erreur est plus compliqué voir plus bas.

je corrige mon exemple des fenêtres avec support couche alpha.

Il y a une obligation pour les zones de l'image qui sont transparente à 100%
la couleur doit être noire sur ces zones.

Et photoshop n'a pas trop l'air motivé sur ce points, donc cette exemple corrige ce problème

il faut toujours les fonctions de la lib du message plus haut

Code : Tout sélectionner

Retiré

Re: Fenêtre avec skin au format PNG (support alpha)

Publié : ven. 11/sept./2009 19:11
par Anonyme2
Le Soldat Inconnu a écrit : Visiblement, cela utilise la librairie GDI de crosoft

Si mon ami Denis peut me dire si ce genre de chose lui parle vu qu'il a beaucoup travailler sur GDI. Merci

Heu, j'ai pas regardé (c'est GDI+ car GDI existe mais est limité d'ou GDI+)

Re: Fenêtre avec skin au format PNG (support alpha)

Publié : sam. 12/sept./2009 11:41
par Le Soldat Inconnu
C'est pas grave, mon bon Denis, en fait, dans l'exemple en C, la lib GDI sert juste à ouvrir le format PNG
Merci :)


Sinon, j'ai fait des corrections dans mes exemples

Et je conseile PB4.40 pour le support de la couche Alpha, sinon, c'est le gros bazar

Re: Fenêtre avec skin au format PNG (support alpha)

Publié : lun. 14/sept./2009 16:15
par Le Soldat Inconnu
Bon, je n'avais un bon rendu sur mes images, et j'ai trouvé le problème. Problème Microsoft bien entendu, qui ne sait pas faire de mélange entre 2 couleurs

A savoir microsoft travaille de cette manière pour mélangé 2 couleurs :
Dst.Red = Src.Red + (1 - Src.Alpha) * Dst.Red
Dst.Green = Src.Green + (1 - Src.Alpha) * Dst.Green
Dst.Blue = Src.Blue + (1 - Src.Alpha) * Dst.Blue

Ce qui est totalement faux, il faut faire comme cela
Dst.Red = Src.Red * Src.Alpha + (1 - Src.Alpha) * Dst.Red
Dst.Green = Src.Green * Src.Alpha + (1 - Src.Alpha) * Dst.Green
Dst.Blue = Src.Blue * Src.Alpha + (1 - Src.Alpha) * Dst.Blue

En gros, quand j'ajoute à une couleur une autre avec de la transparence à 70%, je me retrouve avec 30% de la couleur de base et 70% de la nouvelle couleur, et pas comme microsoft le fait en prenant 100% de la couleur de base + 70% de l'autre couleur (ce qui fait au passage 170% bravo)

Donc j'ai déjà trouvé la méthode, il faut que je fasse le calcul (Src.Red * Src.Alpha ; ...) directement sur mon image avant de l'envoyer comme skin.
Maintenant, je cherche à optimiser.

Donc tous mes exemples plus haut sont faux, attendez la mise à jour.

Re: Fenêtre avec skin au format PNG (support alpha)

Publié : mar. 15/sept./2009 19:06
par Le Soldat Inconnu
Alors voilà, c'est au point.

J'ai remis à jour les codes plus haut.
Chez moi, le traitement de l'image pour palier les bizarrerie microsoft donne 32ms pour une image de 1024*1024. Donc très très rapide. Tant mieux

Donc il faut de préférence la version 4.40, pas essayé avec 4.30 mais je pense que cela doit fonctionner (mais c'est pas le top)

et pour finir, voici un aperçu de ce que cela peut donner
Image
La fenêtre, c'est le bouton vert. Donc grace au PNG et la couche alpha, contour net, ombre, etc ...

Si d'autres peuvent tester chez eux le bon fonctionnement, 2000, XP, Vista (si vous avez opté pour cet ... hum ...chose), 7

Merci

voici un code tout près

Code : Tout sélectionner

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

Re: Fenêtre avec skin au format PNG (support alpha)

Publié : mar. 15/sept./2009 19:36
par Jacobus
Voici deux screens sous ce que tu appelles hum... chose là... Vista je crois
Exemple utilisé le n°1 with PB 4.40
Image
Le second de la même fenêtre, avec fond différent.
Image
Le 2 et le 3 fonctionnent bien aussi, mais le 4 craint. Je ne vois rien et on ne peut fermer qu'en stoppant dans PB
je teste le dernier...
voilà
Image
Ca fonctionne. Manque le bouton pour quitter car le systèm menu n'apparaît sur aucune.

Re: Fenêtre avec skin au format PNG (support alpha)

Publié : jeu. 01/oct./2009 18:39
par venom
c'est mega bon sa :P
je vais regarder de plus pres merci du code





@++

Re: Fenêtre avec skin au format PNG (support alpha)

Publié : sam. 03/oct./2009 19:32
par Le Soldat Inconnu
Voici un code qui mets en évidence le problème que j'ai rencontré sur la gestion de la couche Alpha avec UpdateLayeredWindow_(

Fenêtre à gauche sans la correction, et celle de droite avec la correction.

voici l'image originale
Image

Code : Tout sélectionner

; PureBasic 4.40

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, Calcul.l) ; 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
	
	If Calcul
		; 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)
	EndIf
	
	; L'image est mise en skin de la fenêtre
	Blend\SourceConstantAlpha = 255 ; 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

If CatchImage(0, ?Image)
	
	If OpenWindow(0, 100, 100, ImageWidth(0), ImageHeight(0), "Test 1", #PB_Window_BorderLess)
		
		SetLayeredWindow2(WindowID(0))
		AlphaImageWindow2(WindowID(0), ImageID(0), 0)
		
		StickyWindow(0, 1)
		
	EndIf
	If OpenWindow(1, 300, 100, ImageWidth(0), ImageHeight(0), "Test 2", #PB_Window_BorderLess)
		
		SetLayeredWindow2(WindowID(1))
		AlphaImageWindow2(WindowID(1), ImageID(0), 1)
		
		StickyWindow(1, 1)
		
	EndIf
	
	Repeat
		Event = WaitWindowEvent()
		
		If Event = #WM_LBUTTONDOWN
			SendMessage_(WindowID(EventWindow()), #WM_NCLBUTTONDOWN, #HTCAPTION, 0)
		EndIf
		
	Until Event = #PB_Event_CloseWindow
	
EndIf
	
DataSection
	image:
	Data.l $474E5089,$0A1A0A0D,$0D000000,$52444849,$80000000,$80000000,$00000608,$613EC300,$000000CB,$4D416704,$AF000041,$8A0537C8
	Data.l $000000E9,$58457419,$666F5374,$72617774,$64410065,$2065626F,$67616D49,$61655265,$C9717964,$00003C65,$4449EA02,$DA785441
	Data.l $72599BEC,$451440DA,$98035A9F,$F34BD198,$EC8AB22E,$180A3B2C,$4D6EAC1B,$313B02B9,$2A299258,$A9CE543F,$5BBB75BA,$80E24943
	Data.l $611A88BE,$7BA9E766,$F75D43E6,$3549AFCC,$0F1AEF30,$D7D57DAD,$35E9731C,$D72F757C,$0F99EFA6,$EB67E775,$106BFE0C,$01000100
	Data.l $01000100,$01000100,$01000100,$01000100,$01000100,$01000100,$01000100,$01000100,$01000100,$01000100,$01000100,$01000100
	Data.l $01000100,$56E00100,$77E7EC48,$459C7455,$DB71DFD1,$E3EFE71F,$E7D16B3F,$45B64BB5,$C9FAF3EE,$C63B3B9A,$B9D3EFF5,$D79C75DD
	Data.l $E3BB9D9D,$7BEED79C,$FB57CC72,$C763DD75,$0CF4F8F3,$35DEE82E,$276EDB3B,$E005F8DB,$00080015,$00080008,$00080008,$00080008
	Data.l $00080008,$00080008,$00080008,$00080008,$00080008,$00080008,$00080008,$00080008,$00080008,$00080008,$00080008,$47FB4137
	Data.l $14511FF1,$E738C7D9,$FD43E73A,$35F9F39E,$77B8E389,$5A1E35DE,$D5FFB4BB,$AEE34331,$7BE935F9,$FBDD43E6,$E01DF2D9,$00080015
	Data.l $00080008,$00080008,$00080008,$00080008,$00080008,$00080008,$00080008,$00080008,$00080008,$00080008,$00080008,$00080008
	Data.l $00080008,$00080008,$3CD440B7,$6B95363E,$FBD7197C,$EA766E32,$9FA922E7,$21D6A98E,$10EA95AD,$E87676DF,$ADCACF8D,$2F36AACF
	Data.l $B5EE5679,$0AACF3E6,$A6D4AF5A,$699D44F5,$A89EAC7D,$67AD3EA7,$E97AB9EA,$62426393,$5621566D,$CE08B6C7,$59B385E6,$197DD911
	Data.l $1B34A4D9,$B9A33A29,$D58D71A6,$AB04A971,$D2AB5792,$B3E9959D,$DB22B5B2,$A30B6B28,$997F8CB7,$F2DAF43F,$DDFCC6F1,$AB78FCD6
	Data.l $BBF2CEF1,$4BABDABD,$29D8D6A5,$F563C6A9,$3E5A9944,$3A17AB9A,$6CF2D2C7,$4DD07EA5,$3548583D,$B4BA4256,$885B9922,$DFC45667
	Data.l $2B1374AC,$74494CA3,$535B1695,$8914D625,$4FB2B9D5,$56A5DAAD,$CCDB2B3E,$6CB7A78A,$656B0B32,$CC8F5233,$B293FDAB,$96465E55
	Data.l $725579B7,$5750585D,$AB1C698A,$4CAC6553,$AA657B94,$6DF333CC,$D97E3A96,$B0E87A76,$522C2D4A,$1589162B,$589A6533,$F84CAF79
	Data.l $0015E005,$00080008,$00080008,$00080008,$00080008,$00080008,$00080008,$00080008,$00080008,$00080008,$00080008,$00080008
	Data.l $00080008,$00080008,$00080008,$C1370008,$0006016F,$7D698A9A,$EDA484F5,$00000000,$444E4549,$826042AE
EndDataSection ;}


Re: Fenêtre avec skin au format PNG (support alpha)

Publié : lun. 05/oct./2009 17:55
par Le Soldat Inconnu
Mise à jour du code de la LIB pour une simplification du code.

Merci à Olivier pour l'astuce

Re: Fenêtre avec skin au format PNG (support alpha)

Publié : mar. 06/oct./2009 18:14
par Ar-S
Merci pour ce travail sur le skinage. J'aimerai tester ta lib pour me faire une fenêtre "A Propos" personnalisée avec l'image suivante mais je ne pige pas vraiment comment m'y prendre. Ai-je bon en ayant créer l'image de la sorte ?

image about.png
Image

image alpha about_a.png
Image

Ou suis je à coté de la plaque ?

Re: Fenêtre avec skin au format PNG (support alpha)

Publié : mar. 06/oct./2009 20:09
par Le Soldat Inconnu
totalement à coté de la plaque :), du moins pour skinner une fenêtre avec un PNG

Fais une seule image avec couche alpha (donc fond transparent au lieu de mauve)

Et après, tu dois dessiner ton texte sur l'image (malheureusement, pas de gadget possible dans cet astuce)
Et gérer les clics en fonction de la position des éléments.

L'autre solution est de rajouter une autre fenêtre contenant la zone de texte par dessus la fenêtre skinner.

Je vais te faire un exemple :) (mais la je vais faire la soupe, patiente un poil)