Designers and front-end developers turn images into palettes more often than they admit. A new client hands over a slide deck and asks for “the same vibe on the website.” A photographer wants the portfolio chrome to echo the hero image. A marketing team needs a landing page that picks up the dominant colors from the product shot at the top. Each of these starts with the same question: what colors are actually in this picture, and which ones carry the most visual weight?
You can answer that by hand — open the file in Figma, hold down the eyedropper, sample five or six places that look representative, write the hexes into your stylesheet, and hope you got it right. Or you can let an algorithm do it: cluster every visible pixel into k groups, report each group’s mean color along with the share of pixels it claims, and emit a palette that already includes weight metadata for downstream decisions.
The browser is the right place for this work. The image already lives in memory once it loads, Canvas exposes the pixel data, and a few hundred lines of JavaScript can run k-means fast enough to feel instant. No upload, no roundtrip, no third party seeing what you are working on.
Try the Image Color Palette Extractor →
When you reach for an image-driven palette
Image-driven palettes shine in a handful of recurring situations. The pattern is always the same: the visual is fixed, and the palette must agree with it.
| Scenario | Why image extraction wins |
|---|---|
| Onboarding a new client | Their existing brand assets are the palette. Reverse-engineering them takes minutes instead of guessing what hex matches their logo. |
| Photographer portfolio | The site chrome should echo the hero photo so neither competes. Pulling the palette from the photo guarantees harmony. |
| E-commerce product page | The product shot’s dominant tones can drive accent colors, badges, and call-to-action borders for visual continuity. |
| Stock-art landing pages | Stock photography is unforgiving — pick the wrong accent and the layout looks pasted on. The right accent comes from the image itself. |
| Competitive analysis | Comparing weight percentages between your hero image and a competitor’s makes color strategy quantifiable instead of subjective. |
| Editorial cover image | Pull a 5-color palette from the cover, use the dominant tone for the title, the second for byline, the third for borders. |
If your starting point is “I have a hex code and want a scheme,” the right tool is a Color Palette Generator (complementary, analogous, triadic schemes derived from a base hex). If your starting point is “I have an image,” reverse extraction is the workflow that respects the source material.
How k-means builds the palette
K-means is the simplest clustering algorithm that still produces designer-friendly results. The four-step loop:
1. Pick k random pixels from the image as initial centroids.
2. Assign every pixel to the centroid with the smallest RGB distance.
3. Move each centroid to the mean position of the pixels assigned to it.
4. Repeat 2 and 3 until centroids stop moving (or 24 iterations, whichever first).
The interesting choices are not in the loop itself but around it.
Downsampling. Running k-means on a 4K photo means 8 million pixel comparisons per iteration, which is too slow for a browser tool that should feel instant. Resizing the image so the longest edge is 200 pixels collapses the work to roughly 40 000 sample pixels. With 8 centroids and 24 iterations the cost lands around 8 million distance evaluations total — well under 100 ms on a current laptop. The downsampling does not lose color information that matters; it loses spatial information you would not be using anyway.
Initialization. Pure random selection occasionally seeds two centroids on near-identical pixels. The tool sidesteps the worst cases by deduplicating sampled centroids before the first iteration, but k-means remains stochastic. Two runs on the same image with the same k may converge to slightly different clusters. The cure is either a re-run for a fresh seed, or a larger k so the centroids cover the color space more deterministically.
Distance metric. Euclidean distance in RGB is the textbook choice and works well enough for visual extraction. Designers occasionally argue that perceptual spaces like Oklab would produce more “natural” clusters; in practice the gain is marginal because the output palette is for human eyes, and the user can resort the result by hue or lightness afterwards. Sticking with RGB keeps the math fast and the implementation auditable.
Cluster merging. Even with deduplicated initialization, k-means sometimes converges with two cluster centers separated by an imperceptible delta. The tool merges any two centroids whose summed RGB difference is under 6 (a hard-to-perceive distance) and adds their pixel weights together. The result: no two output swatches look identical, regardless of k.
Pre-filters. Two filters pull weight from the algorithm. Skipping transparent pixels (alpha < 128) is on by default — alpha channels in PNGs would otherwise count toward palettes meant to describe the visible content. Skipping near-white pixels (luminance > 0.95) is opt-in; it is useful for product photos where a white studio backdrop would otherwise dominate the result, and harmful for editorial layouts where the white is the design.
The four color spaces — and when to use each
A palette is only useful if you can paste it into the next tool in the chain. The extractor outputs four color spaces per swatch so the pipeline never has to convert by hand.
| Space | Strength | Use case |
|---|---|---|
| HEX | Universal interop, smallest token | Sharing in chat, GitHub, Figma file metadata |
| RGB | Modern space-separated syntax rgb(160 90 44) | Hand-edited stylesheets, CSS variables |
| HSL | Hue + saturation + lightness on a single axis | Quick variations, hover states (raise lightness 10%) |
| OKLCH | Perceptually uniform L, C, H | Design tokens, automated palette generation, contrast-aware shifts |
The case for OKLCH deserves a closer look because it is still under-used in production code. The L axis in HSL is mathematically simple but perceptually uneven — going from L=50 to L=70 looks like a much bigger jump on a yellow than on a blue. OKLCH replaces that axis with a perceptually uniform L derived from Oklab. As a result, automated transformations (lighten by 10%, rotate hue by 30°) produce results that look like equal steps to the human eye. If you are building a design token system that needs predictable lightness ramps, OKLCH is the right output format.
Common pitfalls
A few patterns trip up first-time users of an automated palette extractor.
The image has a huge near-white background. Three of your eight centroids end up landing in the off-white range, and the actual subject of the photo only contributes one or two swatches. Toggle “Skip near-white” — the algorithm now ignores pixels with luminance > 0.95, freeing those centroids to find real content.
The image is mostly transparent. The alpha pre-filter handles the common case (PNG icons over a transparent background). If the image is fully transparent, the tool reports “no visible pixels remained after the filters” rather than rendering an empty palette.
The result is unstable between runs. This is k-means’ random initialization. The fix is either a higher k (more centroids spread the random seeds wider) or accepting that the dominant 3-4 colors are stable across runs even when the trailing 4-5 wobble. Re-extract until the swatches you care about lock in.
Extracted colors look different than the eyedropper sample. K-means reports the mean of each cluster, not a sampled pixel. If the photo has a deep red on the left fading into orange on the right, k-means will likely return the in-between color where the cluster center settled. Eyedropper at a specific point returns the color at that point. Both are correct; they are different questions. For accent colors that should match a specific feature in the photo, sample manually; for tone-of-voice palettes that summarize the picture, k-means is the right tool.
Asking for too many colors on a simple image. A logo on flat black has at most 3-5 distinct colors. Asking for 16 forces k-means to invent micro-clusters by splitting near-identical groups. The output is fine but contains effective duplicates. The cluster-merging step de-dupes when distances are tiny, but you can also dial k down to match the image’s actual color count.
A practical workflow
The flow that ships work fastest:
1. Drop the source image. Defaults to k=8, sorted by frequency.
2. Toggle "Skip near-white" if the image has a studio backdrop.
3. Click "Re-extract" once or twice to confirm the dominant colors are stable.
4. Click any swatch's color top to copy its hex.
5. Use "Copy CSS variables" to grab the full set as a :root block.
6. Paste into your design tokens.
7. Run the most important pairs through the Color Contrast Checker
(https://zerotool.dev/tools/color-contrast-checker/) to make sure
text-on-color combinations meet WCAG AA.
If you maintain a Tailwind config, the bulk-copy “Tailwind” button emits a snippet you can drop directly under theme.extend.colors.palette, naming the swatches c1 through cN. Rename them to your domain afterwards (primary, accent, surface, etc.) and you are done.
Privacy and performance
The browser is a privacy-friendly runtime for this kind of work. The image is read with FileReader.readAsDataURL, decoded into an HTMLImageElement, drawn onto an offscreen canvas at sampling resolution, and clustered in JavaScript on your CPU. Image bytes and pixel data stay on your device; the only network requests on the page are the static assets that loaded with the tool itself.
Performance numbers from a real measurement on a Mac with an Apple Silicon CPU:
| Image | Decode + draw | k-means (k=8) | Total |
|---|---|---|---|
| 800×600 PNG | ~12 ms | ~35 ms | ~47 ms |
| 1920×1080 JPEG | ~25 ms | ~40 ms | ~65 ms |
| 3840×2160 JPEG | ~70 ms | ~45 ms | ~115 ms |
| 8000×6000 photograph | ~180 ms | ~50 ms | ~230 ms |
The k-means runtime is bounded by the downsampled buffer size, not the source image, so very large photos take longer mostly because of the decode-and-draw step.
How this differs from Adobe Color and Coolors
Adobe Color’s “Extract from image” tab is the established benchmark and produces nice 5-color palettes. It runs server-side, asks you to sign in to save the palette into a Creative Cloud library, and is built around designers who already live inside the Adobe ecosystem. Coolors’ image picker is similar in scope. Both are great for inspiration; both feel slightly off when you actually need to ship the result into code.
The ZeroTool extractor sits in a different niche: open-tab tooling for developers who already have a stylesheet open in another tab. Trade-offs:
- Four color spaces per swatch (HEX, RGB, HSL, OKLCH) shown side-by-side — saves a conversion step when copying directly into code.
- Bulk export to CSS variables, JSON, and Tailwind config instead of palette images.
- Adjustable
kfrom 3 to 16 instead of a fixed five. - Weight percentage per swatch — important when deciding which extracted color becomes the brand accent.
- 100% offline after the page loads.
- No saved palettes, no cloud library, no team sharing — by design, since “save” requires an account and an account requires data leaving the browser.
If you need the palette to live in a shared library that your whole team can browse, Adobe Color is still the right answer. If you need to drop the palette into a :root block in the next thirty seconds, this tool is built for that.
Further reading
- Color Palette Generator — Generate complementary, analogous, triadic, or tetradic schemes from a single base hex.
- Color Shades Generator — Pull a 9-step lightness ramp from any base color, useful when you want shades of an extracted swatch.
- Color Converter — Translate freely between HEX, RGB, and HSL with a live preview.
- Color Contrast Checker — Verify each pair in your extracted palette meets WCAG AA / AAA against the backgrounds it will sit on.
- MDN: oklch() color function — Reference for OKLCH syntax and browser support.
- Björn Ottosson on Oklab — Original write-up of the perceptual color space the tool uses for OKLCH conversion.
- k-means clustering on Wikipedia — Background on the algorithm, including pitfalls and refinements like k-means++ and the elbow method for choosing
k.
The image color palette extractor is one piece of ZeroTool’s color toolkit. Pair it with the contrast checker before shipping; pair it with the shades generator when one extracted color needs to expand into a full ramp.