You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, contrast = 1.2, brightness = 0, grainIntensity = 10) {
// Ensure parameters are numbers and handle potential NaN or invalid values.
let numContrast = Number(contrast);
if (isNaN(numContrast)) {
console.warn(`Invalid contrast value provided ('${contrast}'). Using default value 1.2.`);
numContrast = 1.2; // Default contrast
}
let numBrightness = Number(brightness);
if (isNaN(numBrightness)) {
console.warn(`Invalid brightness value provided ('${brightness}'). Using default value 0.`);
numBrightness = 0; // Default brightness
}
let numGrainIntensity = Number(grainIntensity);
if (isNaN(numGrainIntensity)) {
console.warn(`Invalid grainIntensity value provided ('${grainIntensity}'). Using default value 10.`);
numGrainIntensity = 10; // Default grain intensity
}
// Grain intensity should not be negative as it might lead to unexpected behavior.
numGrainIntensity = Math.max(0, numGrainIntensity);
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Use naturalWidth/Height for intrinsic image dimensions, fallback to width/height.
const imgWidth = originalImg.naturalWidth || originalImg.width;
const imgHeight = originalImg.naturalHeight || originalImg.height;
canvas.width = imgWidth;
canvas.height = imgHeight;
// If image dimensions are zero (e.g., image not loaded or invalid), return an empty canvas.
if (imgWidth === 0 || imgHeight === 0) {
console.error("Original image has zero width or height. Cannot process.");
// Optionally draw an error message on the canvas if it's small but non-zero
// For 0x0 canvas, this won't be visible but avoids further errors.
if (canvas.width > 0 && canvas.height > 0) {
ctx.fillStyle = 'red';
ctx.font = '12px Arial';
ctx.fillText('Error: Invalid image dimensions.', 5, canvas.height / 2);
}
return canvas;
}
ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
let imageData;
try {
imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
} catch (e) {
console.error("Could not get image data from canvas. This might be a Cross-Origin Resource Sharing (CORS) issue if the image is from another domain and not CORS-enabled.", e);
// Draw an error message on the canvas to inform the user.
ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear any partially drawn image.
ctx.fillStyle = 'rgba(0,0,0,0.7)';
ctx.fillRect(0,0,canvas.width, canvas.height);
ctx.fillStyle = 'white';
ctx.font = `bold ${Math.min(24, canvas.width / 15)}px Arial`;
ctx.textAlign = 'center';
ctx.fillText('Error: Cannot process image data.', canvas.width / 2, canvas.height / 2 - 15);
ctx.font = `${Math.min(16, canvas.width / 25)}px Arial`;
ctx.fillText('Possible CORS issue or invalid image.', canvas.width / 2, canvas.height / 2 + 15);
return canvas;
}
const data = imageData.data;
// Iterate over each pixel (4 bytes per pixel: 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];
// 1. Convert to grayscale using the luminosity method (standard weights for perceived brightness)
let gray = 0.299 * r + 0.587 * g + 0.114 * b;
// 2. Apply brightness adjustment
// numBrightness can be positive (lighter) or negative (darker).
gray += numBrightness;
// 3. Apply contrast adjustment
// Formula: NewValue = Factor * (OldValue - MidPoint) + MidPoint
// MidPoint is 128 for a 0-255 range.
// numContrast = 1.0 results in no change to contrast.
// Values > 1.0 increase contrast, < 1.0 decrease it.
gray = numContrast * (gray - 128) + 128;
// 4. Simulate film grain
// Add random noise. numGrainIntensity controls the amplitude of the noise.
if (numGrainIntensity > 0) {
// Generate noise value between -0.5 and 0.5, then scale by intensity.
const noise = (Math.random() - 0.5) * numGrainIntensity;
gray += noise;
}
// Clamp the resulting gray value to the valid 0-255 range
gray = Math.max(0, Math.min(255, gray));
// Set the new R, G, B values to the calculated gray value
data[i] = gray; // Red channel
data[i + 1] = gray; // Green channel
data[i + 2] = gray; // Blue channel
// Alpha channel (data[i+3]) is left unchanged to preserve transparency.
}
// 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!
The Image Ilford XP2 Super Filter Effect Application applies a monochromatic filter effect to images, emulating the classic film look of Ilford XP2 Super. Users can customize the intensity of contrast, brightness, and grain to achieve their desired aesthetic. This tool is ideal for photographers and graphic designers looking to give their digital images a timeless, vintage feel reminiscent of black and white film photography.