Pillow/Tests/test_format_hsv.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

153 lines
3.6 KiB
Python
Raw Normal View History

from __future__ import annotations
2024-01-20 14:23:03 +03:00
import colorsys
import itertools
2024-02-17 07:00:38 +03:00
from typing import Callable
2014-07-22 09:36:40 +04:00
from PIL import Image
2020-02-25 12:57:27 +03:00
from .helper import assert_image_similar, hopper
2014-08-28 15:44:19 +04:00
2014-07-22 09:36:40 +04:00
2024-02-17 07:00:38 +03:00
def int_to_float(i: int) -> float:
2020-02-25 12:57:27 +03:00
return i / 255
2014-08-28 15:44:19 +04:00
2024-02-17 07:00:38 +03:00
def tuple_to_ints(tp: tuple[float, float, float]) -> tuple[int, int, int]:
2020-02-25 12:57:27 +03:00
x, y, z = tp
return int(x * 255.0), int(y * 255.0), int(z * 255.0)
2014-07-22 09:36:40 +04:00
2014-08-28 15:44:19 +04:00
def test_sanity() -> None:
2020-02-25 12:57:27 +03:00
Image.new("HSV", (100, 100))
2025-02-15 15:23:59 +03:00
def linear_gradient() -> Image.Image:
im = Image.linear_gradient(mode="L")
im90 = im.rotate(90)
2020-02-25 12:57:27 +03:00
2025-02-15 15:23:59 +03:00
(px, h) = im.size
2020-02-25 12:57:27 +03:00
r = Image.new("L", (px * 3, h))
g = r.copy()
b = r.copy()
2025-02-15 15:23:59 +03:00
r.paste(im, (0, 0))
r.paste(im90, (px, 0))
2020-02-25 12:57:27 +03:00
2025-02-15 15:23:59 +03:00
g.paste(im90, (0, 0))
g.paste(im, (2 * px, 0))
2020-02-25 12:57:27 +03:00
2025-02-15 15:23:59 +03:00
b.paste(im, (px, 0))
b.paste(im90, (2 * px, 0))
2020-02-25 12:57:27 +03:00
2025-02-15 15:23:59 +03:00
return Image.merge("RGB", (r, g, b))
2020-02-25 12:57:27 +03:00
2024-02-17 07:00:38 +03:00
def to_xxx_colorsys(
im: Image.Image,
func: Callable[[float, float, float], tuple[float, float, float]],
mode: str,
) -> Image.Image:
2020-02-25 12:57:27 +03:00
# convert the hard way using the library colorsys routines.
(r, g, b) = im.split()
conv_func = int_to_float
converted = [
tuple_to_ints(func(conv_func(_r), conv_func(_g), conv_func(_b)))
for (_r, _g, _b) in itertools.zip_longest(r.tobytes(), g.tobytes(), b.tobytes())
]
new_bytes = b"".join(
bytes(chr(h) + chr(s) + chr(v), "latin-1") for (h, s, v) in converted
)
hsv = Image.frombytes(mode, r.size, new_bytes)
return hsv
2024-02-17 07:00:38 +03:00
def to_hsv_colorsys(im: Image.Image) -> Image.Image:
2020-02-25 12:57:27 +03:00
return to_xxx_colorsys(im, colorsys.rgb_to_hsv, "HSV")
2024-02-17 07:00:38 +03:00
def to_rgb_colorsys(im: Image.Image) -> Image.Image:
2020-02-25 12:57:27 +03:00
return to_xxx_colorsys(im, colorsys.hsv_to_rgb, "RGB")
2025-02-15 15:23:59 +03:00
def test_linear_gradient() -> None:
src = linear_gradient().resize((3 * 32, 32), Image.Resampling.BILINEAR)
2020-02-25 12:57:27 +03:00
im = src.convert("HSV")
comparable = to_hsv_colorsys(src)
assert_image_similar(
im.getchannel(0), comparable.getchannel(0), 1, "Hue conversion is wrong"
)
assert_image_similar(
2020-08-31 00:37:17 +03:00
im.getchannel(1),
comparable.getchannel(1),
1,
"Saturation conversion is wrong",
2020-02-25 12:57:27 +03:00
)
assert_image_similar(
im.getchannel(2), comparable.getchannel(2), 1, "Value conversion is wrong"
)
comparable = src
im = im.convert("RGB")
assert_image_similar(
im.getchannel(0), comparable.getchannel(0), 3, "R conversion is wrong"
)
assert_image_similar(
im.getchannel(1), comparable.getchannel(1), 3, "G conversion is wrong"
)
assert_image_similar(
im.getchannel(2), comparable.getchannel(2), 3, "B conversion is wrong"
)
def test_convert() -> None:
2020-02-25 12:57:27 +03:00
im = hopper("RGB").convert("HSV")
comparable = to_hsv_colorsys(hopper("RGB"))
assert_image_similar(
im.getchannel(0), comparable.getchannel(0), 1, "Hue conversion is wrong"
)
assert_image_similar(
2020-08-31 00:37:17 +03:00
im.getchannel(1),
comparable.getchannel(1),
1,
"Saturation conversion is wrong",
2020-02-25 12:57:27 +03:00
)
assert_image_similar(
im.getchannel(2), comparable.getchannel(2), 1, "Value conversion is wrong"
)
def test_hsv_to_rgb() -> None:
2020-02-25 12:57:27 +03:00
comparable = to_hsv_colorsys(hopper("RGB"))
converted = comparable.convert("RGB")
comparable = to_rgb_colorsys(comparable)
assert_image_similar(
2020-08-31 00:37:17 +03:00
converted.getchannel(0),
comparable.getchannel(0),
3,
"R conversion is wrong",
2020-02-25 12:57:27 +03:00
)
assert_image_similar(
2020-08-31 00:37:17 +03:00
converted.getchannel(1),
comparable.getchannel(1),
3,
"G conversion is wrong",
2020-02-25 12:57:27 +03:00
)
assert_image_similar(
2020-08-31 00:37:17 +03:00
converted.getchannel(2),
comparable.getchannel(2),
3,
"B conversion is wrong",
2020-02-25 12:57:27 +03:00
)