You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, desaturation = 0.35, contrast = 0.15, tintColor = "rgba(220, 230, 255, 0.08)", vignetteStrength = 0.2) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const w = originalImg.naturalWidth;
const h = originalImg.naturalHeight;
if (w === 0 || h === 0) {
canvas.width = 0;
canvas.height = 0;
// Optionally, log a warning or throw an error
// console.warn("Original image has zero width or height. Returning empty canvas.");
return canvas;
}
canvas.width = w;
canvas.height = h;
// Draw the original image onto the canvas
ctx.drawImage(originalImg, 0, 0, w, h);
// Get image data for pixel manipulation
const imageData = ctx.getImageData(0, 0, w, h);
const data = imageData.data;
// Constants for luminance calculation (NTSC standard)
// L = R*0.299 + G*0.587 + B*0.114
const LUM_R_COEFF = 0.299;
const LUM_G_COEFF = 0.587;
const LUM_B_COEFF = 0.114;
// Apply desaturation and contrast pixel by pixel
for (let i = 0; i < data.length; i += 4) {
let r = data[i];
let g = data[i + 1];
let b = data[i + 2];
// 1. Apply Desaturation
// desaturation: 0 (original color) to 1 (grayscale)
if (desaturation > 0) {
const luminance = LUM_R_COEFF * r + LUM_G_COEFF * g + LUM_B_COEFF * b;
r = r * (1 - desaturation) + luminance * desaturation;
g = g * (1 - desaturation) + luminance * desaturation;
b = b * (1 - desaturation) + luminance * desaturation;
}
// 2. Apply Contrast
// contrast: 0 (no change), positive increases contrast, negative decreases.
// E.g., 0.15 means a 15% increase in contrast.
if (contrast !== 0) {
const contrastFactor = 1.0 + contrast;
// Adjust contrast by scaling distance from midpoint (127.5)
r = ((r / 255.0 - 0.5) * contrastFactor + 0.5) * 255.0;
g = ((g / 255.0 - 0.5) * contrastFactor + 0.5) * 255.0;
b = ((b / 255.0 - 0.5) * contrastFactor + 0.5) * 255.0;
}
// Clamp values to the valid 0-255 range
data[i] = Math.max(0, Math.min(255, r));
data[i + 1] = Math.max(0, Math.min(255, g));
data[i + 2] = Math.max(0, Math.min(255, b));
}
// Put the modified image data back onto the canvas
ctx.putImageData(imageData, 0, 0);
// 3. Apply Tint Color Overlay
// tintColor: a CSS color string (e.g., "rgba(R,G,B,A)") or "none"
if (typeof tintColor === 'string' && tintColor.toLowerCase() !== "none" && tintColor.trim() !== "") {
ctx.globalCompositeOperation = 'source-over'; // Ensure standard alpha blending
ctx.fillStyle = tintColor;
ctx.fillRect(0, 0, w, h);
}
// 4. Apply Vignette Effect
// vignetteStrength: 0 (no vignette) to 1 (strong vignette)
if (vignetteStrength > 0) {
ctx.globalCompositeOperation = 'source-over'; // Ensure standard alpha blending
const centerX = w / 2;
const centerY = h / 2;
// The outer radius of the gradient should reach the corners of the image.
const outerRadius = Math.sqrt(Math.pow(centerX, 2) + Math.pow(centerY, 2));
// The inner radius determines how far the clear area extends from the center.
// vignetteStrength influences both the size of this clear area and the darkness.
// The 0.8 factor makes the gradient transition smoother.
const innerRadiusRatio = 1.0 - (Math.min(1.0, vignetteStrength) * 0.8);
const innerRadius = outerRadius * Math.max(0, innerRadiusRatio);
const gradient = ctx.createRadialGradient(centerX, centerY, innerRadius, centerX, centerY, outerRadius);
// Vignette fades from transparent black at the center to semi-transparent black at the edges.
gradient.addColorStop(0, 'rgba(0,0,0,0)');
gradient.addColorStop(1, `rgba(0,0,0,${Math.min(1.0, vignetteStrength)})`);
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, w, h);
}
// Reset globalCompositeOperation to default (though typically not needed if this is the last drawing operation)
ctx.globalCompositeOperation = 'source-over';
return canvas;
}
Apply Changes