Please bookmark this page to avoid losing your image tool!

Image Color Formula Calculator

(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, iterations = 8) {
    numColors = Number(numColors) || 5;
    iterations = Number(iterations) || 8;

    // 1. Prepare a downscaled canvas for faster pixel processing
    const processCanvas = document.createElement('canvas');
    const processCtx = processCanvas.getContext('2d');
    
    // Scale image down to a maximum of 100x100 for fast K-Means clustering
    const MAX_DIM = 100;
    const scale = Math.min(MAX_DIM / originalImg.width, MAX_DIM / originalImg.height, 1);
    const pw = Math.round(originalImg.width * scale);
    const ph = Math.round(originalImg.height * scale);
    
    processCanvas.width = pw || 1;
    processCanvas.height = ph || 1;
    processCtx.drawImage(originalImg, 0, 0, pw, ph);
    
    const imgData = processCtx.getImageData(0, 0, processCanvas.width, processCanvas.height).data;
    
    // 2. Extract opaque pixels
    const pixels = [];
    for (let i = 0; i < imgData.length; i += 4) {
        if (imgData[i + 3] > 128) { // Ignore transparent pixels
            pixels.push([imgData[i], imgData[i + 1], imgData[i + 2]]);
        }
    }
    
    if (pixels.length === 0) {
        pixels.push([0, 0, 0]); // Fallback if image is completely transparent
    }

    // 3. Simple K-Means++ Initialization
    let centroids = [];
    // Pick first centroid randomly
    centroids.push(pixels[Math.floor(Math.random() * pixels.length)].slice());
    
    // Pick the rest of the centroids by trying to find points dispersed from existing ones
    for (let i = 1; i < numColors; i++) {
        let maxSqDist = -1;
        let nextCentroid = pixels[0];
        
        // Sample random pixels to find a dispersed centroid (optimisation over checking all)
        for (let step = 0; step < 100; step++) {
            let candidate = pixels[Math.floor(Math.random() * pixels.length)];
            let minSqDist = Infinity;
            for (let c of centroids) {
                let dist = (candidate[0] - c[0])**2 + (candidate[1] - c[1])**2 + (candidate[2] - c[2])**2;
                if (dist < minSqDist) {
                    minSqDist = dist;
                }
            }
            if (minSqDist > maxSqDist) {
                maxSqDist = minSqDist;
                nextCentroid = candidate;
            }
        }
        centroids.push(nextCentroid.slice());
    }

    // 4. K-Means Clustering Iterations
    let clusters = [];
    for (let iter = 0; iter < iterations; iter++) {
        clusters = Array.from({ length: numColors }, () => []);
        
        // Assign pixels to closest centroid
        for (let p of pixels) {
            let minSqDist = Infinity;
            let bestIdx = 0;
            for (let i = 0; i < numColors; i++) {
                let c = centroids[i];
                let dist = (p[0] - c[0])**2 + (p[1] - c[1])**2 + (p[2] - c[2])**2;
                if (dist < minSqDist) {
                    minSqDist = dist;
                    bestIdx = i;
                }
            }
            clusters[bestIdx].push(p);
        }
        
        // Update centroids to the mean of their clusters
        for (let i = 0; i < numColors; i++) {
            if (clusters[i].length > 0) {
                let sumR = 0, sumG = 0, sumB = 0;
                for (let p of clusters[i]) {
                    sumR += p[0];
                    sumG += p[1];
                    sumB += p[2];
                }
                centroids[i] = [
                    Math.round(sumR / clusters[i].length),
                    Math.round(sumG / clusters[i].length),
                    Math.round(sumB / clusters[i].length)
                ];
            }
        }
    }

    // 5. Aggregate and Sort Clusters
    let resultClusters = [];
    for (let i = 0; i < numColors; i++) {
        if (clusters[i].length > 0) {
            resultClusters.push({
                centroid: centroids[i],
                count: clusters[i].length
            });
        }
    }
    
    // Sort descending by proportion
    resultClusters.sort((a, b) => b.count - a.count);

    // 6. Build the Visual UI (Kormulator Output)
    const container = document.createElement('div');
    container.style.fontFamily = 'system-ui, -apple-system, sans-serif';
    container.style.padding = '20px';
    container.style.backgroundColor = '#f7f9fa';
    container.style.borderRadius = '12px';
    container.style.display = 'flex';
    container.style.flexDirection = 'column';
    container.style.alignItems = 'center';
    container.style.boxShadow = '0 8px 16px rgba(0,0,0,0.05)';
    container.style.maxWidth = '600px';
    container.style.margin = '0 auto';
    container.style.boxSizing = 'border-box';

    // Title
    const title = document.createElement('h2');
    title.textContent = 'Image Color Formula';
    title.style.margin = '0 0 20px 0';
    title.style.color = '#333';
    container.appendChild(title);

    // Render Original Image
    const imgCanvas = document.createElement('canvas');
    const imgCtx = imgCanvas.getContext('2d');
    // Bound display size while maintaining aspect ratio
    const DISPLAY_MAX = 400;
    const dispScale = Math.min(DISPLAY_MAX / originalImg.width, DISPLAY_MAX / originalImg.height, 1);
    imgCanvas.width = originalImg.width * dispScale;
    imgCanvas.height = originalImg.height * dispScale;
    imgCtx.drawImage(originalImg, 0, 0, imgCanvas.width, imgCanvas.height);
    
    imgCanvas.style.maxWidth = '100%';
    imgCanvas.style.borderRadius = '8px';
    imgCanvas.style.marginBottom = '24px';
    imgCanvas.style.boxShadow = '0 2px 8px rgba(0,0,0,0.15)';
    container.appendChild(imgCanvas);

    // Distribution Bar
    const bar = document.createElement('div');
    bar.style.display = 'flex';
    bar.style.width = '100%';
    bar.style.height = '36px';
    bar.style.borderRadius = '18px';
    bar.style.overflow = 'hidden';
    bar.style.boxShadow = '0 2px 6px rgba(0,0,0,0.1)';
    bar.style.marginBottom = '24px';
    container.appendChild(bar);

    // Swatch Cards Container
    const details = document.createElement('div');
    details.style.display = 'grid';
    details.style.gridTemplateColumns = 'repeat(auto-fit, minmax(100px, 1fr))';
    details.style.gap = '16px';
    details.style.width = '100%';
    container.appendChild(details);

    // Utility to Convert RGB to Hex String
    const rgbToHex = (r, g, b) => {
        return "#" + (1 << 24 | r << 16 | g << 8 | b).toString(16).slice(1).toUpperCase();
    };

    // Populate UI with Cluster Data
    let cumulativePct = 0;
    for (let i = 0; i < resultClusters.length; i++) {
        let cluster = resultClusters[i];
        
        let hex = rgbToHex(cluster.centroid[0], cluster.centroid[1], cluster.centroid[2]);
        
        // Handle rounding visually so the bar fills perfectly
        let rawPct = (cluster.count / pixels.length) * 100;
        let pctLabelText = rawPct.toFixed(1) + '%';
        if (i === resultClusters.length - 1) { // ensure the last piece fills the gap
            rawPct = 100 - cumulativePct;
        }
        cumulativePct += rawPct;

        // Progress Bar Segment
        let segment = document.createElement('div');
        segment.style.width = rawPct + '%';
        segment.style.backgroundColor = hex;
        segment.style.transition = 'width 0.3s ease';
        segment.title = `${hex} (${pctLabelText})`;
        bar.appendChild(segment);

        // Feature Card
        let card = document.createElement('div');
        card.style.backgroundColor = '#fff';
        card.style.padding = '12px 8px';
        card.style.borderRadius = '10px';
        card.style.display = 'flex';
        card.style.flexDirection = 'column';
        card.style.alignItems = 'center';
        card.style.boxShadow = '0 2px 5px rgba(0,0,0,0.04)';
        card.style.border = '1px solid #eee';

        let swatch = document.createElement('div');
        swatch.style.width = '40px';
        swatch.style.height = '40px';
        swatch.style.backgroundColor = hex;
        swatch.style.borderRadius = '50%';
        swatch.style.marginBottom = '12px';
        swatch.style.boxShadow = 'inset 0 1px 3px rgba(0,0,0,0.2)';

        let hexLabel = document.createElement('div');
        hexLabel.textContent = hex;
        hexLabel.style.fontWeight = '600';
        hexLabel.style.fontSize = '14px';
        hexLabel.style.color = '#333';
        hexLabel.style.marginBottom = '4px';

        let pctLabel = document.createElement('div');
        pctLabel.textContent = pctLabelText;
        pctLabel.style.color = '#777';
        pctLabel.style.fontSize = '13px';

        card.appendChild(swatch);
        card.appendChild(hexLabel);
        card.appendChild(pctLabel);
        details.appendChild(card);
    }

    return container;
}

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 Color Formula Calculator is a tool designed to analyze images and extract their dominant color palettes. By using advanced clustering algorithms, it identifies the most prominent colors within an image and calculates their exact hex codes and the percentage of the image they occupy. This tool is highly useful for graphic designers, web developers, and artists who need to create consistent color schemes, extract brand colors from logos, or generate cohesive color palettes for digital projects.

Leave a Reply

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