Voici un petit essai sur les modes de fusions (comme photoshop).
Infos
Je "gère" le canal alpha des images, donc ça marche avec des circle() ou box(), et aussi avec des drawalphaimage().
Pour ça, voici la technique :
- "composer" d'abord l'image et le fond en blendmode, uniquement en fonction d el'alpha opaque
- puis superposer l'image obtenue avec le fond (calque du dessous).
Modes de fusion testés
- normal
- multiply ( produit)
- screen (superposition)
- add ou color dodge (densité lumière -)
- overlay (incrustation)
Code
Code : Tout sélectionner
;{ infos
; test blendmode by blendman 07/2011
; pb : 4.60
;}
;{ variables & globales
Global mode.b = 1
;}
;{ init
If UseJPEGImageDecoder() =0 Or UsePNGImageDecoder() =0
End
EndIf
;}
;{ declare
Declare affiche_img()
Declare bm_add(x, y, SourceColor, TargetColor)
Declare bm_multiply(x, y, SourceColor, TargetColor)
Declare bm_overlay(x, y, SourceColor, TargetColor)
Declare bm_screen(x, y, SourceColor, TargetColor)
Declare Changemode()
;}
;{ open window & create image
If OpenWindow(0, 0, 0, 400, 200, "2DDrawing Example - Blendmode test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
;{ menu
If CreateMenu(0,WindowID(0))
MenuTitle("BlendMode")
MenuItem(1,"BlendMode suivant"+Chr(9)+"+")
MenuItem(2,"BlendMode précédent"+Chr(9)+"-")
EndIf
;}
;{ images
LoadImage(1, #PB_Compiler_Home + "examples/sources/data/clouds.jpg")
; test avec une image, mais pour le moment, ne fonctionne pas complètement (manque le canal alpha avant le blendmode)
CreateImage(2,400,200,32)
StartDrawing(ImageOutput(2))
DrawingMode(#PB_2DDrawing_AlphaChannel)
Box(0,0,400,200,RGBA(0,0,0,0))
DrawingMode(#PB_2DDrawing_AlphaBlend)
Circle(300, 100, 100,RGBA(255,0,0,255))
StopDrawing()
If CreateImage(0, 400, 200,32)
affiche_Img()
EndIf
;}
;{ shortcut
AddKeyboardShortcut(0,#PB_Shortcut_Add,1)
AddKeyboardShortcut(0,#PB_Shortcut_Subtract,2)
;}
Else
MessageRequester("Erreur", "impossible d'ouvrir une fenêtre")
End
EndIf
;}
Repeat
Changemode()
Until Event = #PB_Event_CloseWindow
;{ procedure
Procedure affiche_img()
If StartDrawing(ImageOutput(0))
DrawingMode(#PB_2DDrawing_AlphaChannel) ; pour la transparence
Box(0,0,400,200,RGBA(0,0,0,0))
DrawingMode(#PB_2DDrawing_AlphaBlend)
DrawImage(ImageID(1), 0, 0, 400, 200) ; image de fond, on peut utiliser une image avec transparence
; puis on affiche l'image du dessus en fonction du mode de fusion choisi
If mode =0 ; normal
DrawingMode(#PB_2DDrawing_Default)
Circle(300, 100, 80, #Red)
ElseIf mode <>0
DrawingMode(#PB_2DDrawing_CustomFilter)
If mode = 1 ; add
CustomFilterCallback(@bm_add())
Circle(300, 100, 80, RGBA(125,125,125,255))
ElseIf mode = 2 ; multiply
CustomFilterCallback(@bm_multiply())
Circle(300, 100, 80, #Red)
ElseIf mode = 3 ; overlay
CustomFilterCallback(@bm_overlay())
Circle(300, 100, 80, #Red)
ElseIf mode = 4 ; screen
CustomFilterCallback(@bm_screen())
Circle(300, 100, 80, RGBA(125,125,125,255))
EndIf
EndIf
;DrawAlphaImage(ImageID(2),0,0) ;>>>>>>>>>>>>>>> bug actuellement dans certains cas, à revoir, car il manque la gestion du canal alpha.
StopDrawing()
ImageGadget(0, 0, 0, 400, 200, ImageID(0))
EndIf
Select mode
Case 0
SetWindowTitle(0,"Mode : Normal - cercle rouge")
Case 1
SetWindowTitle(0,"Mode : Add - cercle blanc")
Case 2
SetWindowTitle(0,"Mode : Multiply - cercle rouge")
Case 3
SetWindowTitle(0,"Mode : Overlay - cercle rouge")
Case 4
SetWindowTitle(0,"Mode : Screen - cercle blanc")
EndSelect
EndProcedure
Procedure.l min(a.l,b.l)
If a>b
ProcedureReturn b
EndIf
ProcedureReturn a
EndProcedure
Procedure bm_screen(x, y, SourceColor, TargetColor)
; color = 255 - ( ( 255 - bottom ) * ( 255 - top ) ) / 255
red = 255 -((255-Red(SourceColor))*(255-Red(TargetColor)))/255
green = 255 -((255-Green(SourceColor))*(255-Green(TargetColor)))/255
blue = 255 -((255-Blue(SourceColor))*(255-Blue(TargetColor)))/255
ProcedureReturn RGBA(red,green,blue, Alpha(TargetColor))
EndProcedure
Procedure bm_add(x, y, SourceColor, TargetColor)
; color = top >= 255? 255 : min(bottom * 255 / (255 - top), 255)
If Red(TargetColor) >= 255
Red.l= 255
Else
result.l= 255 - Red(SourceColor)
If result >0
Red =min(Red(TargetColor) * 255 / (result), 255)
ElseIf result =0
red=min(Red(TargetColor) * 255, 255)
EndIf
EndIf
If Blue(TargetColor) >= 255
blue = 255
Else
result= 255 - Blue(SourceColor)
If result >0
blue=min(Blue(TargetColor) * 255 / (result), 255)
ElseIf result =0
blue = min(Blue(TargetColor) * 255, 255)
EndIf
EndIf
If Green(TargetColor) >= 255
Green = 255
Else
result= 255 - Green(SourceColor)
If result >0
Green =min(Green(TargetColor) * 255 / (result), 255)
ElseIf result =0
green =min(Green(TargetColor) * 255, 255)
EndIf
EndIf
ProcedureReturn RGBA(red, green, blue, Alpha(TargetColor))
EndProcedure
Procedure bm_multiply(x, y, SourceColor, TargetColor)
ProcedureReturn RGBA((Red(SourceColor)*Red(TargetColor))/255,(Green(SourceColor)*Green(TargetColor))/255,(Blue(SourceColor)*Blue(TargetColor))/255, Alpha(TargetColor)*Alpha(TargetColor)/255)
EndProcedure
Macro overlay(color_source,color_targ, colo)
If color_source <128
colo = ( 2 * color_source*color_targ ) / 255
Else
colo =255 - ( 2 * ( 255 - color_source ) * ( 255 - color_targ ) / 255 )
EndIf
EndMacro
Procedure bm_overlay(x, y, SourceColor, TargetColor)
; color = bottom < 128 ? ( 2 * bottom * top ) / 255 : 255 - ( 2 * ( 255 - bottom ) * ( 255 - top ) / 255 )
overlay(Red(TargetColor),Red(SourceColor), red)
overlay(Blue(TargetColor),Blue(SourceColor), blue)
overlay(Green(TargetColor),Green(SourceColor), green)
ProcedureReturn RGBA(red, green, blue, Alpha(TargetColor))
EndProcedure
Procedure Changemode()
Event = WaitWindowEvent()
Select event
Case #PB_Event_CloseWindow
End
Case #PB_Event_Menu
Select EventMenu()
Case 1
If mode<4
mode +1
Else
mode = 0
EndIf
affiche_img()
Case 2
If mode>0
mode -1
Else
mode = 4
EndIf
affiche_img()
EndSelect
EndSelect
EndProcedure
;}
http://www.vanderlee.com/tut_fm_mixingmodes.html
http://download.java.net/javadesktop/sc ... .Mode.html
http://www.pegtop.net/delphi/articles/blendmodes/
N'hésitez pas à poster si vous avez des remarques ou si vous modifier/ajouter quelque chose au code.
ce n'est pas nécessairement la meilleure technique, mais elle me semble simple et intéressante

EDIT : et voici le code qui fonctionne avec une image en tant que layer, cte classe

Code : Tout sélectionner
;{ infos
; test blendmode by blendman 07/2011
; pb : 4.60
;}
;{ variables & globales
Enumeration
#fond
#layer1
#alpha_layer1
#tempo
#result
#imagefinal
EndEnumeration
Global mode.b = 1
;}
;{ init
If UseJPEGImageDecoder() =0 Or UsePNGImageDecoder() =0
End
EndIf
;}
;{ declare
Declare affiche_img()
Declare bm_add(x, y, SourceColor, TargetColor)
Declare bm_multiply(x, y, SourceColor, TargetColor)
Declare bm_overlay(x, y, SourceColor, TargetColor)
Declare bm_screen(x, y, SourceColor, TargetColor)
Declare Changemode()
;}
;{ open window & create image
If OpenWindow(0, 0, 0, 400, 200, "2DDrawing Example - Blendmode test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
;{ menu
If CreateMenu(0,WindowID(0))
MenuTitle("BlendMode")
MenuItem(1,"BlendMode suivant"+Chr(9)+"+")
MenuItem(2,"BlendMode précédent"+Chr(9)+"-")
EndIf
;}
;{ images
LoadImage(#fond, #PB_Compiler_Home + "examples/sources/data/clouds.jpg") ; le fond "nuages"
; l'image (layer1 : ici un simple cercle rouge
CreateImage(#layer1,400,200,32)
StartDrawing(ImageOutput(#layer1))
DrawingMode(#PB_2DDrawing_AlphaChannel)
Box(0,0,400,200,RGBA(0,0,0,0))
DrawingMode(#PB_2DDrawing_AlphaBlend)
Circle(300, 100, 100,RGBA(255,0,0,255))
StopDrawing()
CopyImage(#layer1,#alpha_layer1)
; copy pour l'image temporaire pour le canal alpha
CreateImage(#tempo,400,200,32)
StartDrawing(ImageOutput(#tempo))
DrawingMode(#PB_2DDrawing_AlphaChannel)
Box(0,0,400,200,RGBA(0,0,0,0))
StopDrawing()
If CreateImage(#imagefinal, 400, 200,32)
affiche_Img()
EndIf
;}
;{ shortcut
AddKeyboardShortcut(0,#PB_Shortcut_Add,1)
AddKeyboardShortcut(0,#PB_Shortcut_Subtract,2)
;}
Else
MessageRequester("Erreur", "impossible d'ouvrir une fenêtre")
End
EndIf
;}
Repeat
Changemode()
Until Event = #PB_Event_CloseWindow
;{ procedure
Procedure affiche_img()
; on calcule le blendmode, uniquement sur l'alpha opaque lié au layer1
If StartDrawing(ImageOutput(#tempo))
; image de fond, on peut utiliser une image avec transparence
DrawingMode(#PB_2DDrawing_AlphaBlend)
DrawImage(ImageID(#fond), 0, 0, 400, 200)
; puis on affiche l'image du dessus en fonction du mode de fusion choisi
If mode =0 ; normal
DrawingMode(#PB_2DDrawing_Default)
ElseIf mode <>0
DrawingMode(#PB_2DDrawing_CustomFilter)
If mode = 1 ; add
CustomFilterCallback(@bm_add())
ElseIf mode = 2 ; multiply
CustomFilterCallback(@bm_multiply())
ElseIf mode = 3 ; overlay
CustomFilterCallback(@bm_overlay())
ElseIf mode = 4 ; screen
CustomFilterCallback(@bm_screen())
EndIf
EndIf
DrawAlphaImage(ImageID(#layer1),0,0)
DrawingMode(#PB_2DDrawing_AlphaChannel)
DrawAlphaImage(ImageID(#alpha_layer1),0,0)
StopDrawing()
EndIf
; on calcule le resultat, l'image finale
If StartDrawing(ImageOutput(#imagefinal))
DrawImage(ImageID(#fond), 0, 0, 400, 200) ; image de fond, on peut utiliser une image avec transparence
DrawingMode(#PB_2DDrawing_AlphaBlend)
DrawAlphaImage(ImageID(#tempo),0,0)
StopDrawing()
EndIf
ImageGadget(0, 0, 0, 400, 200, ImageID(#imagefinal))
Select mode
Case 0
SetWindowTitle(0,"Mode : Normal - cercle rouge")
Case 1
SetWindowTitle(0,"Mode : Add - cercle blanc")
Case 2
SetWindowTitle(0,"Mode : Multiply - cercle rouge")
Case 3
SetWindowTitle(0,"Mode : Overlay - cercle rouge")
Case 4
SetWindowTitle(0,"Mode : Screen - cercle blanc")
EndSelect
EndProcedure
Procedure.l min(a.l,b.l)
If a>b
ProcedureReturn b
EndIf
ProcedureReturn a
EndProcedure
Procedure bm_screen(x, y, SourceColor, TargetColor)
; color = 255 - ( ( 255 - bottom ) * ( 255 - top ) ) / 255
red = 255 -((255-Red(SourceColor))*(255-Red(TargetColor)))/255
green = 255 -((255-Green(SourceColor))*(255-Green(TargetColor)))/255
blue = 255 -((255-Blue(SourceColor))*(255-Blue(TargetColor)))/255
ProcedureReturn RGBA(red,green,blue, Alpha(TargetColor))
EndProcedure
Procedure bm_add(x, y, SourceColor, TargetColor)
; color = top >= 255? 255 : min(bottom * 255 / (255 - top), 255)
If Red(TargetColor) >= 255
Red.l= 255
Else
result.l= 255 - Red(SourceColor)
If result >0
Red =min(Red(TargetColor) * 255 / (result), 255)
ElseIf result =0
red=min(Red(TargetColor) * 255, 255)
EndIf
EndIf
If Blue(TargetColor) >= 255
blue = 255
Else
result= 255 - Blue(SourceColor)
If result >0
blue=min(Blue(TargetColor) * 255 / (result), 255)
ElseIf result =0
blue = min(Blue(TargetColor) * 255, 255)
EndIf
EndIf
If Green(TargetColor) >= 255
Green = 255
Else
result= 255 - Green(SourceColor)
If result >0
Green =min(Green(TargetColor) * 255 / (result), 255)
ElseIf result =0
green =min(Green(TargetColor) * 255, 255)
EndIf
EndIf
ProcedureReturn RGBA(red, green, blue, Alpha(TargetColor))
EndProcedure
Procedure bm_multiply(x, y, SourceColor, TargetColor)
ProcedureReturn RGBA((Red(SourceColor)*Red(TargetColor))/255,(Green(SourceColor)*Green(TargetColor))/255,(Blue(SourceColor)*Blue(TargetColor))/255, Alpha(TargetColor)*Alpha(TargetColor)/255)
EndProcedure
Macro overlay(color_source,color_targ, colo)
If color_source <128
colo = ( 2 * color_source*color_targ ) / 255
Else
colo =255 - ( 2 * ( 255 - color_source ) * ( 255 - color_targ ) / 255 )
EndIf
EndMacro
Procedure bm_overlay(x, y, SourceColor, TargetColor)
; color = bottom < 128 ? ( 2 * bottom * top ) / 255 : 255 - ( 2 * ( 255 - bottom ) * ( 255 - top ) / 255 )
overlay(Red(TargetColor),Red(SourceColor), red)
overlay(Blue(TargetColor),Blue(SourceColor), blue)
overlay(Green(TargetColor),Green(SourceColor), green)
ProcedureReturn RGBA(red, green, blue, Alpha(TargetColor))
EndProcedure
Procedure Changemode()
Event = WaitWindowEvent()
Select event
Case #PB_Event_CloseWindow
End
Case #PB_Event_Menu
Select EventMenu()
Case 1
If mode<4
mode +1
Else
mode = 0
EndIf
affiche_img()
Case 2
If mode>0
mode -1
Else
mode = 4
EndIf
affiche_img()
EndSelect
EndSelect
EndProcedure
;}