color_tools.conversions
Color space conversion functions.
Handles conversions between: - sRGB (0-255) ↔ XYZ ↔ LAB ↔ LCH - sRGB ↔ HSL (various formats) - Gamma correction (sRGB companding)
All conversions use D65 illuminant and proper color science math.
Example
>>> from color_tools import rgb_to_lab, lab_to_lch, rgb_to_hsl
>>>
>>> # Convert vibrant orange from web color
>>> orange_rgb = (255, 128, 0)
>>>
>>> # To LAB for perceptual analysis
>>> lab = rgb_to_lab(orange_rgb)
>>> print(f"LAB: L={lab[0]:.1f} a={lab[1]:.1f} b={lab[2]:.1f}")
LAB: L=67.8 a=43.4 b=78.0
>>>
>>> # To LCH for hue/chroma work
>>> lch = lab_to_lch(lab)
>>> print(f"LCH: L={lch[0]:.1f} C={lch[1]:.1f} H={lch[2]:.1f}°")
LCH: L=67.8 C=88.6 H=60.9°
>>>
>>> # To HSL for web design
>>> hsl = rgb_to_hsl(orange_rgb)
>>> print(f"HSL: {hsl[0]:.0f}° {hsl[1]:.0f}% {hsl[2]:.0f}%")
HSL: 30° 100% 50%
- color_tools.conversions.rgb_to_xyz(rgb)[source]
Convert sRGB (0-255) to CIE XYZ using D65 illuminant.
XYZ is a device-independent color space that represents how the human eye responds to light. It’s the bridge between RGB and LAB.
- color_tools.conversions.xyz_to_lab(xyz)[source]
Convert CIE XYZ to L*a*b* using D65 illuminant.
LAB is perceptually uniform - equal distances in LAB space correspond to roughly equal perceived color differences. Perfect for color matching!
L*: Lightness (0=black, 100=white)
a*: Green←→Red axis
b*: Blue←→Yellow axis
- color_tools.conversions.rgb_to_lab(rgb)[source]
Convert sRGB (0-255) to CIE L*a*b*.
This is the main conversion you’ll use for color matching! Goes RGB → XYZ → LAB in one shot.
- color_tools.conversions.lab_to_xyz(lab)[source]
Convert CIE L*a*b* to XYZ using D65 illuminant.
Reverses the LAB → XYZ transformation.
- color_tools.conversions.lab_to_lch(lab)[source]
Convert L*a*b* to L*C*h° (cylindrical LAB).
LCH is more intuitive than LAB for certain operations: - L* (Lightness): Same as LAB, 0-100 - C* (Chroma): Color intensity/saturation, sqrt(a² + b²) - h° (Hue): Hue angle in degrees, 0-360
- color_tools.conversions.lch_to_rgb(lch, clamp=True)[source]
Convert L*C*h° directly to sRGB (0-255).
- color_tools.conversions.rgb_to_hsl(rgb)[source]
Convert RGB (0-255) to HSL (H: 0-360, S: 0-100, L: 0-100).
This is the standard HSL representation: - H: Hue in degrees (0° = red, 120° = green, 240° = blue) - S: Saturation as percentage (0% = gray, 100% = pure color) - L: Lightness as percentage (0% = black, 50% = pure color, 100% = white)
- color_tools.conversions.rgb_to_winhsl240(rgb)[source]
Convert RGB (0-255) to winHSL240 — the Windows OS variant.
Used by Windows applications including Paint, WordPad, and Win32 GDI APIs. Components are scaled to:
H: 0–239 (240 = 0° again, so the valid range stops at 239)
S: 0–240
L: 0–240
This is subtly different from the range you might expect: hue stops at 239, not 240, because 240 wraps back to 0° (red) and would be a duplicate.
- color_tools.conversions.rgb_to_winhsl255(rgb)[source]
Convert RGB (0-255) to winHSL255 — the Microsoft Office variant.
Used by Microsoft Office applications (Word, Excel, PowerPoint colour pickers). Components are scaled to:
H: 0–254 (255 = 0° again, so the valid range stops at 254)
S: 0–255
L: 0–255
Like winHSL240, the hue ceiling is one less than the scale factor because the maximum would alias back to 0° (red).
- color_tools.conversions.rgb_to_winhsl(rgb)
Convert RGB (0-255) to winHSL240 — the Windows OS variant.
Used by Windows applications including Paint, WordPad, and Win32 GDI APIs. Components are scaled to:
H: 0–239 (240 = 0° again, so the valid range stops at 239)
S: 0–240
L: 0–240
This is subtly different from the range you might expect: hue stops at 239, not 240, because 240 wraps back to 0° (red) and would be a duplicate.
- color_tools.conversions.hsl_to_rgb(hsl)[source]
Convert HSL (H: 0-360, S: 0-100, L: 0-100) to RGB (0-255).
This is the inverse of rgb_to_hsl(), converting from the standard HSL representation back to 8-bit RGB values.
- color_tools.conversions.rgb_to_cmy(rgb)[source]
Convert RGB (0-255) to CMY (C: 0-100, M: 0-100, Y: 0-100).
CMY is the simple subtractive complement of RGB. Each channel is the percentage of ink needed to absorb the corresponding RGB primary:
C = 100 × (1 - R/255) (cyan absorbs red)
M = 100 × (1 - G/255) (magenta absorbs green)
Y = 100 × (1 - B/255) (yellow absorbs blue)
Unlike CMYK, CMY has no black channel; pure black requires C=M=Y=100. CMY is useful for simple subtractive-model analysis and as the intermediate step when computing CMYK.
- Parameters:
rgb (
Tuple[int,int,int]) – RGB tuple (0-255 for each component)- Return type:
- Returns:
CMY tuple (Cyan 0-100%, Magenta 0-100%, Yellow 0-100%)
Example
>>> rgb_to_cmy((255, 0, 0)) # pure red (0.0, 100.0, 100.0) >>> rgb_to_cmy((0, 0, 0)) # black (100.0, 100.0, 100.0) >>> rgb_to_cmy((255, 255, 255)) # white (0.0, 0.0, 0.0)
- color_tools.conversions.cmy_to_rgb(cmy)[source]
Convert CMY (C: 0-100, M: 0-100, Y: 0-100) to RGB (0-255).
Inverts the CMY model: each RGB channel is the fraction of light not absorbed by the corresponding ink:
R = 255 × (1 - C/100)
G = 255 × (1 - M/100)
B = 255 × (1 - Y/100)
- Parameters:
cmy (
Tuple[float,float,float]) – CMY tuple (Cyan 0-100%, Magenta 0-100%, Yellow 0-100%)- Return type:
- Returns:
RGB tuple (0-255 for each component)
Example
>>> cmy_to_rgb((0.0, 100.0, 100.0)) # cyan=0, full magenta+yellow → red (255, 0, 0) >>> cmy_to_rgb((100.0, 100.0, 100.0)) # full ink → black (0, 0, 0) >>> cmy_to_rgb((0.0, 0.0, 0.0)) # no ink → white (255, 255, 255)
- color_tools.conversions.rgb_to_cmyk(rgb)[source]
Convert RGB (0-255) to CMYK (C: 0-100, M: 0-100, Y: 0-100, K: 0-100).
CMYK is the standard four-channel subtractive color model used in print. The black (K) channel is extracted from the CMY values so that dark colors use less ink overall and produce a richer, more accurate black:
K = 100 × (1 - max(R, G, B) / 255)
C = 100 × (1 - R/255 - K/100) / (1 - K/100) [0 if K = 100]
M = 100 × (1 - G/255 - K/100) / (1 - K/100)
Y = 100 × (1 - B/255 - K/100) / (1 - K/100)
Pure black (0, 0, 0) maps to C=0, M=0, Y=0, K=100 rather than C=100, M=100, Y=100, K=0, which is the key advantage over plain CMY.
- Parameters:
rgb (
Tuple[int,int,int]) – RGB tuple (0-255 for each component)- Return type:
- Returns:
CMYK tuple (Cyan 0-100%, Magenta 0-100%, Yellow 0-100%, Key/Black 0-100%)
Example
>>> rgb_to_cmyk((255, 0, 0)) # pure red (0.0, 100.0, 100.0, 0.0) >>> rgb_to_cmyk((0, 0, 0)) # black → K=100, C=M=Y=0 (0.0, 0.0, 0.0, 100.0) >>> rgb_to_cmyk((255, 255, 255)) # white → all zero (0.0, 0.0, 0.0, 0.0) >>> rgb_to_cmyk((128, 64, 192)) (33.3333, 66.6667, 0.0, 24.7059)
- color_tools.conversions.cmyk_to_rgb(cmyk)[source]
Convert CMYK (C: 0-100, M: 0-100, Y: 0-100, K: 0-100) to RGB (0-255).
Inverts the CMYK model. The K channel reduces the effective lightness before the CMY channels are applied:
R = 255 × (1 - C/100) × (1 - K/100)
G = 255 × (1 - M/100) × (1 - K/100)
B = 255 × (1 - Y/100) × (1 - K/100)
- Parameters:
cmyk (
Tuple[float,float,float,float]) – CMYK tuple (Cyan 0-100%, Magenta 0-100%, Yellow 0-100%, Key/Black 0-100%)- Return type:
- Returns:
RGB tuple (0-255 for each component)
Example
>>> cmyk_to_rgb((0.0, 100.0, 100.0, 0.0)) # red (255, 0, 0) >>> cmyk_to_rgb((0.0, 0.0, 0.0, 100.0)) # black via K (0, 0, 0) >>> cmyk_to_rgb((0.0, 0.0, 0.0, 0.0)) # white (255, 255, 255)