Claude Code for colorsys: Python Color Space Conversion — Claude Skills 360 Blog
Blog / AI / Claude Code for colorsys: Python Color Space Conversion
AI

Claude Code for colorsys: Python Color Space Conversion

Published: October 15, 2028
Read time: 5 min read
By: Claude Skills 360

Python’s colorsys module converts between RGB, HLS (hue–lightness–saturation), HSV (hue–saturation–value), and YIQ color spaces. All values are normalized to the range [0.0, 1.0]. import colorsys. rgb_to_hsv: h, s, v = colorsys.rgb_to_hsv(r, g, b) — hue [0,1), saturation [0,1], value [0,1]. hsv_to_rgb: r, g, b = colorsys.hsv_to_rgb(h, s, v). rgb_to_hls: h, l, s = colorsys.rgb_to_hls(r, g, b) — note HLS order, not HSL. hls_to_rgb: r, g, b = colorsys.hls_to_rgb(h, l, s). rgb_to_yiq: y, i, q = colorsys.rgb_to_yiq(r, g, b) — Y=luma, I=in-phase, Q=quadrature; ranges vary. yiq_to_rgb: r, g, b = colorsys.yiq_to_rgb(y, i, q). All inputs/outputs are floats in [0,1] for RGB and HSV/HLS; YIQ ranges: Y [0,1], I [-0.596, 0.596], Q [-0.523, 0.523]. To work with (0–255) integer RGB: divide by 255 before passing, multiply by 255 after. Claude Code generates color palettes, gradient generators, hue-rotation tools, accessible contrast checkers, and image recolouring pipelines.

CLAUDE.md for colorsys

## colorsys Stack
- Stdlib: import colorsys
- RGB→HSV:  h, s, v = colorsys.rgb_to_hsv(r/255, g/255, b/255)
- HSV→RGB:  r, g, b = colorsys.hsv_to_rgb(h, s, v); R=int(r*255)
- RGB→HLS:  h, l, s = colorsys.rgb_to_hls(r/255, g/255, b/255)
- HLS→RGB:  r, g, b = colorsys.hls_to_rgb(h, l, s)
- Notation: all floats in [0,1]; colorsys uses HLS not HSL order

colorsys Color Pipeline

# app/colorsysutil.py — convert, palette, gradient, contrast, harmonies, recolor
from __future__ import annotations

import colorsys
import math
from dataclasses import dataclass
from typing import NamedTuple


# ─────────────────────────────────────────────────────────────────────────────
# 1. Color type and conversion helpers
# ─────────────────────────────────────────────────────────────────────────────

class RGB(NamedTuple):
    r: int    # 0–255
    g: int
    b: int

    def to_hex(self) -> str:
        return f"#{self.r:02X}{self.g:02X}{self.b:02X}"

    @classmethod
    def from_hex(cls, hex_color: str) -> "RGB":
        h = hex_color.lstrip("#")
        return cls(int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16))

    def to_float(self) -> tuple[float, float, float]:
        return self.r / 255, self.g / 255, self.b / 255

    @classmethod
    def from_float(cls, r: float, g: float, b: float) -> "RGB":
        return cls(round(r * 255), round(g * 255), round(b * 255))

    def __str__(self) -> str:
        return f"RGB({self.r}, {self.g}, {self.b}) {self.to_hex()}"


class HSV(NamedTuple):
    h: float    # 0.0–1.0  (multiply by 360 for degrees)
    s: float    # 0.0–1.0
    v: float    # 0.0–1.0

    def to_degrees(self) -> tuple[float, float, float]:
        return self.h * 360, self.s, self.v

    def __str__(self) -> str:
        return f"HSV({self.h*360:.1f}°, {self.s*100:.1f}%, {self.v*100:.1f}%)"


class HLS(NamedTuple):
    h: float    # 0.0–1.0
    l: float    # 0.0–1.0  (lightness)
    s: float    # 0.0–1.0  (saturation)

    def __str__(self) -> str:
        return f"HLS({self.h*360:.1f}°, {self.l*100:.1f}%, {self.s*100:.1f}%)"


def rgb_to_hsv(color: RGB) -> HSV:
    h, s, v = colorsys.rgb_to_hsv(*color.to_float())
    return HSV(h, s, v)


