Add procedure to blend a list of colors to a 16-length list for LED bars

This commit is contained in:
Constantin Gierczak--Galle 2023-12-09 17:49:51 +01:00
parent a4cd232390
commit 9e06823fed
2 changed files with 88 additions and 0 deletions

87
pyjecteur/common.py Normal file
View file

@ -0,0 +1,87 @@
import logging
from colour import Color
from typing import List, Callable, Optional, Union, Tuple
from enum import Enum
LedBarLen = 16
def remove_duplicates(colors: List[Color]) -> Tuple[List[Color], List[int]]:
if len(colors) == 0:
return ([], [])
colors_res = [colors[0]]
res_nb = [1]
for i in range(1, len(colors)):
if colors[i] != colors_res[-1]:
colors_res.append(colors[i])
res_nb.append(1)
else:
res_nb[-1] += 1
return (colors_res, res_nb)
def reduplicate(colors: List[Color], repetitions: List[int]) -> List[Color]:
"""
Re-duplicates a list. Takes in a list of elements and a list of numbers of
repetitions. Concatetantes the repeted elements.
Requires both lists to have the same length
"""
res = []
for i in range(len(colors)):
for _ in range(repetitions[i]):
res.append(colors[i])
return res
class InterpType(Enum):
"""
Interpolation algorithm
"""
NEAREST = 1
LINEAR = 2
class Filling(Enum):
VOID = 1
EXTREMA = 2
GREATEST = 3
def blendLedBar(colors: List[Color],
blending: Optional[InterpType] = InterpType.NEAREST,
filling: Optional[Filling] = Filling.GREATEST,
void_color: Optional[Color] = Color("black")) -> List[Color]:
total_len = len(colors)
(deduped, rep_nb) = remove_duplicates(colors)
if len(deduped) > LedBarLen:
# After dedup, there are still too many colors. Only show the first ones
logging.warning(f"LED bar interpolation: More than {LedBarLen} colors. Dropping colors")
return deduped[:LedBarLen]
if len(colors) > LedBarLen:
# TODO: Try and dedup some colors to save space
return colors[:LedBarLen]
if blending == InterpType.NEAREST:
factor = LedBarLen // total_len
# First pass
for i in range(len(rep_nb)):
rep_nb[i] *= factor
gap = LedBarLen - total_len * factor
# TODO: Add GREATEST
# The idea is to first add a repetition to the already longest
# repetition to hurt the color ratio as little as possible
if gap == 0:
return reduplicate(deduped, rep_nb)
# If there is still
elif filling == Filling.VOID:
return (reduplicate(deduped, rep_nb) + ([void_color] * gap))
elif filling == Filling.EXTREMA:
bot_gap = gap // 2
top_gap = gap - bot_gap
return (([deduped[0]] * top_gap) + reduplicate(deduped, rep_nb) +
([deduped[-1]] * bot_gap))

View file

@ -21,6 +21,7 @@ in
ps.black ps.black
ps.pylint ps.pylint
ps.ipython ps.ipython
ps.python-lsp-server
])) ]))
pkgs.pyright pkgs.pyright
]; ];