You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(
originalImg,
desaturationLevel = 0.85,
contrastAmount = 1.5,
darknessMultiplier = 0.75,
tintColorHex = "151025", // A dark, desaturated purple-blue: R=21, G=16, B=37
tintStrength = 0.25,
vignetteStrength = 0.4
) {
const canvas = document.createElement('canvas');
// Using { willReadFrequently: true } can optimize repeated getImageData/putImageData calls
const ctx = canvas.getContext('2d', { willReadFrequently: true });
// Ensure the image has valid dimensions
if (originalImg.naturalWidth === 0 || originalImg.naturalHeight === 0) {
// Return a minimal 1x1 canvas if the image is not loaded or has no dimensions
// This prevents errors in getImageData for 0-width/height canvases
canvas.width = 1;
canvas.height = 1;
// Optionally, you could fill it with a transparent or black pixel
// ctx.fillStyle = 'rgba(0,0,0,0)';
// ctx.fillRect(0,0,1,1);
return canvas;
}
canvas.width = originalImg.naturalWidth;
canvas.height = originalImg.naturalHeight;
// Draw the original image onto the canvas
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
// Get image data to manipulate pixels
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
// Parse tintColorHex to R, G, B components
// Handles potentially malformed hex strings by defaulting components to 0 if parsing fails
const parseHexComponent = (hexString) => parseInt(hexString, 16) || 0;
const tintR = parseHexComponent(tintColorHex.substring(0, 2));
const tintG = parseHexComponent(tintColorHex.substring(2, 4));
const tintB = parseHexComponent(tintColorHex.substring(4, 6));
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
// Calculate maximum distance from center to a corner (for vignette normalization)
const maxDist = Math.sqrt(centerX * centerX + centerY * centerY);
// Process each pixel
for (let i = 0; i < data.length; i += 4) {
let r = data[i];
let g = data[i + 1];
let b = data[i + 2];
// Alpha channel (data[i+3]) is preserved
// 1. Desaturation
// Calculate luminance (perceived brightness)
const luminance = 0.299 * r + 0.587 * g + 0.114 * b;
// Mix original color with luminance based on desaturationLevel
r = r * (1 - desaturationLevel) + luminance * desaturationLevel;
g = g * (1 - desaturationLevel) + luminance * desaturationLevel;
b = b * (1 - desaturationLevel) + luminance * desaturationLevel;
// 2. Contrast
if (contrastAmount !== 1.0) { // Apply contrast only if contrastAmount is not neutral
// Adjust contrast: map values to [-0.5, 0.5], scale, then map back to [0, 255]
r = ((r / 255 - 0.5) * contrastAmount + 0.5) * 255;
g = ((g / 255 - 0.5) * contrastAmount + 0.5) * 255;
b = ((b / 255 - 0.5) * contrastAmount + 0.5) * 255;
}
// 3. Darkness
// Apply overall darkness multiplier
r *= darknessMultiplier;
g *= darknessMultiplier;
b *= darknessMultiplier;
// 4. Tint
if (tintStrength > 0) {
// Blend current color with tint color
r = r * (1 - tintStrength) + tintR * tintStrength;
g = g * (1 - tintStrength) + tintG * tintStrength;
b = b * (1 - tintStrength) + tintB * tintStrength;
}
// 5. Vignette
if (vignetteStrength > 0 && maxDist > 0) { // maxDist check for 1x1 or degenerate cases
// Calculate current pixel's coordinates
const x = (i / 4) % canvas.width;
const y = Math.floor((i / 4) / canvas.width);
// Calculate distance from center
const dx = x - centerX;
const dy = y - centerY;
const distNormalized = Math.sqrt(dx * dx + dy * dy) / maxDist; // Normalized distance (0 at center, 1 at corners)
// Calculate vignette effect (stronger further from center)
// Using Math.pow(distNormalized, 2) for a smoother, quadratic falloff
const vignetteEffect = 1.0 - Math.pow(distNormalized, 2) * vignetteStrength;
r *= vignetteEffect;
g *= vignetteEffect;
b *= vignetteEffect;
}
// Clamp RGB values to [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);
return canvas;
}
Apply Changes