2626
2727from blendmodes .blendtype import BlendType
2828
29+ HALF_THRESHOLD = 0.5
30+
2931
3032def normal (background : np .ndarray , foreground : np .ndarray ) -> np .ndarray :
3133 """BlendType.NORMAL."""
@@ -76,7 +78,7 @@ def glow(background: np.ndarray, foreground: np.ndarray) -> np.ndarray:
7678def overlay (background : np .ndarray , foreground : np .ndarray ) -> np .ndarray :
7779 """BlendType.OVERLAY."""
7880 return np .where (
79- background < 0.5 ,
81+ background < HALF_THRESHOLD ,
8082 2 * background * foreground ,
8183 1.0 - (2 * (1.0 - background ) * (1.0 - foreground )),
8284 )
@@ -125,7 +127,7 @@ def softlight(background: np.ndarray, foreground: np.ndarray) -> np.ndarray:
125127def hardlight (background : np .ndarray , foreground : np .ndarray ) -> np .ndarray :
126128 """BlendType.HARDLIGHT."""
127129 return np .where (
128- foreground < 0.5 ,
130+ foreground < HALF_THRESHOLD ,
129131 np .minimum (background * 2 * foreground , 1.0 ),
130132 np .minimum (1.0 - ((1.0 - background ) * (1.0 - (foreground - 0.5 ) * 2.0 )), 1.0 ),
131133 )
@@ -148,16 +150,16 @@ def divide(background: np.ndarray, foreground: np.ndarray) -> np.ndarray:
148150
149151def pinlight (background : np .ndarray , foreground : np .ndarray ) -> np .ndarray :
150152 """BlendType.PINLIGHT."""
151- return np .minimum (background , 2 * foreground ) * (foreground < 0.5 ) + np .maximum (
153+ return np .minimum (background , 2 * foreground ) * (foreground < HALF_THRESHOLD ) + np .maximum (
152154 background , 2 * (foreground - 0.5 )
153- ) * (foreground >= 0.5 )
155+ ) * (foreground >= HALF_THRESHOLD )
154156
155157
156158def vividlight (background : np .ndarray , foreground : np .ndarray ) -> np .ndarray :
157159 """BlendType.VIVIDLIGHT."""
158- return colourburn (background , foreground * 2 ) * (foreground < 0.5 ) + colourdodge (
160+ return colourburn (background , foreground * 2 ) * (foreground < HALF_THRESHOLD ) + colourdodge (
159161 background , 2 * (foreground - 0.5 )
160- ) * (foreground >= 0.5 )
162+ ) * (foreground >= HALF_THRESHOLD )
161163
162164
163165def exclusion (background : np .ndarray , foreground : np .ndarray ) -> np .ndarray :
@@ -543,60 +545,54 @@ def blendLayersArray(
543545 """
544546
545547 # Convert the Image.Image to a numpy array if required
546- if isinstance (background , Image .Image ):
547- background = np .array (background .convert ("RGBA" ))
548- if isinstance (foreground , Image .Image ):
549- foreground = np .array (foreground .convert ("RGBA" ))
548+ bg = np .array (background .convert ("RGBA" )) if isinstance (background , Image .Image ) else background
549+ fg = np .array (foreground .convert ("RGBA" )) if isinstance (foreground , Image .Image ) else foreground
550550
551551 # do any offset shifting first
552552 if offsets [0 ] > 0 :
553- foreground = np .hstack (
554- (np .zeros ((foreground .shape [0 ], offsets [0 ], 4 ), dtype = np .float64 ), foreground )
555- )
553+ fg = np .hstack ((np .zeros ((bg .shape [0 ], offsets [0 ], 4 ), dtype = np .float64 ), fg ))
556554 elif offsets [0 ] < 0 :
557- if offsets [0 ] > - 1 * foreground .shape [1 ]:
558- foreground = foreground [:, - 1 * offsets [0 ] :, :]
555+ if offsets [0 ] > - 1 * fg .shape [1 ]:
556+ fg = fg [:, - 1 * offsets [0 ] :, :]
559557 else :
560558 # offset offscreen completely, there is nothing left
561- return np .zeros (background .shape , dtype = np .float64 )
559+ return np .zeros (bg .shape , dtype = np .float64 )
562560 if offsets [1 ] > 0 :
563- foreground = np .vstack (
564- (np .zeros ((offsets [1 ], foreground .shape [1 ], 4 ), dtype = np .float64 ), foreground )
565- )
561+ fg = np .vstack ((np .zeros ((offsets [1 ], fg .shape [1 ], 4 ), dtype = np .float64 ), fg ))
566562 elif offsets [1 ] < 0 :
567- if offsets [1 ] > - 1 * foreground .shape [0 ]:
568- foreground = foreground [- 1 * offsets [1 ] :, :, :]
563+ if offsets [1 ] > - 1 * fg .shape [0 ]:
564+ fg = fg [- 1 * offsets [1 ] :, :, :]
569565 else :
570566 # offset offscreen completely, there is nothing left
571- return np .zeros (background .shape , dtype = np .float64 )
567+ return np .zeros (bg .shape , dtype = np .float64 )
572568
573569 # resize array to fill small images with zeros
574- if foreground .shape [0 ] < background .shape [0 ]:
575- foreground = np .vstack (
570+ if fg .shape [0 ] < bg .shape [0 ]:
571+ fg = np .vstack (
576572 (
577- foreground ,
573+ fg ,
578574 np .zeros (
579- (background .shape [0 ] - foreground .shape [0 ], foreground .shape [1 ], 4 ),
575+ (bg .shape [0 ] - fg .shape [0 ], fg .shape [1 ], 4 ),
580576 dtype = np .float64 ,
581577 ),
582578 )
583579 )
584- if foreground .shape [1 ] < background .shape [1 ]:
585- foreground = np .hstack (
580+ if fg .shape [1 ] < bg .shape [1 ]:
581+ fg = np .hstack (
586582 (
587- foreground ,
583+ fg ,
588584 np .zeros (
589- (foreground .shape [0 ], background .shape [1 ] - foreground .shape [1 ], 4 ),
585+ (fg .shape [0 ], bg .shape [1 ] - fg .shape [1 ], 4 ),
590586 dtype = np .float64 ,
591587 ),
592588 )
593589 )
594590
595591 # crop the source if the backdrop is smaller
596- foreground = foreground [: background .shape [0 ], : background .shape [1 ], :]
592+ fg = fg [: bg .shape [0 ], : bg .shape [1 ], :]
597593
598- lower_norm = background / 255.0
599- upper_norm = foreground / 255.0
594+ lower_norm = bg / 255.0
595+ upper_norm = fg / 255.0
600596
601597 upper_alpha = upper_norm [:, :, 3 ] * opacity
602598 lower_alpha = lower_norm [:, :, 3 ]
@@ -639,10 +635,14 @@ def alpha_comp_shell(
639635
640636 blend_rgb = blend (lower_rgb , upper_rgb , blendType )
641637
642- lower_rgb_part = np . multiply ((( 1.0 - upper_alpha ) * lower_alpha )[:, :, None ], lower_rgb )
643- upper_rgb_part = np . multiply ((( 1.0 - lower_alpha ) * upper_alpha )[:, :, None ], upper_rgb )
644- blended_rgb_part = np . multiply (( lower_alpha * upper_alpha )[:, :, None ], blend_rgb )
638+ lower_rgb_factor = ( 1.0 - upper_alpha ) * lower_alpha
639+ upper_rgb_factor = ( 1.0 - lower_alpha ) * upper_alpha
640+ blended_rgb_factor = lower_alpha * upper_alpha
645641
646- out_rgb = np .divide ((lower_rgb_part + upper_rgb_part + blended_rgb_part ), out_alpha [:, :, None ])
642+ out_rgb = (
643+ lower_rgb_factor [:, :, None ] * lower_rgb
644+ + upper_rgb_factor [:, :, None ] * upper_rgb
645+ + blended_rgb_factor [:, :, None ] * blend_rgb
646+ ) / out_alpha [:, :, None ]
647647
648648 return out_rgb , out_alpha
0 commit comments