AnyTool
Your files never leave your device. All processing happens locally in your browser.

How do I extract a colour palette from an image?

Drop, paste or pick an image in the Color Palette Extractor and it reads the pixels in your browser to find the dominant colours. It draws your image to an offscreen canvas, downscales it for speed, and runs a modified median-cut quantizer to reduce every pixel to the number of colours you choose. Each swatch shows HEX, RGB and HSL, its share of the image as a percentage, the nearest CSS named colour and its WCAG contrast on white and black — copy any value or export the whole palette as CSS variables, SCSS, a Tailwind snippet, JSON or a labelled PNG. The image is never uploaded; everything runs on your device.

  • Upload, drag & drop, or paste an image straight from the clipboard
  • Choose 2–12 colours; the palette re-computes instantly
  • Each swatch: HEX / RGB / HSL, pixel-share %, nearest named colour, WCAG contrast
  • Export HEX / RGB / HSL lists, CSS variables, SCSS, Tailwind config, JSON or a PNG sheet
  • 100% client-side — the picture never leaves your browser

What is

Colour palette extraction (colour quantization)

Colour palette extraction is the process of reducing the thousands of distinct colours in a photograph or graphic down to a small, representative set of dominant colours. It is an application of colour quantization: pixels are grouped into clusters of similar colour and each cluster is represented by one average colour. A classic method is median cut, which repeatedly splits the RGB colour cube along its longest axis at the median; the modified median cut used by tools like Leptonica and pngquant prioritises splitting the most populous boxes so small but distinct colours survive. The output is typically 2–16 swatches with their hex codes and their share of the image.

Design

Related terms

colour quantizationmedian cutmodified median cut (MMCQ)dominant colourk-means clusteringoctree quantizationHEXRGBHSLWCAG contrastsRGBcanvas getImageData

Frequently Asked Questions

No. The image is decoded and drawn to an offscreen canvas in your browser, and its pixels are read and quantized entirely on your device. There is no upload, no server and no CDN in the processing path, and the picture is never stored anywhere.

Extraction is 100% client-side. When you drop, paste or pick a file, the browser decodes it and draws it to an offscreen <canvas> element; the tool then calls getImageData to read the raw RGBA pixels and runs the median-cut quantizer on them right there in the page. Nothing is transmitted — there is no upload endpoint, no server-side processing and no CDN involved in reading your image — and the file is never logged or saved. The tool works offline once cached, and closing the tab discards both the image and the palette.

It uses a modified median-cut quantizer: it puts every sampled pixel in one box, then repeatedly splits the box with the largest colour range and pixel count into two along its longest colour axis, until it has the number of colours you asked for. Each box becomes its population-weighted average colour.

The tool samples the visible pixels of a downscaled copy of your image and treats them as points in the RGB colour cube. It starts with one box containing all of them and, at each step, picks the box with the greatest priority (its colour-cube volume multiplied by how many pixels it holds) and splits it at the median of its longest channel into two smaller boxes. Weighting by population — the “modified” part of modified median cut — stops a single huge, near-uniform background from monopolising the palette, so small but distinct clusters such as a logo or accent still get a swatch. When it reaches your chosen colour count, each box is reported as the population-weighted average of its pixels, and the swatches are ordered from the largest area share to the smallest.

Because each swatch is the average of a cluster of similar pixels, not a single eyedropper pick, and the image is downscaled and sampled for speed. Heavy JPEG compression can also add edge colours. Increase the colour count for a closer match, or feed a PNG/WebP instead of a JPEG.

A palette is a summary, so exactness is traded for representativeness. The tool works on a downscaled (≤320px), stride-sampled copy so it stays instant, and each colour it returns is the population-weighted average of a whole cluster of similar pixels rather than one exact pixel — so a swatch can sit slightly between the shades it represents. Lossy JPEG compression makes this worse: its 8×8 DCT blocks and 4:2:0 chroma subsampling invent blocky edge and ringing colours that can surface in the palette. To get closer to the source, raise the number of colours, or use a lossless PNG/WebP. Remember too that “dominant” means most area, which is not always the most eye-catching accent.

You can copy any single swatch as HEX, RGB or HSL, copy the whole palette as a list, or export CSS custom properties, SCSS variables, a Tailwind colours snippet, JSON, or download a labelled PNG swatch sheet — all generated locally.

Every swatch is copyable in your chosen format (HEX, RGB or HSL) with one tap, and the whole palette can be copied as a comma-separated list or exported in developer-ready formats: CSS custom properties (:root { --color-1: … }), SCSS variables, a Tailwind theme.extend.colors snippet, or a JSON array that also records each colour’s share and nearest named colour. You can also download a PNG swatch sheet with the hex, percentage and RGB drawn on each band, rendered on an offscreen canvas. All of these are serialised in your browser — nothing is generated on a server.

Detailed Explanation

Methodology

How the Color Palette Extractor Works

The page decodes the user’s image and draws it to an OFFSCREEN <canvas>, downscaled so its longest edge is at most 320px, then reads the raw RGBA pixels with getImageData. A pure engine (paletteExtractEngine.ts) stride-samples the visible (opaque) pixels down to roughly 24,000 points and runs a MODIFIED MEDIAN CUT quantizer: all points start in one box, and the box with the greatest priority — its colour-cube volume multiplied by its pixel population — is split at the median of its longest RGB channel, repeating until the requested colour count is reached. Each box is reported as the population-weighted average of its pixels, ordered by area share. Everything runs in the browser; the image is never uploaded.

  • Image drawn to an offscreen canvas and read with getImageData — no upload
  • Downscaled to ≤320px and stride-sampled to ~24k pixels for instant results
  • Modified median cut splits the most populous box first (volume × count)
  • Each swatch is the population-weighted average of its cluster
  • Colours are ordered from largest area share to smallest
How It Works

Why Modified Median Cut Beats Plain Median Cut

Plain median cut always splits the box with the widest colour range, which lets a single large, near-uniform region (a sky, a white background) dominate the palette while small vivid clusters — a logo, an accent colour — get merged away. The modified median cut used by Leptonica and pngquant weights the choice by POPULATION as well as range, so a box is split when it is both wide and heavily populated. This tool multiplies each box’s colour-cube volume by its pixel count to pick the next split, which preserves small-but-distinct colours far better than range alone, giving a palette that matches what a human perceives as the image’s key colours.

  • Plain median cut can let one huge region monopolise the palette
  • Modified median cut weights by pixel population, not just range
  • This preserves small, distinct clusters such as logos and accents
  • Priority used here = colour-cube volume × pixel count
  • Alternatives include k-means and octree quantization
Technical Details

HEX, RGB, HSL, Named Colour and WCAG Contrast

For each dominant colour the engine (via the culori library, loaded lazily so the shell paints first) derives an opaque HEX string, an RGB triple, an HSL triple, and the swatch’s share of the sampled pixels as a percentage. It finds the NEAREST CSS named colour by minimising perceptual distance (ΔE in OKLab) against the 147 standard keywords, and computes the WCAG 2.1 contrast ratio of the colour as text on pure white and pure black so designers can immediately see where a colour is legible. Exports cover HEX/RGB/HSL lists, CSS custom properties, SCSS variables, a Tailwind theme snippet, JSON (with share and nearest name), and a labelled PNG swatch sheet rendered on an offscreen canvas.

  • Per colour: HEX, RGB, HSL, pixel-share %, nearest named colour, WCAG contrast
  • Nearest name uses perceptual ΔE in OKLab against 147 CSS keywords
  • Contrast reported vs white and black (AA body text needs 4.5:1)
  • Copy any single value or the whole palette in HEX/RGB/HSL
  • Export CSS variables, SCSS, Tailwind, JSON, or a PNG sheet
Limitations

Honest Limitations of Palette Extraction

A palette is a summary, so accuracy is traded for representativeness. Extraction runs on a downscaled, stride-sampled copy, and each swatch is the average of a whole cluster rather than an exact pixel, so it can sit slightly between the shades it represents — raising the colour count narrows this. Lossy JPEG compression makes it worse: 8×8 DCT blocks and 4:2:0 chroma subsampling invent blocky edge and ringing colours that can surface in the palette, so lossless PNG/WebP inputs give cleaner results. Fully transparent pixels are ignored so only visible colour counts, and a very small palette can produce false-contour banding across smooth gradients. “Dominant” means most area, which is not always the most striking accent. Median cut is a heuristic, not a perceptual ground truth.

  • Works on a downscaled (≤320px), stride-sampled copy for speed
  • Each swatch is a cluster average, not an exact eyedropper pick
  • Heavy JPEG artefacts can add false edge colours — prefer PNG/WebP
  • Transparent pixels are skipped; a tiny palette can band gradients
  • “Dominant” = most area, not necessarily the most eye-catching colour
Privacy & Security

Private by Design

Everything happens on the user’s device. The image is decoded and drawn to an offscreen canvas in the browser tab, its pixels are read and quantized locally, and the palette, export code and PNG sheet are all generated in-page — there is no upload endpoint, no server-side processing and no CDN in the path that touches your image. The sample images offered when no file is loaded are drawn locally with inline SVG, so even they trigger no image download. The tool works offline once cached, keeps no accounts, sets no tracking, and discards the image and palette the moment the tab is closed.

  • Image decoded and sampled entirely in the browser — never uploaded
  • Palette, exports and PNG sheet are all generated in-page
  • Built-in sample images are local inline SVG — no image download
  • Works offline once cached; no accounts, no tracking
  • Image and palette are discarded when the tab closes
Colour quantization methods for palette extraction
MethodHow it worksTrade-off
Modified median cut (this tool)Split the box with the largest volume × pixel count at its medianFast, preserves small vivid clusters; heuristic, not perceptual
Plain median cutSplit the box with the widest colour rangeSimple and fast; large regions can dominate the palette
K-means clusteringIteratively refine N cluster centroids to minimise distanceOften higher quality; slower and sensitive to initial seeds
Octree quantizationInsert colours into an octree and merge the least-used nodesLow memory, good for GIF; more complex to implement

This tool uses a population-weighted modified median cut (as in Leptonica and pngquant) for a good balance of speed and quality, run entirely in the browser. As of July 2026.