def hsv_to_rgb(color: HSV) -> RGB:
    return RGB.from_float(*colorsys.hsv_to_rgb(color.h, color.s, color.v))


def rgb_to_hls(color: RGB) -> HLS:
    h, l, s = colorsys.rgb_to_hls(*color.to_float())
    return HLS(h, l, s)


def hls_to_rgb(color: HLS) -> RGB:
    return RGB.from_float(*colorsys.hls_to_rgb(color.h, color.l, color.s))


def hex_to_hsv(hex_color: str) -> HSV:
    return rgb_to_hsv(RGB.from_hex(hex_color))


def hsv_to_hex(hsv: HSV) -> str:
    return hsv_to_rgb(hsv).to_hex()


# ─────────────────────────────────────────────────────────────────────────────
# 2. Color manipulation
# ─────────────────────────────────────────────────────────────────────────────

def rotate_hue(color: RGB, degrees: float) -> RGB:
    """
    Rotate the hue of a color by given degrees (0–360).

    Example:
        red = RGB(255, 0, 0)
        green = rotate_hue(red, 120)   # 120° rotation
    """
    hsv = rgb_to_hsv(color)
    new_h = (hsv.h + degrees / 360) % 1.0
    return hsv_to_rgb(HSV(new_h, hsv.s, hsv.v))


def adjust_lightness(color: RGB, delta: float) -> RGB:
    """
    Lighten (+) or darken (-) a color by changing HLS lightness.
    delta: fractional amount to add to lightness, e.g. 0.2 = 20% lighter.

    Example:
        darker = adjust_lightness(RGB(100, 200, 100), -0.2)
    """
    hls = rgb_to_hls(color)
    new_l = max(0.0, min(1.0, hls.l + delta))
    return hls_to_rgb(HLS(hls.h, new_l, hls.s))


def adjust_saturation(color: RGB, delta: float) -> RGB:
    """
    Increase (+) or decrease (-) saturation.

    Example:
        muted = adjust_saturation(RGB(200, 50, 50), -0.3)
    """
    hls = rgb_to_hls(color)
    new_s = max(0.0, min(1.0, hls.s + delta))
    return hls_to_rgb(HLS(hls.h, hls.l, new_s))


def grayscale(color: RGB) -> RGB:
    """Convert a color to its grayscale equivalent (perceptual luminance)."""
    y, _, _ = colorsys.rgb_to_yiq(*color.to_float())
    v = round(y * 255)
    return RGB(v, v, v)


# ─────────────────────────────────────────────────────────────────────────────
# 3. Palette and gradient generation
# ─────────────────────────────────────────────────────────────────────────────

def hue_palette(
    n: int,
    saturation: float = 0.8,
    value: float = 0.9,
    start_hue: float = 0.0,
) -> list[RGB]:
    """
    Generate n evenly-spaced hues at fixed saturation and value.

    Example:
        palette = hue_palette(6)
        for color in palette:
            print(color)
    """
    return [
        hsv_to_rgb(HSV((start_hue + i / n) % 1.0, saturation, value))
        for i in range(n)
    ]


def gradient(
    start: RGB,
    end: RGB,
    steps: int = 10,
    space: str = "rgb",
) -> list[RGB]:
    """
    Generate a smooth gradient between two colors in RGB or HSV space.

    space: "rgb" (linear RGB interpolation) or "hsv" (hue wheel interpolation).

    Example:
        g = gradient(RGB(255, 0, 0), RGB(0, 0, 255), steps=8, space="hsv")
    """
    result: list[RGB] = []
    for i in range(steps):
        t = i / max(steps - 1, 1)
        if space == "hsv":
            h1, s1, v1 = rgb_to_hsv(start)
            h2, s2, v2 = rgb_to_hsv(end)
            # Interpolate hue on the short arc
            dh = h2 - h1
            if dh > 0.5:  dh -= 1.0
            if dh < -0.5: dh += 1.0
            h = (h1 + t * dh) % 1.0
            s = s1 + t * (s2 - s1)
            v = v1 + t * (v2 - v1)
            result.append(hsv_to_rgb(HSV(h, s, v)))
        else:
            r = round(start.r + t * (end.r - start.r))
            g = round(start.g + t * (end.g - start.g))
            b = round(start.b + t * (end.b - start.b))
            result.append(RGB(r, g, b))
    return result


