You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, strength = 0.7) {
// Clamp strength to be between 0 and 1
strength = Math.max(0, Math.min(1, strength));
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Use naturalWidth/Height for HTMLImageElement, or width/height for other canvas/image sources
canvas.width = originalImg.naturalWidth || originalImg.width;
canvas.height = originalImg.naturalHeight || originalImg.height;
// Draw the original image onto the canvas
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
// If strength is 0, no effect is applied, return the canvas with the original image
if (strength === 0) {
return canvas;
}
// --- Helper function for clamping pixel values ---
function clamp(value, min = 0, max = 255) {
return Math.max(min, Math.min(max, Math.round(value)));
}
// --- Effect Base Configurations (these are for strength = 1.0) ---
const baseNoiseAmount = 40; // Max random offset for pixel values (+/- baseNoiseAmount/2)
const baseTintIntensity = 0.6; // Max mix factor for the color tint
const tintColor = { r: 70, g: 150, b: 50 }; // Sickly greenish tint
const baseScanLineOpacity = 0.12; // Max opacity for scan lines
const scanLineColorRGB = { r: 20, g: 60, b: 20 }; // Dark green for scan lines
const scanLineInterval = 3; // Draw a line every N pixels
const scanLineHeight = 1; // Height of scan lines in pixels
const baseVignetteOpacity = 0.75; // Max opacity for the vignette effect
const vignetteColorRGB = { r: 10, g: 30, b: 10 }; // Very dark green for vignette
const vignetteTightness = 0.7; // Controls how far the vignette spreads (0-1, higher is tighter)
// --- Calculate effective values based on global strength ---
const effectiveNoise = baseNoiseAmount * strength;
const effectiveTint = baseTintIntensity * strength;
const effectiveScanLineOpacity = baseScanLineOpacity * strength;
const effectiveVignetteOpacity = baseVignetteOpacity * strength;
// --- Pixel Manipulation: Noise and Tint ---
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
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 Noise
if (effectiveNoise > 0) {
// Add random value between -effectiveNoise/2 and +effectiveNoise/2
const noiseVal = (Math.random() - 0.5) * effectiveNoise;
r += noiseVal;
g += noiseVal;
b += noiseVal;
}
// 2. Apply Color Tint (lerp towards tintColor)
if (effectiveTint > 0) {
r = r * (1 - effectiveTint) + tintColor.r * effectiveTint;
g = g * (1 - effectiveTint) + tintColor.g * effectiveTint;
b = b * (1 - effectiveTint) + tintColor.b * effectiveTint;
}
data[i] = clamp(r);
data[i+1] = clamp(g);
data[i+2] = clamp(b);
// Alpha channel (data[i+3]) remains unchanged
}
ctx.putImageData(imageData, 0, 0);
// --- Draw Scan Lines (Overlay) ---
// Only draw if opacity is significant enough to be visible
if (effectiveScanLineOpacity > 0.005) {
ctx.fillStyle = `rgba(${scanLineColorRGB.r}, ${scanLineColorRGB.g}, ${scanLineColorRGB.b}, ${effectiveScanLineOpacity})`;
for (let y = 0; y < canvas.height; y += scanLineInterval) {
ctx.fillRect(0, y, canvas.width, scanLineHeight);
}
}
// --- Draw Vignette (Overlay) ---
// Only draw if opacity is significant
if (effectiveVignetteOpacity > 0.005) {
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const maxRadius = Math.sqrt(centerX * centerX + centerY * centerY);
// Calculate the inner radius of the vignette's transparent area
// vignetteOuterStopFactor defines where the opaque part of vignette starts relative to max radius
const vignetteOuterStopFactor = 1 - (effectiveVignetteOpacity * vignetteTightness);
const innerRadius = maxRadius * Math.max(0, vignetteOuterStopFactor); // Ensure innerRadius isn't negative
const gradient = ctx.createRadialGradient(centerX, centerY, innerRadius, centerX, centerY, maxRadius);
// Inner part of gradient (transparent)
gradient.addColorStop(0, `rgba(${vignetteColorRGB.r}, ${vignetteColorRGB.g}, ${vignetteColorRGB.b}, 0)`);
// Outer part of gradient (colored and semi-transparent)
gradient.addColorStop(1, `rgba(${vignetteColorRGB.r}, ${vignetteColorRGB.g}, ${vignetteColorRGB.b}, ${effectiveVignetteOpacity})`);
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
return canvas;
}
Apply Changes