Please bookmark this page to avoid losing your image tool!

Image Neon Night City Filter

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
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!

Description

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.

Leave a Reply

Your email address will not be published. Required fields are marked *