# ─────────────────────────────────────────────────────────────────────────────
# 4. Color harmony schemes
# ─────────────────────────────────────────────────────────────────────────────

def complementary(color: RGB) -> RGB:
    """Return the complementary color (180° hue rotation)."""
    return rotate_hue(color, 180)


def analogous(color: RGB, angle: float = 30) -> tuple[RGB, RGB]:
    """Return two analogous colors at ±angle degrees."""
    return rotate_hue(color, -angle), rotate_hue(color, angle)


def triadic(color: RGB) -> tuple[RGB, RGB]:
    """Return two colors forming a triadic harmony (120° apart)."""
    return rotate_hue(color, 120), rotate_hue(color, 240)


def split_complementary(color: RGB, angle: float = 150) -> tuple[RGB, RGB]:
    """Return split-complementary colors at ±angle from the complement."""
    return rotate_hue(color, angle), rotate_hue(color, 360 - angle)


def tetradic(color: RGB) -> tuple[RGB, RGB, RGB]:
    """Return three colors forming a tetradic (square) harmony."""
    return rotate_hue(color, 90), rotate_hue(color, 180), rotate_hue(color, 270)


# ─────────────────────────────────────────────────────────────────────────────
# 5. Contrast and accessibility
# ─────────────────────────────────────────────────────────────────────────────

def relative_luminance(color: RGB) -> float:
    """
    Compute WCAG 2.1 relative luminance for a color.
    Returns a value in [0.0, 1.0] where 0 = black, 1 = white.
    """
    def linearize(c: float) -> float:
        return c / 12.92 if c <= 0.04045 else ((c + 0.055) / 1.055) ** 2.4

    r, g, b = (linearize(x / 255) for x in (color.r, color.g, color.b))
    return 0.2126 * r + 0.7152 * g + 0.0722 * b


def contrast_ratio(a: RGB, b: RGB) -> float:
    """
    Compute WCAG 2.1 contrast ratio between two colors.
    Returns a value in [1, 21]. WCAG AA requires >= 4.5 for normal text.

    Example:
        ratio = contrast_ratio(RGB(0, 0, 0), RGB(255, 255, 255))
        print(ratio)   # 21.0
    """
    la = relative_luminance(a)
    lb = relative_luminance(b)
    light = max(la, lb)
    dark  = min(la, lb)
    return (light + 0.05) / (dark + 0.05)


def wcag_level(ratio: float) -> str:
    """Return WCAG compliance level: 'AAA', 'AA', 'AA Large', or 'Fail'."""
    if ratio >= 7.0:   return "AAA"
    if ratio >= 4.5:   return "AA"
    if ratio >= 3.0:   return "AA Large"
    return "Fail"


def best_text_color(background: RGB) -> RGB:
    """
    Return black or white whichever has better contrast on background.

    Example:
        text = best_text_color(RGB(0, 120, 200))   # white on dark blue
    """
    lum = relative_luminance(background)
    return RGB(0, 0, 0) if lum > 0.179 else RGB(255, 255, 255)


# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    print("=== colorsys demo ===")

    # ── conversions ────────────────────────────────────────────────────────────
    print("\n--- color space conversions ---")
    test_colors = [
        RGB(255, 0, 0),     # pure red
        RGB(0, 200, 100),   # teal
        RGB(128, 0, 128),   # purple
        RGB(255, 165, 0),   # orange (approximate)
    ]
    for color in test_colors:
        hsv = rgb_to_hsv(color)
        hls = rgb_to_hls(color)
        y, _, _ = colorsys.rgb_to_yiq(*color.to_float())
        print(f"  {color}{hsv}  {hls}  Y={y:.3f}")

    # ── round-trip ─────────────────────────────────────────────────────────────
    print("\n--- round-trip test ---")
    for color in test_colors:
        back = hsv_to_rgb(rgb_to_hsv(color))
        ok = abs(back.r - color.r) <= 1 and abs(back.g - color.g) <= 1 and abs(back.b - color.b) <= 1
        print(f"  {color.to_hex()} → HSV → {back.to_hex()}  ok={ok}")

    # ── hue rotation & adjustments ─────────────────────────────────────────────
    print("\n--- hue rotation ---")
    red = RGB(200, 50, 50)
    for deg in [0, 60, 120, 180, 240, 300]:
        rotated = rotate_hue(red, deg)
        print(f"  {deg:3d}°: {rotated}")

    # ── palette ────────────────────────────────────────────────────────────────
    print("\n--- hue_palette(8) ---")
    palette = hue_palette(8, saturation=0.75, value=0.9)
    print("  " + "  ".join(c.to_hex() for c in palette))

    # ── gradient ───────────────────────────────────────────────────────────────
    print("\n--- gradient (red → blue, 6 steps, HSV) ---")
    grad = gradient(RGB(220, 30, 30), RGB(30, 30, 220), steps=6, space="hsv")
    print("  " + "  ".join(c.to_hex() for c in grad))

    # ── harmonies ──────────────────────────────────────────────────────────────
    print("\n--- color harmonies for coral #FF6B6B ---")
    coral = RGB.from_hex("#FF6B6B")
    comp = complementary(coral)
    tri1, tri2 = triadic(coral)
    print(f"  original:      {coral}")
    print(f"  complementary: {comp}")
    print(f"  triadic:       {tri1}  {tri2}")

    # ── contrast / accessibility ───────────────────────────────────────────────
    print("\n--- contrast ratios ---")
    pairs = [
        (RGB(0, 0, 0),     RGB(255, 255, 255)),  # black on white
        (RGB(0, 120, 200), RGB(255, 255, 255)),  # blue on white
        (RGB(50, 50, 50),  RGB(80, 80, 80)),     # dark gray on slightly lighter gray
    ]
    for fg, bg in pairs:
        ratio = contrast_ratio(fg, bg)
        level = wcag_level(ratio)
        best  = best_text_color(bg)
        print(f"  {fg.to_hex()} on {bg.to_hex()}  ratio={ratio:.2f}  {level}  best_text={best.to_hex()}")

    # ── grayscale ──────────────────────────────────────────────────────────────
    print("\n--- grayscale ---")
    for c in test_colors:
        gray = grayscale(c)
        print(f"  {c.to_hex()}{gray.to_hex()}")

    print("\n=== done ===")

For the PIL.Image / Pillow alternative — PIL.ImageColor.getrgb(), PIL.ImageEnhance, and ImageFilter operate on entire images and support color modes including RGBA, L (grayscale), LAB, and HSV — use Pillow when you need to apply color transformations to images pixel by pixel, or when you need colorimetric accuracy for image editing; use colorsys when you need to convert programmatically generated colors for UI theming, data visualization palette generation, or accessibility contrast checking without the overhead of importing a full image processing library. For the colour-science / colormath alternative — colour (PyPI) supports over 100 color spaces including CIE XYZ, Lab, LCHab, OKLab, and spectral reflectance; colormath provides delta-E color difference and ICC profile transforms — use these when you need perceptually uniform color spaces (OKLab, CIELab) for distance-based matching, color difference metrics (ΔE2000), or professional color management workflows; use colorsys for lightweight HSV/HLS/YIQ conversions with zero dependencies. The Claude Skills 360 bundle includes colorsys skill sets covering RGB/HSV/HLS typed color classes with to_hex()/from_hex(), full bidirectional conversion helpers, rotate_hue()/adjust_lightness()/adjust_saturation()/grayscale() manipulation tools, hue_palette()/gradient() generators, complementary()/triadic()/analogous() harmony schemes, and relative_luminance()/contrast_ratio()/wcag_level()/best_text_color() accessibility tools. Start with the free tier to try color space conversion patterns and colorsys pipeline code generation.

Keep Reading

AI

Claude Code for email.contentmanager: Python Email Content Accessors

