Source code for porescene.color.conversion

# SPDX-License-Identifier: GPL-3.0-only
# Copyright (C) 2026 Felix Faber /
# Otto von Guericke University Magdeburg, Thermal Process Engineering

"""
Color Space Conversion
----------------------

Some functions to convert color tuples between following color spaces:

- HEX
- Standard RGB
- Normalized standard RGB
- Normalized linear RGB
"""

from typing import overload

from ._types import (
    ColorTupleFloat3,
    ColorTupleFloat4,
    ColorTupleInt3,
    ColorTupleInt3Float1,
)


[docs] def hex2rgb(h: str) -> ColorTupleInt3 | ColorTupleInt3Float1: """ Convert HEX into sRGB. Returns a three-element or four-element ``tuple`` depending on whether or not a ``alpha`` value is given. Parameters ---------- h The color value in HEX notation. The function supports following forms of HEX string always with and without a prefixed hash (#): * #RGB * #RGBA * #RRGGBB * #RRGGBBAA """ if h.startswith("#"): h = h.strip("#") if len(h) in [3, 4]: he = h[0] + h[0] + h[1] + h[1] + h[2] + h[2] if len(h) == 4: he += h[3] + h[3] else: he = h r = int(he[0:2], 16) g = int(he[2:4], 16) b = int(he[4:6], 16) if len(he) == 8: a = int(he[6:8], 16) / 255 rgb = (r, g, b, a) else: rgb = (r, g, b) return rgb
[docs] def rgb2hex(r: int, g: int, b: int, a: float | None = None) -> str: """ Convert sRGB channels into a hex color string. Returns a ``#RRGGBB`` string, or ``#RRGGBBAA`` when ``a`` [0-1] is given. Parameters ---------- r : int Red color channel [0 - 255] g : int Green color channel [0 - 255] b : int Blue color channel [0 - 255] a : float | None, optional Alpha color channel [0 - 1], by default None Returns ------- str Hex color string """ r, g, b = (max(0, min(255, int(round(v)))) for v in (r, g, b)) if a is None: return "#%02X%02X%02X" % (r, g, b) alpha = max(0, min(255, round(a * 255))) return "#%02X%02X%02X%02X" % (r, g, b, alpha)
@overload def rgb2nrgb(r: int, g: int, b: int, a: None = None) -> ColorTupleFloat3: ... @overload def rgb2nrgb(r: int, g: int, b: int, a: float) -> ColorTupleFloat4: ...
[docs] def rgb2nrgb( r: int, g: int, b: int, a: float | None = None ) -> ColorTupleFloat3 | ColorTupleFloat4: """ Converts sRGB from range [0, 255] into range [0, 1]. """ rn = float(r) / 255 gn = float(g) / 255 bn = float(b) / 255 if a is None: nrgb = (rn, gn, bn) else: nrgb = (rn, gn, bn, a) return nrgb
@overload def nrgb2rgb(r: float, g: float, b: float, a: None = None) -> ColorTupleInt3: ... @overload def nrgb2rgb(r: float, g: float, b: float, a: float) -> ColorTupleInt3Float1: ...
[docs] def nrgb2rgb( r: float, g: float, b: float, a: float | None = None, ) -> ColorTupleInt3 | ColorTupleInt3Float1: """ Converts sRGB from range [0, 1] into range [0, 255]. """ r = int(round(r * 255)) g = int(round(g * 255)) b = int(round(b * 255)) if a is None: rgb = r, g, b else: rgb = r, g, b, a return rgb
@overload def nrgb2lnrgb(r: float, g: float, b: float, a: None = None) -> ColorTupleFloat3: ... @overload def nrgb2lnrgb(r: float, g: float, b: float, a: float) -> ColorTupleFloat4: ...
[docs] def nrgb2lnrgb( r: float, g: float, b: float, a: float | None = None, ) -> ColorTupleFloat3 | ColorTupleFloat4: """ Converts normalized sRGB into normalized linear RGB. """ r = r / 12.92 if r < 0.04045 else ((r + 0.055) / 1.055) ** 2.4 g = g / 12.92 if g < 0.04045 else ((g + 0.055) / 1.055) ** 2.4 b = b / 12.92 if b < 0.04045 else ((b + 0.055) / 1.055) ** 2.4 if a is None: lnrgb = (r, g, b) else: lnrgb = (r, g, b, a) return lnrgb
@overload def lnrgb2nrgb(r: float, g: float, b: float, a: None = None) -> ColorTupleFloat3: ... @overload def lnrgb2nrgb(r: float, g: float, b: float, a: float) -> ColorTupleFloat4: ...
[docs] def lnrgb2nrgb( r: float, g: float, b: float, a: float | None = None, ) -> ColorTupleFloat3 | ColorTupleFloat4: """ Converts normalized linear RGB into sRGB in range [0, 1]. """ r = r * 12.92 if r < 0.04045 / 12.92 else r ** (1 / 2.4) * 1.055 - 0.055 g = g * 12.92 if g < 0.04045 / 12.92 else g ** (1 / 2.4) * 1.055 - 0.055 b = b * 12.92 if b < 0.04045 / 12.92 else b ** (1 / 2.4) * 1.055 - 0.055 if a is None: nrgb = (r, g, b) else: nrgb = (r, g, b, a) return nrgb