You can edit the below JavaScript code to customize the image tool.
async function processImage(originalImg, removeColorStr = "0,255,0", tolerance = 30, newBackground = "transparent") {
const imgWidth = originalImg.naturalWidth || originalImg.width;
const imgHeight = originalImg.naturalHeight || originalImg.height;
// Validate the input image object and its dimensions
if (!originalImg ||
!(originalImg instanceof HTMLImageElement ||
originalImg instanceof HTMLCanvasElement ||
originalImg instanceof SVGImageElement || // Though SVGImageElement might behave differently with drawImage
originalImg instanceof HTMLVideoElement) || // Video frames can also be drawn
imgWidth === 0 || imgHeight === 0) {
console.error("Original image is not a valid image/canvas/video element, not loaded, or has zero dimensions.");
const emptyCanvas = document.createElement('canvas');
emptyCanvas.width = 1;
emptyCanvas.height = 1;
// Async function automatically wraps return value in Promise.resolve()
return emptyCanvas;
}
// Helper function to parse a color string (hex or "r,g,b") into an RGB object.
// Defaults to a specified color (e.g., green) if parsing fails.
function _parseColorToRgb(colorInput, defaultRgb = { r: 0, g: 255, b: 0 }) {
if (typeof colorInput !== 'string') {
// Warn if a non-string, non-default value was unexpectedly passed.
if (colorInput !== defaultRgb && colorInput !== undefined && colorInput !== null) {
console.warn(`Invalid color format (expected string): ${JSON.stringify(colorInput)}. Using default color.`);
}
return defaultRgb;
}
const trimmedStr = colorInput.trim();
// Try parsing hex color (e.g., #RRGGBB or #RGB)
if (trimmedStr.startsWith('#')) {
let hex = trimmedStr.slice(1);
if (hex.length === 3) { // Expand #RGB to #RRGGBB
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
}
if (hex.length === 6) {
const r = parseInt(hex.substring(0, 2), 16);
const g = parseInt(hex.substring(2, 4), 16);
const b = parseInt(hex.substring(4, 6), 16);
if (!isNaN(r) && !isNaN(g) && !isNaN(b)) {
return { r, g, b };
}
}
} else { // Try parsing "r,g,b" string
const parts = trimmedStr.split(',');
if (parts.length === 3) {
const r = parseInt(parts[0].trim(), 10);
const g = parseInt(parts[1].trim(), 10);
const b = parseInt(parts[2].trim(), 10);
// Validate that parsed parts are numbers and within 0-255 range
if (!isNaN(r) && !isNaN(g) && !isNaN(b) &&
[r,g,b].every(p => p >= 0 && p <= 255)) {
return { r, g, b };
}
}
}
// Warn if parsing failed for a non-empty, non-default input string
const isDefaultInputValue = (removeColorStr === colorInput && colorInput === "0,255,0");
if (trimmedStr && !isDefaultInputValue) {
console.warn(`Could not parse color string: "${colorInput}". Using default color.`);
} else if (!trimmedStr && colorInput !== undefined && colorInput !== null) { // Empty string was passed
console.warn(`Empty color string received. Using default color.`);
}
return defaultRgb;
}
const targetRgb = _parseColorToRgb(removeColorStr, { r: 0, g: 255, b: 0 });
let currentTolerance = Number(tolerance);
// Validate tolerance: must be a non-negative number.
if (isNaN(currentTolerance) || currentTolerance < 0) {
console.warn(`Invalid tolerance value: ${tolerance}. Using default 30.`);
currentTolerance = 30;
}
// Create a canvas to process the foreground (remove background)
const fgCanvas = document.createElement('canvas');
fgCanvas.width = imgWidth;
fgCanvas.height = imgHeight;
// Add { willReadFrequently: true } for potential performance optimization if supported
const fgCtx = fgCanvas.getContext('2d', { willReadFrequently: true });
// Draw the original image onto the foreground canvas
fgCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
let imageData;
try {
// Get pixel data from the foreground canvas
imageData = fgCtx.getImageData(0, 0, fgCanvas.width, fgCanvas.height);
} catch (e) {
console.error("Could not get image data from canvas. This might be due to cross-origin restrictions if the original image source is external and not CORS-enabled. Original error:", e);
// Fallback: return a canvas with the original image drawn, but no processing.
const errorCanvas = document.createElement('canvas');
errorCanvas.width = imgWidth;
errorCanvas.height = imgHeight;
errorCanvas.getContext('2d').drawImage(originalImg, 0, 0, imgWidth, imgHeight);
return errorCanvas;
}
const data = imageData.data; // Pixel data array (R,G,B,A, R,G,B,A, ...)
// Iterate through each pixel to modify alpha based on color match
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
// Calculate Euclidean distance between current pixel color and target color
const diff = Math.sqrt(
Math.pow(r - targetRgb.r, 2) +
Math.pow(g - targetRgb.g, 2) +
Math.pow(b - targetRgb.b, 2)
);
// If color difference is within tolerance, make the pixel transparent
if (diff <= currentTolerance) {
data[i + 3] = 0; // Set alpha channel to 0
}
}
// Put the modified pixel data back onto the foreground canvas
fgCtx.putImageData(imageData, 0, 0);
// fgCanvas now contains the original image with parts of its background made transparent.
// Create the final result canvas
const resultCanvas = document.createElement('canvas');
resultCanvas.width = imgWidth;
resultCanvas.height = imgHeight;
const resultCtx = resultCanvas.getContext('2d');
// Helper function to determine if a string is likely an image URL
function isLikelyImageUrl(str) {
if (typeof str !== 'string') return false;
const s = str.toLowerCase().trim();
// Check for data URLs
if (s.startsWith('data:image')) return true;
// Check for absolute URLs
if (s.startsWith('http://') || s.startsWith('https://')) return true;
// Check for common relative/absolute paths ending with image extensions.
// This tries to avoid matching CSS color names that might contain dots.
if (/\.(jpeg|jpg|gif|png|webp)$/i.test(s)) {
// If it looks like a file path (starts with /, ./, ../) or doesn't contain URL scheme characters (:)
return s.startsWith('/') || s.startsWith('./') || s.startsWith('../') || !s.includes(':');
}
return false;
}
// Apply the new background
if (newBackground === "transparent") {
// If new background is transparent, just draw the (processed) foreground onto the result canvas.
// The result canvas is initially transparent.
resultCtx.drawImage(fgCanvas, 0, 0);
} else if (isLikelyImageUrl(newBackground)) {
// If new background is an image URL, load it and draw it.
try {
const bgImg = await new Promise((resolve, reject) => {
const img = new Image();
// Handle potential CORS issues for external background images
img.crossOrigin = "Anonymous";
img.onload = () => resolve(img);
img.onerror = (event) => reject(new Error(`Failed to load background image from: ${newBackground}. Error type: ${event.type}`));
img.src = newBackground;
});
// Draw the loaded background image, scaled to fit the canvas
resultCtx.drawImage(bgImg, 0, 0, resultCanvas.width, resultCanvas.height);
// Draw the processed foreground image on top of the background
resultCtx.drawImage(fgCanvas, 0, 0);
} catch (error) {
console.error(error.message);
// Fallback on error: draw a default (e.g., white) background, then the foreground.
resultCtx.fillStyle = 'white';
resultCtx.fillRect(0, 0, resultCanvas.width, resultCanvas.height);
resultCtx.drawImage(fgCanvas, 0, 0);
}
} else {
// Treat newBackground as a solid color string (e.g., "blue", "#FF0000", "rgba(0,0,255,0.5)")
resultCtx.fillStyle = newBackground;
resultCtx.fillRect(0, 0, resultCanvas.width, resultCanvas.height);
// Draw the processed foreground image on top of the solid color background
resultCtx.drawImage(fgCanvas, 0, 0);
}
return resultCanvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Photo Background Change Tool allows users to seamlessly change the background of an image by removing a specific color. This tool is particularly useful for graphic designers, marketers, or anyone looking to enhance images for social media, presentations, or promotional materials. Users can specify a color to remove and replace it with either a transparent background or a new image/color of their choice, effectively allowing for custom composite images.