Please bookmark this page to avoid losing your image tool!

Image Background Replacement 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.
async function processImage(originalImg, backgroundImageUrl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/wcAAwAB/2+CMflMAAAAAElFTkSuQmCC", keyColorStr = "0,255,0", tolerance = 30) {

    // Helper function to parse a CSS color string to an RGB object
    function parseColorToRGB(colorStr) {
        const d = document.createElement("div");
        d.style.display = "none"; // Avoid affecting layout or visibility
        d.style.color = colorStr;
        document.body.appendChild(d); // Element must be in DOM to get computed style

        let rgb = { r: 0, g: 255, b: 0 }; // Default to bright green (lime)

        try {
            // getComputedStyle correctly parses various color formats (names, hex, rgb, rgba)
            const computedColor = window.getComputedStyle(d).color;
            const match = computedColor.match(/rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})(?:,\s*[\d\.]+)?\)/);
            if (match) {
                rgb = { r: parseInt(match[1]), g: parseInt(match[2]), b: parseInt(match[3]) };
            } else {
                console.warn(`Could not parse color string "${colorStr}" to RGB. Defaulting to green (0,255,0).`);
            }
        } catch (e) {
            console.warn(`Error parsing color string "${colorStr}": ${e}. Defaulting to green (0,255,0).`);
        } finally {
            if (d.parentNode) { // Check if still child of body before removing
                document.body.removeChild(d);
            }
        }
        return rgb;
    }

    const targetKeyColor = parseColorToRGB(keyColorStr);

    // Load the new background image
    const backgroundImg = await new Promise((resolve, reject) => {
        const img = new Image();
        
        // Determine if the background image URL is cross-origin
        let isCrossOrigin = false;
        try {
            const bgUrl = new URL(backgroundImageUrl, window.location.href);
            if (bgUrl.origin !== window.location.origin) {
                isCrossOrigin = true;
            }
        } catch (e) {
            // Invalid URL, let img.src handle it, will likely error
        }

        if (isCrossOrigin) {
            img.crossOrigin = "Anonymous";
        }
        
        img.onload = () => resolve(img);
        img.onerror = (errorEvent) => {
            console.warn(`Failed to load background image from "${backgroundImageUrl}". Using a default 1x1 white background. Error: ${errorEvent.type}`);
            const fallbackImg = new Image();
            fallbackImg.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/wcAAwAB/2+CMflMAAAAAElFTkSuQmCC"; // 1x1 opaque white PNG
            fallbackImg.onload = () => resolve(fallbackImg);
            fallbackImg.onerror = (fallbackErrorEvent) => {
                console.error("Failed to load fallback background image. This indicates a critical issue.", fallbackErrorEvent);
                // Reject with an error, as we can't proceed without any background
                reject(new Error("Failed to load background image and fallback image."));
            };
        };
        img.src = backgroundImageUrl;
    }).catch(error => {
        // This catch is for the promise reject from fallbackImg.onerror
        console.error(error.message);
        // Create a dummy fully transparent image so it can be drawn without erroring later
        const dummyImg = new Image();
        dummyImg.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; // 1x1 transparent gif
        return new Promise(resolve => { dummyImg.onload = () => resolve(dummyImg); }); // Ensure it's loaded
    });


    const width = originalImg.naturalWidth || originalImg.width;
    const height = originalImg.naturalHeight || originalImg.height;

    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d');

    if (width === 0 || height === 0) {
        console.warn("Original image has zero width or height.");
        // Draw background if it's valid and canvas has no area, result is effectively empty or just background
        if (backgroundImg && backgroundImg.naturalWidth > 0 && backgroundImg.naturalHeight > 0) {
             ctx.drawImage(backgroundImg, 0, 0, width, height); // width/height might be 0, resulting in no draw
        }
        return canvas; // Return empty or background-only canvas
    }

    // Draw original image to a temporary canvas to get its pixel data
    const tempCanvas = document.createElement('canvas');
    tempCanvas.width = width;
    tempCanvas.height = height;
    const tempCtx = tempCanvas.getContext('2d', { willReadFrequently: true }); // Hint for optimization
    
    tempCtx.drawImage(originalImg, 0, 0, width, height);
    
    let imageData;
    try {
        imageData = tempCtx.getImageData(0, 0, width, height);
    } catch (e) {
        console.error("Could not get image data from originalImg. This often happens due to CORS restrictions if the image is loaded from a different domain without `crossOrigin=\"anonymous\"` set on the Image element. Fallback: returning original image drawn on a canvas without background replacement.", e);
        ctx.clearRect(0,0,width,height); // Ensure canvas is clean
        ctx.drawImage(originalImg, 0, 0, width, height);
        return canvas;
    }
    
    const data = imageData.data;
    // Create new ImageData for the foreground (original image with background made transparent)
    const foregroundImageData = tempCtx.createImageData(width, height);
    const fgData = foregroundImageData.data;

    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];

        // Calculate color distance (Manhattan distance)
        const distance = Math.abs(r - targetKeyColor.r) + 
                         Math.abs(g - targetKeyColor.g) + 
                         Math.abs(b - targetKeyColor.b);

        if (distance <= tolerance) {
            // This pixel is part of the background key color: make it transparent
            fgData[i + 3] = 0; // Set alpha to 0
            // Optional optimization: copy r,g,b if you want to preserve color for semi-transparent keyed pixels.
            // Not needed here as we make it fully transparent.
            // fgData[i] = r; fgData[i+1] = g; fgData[i+2] = b;
        } else {
            // This pixel is foreground: copy it as is
            fgData[i]     = r;
            fgData[i + 1] = g;
            fgData[i + 2] = b;
            fgData[i + 3] = a; // Preserve original alpha
        }
    }

    // Put the processed foreground image data onto the temporary canvas
    tempCtx.putImageData(foregroundImageData, 0, 0);

    // Composite the final image on the main output canvas:
    // 1. Draw the new background image, scaled to fit the canvas dimensions
    if (backgroundImg && backgroundImg.naturalWidth > 0 && backgroundImg.naturalHeight > 0) {
        ctx.drawImage(backgroundImg, 0, 0, width, height);
    } else {
        // If background is still not loaded (e.g. fallback also failed, though handled by dummy), fill with a color
        ctx.fillStyle = 'rgba(0,0,0,0)'; // Transparent
        ctx.fillRect(0, 0, width, height);
    }
    
    // 2. Draw the processed foreground (from tempCanvas) on top of the background
    ctx.drawImage(tempCanvas, 0, 0, width, height);

    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 Background Replacement Tool allows users to easily replace the background of an image by removing specific colors, such as a green screen effect. This tool is particularly useful for tasks such as creating promotional materials, editing photos, or designing graphics for web and social media. Users can upload their image, specify the color to be replaced, and choose a new background image, enabling seamless integration of their subject into a different context.

Leave a Reply

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