Skip to content

Building a colour palette from an image (and checking its contrast)

How dominant-colour extraction works, why the swatches are not the ones you expected, and how to read the WCAG contrast figure before setting type in one.

By Wajahat Rasoul ·

How dominant-colour extraction works

A photograph does not contain five colours; it contains tens of thousands. Extraction is a clustering problem: group all those pixels into a small number of buckets, then report one representative colour per bucket.

The palette extractor uses Color Thief, which builds a colour histogram and splits it repeatedly along its widest axis — median cut — until it has as many groups as you asked for. Each group's average becomes a swatch.

Two consequences follow directly from that method, and they explain most surprises.

Why the swatches are not what you expected

The most striking colour is often missing

Median cut is driven by how many pixels hold a colour, not by how much attention it attracts. A red jacket occupying 3% of the frame loses to a grey sky occupying 40%, even though the jacket is what you remember. Crop to the region you care about first — the cropper is the fastest way — and extract from that.

Two swatches look almost identical

That happens when an image is dominated by one hue in several brightnesses: a sunset, a forest, a studio shot on a coloured backdrop. The algorithm is faithfully reporting that the image really is mostly that colour. Asking for fewer swatches usually produces a more useful spread.

HEX, RGB and HSL — three ways to say one colour

NotationExampleBest for
HEX#2E5AACPasting into CSS, design tools and brand documents.
RGBrgb(46, 90, 172)Anywhere you need the channels separately, or an alpha value.
HSLhsl(219, 58%, 43%)Adjusting a colour by hand — hue, saturation and lightness move independently.
Same colour, three notations. The extractor copies any of them.

HSL is the one worth learning. Building a tint or shade in HEX means guessing at six characters; in HSL you keep the hue and saturation and move the lightness, which is how consistent scales get made.

Reading the contrast figure

Next to each swatch is a WCAG contrast ratio — the relationship between the relative luminance of two colours, running from 1:1 (identical) to 21:1 (black on white).

RatioMeetsUse
4.5:1AA, normal textThe everyday minimum for body copy.
3:1AA, large textFrom roughly 24px, or 19px bold. Also the minimum for UI borders and icons.
7:1AAA, normal textStricter target; worth aiming at for long reading.

Two things it is easy to get wrong. First, contrast is a property of a pair of colours — a swatch is not “accessible” on its own, only against the background you put it on. Second, hue does not enter into it: two colours can be wildly different and still fail, because they are equally bright.

Colour alone is never the message

Around one in twelve men has some form of colour vision deficiency. If red versus green is the only thing distinguishing two states, some readers see one state. Add a label, an icon or a pattern alongside it.

Turning swatches into a usable palette

  1. Extract from an image that already has the mood you want — a reference photograph, a frame from a film, a piece of packaging.
  2. Pick one dominant and one accent. Most palettes fail by having three colours all competing to be the loudest.
  3. Build neutrals from the dominant hue. Take its HSL, drop the saturation to single figures, and vary the lightness. Greys tinted towards the palette look deliberate; pure grey often looks flat beside a warm image.
  4. Check every text pairing you will actually use against the 4.5:1 line, and adjust lightness — not hue — until it passes.
  5. Export and keep it. The extractor writes JSON for handing to code, and a rendered PNG for pasting into a document or a brief.

One caveat if any of this is heading for print: these are screen colours, and saturated screen colours are exactly the ones ink struggles to reproduce. RGB vs CMYK covers what survives the trip.

Tools for this

Everything here runs in your browser — no upload, no account.

Related guides