You have a photo and you want its colours as hex codes. The short answer: run it through a palette extractor, take the top four to six colours, then adjust them by hand before you use them for anything. Extraction tells you honestly what is in the image. It does not hand you a design system, and it says nothing about whether text will be readable on top of those colours.

That gap between "these are the colours in the photo" and "these are colours I can build with" is where most people get stuck. Here is what the extraction is actually doing, and what you have to decide yourself.

Getting the hex codes out

Drop the image into the colour palette extractor, pick how many colours you want with the slider, and you get a row of swatches. Each one shows its HEX, its RGB, its HSL, and the percentage of the image that colour accounts for. Click a swatch to copy the hex. There is a button to download the whole set as CSS custom properties if you would rather paste variables than six separate values.

The image is read in your browser. It is never uploaded anywhere, which matters more than it sounds like it does when the photo is an unreleased product shot or a client's brand asset.

That part takes about five seconds. Everything below is about what to do with the numbers once you have them.

Why the average colour of a photo is almost always mud

A lot of people assume "dominant colour" means "average colour". It does not, and the difference is the whole point.

If you average every pixel in a normal photograph, you get brown. Or a greyish olive, or a dull taupe, but essentially brown. This happens because averaging is a pull toward the middle. Blue sky and orange sand sit on opposite sides of the colour wheel, so averaging them cancels most of the saturation and leaves something near grey. Add the warm bias of skin, wood, foliage and earth tones that fill most photos, and grey drifts to brown.

Astronomers ran into the same thing at a much larger scale. When a team at Johns Hopkins averaged the light of tens of thousands of galaxies to find the average colour of the visible universe, the answer was a pale beige. They nicknamed it cosmic latte. Average enough of anything and you get beige.

There is a second, more technical reason averages look muddier than they should. The RGB values in a JPEG or PNG are gamma-encoded, not linear measurements of light. Adding those encoded numbers together and dividing does not give you the colour you would get by physically mixing that light. It gives you something darker and less saturated. Averaging in linear light and converting back produces a noticeably brighter result, which is why some tools disagree about the "average colour" of the same photo.

Practical takeaway: if a tool gives you one colour for an image and it looks like weak coffee, it is averaging. If it gives you a set of distinct colours you can recognise from the photo, it is clustering. You want clustering.

What dominant colour extraction actually does

Think of every pixel in the image as a dot floating in a three-dimensional box, where the axes are red, green and blue. A photo of a beach at sunset puts a dense cloud of dots up in the orange corner, another cloud in the pale blue region, a scattering in the dark browns. The image has millions of pixels but only a handful of places where they bunch up.

Extraction is the job of finding those bunches and picking one representative colour for each.

The classic method is median cut, developed in the early 1980s for squeezing photographs onto displays that could only show 256 colours at once. It works by repeated splitting. Start with one box containing every pixel. Find the axis along which the colours are most spread out, cut the box in half at the median along that axis, and you have two boxes. Repeat on whichever box is now the most spread out. Keep going until you have as many boxes as colours you asked for, then average the pixels inside each box. Because it splits at the median rather than the midpoint, dense regions get subdivided more finely than sparse ones, so common colours get better representation than rare ones. That is the algorithm behind the palette tool here.

K-means clustering is the other common approach. You drop a number of markers into the colour cloud at random, assign every pixel to its nearest marker, move each marker to the centre of the pixels that chose it, and repeat until the markers stop moving. It often produces slightly more natural groupings than median cut, at the cost of being slower and giving marginally different results between runs.

Both share one weakness worth knowing about. Distance in RGB space does not match how different two colours look to a human eye. We discriminate far more finely between greens than between deep blues, so a clustering algorithm working in raw RGB will sometimes lump together two greens you can clearly tell apart while splitting two near-identical navies. Perceptually uniform colour spaces such as CIELAB exist precisely to fix this, and tools that cluster there tend to produce palettes that feel better sorted. It is a refinement, not a different result: the big clusters in a photo are the big clusters either way.

An X-Rite ColorChecker Passport open on a wooden table, showing grids of coloured and grey reference patches
A photographic colour target works in the opposite direction to extraction: every patch has a published value, so the camera can be measured against a known answer. Extraction has no known answer, it infers a handful of colours from millions of pixels. Photo: Robert Cooke (CC BY 2.0).

A palette that describes an image is not a palette you can design with

This is the distinction that saves you time.

An extracted palette is a description. It answers "what colours is this photo made of", and it answers accurately. A design palette answers a different question: "what colours should this interface use". Those overlap, but they are not the same set.

Photos are full of colours that are structurally important to the image and useless in a layout. The muted grey-greens of an out-of-focus background take up 30% of the frame and describe nothing anyone would want as a button colour. Meanwhile the single vivid red of a jacket, occupying 2% of the pixels, is the colour that makes the photo feel like it does.

So treat extraction output as raw material. Typical adjustments after you have the hex codes:

  • Push saturation up on your accent. Extracted colours are averages of a cluster, so they land slightly duller than the punchiest pixels in that cluster.
  • Pull saturation down on your background. A large area at full saturation is exhausting to look at, whatever the photo does.
  • Build a light and dark variant of each keeper by holding the hue and moving the lightness. This gives you hover states, borders and text colours that belong to the same family.
  • Add a near-black and a near-white that are tinted toward your dominant hue rather than pure #000000 and #FFFFFF. This is a small change that makes a palette feel deliberate.

How many colours you actually need

Four to six. The slider goes to twelve, and twelve is occasionally useful for studying an image, but twelve colours is not a palette, it is an inventory.

