You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(
originalImg,
blurPx = 1, // Typical blur amount in pixels. Set to 0 for no blur.
saturation = 0.8, // Saturation level. 1 is original, 0 is grayscale, >1 is oversaturated. Default 0.8 for slight desaturation.
sepia = 0.15, // Sepia tone intensity. 0 is no sepia, 1 is full sepia. Default 0.15 for a subtle effect.
vignetteStrength = 0.7, // Darkness of the vignette. 0 is no vignette, 1 is fully opaque (black) edges.
vignetteClearRadius = 0.3, // Proportion of the image diagonal for the central clear area of the vignette (0 to 1). Larger value means larger clear area.
vignetteFalloffEndRadius = 0.75 // Proportion of the image diagonal where the vignette reaches its full strength (0 to 1). Must be >= vignetteClearRadius.
) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const imgWidth = originalImg.naturalWidth || originalImg.width;
const imgHeight = originalImg.naturalHeight || originalImg.height;
if (!imgWidth || !imgHeight || imgWidth <= 0 || imgHeight <= 0) {
console.error("Image has invalid dimensions.");
// Return a small indicator canvas for invalid image input
canvas.width = 150;
canvas.height = 100;
ctx.fillStyle = "#777";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "white";
ctx.font = "12px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("Invalid Image Dimensions", canvas.width / 2, canvas.height / 2);
return canvas;
}
canvas.width = imgWidth;
canvas.height = imgHeight;
// Sanitize parameters
blurPx = Math.max(0, Number(blurPx) || 0);
let tempSaturation = Number(saturation);
saturation = isNaN(tempSaturation) ? 0.8 : Math.max(0, tempSaturation);
sepia = Math.max(0, Math.min(1, Number(sepia) || 0));
vignetteStrength = Math.max(0, Math.min(1, Number(vignetteStrength) || 0));
vignetteClearRadius = Math.max(0, Math.min(1, Number(vignetteClearRadius) || 0));
vignetteFalloffEndRadius = Math.max(0, Math.min(1, Number(vignetteFalloffEndRadius) || 0));
// Ensure vignetteFalloffEndRadius is logically after vignetteClearRadius
if (vignetteFalloffEndRadius < vignetteClearRadius) {
// If falloff is set before clear radius, swap them or set falloff to clear radius.
// For simplicity, let's make them equal for a sharp transition if misconfigured this way.
vignetteFalloffEndRadius = vignetteClearRadius;
}
// 1. Apply image filters (blur, saturation, sepia)
let filterEffects = [];
if (blurPx > 0) {
filterEffects.push(`blur(${blurPx}px)`);
}
// Apply saturation (default is 0.8, 1 would be no change)
filterEffects.push(`saturate(${saturation})`);
if (sepia > 0) {
filterEffects.push(`sepia(${sepia})`);
}
if (filterEffects.length > 0) {
ctx.filter = filterEffects.join(' ');
}
// 2. Draw the image onto the canvas. This applies the filters.
try {
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
} catch (e) {
console.error("Error drawing image for pinhole effect:", e);
// Fallback if image drawing fails (e.g., tainted canvas with external image without CORS)
ctx.filter = 'none'; // Reset any filters
ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear canvas
ctx.fillStyle = "#777"; // Background color
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "white"; // Text color
ctx.font = `${Math.min(20, Math.max(10, canvas.width / 15))}px Arial`; // Dynamic font size
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("Error rendering image", canvas.width / 2, canvas.height / 2);
return canvas;
}
// Reset filter context property so it doesn't affect the vignette drawing
ctx.filter = 'none';
// 3. Apply Vignette effect
if (vignetteStrength > 0) {
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
// The reference radius for vignette percentages; using diagonal to cover corners.
const maxRadius = Math.sqrt(centerX * centerX + centerY * centerY);
let gradientInnerRadius = maxRadius * vignetteClearRadius;
let gradientOuterRadius = maxRadius * vignetteFalloffEndRadius;
// Ensure outer radius is strictly greater than inner radius for createRadialGradient
if (gradientOuterRadius <= gradientInnerRadius) {
// If they are equal or outer is smaller (due to params or float precision),
// make outer slightly larger to create a minimal gradient area (sharp vignette).
gradientOuterRadius = gradientInnerRadius + 0.00001 * maxRadius;
if (gradientOuterRadius <= gradientInnerRadius) { // If maxRadius is 0 or tiny
gradientOuterRadius = gradientInnerRadius + 0.1; // Small absolute difference
}
}
// Ensure inner radius is not negative (can happen if maxRadius is effectively 0, though unlikely with prior checks)
gradientInnerRadius = Math.max(0, gradientInnerRadius);
const vignetteGradient = ctx.createRadialGradient(
centerX, centerY, gradientInnerRadius,
centerX, centerY, gradientOuterRadius
);
// Vignette transitions from transparent in the center to dark at the edges.
vignetteGradient.addColorStop(0, 'rgba(0, 0, 0, 0)');
vignetteGradient.addColorStop(1, `rgba(0, 0, 0, ${vignetteStrength})`);
ctx.fillStyle = vignetteGradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
return canvas;
}
Apply Changes