You can edit the below JavaScript code to customize the image tool.
/**
* Removes red-eye effect from an image using a pixel-based heuristic.
*
* @param {Image} originalImg The original HTMLImageElement. It's assumed this image is loaded
* and has `naturalWidth` and `naturalHeight` > 0.
* @param {number} [minRedValue=70] The minimum value for the red channel (0-255) for a pixel
* to be considered as potential red-eye. Higher values are stricter.
* @param {number} [redDominanceFactor=1.5] How much the red channel must dominate the green and
* blue channels (e.g., R > G * factor && R > B * factor).
* A factor of 1.0 means red just needs to be greater.
* Higher values mean red must be much stronger.
* @returns {HTMLCanvasElement} A canvas element with the red-eye effect reduced or removed.
* In case of errors (e.g., invalid image dimensions, CORS restrictions),
* it returns a canvas displaying an error message.
*/
function processImage(originalImg, minRedValue = 70, redDominanceFactor = 1.5) {
const canvas = document.createElement('canvas');
// Using { willReadFrequently: true } can be an optimization hint for the browser
// for contexts where getImageData/putImageData are used often.
const ctx = canvas.getContext('2d', { willReadFrequently: true });
const imgWidth = originalImg.naturalWidth;
const imgHeight = originalImg.naturalHeight;
// Validate image dimensions first
if (imgWidth === 0 || imgHeight === 0) {
// Setup a canvas to display an error message for invalid image dimensions
canvas.width = 300; // Arbitrary small size for the error message canvas
canvas.height = 80;
ctx.font = "bold 14px Arial";
ctx.fillStyle = "#700"; // Dark red color for the text
ctx.textAlign = "center";
ctx.textBaseline = "middle"; // Vertically center text
ctx.fillText("Error: Image dimensions are invalid (0x0).", canvas.width / 2, canvas.height / 2);
console.error("processImage: Original image dimensions are 0x0.");
return canvas;
}
// Set canvas dimensions to match the original image
canvas.width = imgWidth;
canvas.height = imgHeight;
try {
// Draw the original image onto the canvas
ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
// Get the pixel data from the canvas. This can throw a security error for cross-origin images.
const imageData = ctx.getImageData(0, 0, imgWidth, imgHeight);
const data = imageData.data; // This is a Uint8ClampedArray: [R, G, B, A, R, G, B, A, ...]
// Although dimensions are checked, imageData.data could theoretically be null
// (e.g., out of memory for extremely large canvases), though rare.
if (!data) {
console.error("processImage: Failed to retrieve ImageData.data (is null).");
ctx.font = "bold 16px Arial";
// Draw a semi-transparent background for the error text for better visibility
ctx.fillStyle = "rgba(128, 0, 0, 0.75)"; // Dark red, semi-transparent
ctx.fillRect(0, canvas.height / 2 - 20, canvas.width, 40); // Background rectangle
ctx.fillStyle = "white"; // Text color
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("Error: Could not retrieve pixel data.", canvas.width / 2, canvas.height / 2);
return canvas; // Return canvas (original image may be drawn) with error message
}
// Iterate over each pixel (each pixel consists of 4 components: R, G, B, A)
for (let i = 0; i < data.length; i += 4) {
const r = data[i]; // Red channel value
const g = data[i+1]; // Green channel value
const b = data[i+2]; // Blue channel value
// const alpha = data[i+3]; // Alpha channel, preserved
// Red-eye detection heuristic:
// 1. The red component must be above a minimum threshold.
// 2. The red component must be significantly stronger than both green and blue components.
if (r > minRedValue &&
r > (g * redDominanceFactor) &&
r > (b * redDominanceFactor)) {
// This pixel is identified as part of a red-eye.
// Correct it by converting the pixel to a grayscale value.
// The gray value is derived from the average of the green and blue components,
// which are assumed to be less affected by the red-eye phenomenon.
const gray = Math.floor((g + b) / 2);
data[i] = gray; // Set Red component to the new gray value
data[i+1] = gray; // Set Green component to the new gray value
data[i+2] = gray; // Set Blue component to the new gray value
// The alpha channel (data[i+3]) remains unchanged.
}
}
// Put the modified pixel data back onto the canvas
ctx.putImageData(imageData, 0, 0);
} catch (e) {
// Catch errors, most commonly SecurityError due to CORS restrictions on getImageData
console.error("processImage: Error during image processing:", e.message, e);
// Display an error message on the canvas.
// If ctx.drawImage succeeded, the original image is on the canvas under this message.
ctx.font = "bold 16px Arial";
ctx.fillStyle = "rgba(128, 0, 0, 0.75)"; // Dark red, semi-transparent background
ctx.fillRect(0, canvas.height / 2 - 20, canvas.width, 40); // Background rectangle for text
ctx.fillStyle = "white"; // Text color
ctx.textAlign = "center";
ctx.textBaseline = "middle";
let errorMessage = "Error: Pixel access denied.";
if (e.name === 'SecurityError') {
errorMessage += " (CORS issue?)";
}
ctx.fillText(errorMessage, canvas.width / 2, canvas.height / 2);
}
return canvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Image Red-eye Removal Tool provides a simple and effective way to eliminate red-eye effects from photographs. This tool is particularly useful for improving the appearance of portraits where flash photography has caused red-eye, making the eyes appear unnatural. By analyzing the pixel data of an image, it identifies and adjusts the red-eye pixels, converting them to a more natural gray tone. This tool can be beneficial for personal photo touch-ups, professional editing, or preparing images for social media sharing, ensuring your photos look polished and aesthetically pleasing.