Please bookmark this page to avoid losing your image tool!

Image Ingredient List Generator

(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.
async function processImage(originalImg, numColors = 5) {
    /**
     * Helper function to convert an RGB color to a HEX string.
     * @param {number} r - Red value (0-255)
     * @param {number} g - Green value (0-255)
     * @param {number} b - Blue value (0-255)
     * @returns {string} The HEX color string (e.g., "#RRGGBB").
     */
    const rgbToHex = (r, g, b) => {
        const toHex = (c) => ('0' + c.toString(16)).slice(-2);
        return `#${toHex(r)}${toHex(g)}${toHex(b)}`.toUpperCase();
    };

    // Create a canvas to draw the image and access its pixel data.
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d', {
        willReadFrequently: true
    });

    // For performance, scale the image down to a smaller processing width.
    // This dramatically reduces the number of pixels to analyze.
    const processingWidth = 100;
    const scale = processingWidth / originalImg.width;
    canvas.width = processingWidth;
    canvas.height = originalImg.height * scale;

    // Draw the scaled image onto the canvas.
    ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);

    let imageData;
    try {
        // Get the pixel data from the canvas. The data is a flat array of
        // [R, G, B, A, R, G, B, A, ...] values.
        imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    } catch (e) {
        // Handle potential security errors if the image is from a different origin (CORS).
        console.error("Could not get image data. This may be due to a CORS issue.", e);
        const errorDiv = document.createElement('div');
        errorDiv.textContent = 'Error: Could not process the image, possibly due to cross-origin restrictions.';
        errorDiv.style.color = 'red';
        errorDiv.style.padding = '20px';
        return errorDiv;
    }
    const data = imageData.data;

    // Use a map to store color data. We use color quantization to group similar
    // colors together, which is much more efficient than tracking every single color.
    // We shift the bits of each color channel to reduce the color space resolution.
    const colorMap = new Map();
    const quantizeShift = 4; // Reduces 8-bit color (256 values) to 4-bit (16 values).

    for (let i = 0; i < data.length; i += 4) {
        const r = data[i];
        const g = data[i + 1];
        const b = data[i + 2];
        const a = data[i + 3];

        // Ignore transparent or mostly transparent pixels.
        if (a < 128) {
            continue;
        }

        // Create a quantized key for the color to group it with similar colors.
        const rKey = r >> quantizeShift;
        const gKey = g >> quantizeShift;
        const bKey = b >> quantizeShift;
        const key = (rKey << 8) | (gKey << 4) | bKey; // Combine into a single number key.

        // If this color bin is new, initialize it.
        if (!colorMap.has(key)) {
            colorMap.set(key, {
                count: 0,
                r: 0,
                g: 0,
                b: 0
            });
        }

        const colorData = colorMap.get(key);
        colorData.count++;
        colorData.r += r; // Store original color values to average them later.
        colorData.g += g;
        colorData.b += b;
    }

    // Convert the map to an array and sort it by frequency (count).
    const sortedColors = Array.from(colorMap.values()).sort((a, b) => b.count - a.count);

    // Ensure numColors is a valid positive number.
    const finalNumColors = Math.max(1, parseInt(String(numColors), 10) || 5);

    // Get the top N most frequent color bins and calculate their average color.
    const dominantColors = sortedColors.slice(0, finalNumColors).map(colorData => {
        const avgR = Math.round(colorData.r / colorData.count);
        const avgG = Math.round(colorData.g / colorData.count);
        const avgB = Math.round(colorData.b / colorData.count);
        return {
            R: avgR,
            G: avgG,
            B: avgB
        };
    });

    // Create the final HTML element to display the results.
    const container = document.createElement('div');
    container.style.fontFamily = 'Arial, sans-serif';
    container.style.padding = '15px';
    container.style.border = '1px solid #ccc';
    container.style.borderRadius = '8px';
    container.style.maxWidth = '400px';

    const title = document.createElement('h3');
    title.textContent = 'Image Ingredients (Доминирующие цвета)';
    title.style.marginTop = '0';
    title.style.marginBottom = '15px';
    title.style.borderBottom = '1px solid #eee';
    title.style.paddingBottom = '10px';
    container.appendChild(title);

    if (dominantColors.length === 0) {
        const noColorsMsg = document.createElement('p');
        noColorsMsg.textContent = 'No significant colors could be extracted from this image.';
        container.appendChild(noColorsMsg);
        return container;
    }

    dominantColors.forEach(color => {
        const hex = rgbToHex(color.R, color.G, color.B);

        const item = document.createElement('div');
        item.style.display = 'flex';
        item.style.alignItems = 'center';
        item.style.marginBottom = '8px';
        item.style.padding = '5px';
        item.style.borderRadius = '5px';
        
        const swatch = document.createElement('div');
        swatch.style.width = '40px';
        swatch.style.height = '40px';
        swatch.style.backgroundColor = hex;
        swatch.style.border = '1px solid #ddd';
        swatch.style.marginRight = '12px';
        swatch.style.borderRadius = '4px';
        swatch.style.flexShrink = '0';

        const info = document.createElement('div');

        const hexCode = document.createElement('div');
        hexCode.textContent = hex;
        hexCode.style.fontWeight = 'bold';
        hexCode.style.fontFamily = 'monospace';

        const rgbCode = document.createElement('div');
        rgbCode.textContent = `RGB(${color.R}, ${color.G}, ${color.B})`;
        rgbCode.style.fontSize = '0.9em';
        rgbCode.style.color = '#555';

        info.appendChild(hexCode);
        info.appendChild(rgbCode);

        // A button to copy the hex code to the clipboard
        const copyButton = document.createElement('button');
        copyButton.textContent = 'Copy';
        copyButton.style.marginLeft = 'auto';
        copyButton.style.padding = '4px 8px';
        copyButton.style.fontSize = '12px';
        copyButton.style.border = '1px solid #ccc';
        copyButton.style.borderRadius = '4px';
        copyButton.style.backgroundColor = '#f0f0f0';
        copyButton.style.cursor = 'pointer';

        copyButton.onclick = () => {
            navigator.clipboard.writeText(hex).then(() => {
                copyButton.textContent = 'Copied!';
                setTimeout(() => {
                    copyButton.textContent = 'Copy';
                }, 1500);
            }).catch(err => {
                console.error('Failed to copy text: ', err);
                alert('Failed to copy color code.');
            });
        };
        
        item.appendChild(swatch);
        item.appendChild(info);
        item.appendChild(copyButton);
        container.appendChild(item);
    });

    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 Ingredient List Generator is a tool designed to analyze an image and extract its dominant colors. With the ability to identify and display the most frequent colors present in the image, this tool can be particularly useful for artists, designers, and developers who want to create color palettes or understand the color composition of images. By generating a list of colors in both RGB and HEX formats, users can easily incorporate these colors into their projects, whether for graphic design, web development, or other creative endeavors.

Leave a Reply

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