Read and write EmailMessage body content with Python's email.contentmanager module and Claude Code — email contentmanager ContentManager for the class that maps content types to get and set handler functions allowing EmailMessage to support get_content and set_content with type-specific behaviour, email contentmanager raw_data_manager for the ContentManager instance that handles raw bytes and str payloads without any conversion, email contentmanager content_manager for the standard ContentManager instance used by email.policy.default that intelligently handles text plain text html multipart and binary content types, email contentmanager get_content_text for the handler that returns the decoded text payload of a text-star message part as a str, email contentmanager get_content_binary for the handler that returns the raw decoded bytes payload of a non-text message part, email contentmanager get_data_manager for the get-handler lookup used by EmailMessage get_content to find the right reader function for the content type, email contentmanager set_content text for the handler that creates and sets a text part correctly choosing charset and transfer encoding, email contentmanager set_content bytes for the handler that creates and sets a binary part with base64 encoding and optional filename Content-Disposition, email contentmanager EmailMessage get_content for the method that reads the message body using the registered content manager handlers, email contentmanager EmailMessage set_content for the method that sets the message body and MIME headers in one call, email contentmanager EmailMessage make_alternative make_mixed make_related for the methods that convert a simple message into a multipart container, email contentmanager EmailMessage add_attachment for the method that attaches a file or bytes to a multipart message, and email contentmanager integration with email.message and email.policy and email.mime and io for building high-level email readers attachment extractors text body accessors HTML readers and policy-aware MIME construction pipelines.

5 min read Feb 12, 2029
AI

Claude Code for email.charset: Python Email Charset Encoding

Control header and body encoding for international email with Python's email.charset module and Claude Code — email charset Charset for the class that wraps a character set name with the encoding rules for header encoding and body encoding describing how to encode text for that charset in email messages, email charset Charset header_encoding for the attribute specifying whether headers using this charset should use QP quoted-printable encoding BASE64 encoding or no encoding, email charset Charset body_encoding for the attribute specifying the Content-Transfer-Encoding to use for message bodies in this charset such as QP or BASE64, email charset Charset output_codec for the attribute giving the Python codec name used to encode the string to bytes for the wire format, email charset Charset input_codec for the attribute giving the Python codec name used to decode incoming bytes to str, email charset Charset get_output_charset for returning the output charset name, email charset Charset header_encode for encoding a header string using the charset's header_encoding method, email charset Charset body_encode for encoding body content using the charset's body_encoding, email charset Charset convert for converting a string from the input_codec to the output_codec, email charset add_charset for registering a new charset with custom encoding rules in the global charset registry, email charset add_alias for adding an alias name that maps to an existing registered charset, email charset add_codec for registering a codec name mapping for use by the charset machinery, and email charset integration with email.message and email.mime and email.policy and email.encoders for building international email senders non-ASCII header encoders Content-Transfer-Encoding selectors charset-aware message constructors and MIME encoding pipelines.

5 min read Feb 11, 2029
AI

Claude Code for email.utils: Python Email Address and Header Utilities

Parse and format RFC 2822 email addresses and dates with Python's email.utils module and Claude Code — email utils parseaddr for splitting a display-name plus angle-bracket address string into a realname and email address tuple, email utils formataddr for combining a realname and address string into a properly quoted RFC 2822 address with angle brackets, email utils getaddresses for parsing a list of raw address header strings each potentially containing multiple comma-separated addresses into a list of realname address tuples, email utils parsedate for parsing an RFC 2822 date string into a nine-tuple compatible with time.mktime, email utils parsedate_tz for parsing an RFC 2822 date string into a ten-tuple that includes the UTC offset timezone in seconds, email utils parsedate_to_datetime for parsing an RFC 2822 date string into an aware datetime object with timezone, email utils formatdate for formatting a POSIX timestamp or the current time as an RFC 2822 date string with optional usegmt and localtime flags, email utils format_datetime for formatting a datetime object as an RFC 2822 date string, email utils make_msgid for generating a globally unique Message-ID string with optional idstring and domain components, email utils decode_rfc2231 for decoding an RFC 2231 encoded parameter value into a tuple of charset language and value, email utils encode_rfc2231 for encoding a string as an RFC 2231 encoded parameter value, email utils collapse_rfc2231_value for collapsing a decoded RFC 2231 tuple to a Unicode string, and email utils integration with email.message and email.headerregistry and datetime and time for building address parsers date formatters message-id generators header extractors and RFC-compliant email construction utilities.

5 min read Feb 10, 2029

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free