You can edit the below JavaScript code to customize the image tool.
/**
* Applies a chromatic aberration effect to an image.
* This effect mimics the phenomenon where a lens fails to focus all colors to the same convergence point,
* resulting in color fringes (typically red and blue) around objects.
* The implementation applies a horizontal shift: red channel to the left, blue channel to the right.
*
* @param {Image} originalImg The original JavaScript Image object. It's assumed to be fully loaded.
* If the image is not loaded, its width/height might be 0, leading to an error or small canvas.
* @param {string|number} shiftAmountParam The amount (in pixels) by which the red and blue color channels are shifted horizontally.
* A positive value shifts red to the left and blue to the right.
* A negative value shifts red to the right and blue to the left.
* Defaults to "5" if not provided or if the provided value is not a valid number.
* @returns {HTMLCanvasElement} A new canvas element with the chromatic aberration effect applied.
* If processing cannot be performed (e.g., due to CORS restrictions on getImageData,
* or if the image is invalid/not loaded), the function will return a canvas
* that might contain the original image (if drawn before failure) or be a small, blank canvas.
*/
function processImage(originalImg, shiftAmountParam = "5") {
// Parse shiftAmountParam to a number.
// All parameters except originalImg should be string or number, with a default.
let shiftAmount = Number(shiftAmountParam);
// Validate the parsed shiftAmount. If it's NaN (Not-a-Number), use the default value.
if (isNaN(shiftAmount)) {
console.warn(`Invalid shiftAmount parameter: "${shiftAmountParam}". Defaulting to 5.`);
shiftAmount = 5;
}
const canvas = document.createElement('canvas');
// For frequent getImageData/putImageData, willReadFrequently can be a performance hint.
const ctx = canvas.getContext('2d', { willReadFrequently: true });
// Use naturalWidth/naturalHeight for the image's intrinsic dimensions.
// Fallback to width/height if natural dimensions are not available (e.g., for some SVGs or if not fully loaded).
const width = originalImg.naturalWidth || originalImg.width;
const height = originalImg.naturalHeight || originalImg.height;
// If image dimensions are zero (e.g., image not loaded or invalid), return a minimal canvas.
if (width === 0 || height === 0) {
console.error("Image has zero dimensions. Ensure the image is fully loaded and valid before calling processImage.");
canvas.width = 1; // Minimal size to avoid errors downstream
canvas.height = 1;
ctx.clearRect(0, 0, 1, 1); // Ensure it's blank
return canvas;
}
canvas.width = width;
canvas.height = height;
// Draw the original image onto the canvas. This is necessary to access its pixel data.
try {
ctx.drawImage(originalImg, 0, 0, width, height);
} catch (e) {
// This can happen if originalImg is not a valid image source (e.g., null, undefined, or a broken URL) or is corrupted.
console.error("Error drawing image to canvas. The image might be corrupt, not fully loaded, or of an unsupported type.", e);
// Return the canvas, which will be blank or partially drawn if drawImage failed.
return canvas;
}
let originalImageData;
try {
// Attempt to get the pixel data from the canvas.
originalImageData = ctx.getImageData(0, 0, width, height);
} catch (e) {
// This error commonly occurs due to Cross-Origin Resource Sharing (CORS) restrictions.
// If the image is hosted on a different domain without appropriate CORS headers,
// the canvas becomes "tainted," and getImageData will throw a security error.
console.error("Could not get image data from canvas. This is often due to CORS policy restrictions if the image is from a different domain. The original image (unprocessed) will be returned on the canvas.", e);
// In this scenario, the canvas already contains the original image (drawn by ctx.drawImage).
// Since we cannot process it further, we return the canvas with the original image.
return canvas;
}
const originalData = originalImageData.data;
// Create a new ImageData object to store the processed pixel data.
// Using ctx.createImageData is generally preferred over `new ImageData()` for broader compatibility.
const outputImageData = ctx.createImageData(width, height);
const outputData = outputImageData.data;
// Iterate over each pixel of the image (y: rows, x: columns).
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const currentIndex = (y * width + x) * 4; // Calculate base index for the current pixel (R,G,B,A components)
// --- Red Channel ---
// Calculate the source x-coordinate for the red channel (shifted left by shiftAmount).
// Clamp the coordinate to ensure it stays within the image boundaries [0, width-1].
const x_r_source = Math.max(0, Math.min(width - 1, x - shiftAmount));
// The y-coordinate for sampling remains unchanged (y_r_source = y).
const r_source_pixel_index = (y * width + x_r_source) * 4; // Base index for the source pixel of the red channel
outputData[currentIndex] = originalData[r_source_pixel_index]; // Assign Red component
// --- Green Channel ---
// The green channel is sampled from the original pixel's location (no shift).
outputData[currentIndex + 1] = originalData[currentIndex + 1]; // Assign Green component
// --- Blue Channel ---
// Calculate the source x-coordinate for the blue channel (shifted right by shiftAmount).
// Clamp the coordinate to ensure it stays within the image boundaries [0, width-1].
const x_b_source = Math.max(0, Math.min(width - 1, x + shiftAmount));
// The y-coordinate for sampling remains unchanged (y_b_source = y).
const b_source_pixel_index = (y * width + x_b_source) * 4; // Base index for the source pixel of the blue channel
outputData[currentIndex + 2] = originalData[b_source_pixel_index + 2]; // Assign Blue component (note: +2 for blue offset)
// --- Alpha Channel ---
// The alpha channel is sampled from the original pixel's location.
outputData[currentIndex + 3] = originalData[currentIndex + 3]; // Assign Alpha component
}
}
// Put the processed image data (with chromatic aberration) back onto the canvas.
ctx.putImageData(outputImageData, 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!
The Image Chromatic Aberration Filter applies a visual effect to images that simulates chromatic aberration, a phenomenon where colors do not converge at the same point, resulting in distinct color fringes around objects. Users can specify the amount of horizontal shift for the red and blue color channels, which creates a noticeable separation of colors. This tool can be useful for graphic designers, digital artists, and photographers looking to enhance their images with creative effects, especially in projects requiring a stylized or retro aesthetic.