1+ # ----------------------------------------------------------------------------------------------------------------------
2+ # - Package Imports -
3+ # ----------------------------------------------------------------------------------------------------------------------
4+ # General Packages
5+ from __future__ import annotations
6+
7+ import math
8+ from typing import Callable
9+
10+ # Custom Library
11+
12+ # Custom Packages
13+ from AthenaColor .Objects .Color .ColorSystem import ColorSystem , RGBA
14+ from AthenaColor .Objects .Color .ColorObjectConversion import to_RGBA
15+ from AthenaColor .Objects .Color .ColorTupleConversion import NormalizeRgba
16+
17+ # ----------------------------------------------------------------------------------------------------------------------
18+ # - Support Code -
19+ # ----------------------------------------------------------------------------------------------------------------------
20+ __all__ = [
21+ "blend_normal" , "blend_linearburn" , "blend_colordodge" , "blend_difference" , "blend_lineardodge" , "blend_screen" ,
22+ "blend_darken" , "blend_linearlight" , "blend_vividlight" , "blend_colorburn" , "blend_multiply" , "blend_lighten" ,
23+ "blend_overlay" , "blend_exclusion" , "blend_hardlight" , "blend_softlight" , "blend_pinlight"
24+ ]
25+
26+ # ----------------------------------------------------------------------------------------------------------------------
27+ # - Support Code -
28+ # ----------------------------------------------------------------------------------------------------------------------
29+ def _blend_function (color1 :ColorSystem ,color2 :ColorSystem , formula :Callable ) -> RGBA :
30+ color1_tuple = NormalizeRgba (* to_RGBA (color1 ).export ())
31+ color2_tuple = NormalizeRgba (* to_RGBA (color2 ).export ())
32+
33+ # WARNING below values are normalized (aka between 0 and 1)
34+ normalized_outcome = (formula (a , b ) for a , b in zip (color1_tuple , color2_tuple ))
35+ return RGBA (* (n * 255 for n in normalized_outcome )) # need to de normalize them again
36+
37+ # ----------------------------------------------------------------------------------------------------------------------
38+ # - Code -
39+ # ----------------------------------------------------------------------------------------------------------------------
40+ def blend_normal (color1 :ColorSystem , color2 :ColorSystem ) -> RGBA :
41+ # possible because to_RGBA creates a new object
42+ return to_RGBA (color2 )
43+
44+ def blend_darken (color1 :ColorSystem , color2 :ColorSystem ) -> RGBA :
45+ formula = lambda a , b : min (a , b )
46+ return _blend_function (color1 ,color2 ,formula )
47+
48+ def blend_multiply (color1 :ColorSystem , color2 :ColorSystem ) -> RGBA :
49+ formula = lambda a ,b : a * b
50+ return _blend_function (color1 ,color2 ,formula )
51+
52+ def blend_colorburn (color1 :ColorSystem , color2 :ColorSystem ) -> RGBA :
53+ formula = lambda a ,b : 1 - (1 - a )/ b
54+ return _blend_function (color1 ,color2 ,formula )
55+
56+ def blend_linearburn (color1 :ColorSystem , color2 :ColorSystem ) -> RGBA :
57+ formula = lambda a ,b : a + b - 1
58+ return _blend_function (color1 ,color2 ,formula )
59+
60+ def blend_lighten (color1 :ColorSystem , color2 :ColorSystem ) -> RGBA :
61+ formula = lambda a ,b : max (a ,b )
62+ return _blend_function (color1 ,color2 ,formula )
63+
64+ def blend_screen (color1 :ColorSystem , color2 :ColorSystem ) -> RGBA :
65+ formula = lambda a ,b : 1 - (1 - a )(1 - b )
66+ return _blend_function (color1 ,color2 ,formula )
67+
68+ def blend_colordodge (color1 :ColorSystem , color2 :ColorSystem ) -> RGBA :
69+ formula = lambda a ,b : a / (1 - b )
70+ return _blend_function (color1 ,color2 ,formula )
71+
72+ def blend_lineardodge (color1 :ColorSystem , color2 :ColorSystem ) -> RGBA :
73+ formula = lambda a ,b : a + b
74+ return _blend_function (color1 ,color2 ,formula )
75+
76+ def blend_overlay (color1 :ColorSystem , color2 :ColorSystem ) -> RGBA :
77+ def formula (a : float , b : float ):
78+ if a < 0.5 :
79+ return 1 - 2 * (1 - a ) * (1 - b )
80+ else :
81+ return 2 * a * b
82+
83+ return _blend_function (color1 ,color2 ,formula )
84+
85+ def blend_softlight (color1 :ColorSystem , color2 :ColorSystem ) -> RGBA :
86+ def formula (a : float , b : float ):
87+ if a <= 0.25 :
88+ g_w3c = ((16 * a - 12 )* a + 4 )* a
89+ else :
90+ g_w3c = math .sqrt (a )
91+
92+ if b <= 0.5 :
93+ return a - (1 - 2 * b )* a * (1 - a )
94+ else :
95+ return a + (2 * b - 1 )* (g_w3c - a )
96+
97+ return _blend_function (color1 ,color2 ,formula )
98+
99+ def blend_hardlight (color1 :ColorSystem , color2 :ColorSystem ) -> RGBA :
100+ def formula (a : float , b : float ):
101+ if b < 0.5 :
102+ return a * (2 * b )
103+ else :
104+ return 1 - (1 - a )* (1 - 2 * (b - 0.5 ))
105+
106+ return _blend_function (color1 ,color2 ,formula )
107+
108+ def blend_vividlight (color1 :ColorSystem , color2 :ColorSystem ) -> RGBA :
109+ def formula (a : float , b : float ):
110+ if b < 0.5 :
111+ return 1 - (1 - a )/ (2 * b )
112+ else :
113+ return a / (1 - 2 * (b - .5 ))
114+
115+ return _blend_function (color1 ,color2 ,formula )
116+
117+ def blend_linearlight (color1 :ColorSystem , color2 :ColorSystem ) -> RGBA :
118+ def formula (a : float , b : float ):
119+ if b < 0.5 :
120+ return a + 2 * b - 1
121+ else :
122+ return a + 2 * (b - .5 )
123+
124+ return _blend_function (color1 ,color2 ,formula )
125+
126+ def blend_pinlight (color1 :ColorSystem , color2 :ColorSystem ) -> RGBA :
127+ def formula (a : float , b : float ):
128+ if b < 0.5 :
129+ return min (a ,2 * b )
130+ else :
131+ return max (a ,2 * (b - .5 ))
132+
133+ return _blend_function (color1 ,color2 ,formula )
134+
135+ def blend_difference (color1 :ColorSystem , color2 :ColorSystem ) -> RGBA :
136+ formula = lambda a ,b : abs (a - b )
137+ return _blend_function (color1 ,color2 ,formula )
138+
139+ def blend_exclusion (color1 :ColorSystem , color2 :ColorSystem ) -> RGBA :
140+ formula = lambda a ,b : 0.5 - 2 * (a - .5 )* (2 - .5 )
141+ return _blend_function (color1 ,color2 ,formula )
0 commit comments