Skip to main content

color.js

Color space conversion and transformation utilities for image colorization

Pathjs/color.js
LanguageJavaScript
Lines557
Sourcejs/color.js
at 406d3e423

Read this when Use this page when tracing browser-side behavior, runtime state, event handling, popups, or UI code around color.

Overview

color.js provides a comprehensive color manipulation library supporting conversions between eight color spaces (RGB, HSV, HSL, XYZ, L*a*b*, YCoCg, Oklab, Oklch) and a "colorize" transform that recolors individual color values while preserving (remapped) lightness.

The primary use case is the colorize transform, which takes an input color value and adopts a reference color's hue/chroma while remapping the input's lightness. Callers use it to theme inline SVG images: rewrite.js (enableLinkIconColor) colorizes link icons on hover, and special-occasions.js (colorizeElements) colorizes UI elements (list bullets, horizontal-rule icons) by rewriting color codes inside inline-SVG CSS variables. The module defaults to Oklch color space for colorization because it provides perceptually uniform hue manipulation with good gamut coverage.

The architecture follows a hub-and-spoke pattern: RGB serves as the interchange format, with XYZ as an intermediate step for perceptual color spaces (Lab, Oklab). All conversions route through RGB, so converting Lab→HSL goes Lab→XYZ→RGB→HSL.


Public API

Color.processColorValue(colorString, transforms, options) → string

Main entry point. Applies a sequence of color transforms to an input color string.

Color.processColorValue("#808080", [
{ type: Color.ColorTransform.COLORIZE, referenceColor: "#3366cc" }
]);
// → "#4a6aa3" (gray tinted blue)

Parameters:

  • colorString: Hex (#rgb or #rrggbb) or rgb()/rgba() format
  • transforms: Array of transform objects with type, referenceColor, optional colorSpace
  • options.output: "hex" or "rgba" (defaults to match input format)

Called by: rewrite.js, special-occasions.js Calls: rgbaFromString, fromRGB, rgbFrom, colorValueTransform_colorize


Color.fromRGB(rgb, targetColorSpace) → object

Converts RGB to any supported color space.

Called by: processColorValue, external callers needing color space conversion Calls: hsvFromRGB, hslFromRGB, labFromRGB, yccFromRGB, oklabFromRGB, oklchFromRGB


Color.rgbFrom(color, sourceColorSpace) → {red, green, blue}

Converts from any supported color space back to RGB.

Called by: processColorValue, external callers Calls: rgbFromHSV, rgbFromHSL, rgbFromLab, rgbFromYCC, rgbFromOklab, rgbFromOklch


Color.rgbaFromString(colorString) → {red, green, blue, alpha}

Parses hex or rgba() color strings into component values (0-255 for RGB; alpha is parsed with parseInt, so fractional values are truncated).

Color.rgbaFromString("#ff8000")  // → {red: 255, green: 128, blue: 0, alpha: 1.0}
Color.rgbaFromString("rgba(255, 128, 0, 0.5)") // → {red: 255, green: 128, blue: 0, alpha: 0}

Color.hexStringFromRGB(rgb) → string

Converts RGB object to #rrggbb hex string.


Color.rgbaStringFromRGBA(rgba) → string

Converts RGBA object to rgba(r, g, b, a) string with padded values.


Internal Architecture

Color Space Enum

Color.ColorSpace = {
RGB, HSV, HSL, XYZ, Lab, YCC, Oklab, Oklch
}

Conversion Graph

                    ┌─────┐
┌─────────┤ RGB ├─────────┐
│ └──┬──┘ │
▼ │ ▼
┌─────┐ │ ┌─────┐
│ HSV │ │ │ HSL │
└─────┘ │ └─────┘

┌────────────┼────────────┐
│ │ │
▼ ▼ ▼
┌─────┐ ┌─────┐ ┌─────┐
│ YCC │ │ XYZ │ │ XYZ │
└─────┘ └──┬──┘ └──┬──┘
│ │
▼ ▼
┌─────┐ ┌───────┐
│ Lab │ │ Oklab │
└─────┘ └───┬───┘


┌───────┐
│ Oklch │
└───────┘

Transform Pipeline

  1. Parse input string → RGBA
  2. Save original alpha
  3. For each transform:
    • Convert to working color space
    • Apply transform
    • Convert back to RGB
  4. Restore alpha
  5. Format output string

Key Patterns

Lightness Remapping in Colorize

The colorize transform doesn't simply copy lightness—it remaps it to avoid crushing blacks or blowing out whites:

let baseLightness = Math.max(Math.min(referenceColor.L, maxBaseValue), minBaseValue);
color.L = baseLightness + (1.0 - baseLightness) * color.L;

This maps the input lightness [0,1] to [baseLightness, 1], ensuring even dark input colors get lifted to maintain the reference color's character.

Oklch Chroma Boosting

Oklch mode includes saturation enhancement to compensate for desaturation during lightness remapping:

let maxChroma = Color.oklchFromRGB(Color.rgbFromOklch({ L: color.L, C: 1.0, h: color.h })).C;
color.C += chromaBoostFactor * (maxChroma - color.C) * (1.0 - color.L * antiClusteringFactor);

The antiClusteringFactor reduces boosting for lighter colors to prevent them from clustering at maximum saturation.

Gamut Correction

After chroma boosting, colors may fall outside the sRGB gamut. The Oklch path includes gamut mapping:

let maxLightness = Color.oklchFromRGB(Color.rgbFromOklch({ L: 1.0, C: color.C, h: color.h })).L;
if (color.L > maxLightness)
color.C *= (1.0 - color.L) / (1.0 - maxLightness);

This reduces chroma for overly-bright colors to keep them representable.


Configuration

Color.ColorTransformSettings

Per-color-space tuning parameters for the colorize transform:

Color SpaceParameterDefaultEffect
OklchminBaseValue0.62Minimum lightness floor
OklchmaxBaseValue0.77Maximum lightness floor
OklchchromaBoostFactor0.75Saturation enhancement strength
OklchantiClusteringFactor0.75Reduces boost for light colors
HSLsaturationBoostFactor0.50HSL-specific saturation boost
HSLantiClusteringFactor0.25HSL-specific clustering prevention

The default color space is Oklch, specified in ColorTransformSettings.colorize.defaultColorSpace.


Integration Points

Global Object

The module exports a single global Color object. No events or callbacks.

Input/Output Formats

  • Input: #rgb, #rrggbb, rgb(r,g,b), rgba(r,g,b,a)
  • Output: Same format as input, or specified via options.output

Internal RGB Format

All internal RGB representations use:

{ red: 0-255, green: 0-255, blue: 0-255, alpha?: 0-1 }

Color Space Object Formats

SpaceProperties
HSV{ hue: 0-1, saturation: 0-1, value: 0-1 }
HSL{ hue: 0-1, saturation: 0-1, lightness: 0-1 }
XYZ{ x, y, z } (D65 illuminant)
Lab{ L: 0-1, a, b }
YCC{ Y: 0-1, Co, Cg }
Oklab{ L: 0-1, a, b }
Oklch{ L: 0-1, C: chroma, h: radians }

See Also