Please bookmark this page to avoid losing your image tool!

Image Jelly Bean Filter Effect Tool

(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, jellyBeanColorsStr = "#FF0000,#00FF00,#0000FF,#FFFF00,#FFA500,#800080,#FF00FF,#00FFFF") {

    // Helper function to parse hex color string (e.g., "#FF0000" or "FF0000") to an RGB object.
    function hexToRgb(hex) {
        // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
        const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
        hex = hex.replace(shorthandRegex, (m, r, g, b) => {
            return r + r + g + g + b + b;
        });

        const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
        return result ? {
            r: parseInt(result[1], 16),
            g: parseInt(result[2], 16),
            b: parseInt(result[3], 16)
        } : null;
    }

    // Helper function to calculate the squared Euclidean distance between two RGB colors.
    // Squared distance is used for efficiency as it avoids Math.sqrt() and preserves order.
    function colorDistance(rgb1, rgb2) {
        const dr = rgb1.r - rgb2.r;
        const dg = rgb1.g - rgb2.g;
        const db = rgb1.b - rgb2.b;
        return dr * dr + dg * dg + db * db;
    }

    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d', { willReadFrequently: true }); // willReadFrequently can optimize getImageData/putImageData

    // Use naturalWidth/Height if available (indicates intrinsic size), otherwise fallback to width/height.
    // This is important if the image object's width/height attributes were styled disproportionately.
    const imgWidth = originalImg.naturalWidth || originalImg.width;
    const imgHeight = originalImg.naturalHeight || originalImg.height;

    canvas.width = imgWidth;
    canvas.height = imgHeight;

    // Draw the original image onto the canvas.
    try {
        ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
    } catch (e) {
        console.error("Error drawing image to canvas. Ensure image is properly loaded and accessible (check CORS if applicable).", e);
        // Return an empty (or partially drawn) canvas if drawing fails.
        return canvas;
    }
    
    // Parse the jellyBeanColorsStr into an array of RGB objects.
    const paletteHex = jellyBeanColorsStr
        .split(',')
        .map(s => s.trim()) // Remove whitespace around color strings
        .filter(s => s.length > 0); // Remove empty strings from split

    if (paletteHex.length === 0) {
        // If the color string is empty, effectively no filter is applied. Return the original image on the canvas.
        return canvas;
    }

    const paletteRgb = paletteHex.map(hexToRgb).filter(rgb => rgb !== null);

    if (paletteRgb.length === 0) {
        // If no valid hex colors could be parsed, return the original image.
        console.warn("No valid jelly bean colors provided or parsed. Returning original image.");
        return canvas;
    }

    let imageData;
    try {
        imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    } catch (e) {
        console.error("Error getting ImageData from canvas. This commonly occurs due to CORS policy if the image is from a different origin and the canvas is tainted.", e);
        // If getImageData fails, we can't process the pixels. Return the canvas with the original image.
        return canvas;
    }
    
    const data = imageData.data; // The pixel data array (RGBA components)

    // Iterate over each pixel (4 bytes at a time: R, G, B, A).
    for (let i = 0; i < data.length; i += 4) {
        const r = data[i];
        const g = data[i + 1];
        const b = data[i + 2];
        // Alpha channel (data[i+3]) is preserved.

        let minDistance = Infinity;
        let closestColor = paletteRgb[0]; // Default to the first color in the palette.

        // Find the color in the palette that is closest to the current pixel's color.
        for (const jellyColor of paletteRgb) {
            const dist = colorDistance({ r, g, b }, jellyColor);
            if (dist < minDistance) {
                minDistance = dist;
                closestColor = jellyColor;
            }
            // Optimization: if a perfect match is found (distance is 0), no need to check further.
            if (minDistance === 0) {
                break;
            }
        }

        // Replace the pixel's color with the closest jelly bean color.
        data[i] = closestColor.r;
        data[i + 1] = closestColor.g;
        data[i + 2] = closestColor.b;
        // data[i+3] (alpha) remains unchanged from the original image.
    }

    // Put the modified pixel data back onto the canvas.
    ctx.putImageData(imageData, 0, 0);

    return canvas;
}

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 Jelly Bean Filter Effect Tool allows users to apply a vibrant jelly bean color filter to their images. By selecting a set of specific jelly bean colors, the tool processes the original image and replaces each pixel’s color with the closest match from the chosen palette. This tool can be used for enhancing photos for social media, creating colorful artwork, or adding a playful touch to digital content. It is ideal for those looking to add a fun and unique visual style to their images.

Leave a Reply

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