Skip to content

Repository files navigation

ph-color

Deterministic, fixed-point color processing for embedded Rust. ph-color provides typed color values, transfer functions, gamut matrices, per-channel gain, interpolation, and quantization without a heap or floating-point dependency on its default target path.

ph-color on crates.io ph-color API documentation ph-color-bake on crates.io ph-color-bake API documentation

Note

Status: Active. ph-color is published at version 0.1.1, and ph-color-bake is published at version 0.1.0. The API is intentionally narrow rather than a comprehensive color library.

Choose a crate

Crate Use it for Runtime
ph-color Applying baked transforms, transfer tables, gain, interpolation, and quantization in firmware no_std, no allocation, no unsafe code, no default dependencies
ph-color-bake Deriving matrices and lookup tables and emitting auditable Rust const source Host-side std and f64

Most applications depend only on ph-color. Run ph-color-bake on a workstation when you need custom coefficients or tables; do not link the baker into target firmware.

Quick start

Add the target crate:

[dependencies]
ph-color = "0.1"

Decode an sRGB value to linear light, apply a typed gain, and encode it again:

use ph_color::{Color, Encoded, Gain, Q0_16, Q4_28, SRGB_EOTF, SRGB_OETF, Srgb};

let encoded = Color::<Srgb, Encoded>::new(Q0_16::array_from_raw([
    65_535, 32_768, 4_096,
]));
let linear = SRGB_EOTF.decode(encoded);
let dimmed = Gain::<Srgb>::from_q428([
    Q4_28::ONE,
    Q4_28::ONE,
    Q4_28::from_raw(201_326_592), // 0.75 in Q4.28
])
.apply(linear);
let output = SRGB_OETF.encode(dimmed);

assert_eq!(output.ch[0], Q0_16::ONE);

The encoding state is part of the type. Matrices and gains accept linear colors, so accidentally applying either operation to an encoded value is a compile-time error.

Runnable examples cover three concrete workflows:

cargo run -p ph-color --example hub75
cargo run -p ph-color --example uv_flood
cargo run -p ph-color --features oklab --example oklab_sketch

These are host-side pipeline sketches. They do not perform hardware I/O or claim validation on a physical display or lamp.

What the target crate provides

  • Color<S, E> values with open color-space types and sealed Linear and Encoded states.
  • Matrix3<Src, Dst> and Gain<S> operations for linear colors.
  • Shipped sRGB EOTF and OETF lookup tables.
  • InterpLut, Gradient, and typed linear or perceptual interpolation.
  • quantize::<BITS> and expand::<BITS> with an exact signed-residual seam, plus zero-parameter round-to-nearest through quantize_round::<BITS>.
  • Optional fixed-point linear-sRGB to/from Oklab conversion with oklab.
  • Optional ColorF32 and supported *_f32 operations with f32.

Features are additive and may be combined:

Feature Adds Important limit
default Fixed-point color, matrix, gain, LUT, interpolation, and quantization APIs No Oklab conversion or f32 API
oklab Fixed-point linear-sRGB to/from Oklab No Oklab f32 entry points
f32 ColorF32 plus supported matrix, gain, LUT, and interpolation operations Does not change fixed-point results

Numeric guarantees

The fixed path uses UQ0.16 channels and Q4.28 coefficients. Matrix and gain operations perform one widening accumulation per output channel, then round-half-away-from-zero and saturate. Public fixed-point results never wrap. For the same API, features, and inputs, results are bit-identical across the checked targets.

The complete compatibility contract—including error bounds, type-state rules, and the quantization residual identity—is in docs/NUMERICS.md.

Scope and limits

ph-color owns the deterministic step from one color value to another. It does not own framebuffers, alpha compositing, parameterized dithering policy, output packing, hardware I/O, animation, or application pipelines. Rounding to nearest is included only because its half-bin threshold, tie rule, and top-of-range saturation have no free parameter. Decisions that take a custom threshold, mask, position, frame index, or accumulator remain out of scope. ICC, CMYK, appearance models, target-side chromatic adaptation, runtime transform derivation, and f64 on the target are also outside its current scope.

Custom matrices, inverse calculations, chromatic adaptation, and lookup-table generation belong in ph-color-bake; the resulting constants belong in the target application. New capabilities are admitted only for a current embedded consumer with testable bounds.

Compatibility and verification

  • Minimum supported Rust version: 1.94.0, edition 2024.
  • The target crate is #![no_std], allocation-free, and #![forbid(unsafe_code)].
  • The release gate links all feature combinations for thumbv6m-none-eabi, thumbv8m.main-none-eabihf, and riscv32imc-unknown-none-elf.
  • Frozen golden vectors, property tests, compile-fail tests, generated-source checks, dependency policy, code-size and static-RAM budgets, panic-symbol checks, and wide-arithmetic checks protect the documented contract.

Run the canonical repository gate from the workspace root:

cargo xtask ci

The command reports passed, failed, and skipped checks separately. Host tests and embedded link checks are software evidence; they are not physical-device, timing, or hardware-qualification evidence.

Project links

License

MIT

About

Fixed-point no_std color math for embedded targets: conversion, transfer functions, matrices, and interpolation.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages