Skip to content

Color Palette Extractor

Palette size

Extracted palette

Upload an image to extract its dominant colors.

Estimates for educational purposes — not financial, medical, or legal advice. See terms.

Extract the dominant colors from any image as a hex palette. Upload a photo, logo, illustration, or screenshot; the tool downsamples it, feeds the pixels to a median-cut quantizer, and outputs a palette of 3 to 10 colors. Everything runs in your browser — the image is never uploaded to a server.

This tool is useful for building moodboards from reference photos, reverse-engineering a brand color scheme from a logo, picking a color palette for a website from a hero image, or just satisfying curiosity about what colors an image actually uses. Click any swatch in the result to copy its hex code, or feed one into the harmony visualizer to build a full scheme around it.

How median cut works

The algorithm takes an array of RGB pixels and a target palette size, then partitions the pixels into that many groups, then averages each group to produce one palette color:

  1. Find the color channel with the widest spread in the pixel set (the one where max − min is largest).
  2. Sort the pixels by that channel.
  3. Split the sorted list at the median into two halves.
  4. Recurse on each half, reducing the remaining depth.
  5. When depth reaches zero, each leaf bucket collapses into a single color — the average of all its pixels.

For a target palette of size $n$, the algorithm runs for $\lceil \log_2 n \rceil$ levels of recursion, producing $2^{\lceil \log_2 n \rceil}$ leaf buckets, which are then truncated to the requested size. For 8 colors, that’s 3 levels of splits and exactly 8 leaves.

Median cut is a 1980s algorithm, originally invented by Paul Heckbert for 24-bit to 8-bit color quantization in GIF encoding. It’s not the most sophisticated approach available — k-means clustering can produce slightly better perceptual results on some images — but it’s fast, deterministic, and has none of k-means’ random-seed behavior. Same input produces the same palette every time.

Example: a sunset photograph

A typical sunset photo has a few dominant color zones: the sky gradient (oranges to deep blues), the ground (shadowy dark), and maybe a few specular highlights. Running median cut with size 5 on such an image will usually recover:

  1. A deep blue from the upper sky
  2. A warmer orange-red from the lower sky
  3. A mid-grey from the transition zone
  4. A near-black from the ground shadows
  5. A bright highlight color from the setting sun

This is a better-than-average case because the color zones are geometrically separable in RGB space — warm sunset colors and cool sky colors fall on opposite sides of the red/blue axis, so the first median cut splits them cleanly.

Logos are much easier because they typically use a small number of flat colors with no gradients. Running median cut with size 4 on the Google logo should recover colors close to Google’s brand blue, red, yellow, and green. The result won’t be exact because of anti-aliasing at the letter edges (some pixels are blends of two brand colors and one background), but it’ll be close enough to use as a starting point — paste the extracted hex into the hex/RGB/HSL converter if you want to nudge it toward a specific saturation or lightness.

Example: a complex photograph

A photograph with lots of colors and smooth gradients — a landscape with a river, trees, sky, and sunlight — is a harder case. Median cut with size 8 will produce something usable, but no small palette can fully represent a photo with hundreds of distinguishable colors. The output is a “what does this image feel like” summary, not a faithful reproduction. If you want a larger palette that captures more of the image’s color range, bump the size up — 10 usually gives a good compromise.

Performance notes

The extractor downsamples any uploaded image to a maximum 400-pixel dimension before sampling pixels, then samples roughly 10,000 pixels for the median cut itself. This gives good results for any reasonable input size while keeping extraction time well under a second on typical hardware. Large source images (several megapixels) don’t slow anything down significantly because of the downsampling.

The entire algorithm runs synchronously in the main thread because even the largest sampled pixel set is fast enough not to need a web worker. If you notice a slow response on an unusually large image, it’s most likely the image decoding, not the quantization.

What this tool does not do

It does not offer k-means clustering, octree quantization, or any of the other color-reduction algorithms — just median cut. It does not let you select regions of the image to extract from (the whole image is always used). It does not preserve relative color proportions in the output — every swatch takes equal space regardless of how many pixels it represents in the source image. And it does not cluster by perceptual similarity using CIELAB or OKLCH; the math runs in straight sRGB space, which can occasionally produce buckets that look unusually close together despite being numerically separated.

For all of these, a more elaborate tool or a design app like Adobe Color is the right move. For “show me the dominant colors of this image, fast”, median cut is perfectly fit for purpose.

Frequently asked questions

What is median-cut quantization?

A classic color-reduction algorithm from the 1980s, originally invented for converting 24-bit color images to 256-color GIFs. The idea is simple: take all the pixels in the image, find the color channel (red, green, or blue) with the widest spread, sort the pixels by that channel, and split them at the median into two halves. Recurse on each half until you have the number of buckets you want, then average each bucket to get a single palette color. It's fast, deterministic, and gives reasonable results without needing any machine learning.

Why not use k-means clustering instead?

K-means gives slightly better perceptual results on some images but is iterative and non-deterministic — you start from random seed points and the output varies from run to run. Median cut is a single pass through the pixel data, always gives the same result for the same input, and runs in the browser without hogging the main thread. For a palette extractor where 'close enough to the real dominant colors' is the bar, median cut is the right tool.

Does my image get uploaded anywhere?

No. The entire extraction happens in your browser. The file you upload is read with the FileReader API, decoded to a canvas, sampled into an array of RGB values, and processed with the median-cut code — all on your device. You can open the devtools network tab while you use the tool and you won't see a single request leave your browser. This matters because people often upload logos and brand assets to palette extractors, and sending those to a third-party server is a bad habit.

Why is the palette sometimes missing a color I can clearly see in the image?

Because median cut splits the pixel set into buckets of roughly equal size. A color that covers only a few percent of the image will end up in the same bucket as neighboring colors and get averaged out. If you want a small accent color to appear in the palette, it needs to have enough pixels to justify its own bucket. For an accent that covers only 5% of an image with a palette size of 5, that's right at the boundary — often it gets merged. Try a larger palette size and you'll see it reappear as its own color.

What palette size should I use?

3 to 6 for getting a feel of a photo's mood or picking colors for a quick moodboard. 8 to 10 for a more detailed breakdown when you want to see secondary and accent colors alongside the dominants. Anything above 10 tends to include colors that are similar enough to each other that the extra entries aren't useful — you'd get more value from a dedicated ramp generator at that point.