pybeamshow/util/color.py

142 lines
3.5 KiB
Python
Raw Normal View History

2023-02-22 22:55:11 +01:00
from dataclasses import dataclass
import random
2023-02-24 18:21:21 +01:00
from typing import Generator, Literal, Sequence, Tuple
2023-02-22 22:55:11 +01:00
import pygame as pg
2023-02-23 02:10:50 +01:00
ColorGenerator = Generator[pg.Color, None, None]
2023-02-22 22:55:11 +01:00
def copy_color(source: pg.Color) -> pg.Color:
return pg.Color(source.r, source.g, source.b, source.a)
@dataclass(frozen=True, slots=True)
class Colors:
Black = pg.Color(0, 0, 0)
White = pg.Color(255, 255, 255)
Red = pg.Color(255, 0, 0)
Green = pg.Color(0, 255, 0)
Blue = pg.Color(0, 0, 255)
Cyan = pg.Color(0, 255, 255)
Yellow = pg.Color(255, 255, 0)
Magenta = pg.Color(255, 0, 255)
2023-02-24 18:21:21 +01:00
def color_static(color: pg.Color) -> ColorGenerator:
while True:
yield color
def color_wheel(hue: int = 0, increase: int = 1, repeat: int = 1) -> ColorGenerator:
2023-02-22 22:55:11 +01:00
color = copy_color(Colors.Red)
h, s, l, a = color.hsla
2023-02-23 01:56:05 +01:00
h = hue % 360
2023-02-22 22:55:11 +01:00
while True:
color.hsla = h, s, l, a
2023-02-24 18:21:21 +01:00
for _ in range(repeat):
yield color
2023-02-22 22:55:11 +01:00
h = (h + increase) % 360
2023-02-23 02:10:50 +01:00
def color_randomize() -> ColorGenerator:
2023-02-22 22:55:11 +01:00
color = copy_color(Colors.Red)
h, s, l, a = color.hsla
color.hsla = random.randrange(0, 360 // 5) * 5, s, l, a
while True:
yield color
color.hsla = random.randrange(0, 360 // 5) * 5, s, l, a
2023-02-23 02:10:50 +01:00
def color_fadeout(initial_color: pg.Color, fade_speed: float) -> ColorGenerator:
2023-02-22 22:55:11 +01:00
color = copy_color(initial_color)
h, s, l, a = color.hsla
l_float = float(l)
while True:
yield color
color.hsla = h, s, int(l_float), a
l_float -= fade_speed
if l_float < 0:
l_float = 0
def color_fade(
initial_color: pg.Color, end_color: pg.Color, duration: int
2023-02-23 02:10:50 +01:00
) -> ColorGenerator:
2023-02-22 22:55:11 +01:00
color = copy_color(initial_color)
h, s, l, a = color.hsla
h2, s2, l2, a2 = end_color.hsla
h_inc = (h2 - h) / duration
s_inc = (s2 - s) / duration
l_inc = (l2 - l) / duration
a_inc = (a2 - a) / duration
h_f = float(h)
s_f = float(s)
l_f = float(l)
a_f = float(a)
while True:
yield color
color.hsla = int(h_f), int(s_f), int(l_f), int(a_f)
if h_f < h2:
h_f += h_inc
if s_f < s2:
s_f += s_inc
if l_f < l2:
l_f += l_inc
if a_f < a2:
a_f += a_inc
2023-02-23 02:10:50 +01:00
def color_cycle(seq: Sequence[pg.Color]) -> ColorGenerator:
2023-02-23 01:56:05 +01:00
it = iter(seq)
while True:
yield next(it)
2023-02-23 02:10:50 +01:00
def color_shuffle(seq: Sequence[pg.Color]) -> ColorGenerator:
2023-02-23 01:56:05 +01:00
while True:
yield random.choice(seq)
2023-02-22 22:55:11 +01:00
def color_darken(color: pg.Color, factor: float) -> pg.Color:
h, s, l, a = color.hsla
new_color = pg.Color(0, 0, 0, 255)
new_color.hsla = h, s, l * factor, a
return new_color
2023-02-24 18:21:21 +01:00
def color_strobe(
color: ColorGenerator,
rate: Tuple[int, int],
phase: int = 0,
flash_color: ColorGenerator = color_static(Colors.Black),
) -> ColorGenerator:
counter = phase
while True:
if counter < rate[0]:
yield from flash_color
else:
yield from color
counter = (counter + 1) % rate[1]
2023-02-22 22:55:11 +01:00
def rainbow_surface(
image: pg.Surface,
orientation: Literal["h", "v"] = "h",
hue: int = 0,
increase: int = 1,
):
wheel = color_wheel(hue, increase)
if orientation == "h":
h = image.get_height()
2023-02-24 18:21:21 +01:00
for x in range(image.get_width() // 5):
pg.draw.line(image, next(wheel), (x * 5, 0), (x * 5, h), width=5)
2023-02-22 22:55:11 +01:00
elif orientation == "v":
w = image.get_width()
2023-02-24 18:21:21 +01:00
for y in range(image.get_height() // 5):
pg.draw.line(image, next(wheel), (0, y * 5), (w, y * 5), width=5)