You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, noiseAmount = 25, bloomIntensity = 0.8, vignetteStrength = 0.7, colorStyle = "cyberpunk") {
// Create the main output canvas
const canvas = document.createElement('canvas');
const width = originalImg.width;
const height = originalImg.height;
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
// 1. Draw base image
ctx.drawImage(originalImg, 0, 0);
// 2. Pixel manipulation (Color Grading, Contrast, Noise)
// This gives the signature gritty, high-contrast, moody aesthetic requested
const imageData = ctx.getImageData(0, 0, width, height);
const data = imageData.data;
// Ensure parameters are correctly typed
noiseAmount = Number(noiseAmount);
bloomIntensity = Number(bloomIntensity);
vignetteStrength = Number(vignetteStrength);
for (let i = 0; i < data.length; i += 4) {
let r = data[i];
let g = data[i + 1];
let b = data[i + 2];
// Gamma adjustment (Darken midtones for moody look)
const gamma = 1.15;
r = 255 * Math.pow(r / 255, gamma);
g = 255 * Math.pow(g / 255, gamma);
b = 255 * Math.pow(b / 255, gamma);
// Increase Contrast aggressively
const contrast = 1.35;
r = ((r / 255 - 0.5) * contrast + 0.5) * 255;
g = ((g / 255 - 0.5) * contrast + 0.5) * 255;
b = ((b / 255 - 0.5) * contrast + 0.5) * 255;
// Calculate perceived luminosity
let lum = 0.299 * r + 0.587 * g + 0.114 * b;
// Color Style Applications ("City Night" Neons)
if (colorStyle === "cyberpunk") {
// Cool deep shadows (blue/purple), Neon highlights (pink/cyan)
b += (255 - lum) * 0.25;
r -= (255 - lum) * 0.1;
g -= (255 - lum) * 0.15;
r += lum * 0.15;
b += lum * 0.1;
g -= lum * 0.05;
} else if (colorStyle === "blade-runner") {
// Heavy cinematic orange & teal
if (lum < 128) {
b += (128 - lum) * 0.4;
g += (128 - lum) * 0.2;
r -= (128 - lum) * 0.3;
} else {
r += (lum - 128) * 0.3;
g += (lum - 128) * 0.1;
b -= (lum - 128) * 0.4;
}
} else if (colorStyle === "gritty-neon") {
// High contrast reds and blues
g = g * 0.6;
r = r * 1.2;
b = b * 1.2;
}
// Add Film Grain / Noise for the "raw" feel
if (noiseAmount > 0) {
const noise = (Math.random() - 0.5) * 2 * noiseAmount;
r += noise;
g += noise;
b += noise;
}
// Clamp values and set back to buffer
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));
}
ctx.putImageData(imageData, 0, 0);
// 3. Bloom Effect (creates the bright glowing city lights)
if (bloomIntensity > 0) {
// Downscale for better performance and broader bloom
const scale = 0.25;
const bloomCanvas = document.createElement('canvas');
bloomCanvas.width = width * scale;
bloomCanvas.height = height * scale;
const bCtx = bloomCanvas.getContext('2d');
bCtx.drawImage(canvas, 0, 0, bloomCanvas.width, bloomCanvas.height);
const bData = bCtx.getImageData(0, 0, bloomCanvas.width, bloomCanvas.height);
const bd = bData.data;
for (let i = 0; i < bd.length; i += 4) {
// Hard threshold - keep only extreme highlights, remove everything else
let lum = 0.299 * bd[i] + 0.587 * bd[i + 1] + 0.114 * bd[i + 2];
if (lum < 160) {
bd[i] = 0;
bd[i + 1] = 0;
bd[i + 2] = 0;
}
}
bCtx.putImageData(bData, 0, 0);
// Apply blur to thresholded canvas
const blurCanvas = document.createElement('canvas');
blurCanvas.width = bloomCanvas.width;
blurCanvas.height = bloomCanvas.height;
const blurCtx = blurCanvas.getContext('2d');
blurCtx.filter = 'blur(10px)';
blurCtx.drawImage(bloomCanvas, 0, 0);
// Composite the blurred glowing lights over the original canvas
ctx.globalCompositeOperation = 'screen';
ctx.globalAlpha = bloomIntensity;
ctx.drawImage(blurCanvas, 0, 0, width, height);
// Reset context operations
ctx.globalCompositeOperation = 'source-over';
ctx.globalAlpha = 1.0;
}
// 4. Cinema Vignette (Edge darkening)
if (vignetteStrength > 0) {
const gradient = ctx.createRadialGradient(
width / 2, height / 2, 0,
width / 2, height / 2, Math.max(width, height) / 1.5
);
gradient.addColorStop(0, 'rgba(0,0,0,0)');
gradient.addColorStop(0.4, 'rgba(0,0,0,0)');
gradient.addColorStop(1, `rgba(0,0,0,${vignetteStrength})`);
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, width, height);
}
return canvas;
}
Apply Changes