Re: Emulating Photoshop's blending modes
Posted: Sat Jul 23, 2011 9:54 am
Hi
Here is another way to do blendmode with imagegadget or canvasgadget :
As you can see, The alpha channel is used for the overlay mode or the other mode, because wa have to use it to not have the rest of the image bleck or white (if the transparency is rgba(0,0,0,0) or rgba(255,255,255,0) for the alpha channel.
I hope this could be usefull for you
.
It could be optimised I think, but it's a good start too
.
Here is another way to do blendmode with imagegadget or canvasgadget :
Code: Select all
;{ infos
; test blendmode by blendman 07/2011
; pb : 4.60
;}
;{ variables & globales
Enumeration
#fond ; the "background"
#layer1
#alpha_layer1
#tempo ; temporary image
#result
#imagefinal ; final image
EndEnumeration
Global mode.b = 1
;}
;{ init
If UseJPEGImageDecoder() =0 Or UsePNGImageDecoder() =0
End
EndIf
;}
;{ declare
Declare affiche_img() ; affiche = show in french
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,"Next BlendMode"+Chr(9)+"+")
MenuItem(2,"Previous BlendMode"+Chr(9)+"-")
EndIf
;}
;{ images
LoadImage(#fond, #PB_Compiler_Home + "examples/sources/data/clouds.jpg") ; the "clouds" image for the background layer
; the layer1 is a simple red circle
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)
; copyfor the temporary image needed for the alpha channel
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("Error", "Can't open a window")
End
EndIf
;}
Repeat
Changemode()
Until Event = #PB_Event_CloseWindow
;{ procedure
Procedure affiche_img()
; calcul of the blendmode, only on the alpha not transparent, on the layer1
If StartDrawing(ImageOutput(#tempo))
; Background image, we can use a transprent image if we want
DrawingMode(#PB_2DDrawing_AlphaBlend)
DrawImage(ImageID(#fond), 0, 0, 400, 200)
; than, we draw the image on the top (the layer1), with the blendmode choosen
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
; then, we have the result, the final image
If StartDrawing(ImageOutput(#imagefinal))
DrawImage(ImageID(#fond), 0, 0, 400, 200) ; background image
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 ")
Case 1
SetWindowTitle(0,"Mode : Add")
Case 2
SetWindowTitle(0,"Mode : Multiply")
Case 3
SetWindowTitle(0,"Mode : Overlay")
Case 4
SetWindowTitle(0,"Mode : Screen")
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
;}
I hope this could be usefull for you

It could be optimised I think, but it's a good start too
