You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, grain = 25, desaturation = 0.15, contrast = 1.1, warmOverlayStrength = 0.05, vignetteStrength = 0.3) {
// Helper function to clamp values, typically for color channels (0-255)
const clamp = (value, min = 0, max = 255) => Math.max(min, Math.min(max, value));
// Basic validation for the input image
if (!originalImg || typeof originalImg.naturalWidth === 'undefined' || originalImg.naturalWidth === 0 || originalImg.naturalHeight === 0) {
console.error("Nikon F3 Effect: Original image is not loaded or is invalid.");
// Return a minimal canvas as a fallback
const fallbackCanvas = document.createElement('canvas');
fallbackCanvas.width = 1;
fallbackCanvas.height = 1;
return fallbackCanvas;
}
const canvas = document.createElement('canvas');
canvas.width = originalImg.naturalWidth;
canvas.height = originalImg.naturalHeight;
const ctx = canvas.getContext('2d');
if (!ctx) {
console.error("Nikon F3 Effect: Could not get canvas 2D context.");
// Return the canvas, though it might be unusable if context failed
return canvas;
}
// Sanitize and prepare parameter values
const safeDesaturation = clamp(desaturation, 0, 1); // 0: no change, 1: grayscale
const safeContrast = Math.max(0, contrast); // 1: no change, >1 increase, <1 decrease
const safeWarmOverlayStrength = clamp(warmOverlayStrength, 0, 1); // 0: no overlay, 1: full strength
const safeGrain = Math.max(0, grain); // Amount of noise, 0: no grain
const safeVignetteStrength = clamp(vignetteStrength, 0, 1); // 0: no vignette, 1: strong vignette
// 1. Apply desaturation and contrast using built-in canvas filters
// Convert desaturation (0-1 a_la user thinking) to saturation value for filter (1 means full saturation, 0 means grayscale)
const saturationValueForFilter = 1 - safeDesaturation;
ctx.filter = `saturate(${saturationValueForFilter}) contrast(${safeContrast})`;
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
ctx.filter = 'none'; // Reset filter for subsequent drawing operations
// 2. Apply a warm color overlay
if (safeWarmOverlayStrength > 0) {
ctx.globalCompositeOperation = 'overlay'; // 'overlay' or 'soft-light' are good for tinting
// Using a warm, slightly desaturated orange/yellow for a vintage feel
ctx.fillStyle = `rgba(255, 200, 150, ${safeWarmOverlayStrength})`;
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = 'source-over'; // Reset composite operation
}
// 3. Add film grain by manipulating pixel data
if (safeGrain > 0) {
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const pixels = imageData.data;
for (let i = 0; i < pixels.length; i += 4) {
// Add monochrome grain (same random value to R, G, B)
// Math.random() - 0.5 gives a range of -0.5 to 0.5
const noise = (Math.random() - 0.5) * safeGrain;
pixels[i] = clamp(pixels[i] + noise); // Red
pixels[i+1] = clamp(pixels[i+1] + noise); // Green
pixels[i+2] = clamp(pixels[i+2] + noise); // Blue
// Alpha channel (pixels[i+3]) remains unchanged
}
ctx.putImageData(imageData, 0, 0);
}
// 4. Apply vignette effect (darkened corners)
if (safeVignetteStrength > 0) {
// Calculate gradient radii. Outer radius covers a significant portion of the image.
// Inner radius shrinks as vignette strength increases, making the dark edges more prominent.
const maxDim = Math.max(canvas.width, canvas.height);
const gradientOuterRadius = maxDim * 0.7; // Extent of the vignette effect
// Ensure inner radius is not negative; it represents the start of the transparent area.
const gradientInnerRadius = Math.max(0, gradientOuterRadius * (1 - safeVignetteStrength * 0.95));
const vigGradient = ctx.createRadialGradient(
canvas.width / 2, canvas.height / 2, gradientInnerRadius,
canvas.width / 2, canvas.height / 2, gradientOuterRadius
);
// Vignette transitions from transparent center to dark edges
vigGradient.addColorStop(0, 'rgba(0,0,0,0)');
// The darkness of the edge is controlled by vignetteStrength
vigGradient.addColorStop(1, `rgba(0,0,0,${safeVignetteStrength})`);
ctx.fillStyle = vigGradient;
ctx.fillRect(0, 0, canvas.width, canvas.height); // Apply gradient overlay
}
return canvas;
}
Apply Changes