accent-extract

accent-extract is a small C11 command-line tool that finds dominant colours in a wallpaper and scores their suitability as UI accents against a supplied background colour. It produces one script-friendly #RRGGBB score record per line on standard output.

Dependencies

The default SDL3_image pkg-config package name is sdl3-image. On a system that calls it SDL3_image, build with SDL_IMAGE_PKG=SDL3_image.

Build and test

make
make test
make clean

Static Linux binaries

compile_static.sh produces fully static musl binaries for Linux AMD64 and ARM64:

./compile_static.sh

Usage

accent-extract wallpaper.png --background '#1e1e1e'

Options:

--background COLOR  Required background colour in #RRGGBB form.
--limit N           Maximum pre-score dominant candidates (default: 20).
--min-score FLOAT   Minimum accent score to print (default: 0.60).
--block-size N      Square averaging block size (default: 16).
--tweak             Refine output lightness and saturation.
--help              Show command help.

Example output:

#7aa2f7 0.884
#c678dd 0.811
#98c379 0.742

Formats and animations

SDL3_image supplies PNG/APNG, JPEG, GIF, WebP, AVIF, BMP, PNM, TGA, TIFF, QOI, JPEG XL, and any other raster decoder enabled in the installed library.

Extraction method

Each frame is divided into blocks (16 by 16 pixels by default), including partial blocks at the right and bottom edges. Pixels are alpha-weighted, so fully transparent pixels contribute nothing. The tool averages in linear sRGB and converts the representative colour back to sRGB. Nearby representatives are merged deterministically using Oklab distance, with prevalence accumulated by visible pixel area and frame duration.

The pre-score pool primarily contains the most prevalent clusters, with up to one half reserved for chromatic clusters. Those reserved slots balance the most prevalent chromatic representatives with the highest-chroma representatives. This prevents a small but visually salient accent from being crowded out by many shades of a neutral background. The vendored accent_score() then scores those candidates against the background; the minimum-score filter is applied and surviving candidates are sorted by score. Prevalence and accent score are not blended into one metric.

With --tweak, surviving colours receive a final perceptual adjustment. Their Oklab lightness separation and chroma are nudged 25% toward the scoring library's preferred values while preserving hue. Out-of-gamut colours are mapped by reducing chroma. A tweak is retained only if it does not lower the accent score; displayed scores are recomputed and the results are re-sorted.

Attribution

The unmodified vendor/accent_score.h is vendored from my own accent-score library.