Skip to content

Commit df8de40

Browse files
committed
optimise _setLum
1 parent 26be4f8 commit df8de40

File tree

3 files changed

+51
-19
lines changed

3 files changed

+51
-19
lines changed

blendmodes/blend.py

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -178,27 +178,34 @@ def _setLum(originalColours: np.ndarray, newLuminosity: np.ndarray) -> np.ndarra
178178
"""Set a new luminosity value for the matrix of color."""
179179
_colours = originalColours.copy()
180180
_luminosity = _lum(_colours)
181+
182+
# Apply deltaLum in a single step
181183
deltaLum = newLuminosity - _luminosity
182-
_colours[:, :, 0] += deltaLum
183-
_colours[:, :, 1] += deltaLum
184-
_colours[:, :, 2] += deltaLum
184+
_colours += deltaLum[..., None] # Broadcasting to RGB channels
185+
186+
# Compute new luminosity, min, and max values
185187
_luminosity = _lum(_colours)
186-
_minColours = np.min(_colours, axis=2)
187-
_MaxColours = np.max(_colours, axis=2)
188-
for i in range(_colours.shape[0]):
189-
for j in range(_colours.shape[1]):
190-
_colour = _colours[i][j]
191-
newLuminosity = _luminosity[i, j]
192-
minColour = _minColours[i, j]
193-
maxColour = _MaxColours[i, j]
194-
if minColour < 0:
195-
_colours[i][j] = newLuminosity + (
196-
((_colour - newLuminosity) * newLuminosity) / (newLuminosity - minColour)
197-
)
198-
if maxColour > 1:
199-
_colours[i][j] = newLuminosity + (
200-
((_colour - newLuminosity) * (1 - newLuminosity)) / (maxColour - newLuminosity)
201-
)
188+
minColours = np.min(_colours, axis=2)
189+
maxColours = np.max(_colours, axis=2)
190+
191+
# Create masks for values that need adjustment
192+
minMask = minColours < 0
193+
maxMask = maxColours > 1
194+
195+
# Apply min correction
196+
_colours[minMask] = (
197+
_luminosity[minMask, None] +
198+
((_colours[minMask] - _luminosity[minMask, None]) * _luminosity[minMask, None]) /
199+
(_luminosity[minMask, None] - minColours[minMask, None])
200+
)
201+
202+
# Apply max correction
203+
_colours[maxMask] = (
204+
_luminosity[maxMask, None] +
205+
((_colours[maxMask] - _luminosity[maxMask, None]) * (1 - _luminosity[maxMask, None])) /
206+
(maxColours[maxMask, None] - _luminosity[maxMask, None])
207+
)
208+
202209
return _colours
203210

204211

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ dev = [
3636
"pyright>=1.1.394",
3737
"pytest>=8.3.4",
3838
"ruff>=0.9.7",
39+
"safety>=3.3.0",
3940
]
4041

4142
[tool.ruff]

tests/test_perf.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from __future__ import annotations
2+
3+
import random
4+
from pathlib import Path
5+
6+
import pytest
7+
from PIL import Image
8+
9+
from blendmodes.blend import BlendType, blendLayers
10+
11+
THISDIR = Path(__file__).resolve().parent
12+
13+
14+
15+
16+
@pytest.mark.parametrize("blend_mode", random.choices(list(BlendType), k=200))
17+
def test_blend_modes(blend_mode: BlendType) -> None:
18+
"""Test blend modes with random selection."""
19+
background = Image.open(THISDIR / "data" / "background.png")
20+
foreground = Image.open(THISDIR / "data" / "foreground.png")
21+
22+
result = blendLayers(background, foreground, blend_mode)
23+
24+
assert result is not None # Ensure we get a valid image back

0 commit comments

Comments
 (0)