A workable set is usually:

  • One dominant colour, most often a background or a large surface
  • One secondary that supports it
  • One accent for things that need attention, used sparingly
  • A dark and a light neutral for text and surfaces

Pull twelve if you want to see the full range of the image, then throw away eight of them. Discarding is the actual design work. Every extra colour you keep is another decision you or someone else has to make on every screen, and colours that are close together in hue tend to read as mistakes rather than variety.

Coverage percentages are not importance rankings

The percentage next to each swatch is honest and often misleading, at the same time.

It tells you how much of the image that colour cluster covers. It says nothing about how much the colour matters. Sky, walls and shadow routinely top the list. The colour a viewer would name if you asked them to describe the photo in one word is frequently sitting fourth or fifth with 4% coverage.

Use the ordering for one thing specifically: deciding what should be a large area and what should be a small one. A colour with 40% coverage will feel natural filling a page background because that is how it appears in the photo. A colour with 3% coverage will feel right as a button or a highlight and will feel oppressive across a full-width section. The percentages are a hint about scale, not about priority.

Anything under roughly 5% is worth checking by eye before you trust it. At that level you are often looking at compression artefacts, JPEG colour fringing, or a stray highlight rather than a real colour in the scene.

Nine coloured pencils laid in a row with their points aligned, arranged from red through yellow and green to dark blue, on a pink background
A set like this gives every colour the same amount of space. A photograph never does, which is why the coverage figure beside each swatch tells you how large an area a colour can comfortably fill. Photo: Artsy Crafty (CC0).

A beautiful palette can still fail contrast

This is the part that gets skipped, and it is the part with legal and practical consequences.

Harmony and contrast are unrelated properties. Two colours can sit next to each other beautifully and be almost unreadable as text on background, because readability depends on the difference in relative luminance, not the difference in hue. A saturated red and a saturated blue look completely different and can have nearly identical luminance. Text in one on the other will be a blur.

The thresholds under WCAG 2.2, which is what most accessibility requirements point at:

ContentLevel AALevel AAA
Normal body text4.5:17:1
Large text (about 24px, or 19px bold)3:14.5:1
UI components, icons, focus indicators3:13:1

The ratio runs from 1:1 (identical) to 21:1 (black on white). You cannot estimate it by looking, and you especially cannot estimate it on a bright laptop screen in a bright room. Run the pairs you intend to use through a contrast checker and take the number seriously.

When a pair fails, you rarely need to abandon the colour. Keep the hue and the saturation, move the lightness until it passes, and you get a colour that still reads as part of the palette. This is why building light and dark variants early is worth the ten minutes.

Two things a contrast ratio will not catch: colour-blind viewers, for whom red and green of similar lightness collapse into the same tone even at an acceptable ratio, and information carried by colour alone. If the only difference between "paid" and "overdue" in your table is red versus green text, add an icon or a word. That is a separate WCAG requirement from contrast, and passing one does not satisfy the other.

A newer contrast model called APCA, which accounts for text weight and size more realistically than the current formula, is being developed for a future version of WCAG. It is not the standard yet. Build to 4.5:1 today.

Extracting brand colours, and when to not bother

Pulling colours from a logo works well, with one caveat about file formats.

Logos are usually flat areas of solid colour, so clustering finds them almost exactly. But if your source is a JPEG, the values you get back will be slightly off. JPEG stores colour information at lower resolution than brightness information, which smears colours across edges, and lossy compression shifts values further. Extract the same logo from a PNG or an SVG export and you will get cleaner numbers.

If you need a company's official brand colour and you are not that company, look for their brand guidelines before you sample a screenshot. Most organisations of any size publish exact hex, RGB, CMYK and Pantone values. Sampling gets you close; guidelines get you correct.

One more limit: colours sampled from a screen image are screen colours. Sending them to print means converting to CMYK, and saturated screen colours often have no printable equivalent, so they shift on the way. That is the same class of problem as assuming a web-resolution image will print sharply, which is covered in more depth in DPI and resolution explained. For anything going to a printer, get a proof rather than trusting the hex.

Choosing a background that does not fight the photo

The most common real use for extraction is putting a photo on a page and needing a background, a heading colour and a button that all look like they belong with it.

A reliable approach: take the darkest or lightest cluster from the image rather than the most colourful one, and desaturate it further. Backgrounds pulled from a mid-tone accent tend to vibrate against the photo, because two similarly saturated colours of different hues compete rather than support each other. A background that is clearly darker or clearly lighter than everything in the photo lets the image sit on top of it instead of arguing with it.

For a heading colour, take the accent, then darken it until it passes contrast against that background. For a button, use the accent at its most saturated, because a button is small and small areas can carry intensity that large areas cannot.

What extraction will not do

Being clear about the limits is what keeps the output useful:

  • It does not find the most striking colour. It finds the most present one. Those are different, and the tool is honest about which one it is reporting.
  • It does not know what the subject is. A person in a red coat against a grey wall produces a grey-dominant palette, because most of the pixels are wall.
  • It cannot rescue a busy image. Photos with dozens of competing colours, a crowded market scene or a cluttered desk, cluster into a set of muddy mid-tones because that genuinely is what the image is made of. Crop to the part you care about and extract from that instead.
  • It does not build a system. Spacing, type, states, semantic roles for each colour: all yours.

Used within those limits, it is a fast and genuinely useful step. Pull six colours from the photo, keep three, build light and dark variants, check every text pairing against 4.5:1, and you have a palette in about fifteen minutes that is grounded in a real image instead of guessed at. The palette extractor handles the first step; the rest is judgement, and it is the part worth spending your time on.