From 78eba690f8cb32a1685c2a31c7b9a54108c0c285 Mon Sep 17 00:00:00 2001 From: facelessuser Date: Thu, 5 Sep 2024 11:56:24 -0600 Subject: [PATCH] Adjust internal handling of compositing --- coloraide/color.py | 7 +++-- coloraide/compositing/__init__.py | 48 ++++++++++++++----------------- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/coloraide/color.py b/coloraide/color.py index da325b08..64866498 100644 --- a/coloraide/color.py +++ b/coloraide/color.py @@ -1207,11 +1207,12 @@ def compose( """Blend colors using the specified blend mode.""" if not isinstance(backdrop, str) and isinstance(backdrop, Sequence): - bcolor = [self._handle_color_input(c) for c in backdrop] + colors = [self._handle_color_input(c) for c in backdrop] else: - bcolor = [self._handle_color_input(backdrop)] + colors = [self._handle_color_input(backdrop)] + colors.insert(0, self) - color = compositing.compose(self, bcolor, blend, operator, space, out_space) + color = compositing.compose(type(self), colors, blend, operator, space, out_space) return self._hotswap(color) if in_place else color def delta_e( diff --git a/coloraide/compositing/__init__.py b/coloraide/compositing/__init__.py index b3268185..a242e65c 100644 --- a/coloraide/compositing/__init__.py +++ b/coloraide/compositing/__init__.py @@ -9,7 +9,8 @@ from . import blend_modes from .. import algebra as alg from ..channels import Channel -from typing import TYPE_CHECKING +from ..types import Vector, ColorInput +from typing import TYPE_CHECKING, Sequence if TYPE_CHECKING: # pragma: no cover from ..color import Color @@ -34,18 +35,19 @@ def clip_channel(coord: float, channel: Channel) -> float: def apply_compositing( - color1: Color, - color2: Color, + color1: Vector, + color2: Vector, + channels: tuple[Channel, ...], blender: blend_modes.Blend | None, operator: str | bool -) -> Color: +) -> Vector: """Perform the actual blending.""" # Get the color coordinates - csa = color1.alpha(nans=False) - cba = color2.alpha(nans=False) - coords1 = color1.coords(nans=False) - coords2 = color2.coords(nans=False) + csa = color1[-1] + cba = color2[-1] + coords1 = color1[:-1] + coords2 = color2[:-1] # Setup compositing compositor = None # type: porter_duff.PorterDuff | None @@ -57,9 +59,6 @@ def apply_compositing( compositor = porter_duff.compositor('source-over')(cba, csa) cra = alg.clamp(compositor.ao(), 0, 1) - # Perform compositing - channels = color1._space.CHANNELS - # Blend each channel. Afterward, clip and apply alpha compositing. i = 0 for cb, cr in zip(coords2, blender.blend(coords2, coords1) if blender else coords1): @@ -77,8 +76,8 @@ def apply_compositing( def compose( - color: Color, - backdrop: list[Color], + color_cls: type[Color], + colors: Sequence[ColorInput], blend: str | bool = True, operator: str | bool = True, space: str | None = None, @@ -86,6 +85,9 @@ def compose( ) -> Color: """Blend colors using the specified blend mode.""" + if not colors: # pragma: no cover + raise ValueError('At least one color is required for compositing.') + # We need to go ahead and grab the blender as we need to check what type of blender it is. blender = None # blend_modes.Blend | None if isinstance(blend, str): @@ -100,18 +102,12 @@ def compose( if out_space is None: out_space = space - if not isinstance(color.CS_MAP[space], RGBish): - raise ValueError(f"Can only compose in an RGBish color space, not {type(color.CS_MAP[space])}") - - if not backdrop: - return color - - dest = backdrop[-1].convert(space) - if len(backdrop) > 1: - for x in range(len(backdrop) - 2, -1, -1): - src = backdrop[x].convert(space) - dest = apply_compositing(src, dest, blender, operator) + if not isinstance(color_cls.CS_MAP[space], RGBish): + raise ValueError(f"Can only compose in an RGBish color space, not {type(color_cls.CS_MAP[space])}") - src = color.convert(space) + dest = color_cls._handle_color_input(colors[-1]).convert(space).normalize(nans=False)[:] + for x in range(len(colors) - 2, -1, -1): + src = color_cls._handle_color_input(colors[x]).convert(space).normalize(nans=False)[:] + dest = apply_compositing(src, dest, color_cls.CS_MAP[space].channels, blender, operator) - return apply_compositing(src, dest, blender, operator).convert(out_space, in_place=True) + return color_cls(space, dest[:-1], dest[-1]).convert(out_space, in_place=True)