Oh MyUtils

Image Color Extractor - Extract Palette from Image Online

Extract dominant colors from any image and generate color palettes. Get HEX, RGB, and HSL values — 100% client-side, no image uploaded.

Frequently Asked Questions

What is an image color extractor and why do I need it?

An image color extractor analyzes the pixels of an uploaded image and identifies the most dominant colors, producing a color palette. It is useful for designers who need to derive a consistent color scheme from photographs, artwork, or brand images. Instead of manually sampling colors with an eyedropper, the tool automatically identifies the most representative colors and provides them in web-ready formats (HEX, RGB, HSL) for immediate use in CSS, design tools, or branding guidelines.

How do I use this image color extractor tool?

1. Drag and drop an image onto the upload area (or click to browse files). 2. The tool automatically extracts the dominant colors and displays them as a palette. 3. Adjust the number of colors using the palette size slider (2-16 colors). 4. Click on any color swatch to copy its HEX, RGB, or HSL value. 5. Use the export options to copy the entire palette as CSS variables, JSON, or plain text. 6. Optionally, sort colors by frequency, hue, or brightness using the sort controls.

Is my image data safe? Are images uploaded to a server?

Your images are 100% safe and never leave your browser. All color extraction is performed client-side using the HTML5 Canvas API. The tool reads pixel data directly from your image in the browser, applies a color quantization algorithm locally, and displays the results. No image data is transmitted to any server, making this tool completely private. You can verify this by using the tool with your network connection disabled after the page loads.

What color quantization algorithm is used?

This tool uses the Median Cut algorithm, a well-established color quantization technique. It works by recursively dividing the color space of the image into smaller regions, splitting at the median along the channel (red, green, or blue) with the widest range. Each region is then averaged to produce a single representative color. Median Cut is fast, deterministic, and produces visually pleasing palettes that accurately represent the dominant colors.

What image formats are supported?

The tool supports PNG, JPEG (JPG), WebP, and GIF images up to 10MB in file size. Transparent pixels in PNG, WebP, and GIF images are automatically ignored during color extraction so they do not skew the palette. For GIF images, only the first (static) frame is analyzed.

How many colors can I extract from an image?

You can extract between 2 and 16 colors. The default is 8 colors, which provides a good balance for most use cases. For simpler images or minimal palettes, 4-6 colors work well. For complex photographs with many distinct color regions, 10-16 colors will capture more nuance. The extraction updates in real-time as you adjust the slider.

What is the difference between sorting by frequency, hue, and brightness?

Frequency (default) orders colors by how much area they occupy in the image, with the most dominant color first. Hue orders colors by their position on the color wheel (0-360 degrees), creating a rainbow-like sequence from red through orange, yellow, green, blue, and violet. Brightness orders colors from lightest to darkest based on their HSL lightness value, useful for creating gradients or identifying contrast ranges.

Can I export the color palette for use in my code?

Yes. The tool offers multiple export formats optimized for developers: CSS Variables generates :root { --color-1: #FF5733; --color-2: #3498DB; ... } ready for CSS. JSON exports an array of objects with hex, rgb, and hsl values for programmatic use. Plain Text provides a simple list of HEX codes, one per line.

Code Examples

// Extract dominant colors from an image using Canvas API + Median Cut
function extractColorsFromImage(imageSource, colorCount = 8) {
  return new Promise((resolve, reject) => {
    const img = new Image();

    img.onload = () => {
      const maxPixels = 10000;
      const scale = Math.min(1, Math.sqrt(maxPixels / (img.width * img.height)));
      const width = Math.max(1, Math.floor(img.width * scale));
      const height = Math.max(1, Math.floor(img.height * scale));

      const canvas = document.createElement("canvas");
      canvas.width = width;
      canvas.height = height;

      const ctx = canvas.getContext("2d");
      ctx.drawImage(img, 0, 0, width, height);

      const imageData = ctx.getImageData(0, 0, width, height);
      const pixels = [];

      for (let i = 0; i < imageData.data.length; i += 4) {
        if (imageData.data[i + 3] < 128) continue;
        pixels.push({
          r: imageData.data[i],
          g: imageData.data[i + 1],
          b: imageData.data[i + 2],
        });
      }

      const colors = medianCut(pixels, colorCount);
      resolve(colors);
    };

    img.onerror = () => reject(new Error("Failed to load image"));

    if (imageSource instanceof File) {
      img.src = URL.createObjectURL(imageSource);
    } else {
      img.src = imageSource;
    }
  });
}

function medianCut(pixels, targetCount) {
  if (pixels.length === 0) return [];
  let buckets = [pixels];

  while (buckets.length < targetCount) {
    let maxRange = -1, maxIndex = 0, splitChannel = "r";

    for (let i = 0; i < buckets.length; i++) {
      if (buckets[i].length < 2) continue;
      for (const ch of ["r", "g", "b"]) {
        const values = buckets[i].map((p) => p[ch]);
        const range = Math.max(...values) - Math.min(...values);
        if (range > maxRange) {
          maxRange = range;
          maxIndex = i;
          splitChannel = ch;
        }
      }
    }

    if (maxRange <= 0) break;

    const toSplit = buckets[maxIndex];
    toSplit.sort((a, b) => a[splitChannel] - b[splitChannel]);
    const mid = Math.floor(toSplit.length / 2);
    buckets.splice(maxIndex, 1, toSplit.slice(0, mid), toSplit.slice(mid));
  }

  const totalPixels = pixels.length;
  return buckets.map((bucket) => {
    const r = Math.round(bucket.reduce((s, p) => s + p.r, 0) / bucket.length);
    const g = Math.round(bucket.reduce((s, p) => s + p.g, 0) / bucket.length);
    const b = Math.round(bucket.reduce((s, p) => s + p.b, 0) / bucket.length);
    const hex = "#" + [r, g, b].map((v) => v.toString(16).padStart(2, "0")).join("").toUpperCase();
    return { hex, rgb: { r, g, b }, percentage: ((bucket.length / totalPixels) * 100).toFixed(1) };
  });
}

// Usage
const input = document.querySelector('input[type="file"]');
input.addEventListener("change", async (e) => {
  const file = e.target.files[0];
  const colors = await extractColorsFromImage(file, 8);
  colors.forEach((c) => console.log(`${c.hex} - ${c.percentage}%`));
});

Related Tools