You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = originalImg.naturalWidth;
canvas.height = originalImg.naturalHeight;
// Draw original image to get its pixel data
ctx.drawImage(originalImg, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data; // This is a live reference to the pixel data on canvas
// Create a copy of original data for making decisions based on unmodified pixels
const originalDataCopy = new Uint8ClampedArray(imageData.data.length);
originalDataCopy.set(imageData.data);
// Filter parameters (tuned for a "Neon Night City" look)
const overallDarkness = 0.25; // Base darkness multiplier for non-highlight areas (0-1)
const highlightThreshold = 165; // Original luminance (0-255) to be considered a highlight
const neonIntensityFactor = 1.6; // Multiplier for highlight brightness
const neonSaturationFactor = 2.8; // Multiplier for highlight saturation
const shadowBlueTintFactor = 1.35; // How much to tint shadows blue (multiplier for B channel)
// Tint for white/grayscale lights if they become neon
const whiteLightNeonTintR = 0.7; // R component factor (e.g., 0.7 for cyan/blue dominant)
const whiteLightNeonTintG = 1.1; // G component factor (e.g., 1.1 for cyan)
const whiteLightNeonTintB = 1.3; // B component factor (e.g., 1.3 for blue/cyan)
const grayscaleTolerance = 18; // Max difference between R,G,B to be considered grayscale
for (let i = 0; i < data.length; i += 4) {
const oR = originalDataCopy[i];
const oG = originalDataCopy[i + 1];
const oB = originalDataCopy[i + 2];
// Calculate luminance of the original pixel
const originalLuminance = 0.299 * oR + 0.587 * oG + 0.114 * oB;
let r = oR;
let g = oG;
let b = oB;
if (originalLuminance > highlightThreshold) {
// This pixel is a highlight, make it NEON
// 1. Boost intensity for all highlights
r = Math.min(255, r * neonIntensityFactor);
g = Math.min(255, g * neonIntensityFactor);
b = Math.min(255, b * neonIntensityFactor);
// Check if the original pixel was grayscale
const isOriginalGrayscale = Math.abs(oR - oG) < grayscaleTolerance &&
Math.abs(oG - oB) < grayscaleTolerance &&
Math.abs(oR - oB) < grayscaleTolerance;
if (isOriginalGrayscale) {
// Grayscale highlights are tinted to a default neon color (e.g., cyan/electric blue)
// Use the current (intensity-boosted) average value as base for tinting
const currentGrayValue = (r + g + b) / 3;
r = Math.min(255, Math.max(0, currentGrayValue * whiteLightNeonTintR));
g = Math.min(255, Math.max(0, currentGrayValue * whiteLightNeonTintG));
b = Math.min(255, Math.max(0, currentGrayValue * whiteLightNeonTintB));
} else {
// For colored lights, boost their existing saturation
const avg = (r + g + b) / 3; // r,g,b are already intensity-boosted
// Ensure avg is a valid number and not pure black/white to avoid issues
if (!isNaN(avg) && avg > 1 && avg < 254) {
r = Math.max(0, Math.min(255, avg + (r - avg) * neonSaturationFactor));
g = Math.max(0, Math.min(255, avg + (g - avg) * neonSaturationFactor));
b = Math.max(0, Math.min(255, avg + (b - avg) * neonSaturationFactor));
}
}
// 2. Fine-tune specific dominant colors for a more classic neon palette
// This applies after initial intensity/saturation changes or tinting
const processedR = r, processedG = g, processedB = b;
const processedMax = Math.max(processedR, processedG, processedB);
if (processedMax > 70) { // Apply only if the color is reasonably bright after initial processing
if (processedB > processedR && processedB > processedG) { // Blue is strictly dominant
b = Math.min(255, processedB + 30);
r = Math.max(0, processedR * 0.85);
g = Math.max(0, processedG * 0.85);
} else if (processedR > processedB && processedR > processedG) { // Red is strictly dominant
r = Math.min(255, processedR + 25);
// Push towards Pink/Magenta by adding some blue component relative to red's strength
b = Math.min(255, processedB + (processedR - processedB) * 0.25 + 10);
g = Math.max(0, processedG * 0.8);
} else if (processedG > processedR && processedG > processedB) { // Green is strictly dominant
g = Math.min(255, processedG + 25);
// Push towards Cyan/Lime by adding some blue component
b = Math.min(255, processedB * 1.05 + 5);
r = Math.max(0, processedR * 0.85);
}
}
} else {
// This is a darker (non-highlight) area
r *= overallDarkness;
g *= overallDarkness;
b *= overallDarkness * shadowBlueTintFactor; // Add blue tint to shadows
}
// Store modified pixel values back into the imageData
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));
// Alpha channel (data[i+3]) remains unchanged
}
// Put the modified pixel data back onto the canvas
ctx.putImageData(imageData, 0, 0);
return canvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Image Neon Night City Filter enhances images by applying a vibrant neon effect, perfect for creating striking and atmospheric visuals. This tool adjusts brightness and saturation for highlighted areas and gives darker regions a blue tint, mimicking the glow of neon lights. It is ideal for transforming urban night photographs, artwork, or any image that could benefit from a futuristic, neon style, making it suitable for graphic design, social media content, or personal projects.