Please bookmark this page to avoid losing your image tool!

Image Dominant Color Extractor

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, numColors = 5, quality = 0.2, quantization = 32) {
    // 1. Input validation and parameter sanitization
    numColors = Math.max(1, Math.floor(numColors));
    quality = Math.max(0.01, Math.min(1, quality)); // Quality between 0.01 (1%) and 1 (100%)
    quantization = Math.max(1, Math.floor(quantization)); // Quantization factor, 1 means exact colors (after scaling)

    // Helper function to convert RGB components to a hex color string
    function rgbComponentsToHex(r, g, b) {
        const componentToHex = (c) => {
            const hex = c.toString(16);
            return hex.length === 1 ? "0" + hex : hex;
        };
        return ("#" + componentToHex(r) + componentToHex(g) + componentToHex(b)).toUpperCase();
    }
    
    // Helper function to parse an "rgb(r,g,b)" string into an object {r, g, b}
    function parseRgbString(rgbString) {
        const match = rgbString.match(/^rgb\((\d+),(\d+),(\d+)\)$/);
        if (!match) return null;
        return {
            r: parseInt(match[1], 10),
            g: parseInt(match[2], 10),
            b: parseInt(match[3], 10)
        };
    }

    // 2. Create canvas and draw scaled image
    const canvas = document.createElement('canvas');
    
    // Use naturalWidth/Height for intrinsic image dimensions
    const imgNaturalWidth = originalImg.naturalWidth;
    const imgNaturalHeight = originalImg.naturalHeight;

    if (imgNaturalWidth === 0 || imgNaturalHeight === 0) {
        const errorDiv = document.createElement('div');
        errorDiv.textContent = "Image has zero dimensions. It might not be loaded correctly or is an invalid image.";
        errorDiv.style.color = 'red';
        errorDiv.style.padding = '10px';
        errorDiv.style.border = '1px solid red';
        return errorDiv;
    }

    // Ensure scaled dimensions are at least 1px
    const scaledWidth = Math.max(1, Math.floor(imgNaturalWidth * quality));
    const scaledHeight = Math.max(1, Math.floor(imgNaturalHeight * quality));
    
    canvas.width = scaledWidth;
    canvas.height = scaledHeight;
    
    const ctx = canvas.getContext('2d');
    if (!ctx) { 
        // This should theoretically not happen for a '2d' context in modern browsers
        // unless canvas dimensions are excessively large or there are severe memory constraints.
        const errorDiv = document.createElement('div');
        errorDiv.textContent = "Could not get 2D rendering context for the canvas.";
        errorDiv.style.color = 'red';
        errorDiv.style.padding = '10px';
        errorDiv.style.border = '1px solid red';
        return errorDiv;
    }
    
    ctx.drawImage(originalImg, 0, 0, scaledWidth, scaledHeight);

    // 3. Get image data
    let imageDataArray;
    try {
        imageDataArray = ctx.getImageData(0, 0, scaledWidth, scaledHeight).data;
    } catch (e) {
        console.error("Error getting image data:", e);
        const errorDiv = document.createElement('div');
        let message = "Could not process image data. ";
        if (e.name === "SecurityError") {
            message += "This might be due to cross-origin restrictions (CORS). Ensure the image is served from the same domain or with appropriate CORS headers.";
        } else {
            message += `Details: ${e.message}`;
        }
        errorDiv.textContent = message;
        errorDiv.style.color = 'red';
        errorDiv.style.padding = '10px';
        errorDiv.style.border = '1px solid red';
        return errorDiv;
    }

    // 4. Count color frequencies
    const colorCounts = {}; // Using an object as a hash map/dictionary
    const alphaThreshold = 128; // Pixels with alpha value below this will be ignored

    for (let i = 0; i < imageDataArray.length; i += 4) { // Iterate R,G,B,A quadruplets
        const r_orig = imageDataArray[i];
        const g_orig = imageDataArray[i + 1];
        const b_orig = imageDataArray[i + 2];
        const a = imageDataArray[i + 3];

        if (a < alphaThreshold) {
            continue; // Skip pixels that are significantly transparent
        }

        // Apply quantization to group similar colors.
        // For each color component (R,G,B), divide by the quantization factor,
        // round to the nearest whole number, then multiply by the quantization factor.
        // Finally, clamp the value to the 0-255 range.
        const r_quantized = Math.min(255, Math.round(r_orig / quantization) * quantization);
        const g_quantized = Math.min(255, Math.round(g_orig / quantization) * quantization);
        const b_quantized = Math.min(255, Math.round(b_orig / quantization) * quantization);
        
        const colorKey = `rgb(${r_quantized},${g_quantized},${b_quantized})`;
        colorCounts[colorKey] = (colorCounts[colorKey] || 0) + 1;
    }

    // 5. Sort colors by frequency in descending order
    const sortedColors = Object.entries(colorCounts)
        .sort((itemA, itemB) => itemB[1] - itemA[1]); // item[1] is the count

    // 6. Get the top N most frequent colors
    const dominantColorsData = sortedColors.slice(0, numColors);

    // 7. Create and return the display element
    const resultContainer = document.createElement('div');
    resultContainer.style.display = 'flex';
    resultContainer.style.flexDirection = 'row'; // Main axis for color swatches
    resultContainer.style.flexWrap = 'wrap';    // Allow wrapping if many colors
    resultContainer.style.gap = '10px';         // Spacing between swatches
    resultContainer.style.padding = '10px';
    resultContainer.style.fontFamily = 'Arial, Helvetica, sans-serif';
    resultContainer.style.alignItems = 'flex-start'; // Align items at the start of the cross axis

    if (dominantColorsData.length === 0) {
        resultContainer.textContent = 'No dominant colors found. The image might be mostly transparent, or the applied settings (quality, quantization) resulted in no qualifying pixels.';
        return resultContainer;
    }

    dominantColorsData.forEach(([colorRgbString, count]) => {
        const swatchWrapper = document.createElement('div');
        swatchWrapper.style.display = 'flex';
        swatchWrapper.style.flexDirection = 'column'; // Stack color box and text vertically
        swatchWrapper.style.alignItems = 'center';    // Center items horizontally
        swatchWrapper.style.padding = '8px';
        swatchWrapper.style.border = '1px solid #eee';
        swatchWrapper.style.borderRadius = '4px';
        swatchWrapper.style.boxShadow = '0 1px 3px rgba(0,0,0,0.1)';
        swatchWrapper.setAttribute('title', `Approximate pixel count: ${count} (after scaling and quantization)`);


        const swatchColorDiv = document.createElement('div');
        swatchColorDiv.style.width = '60px';
        swatchColorDiv.style.height = '60px';
        swatchColorDiv.style.backgroundColor = colorRgbString;
        swatchColorDiv.style.border = '1px solid #ccc'; // Subtle border for the color box
        swatchColorDiv.style.borderRadius = '4px';      // Rounded corners for the color box
        swatchColorDiv.style.marginBottom = '5px';      // Space between color box and text

        const colorHexText = document.createElement('div');
        const rgbParts = parseRgbString(colorRgbString);
        let hexString = colorRgbString; // Fallback to RGB string if parsing fails

        if (rgbParts) {
            hexString = rgbComponentsToHex(rgbParts.r, rgbParts.g, rgbParts.b);
        }
        
        colorHexText.textContent = hexString;
        colorHexText.style.fontSize = '12px';
        colorHexText.style.color = '#333';        // Dark grey text for good readability
        colorHexText.style.marginTop = 'auto';     // Push text to bottom if swatchWrapper has fixed height
        colorHexText.style.textAlign = 'center';

        swatchWrapper.appendChild(swatchColorDiv);
        swatchWrapper.appendChild(colorHexText);
        
        resultContainer.appendChild(swatchWrapper);
    });

    return resultContainer;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

The Image Dominant Color Extractor is a web tool that analyzes images to identify and display the most prominent colors present. Users can specify the number of dominant colors they wish to extract, along with quality settings for the analysis. This tool is particularly useful for graphic designers, digital artists, and marketers who want to understand color schemes for branding or design purposes. It can help in creating color palettes, selecting colors for artwork, or analyzing images for mood and theme based on their colors.

Leave a Reply

Your email address will not be published. Required fields are marked *