Please bookmark this page to avoid losing your image tool!

Image Atompunk Filter Effect Tool

(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, 
                      tintColor = "atompunk_orange", // "sepia", "atompunk_teal", "atompunk_yellow_glow", "#RRGGBB", or "none"
                      tintStrength = 0.5,          // 0.0 to 1.0
                      grainAmount = 25,            // 0 to 100 (noise intensity)
                      vignetteStrength = 0.6,      // 0.0 to 1.0 (opacity of vignette)
                      vignetteSoftness = 0.5,      // 0.1 to 1.0 (spread of vignette)
                      contrast = 1.2,              // 0.5 to 2.0 (1.0 = no change)
                      brightness = 10,             // -100 to 100 (0 = no change)
                      saturation = 0.7             // 0.0 (grayscale) to 2.0 (double saturation), 1.0 = no change
                     ) {
    // Create canvas
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d', { willReadFrequently: true }); // willReadFrequently for performance with getImageData/putImageData

    canvas.width = originalImg.naturalWidth || originalImg.width;
    canvas.height = originalImg.naturalHeight || originalImg.height;

    // Draw original image
    ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);

    // Get image data
    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    const data = imageData.data;
    const width = canvas.width;
    const height = canvas.height;

    // Helper: Clamp value to 0-255
    function clamp(value) {
        return Math.max(0, Math.min(Math.floor(value), 255));
    }

    // Helper: Hex to RGB
    function hexToRgb(hex) {
        if (!hex || typeof hex !== 'string' || hex.charAt(0) !== '#') return null;
        hex = hex.slice(1);
        if (hex.length === 3) {
            hex = hex.split('').map(char => char + char).join('');
        }
        if (hex.length !== 6) return null;
        
        const bigint = parseInt(hex, 16);
        if (isNaN(bigint)) return null;

        const r = (bigint >> 16) & 255;
        const g = (bigint >> 8) & 255;
        const b = bigint & 255;
        return { r, g, b };
    }

    let tintR_val, tintG_val, tintB_val;
    let applyTint = tintColor.toLowerCase() !== "none" && tintStrength > 0;

    if (applyTint) {
        const lowerTintColor = tintColor.toLowerCase();
        if (lowerTintColor === "sepia") {
            // Sepia is handled differently in the loop due to its formula
        } else if (lowerTintColor === "atompunk_orange") {
            tintR_val = 255; tintG_val = 170; tintB_val = 85; // Warm, slightly desaturated orange
        } else if (lowerTintColor === "atompunk_teal") {
            tintR_val = 60; tintG_val = 150; tintB_val = 160; // Muted teal
        } else if (lowerTintColor === "atompunk_yellow_glow") {
            tintR_val = 255; tintG_val = 220; tintB_val = 100; // Retro CRT glow yellow
        } else {
            const rgb = hexToRgb(tintColor);
            if (rgb) {
                tintR_val = rgb.r;
                tintG_val = rgb.g;
                tintB_val = rgb.b;
            } else {
                console.warn("Invalid tintColor provided:", tintColor);
                applyTint = false; 
            }
        }
    }

    // Process pixels
    for (let i = 0; i < data.length; i += 4) {
        let r = data[i];
        let g = data[i + 1];
        let b = data[i + 2];

        // 1. Brightness
        if (brightness !== 0) {
            r += brightness;
            g += brightness;
            b += brightness;
        }

        // 2. Contrast
        if (contrast !== 1.0) {
            // Adjust contrast factor to be in a more common range if needed,
            // but the current formula works directly with contrast parameter.
            // For example, a contrast param of 1.2 increases contrast by 20%.
            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;
        }
        
        r = clamp(r); g = clamp(g); b = clamp(b); // Clamp after brightness/contrast

        // 3. Saturation
        if (saturation !== 1.0) {
            const gray = 0.299 * r + 0.587 * g + 0.114 * b; // Luminance
            r = gray + saturation * (r - gray);
            g = gray + saturation * (g - gray);
            b = gray + saturation * (b - gray);
        }
        
        r = clamp(r); g = clamp(g); b = clamp(b); // Clamp after saturation
        
        // 4. Tint
        if (applyTint) {
            if (tintColor.toLowerCase() === "sepia") {
                const sr = 0.393 * r + 0.769 * g + 0.189 * b;
                const sg = 0.349 * r + 0.686 * g + 0.168 * b;
                const sb = 0.272 * r + 0.534 * g + 0.131 * b;
                r = (1 - tintStrength) * r + tintStrength * sr;
                g = (1 - tintStrength) * g + tintStrength * sg;
                b = (1 - tintStrength) * b + tintStrength * sb;
            } else if (tintR_val !== undefined) { // Custom hex or named Atompunk color
                r = (1 - tintStrength) * r + tintStrength * tintR_val;
                g = (1 - tintStrength) * g + tintStrength * tintG_val;
                b = (1 - tintStrength) * b + tintStrength * tintB_val;
            }
        }

        r = clamp(r); g = clamp(g); b = clamp(b); // Clamp after tint

        // 5. Grain
        if (grainAmount > 0) {
            // grainAmount determines magnitude of noise, e.g., 25 means noise up to +/- 12.5
            const noise = (Math.random() - 0.5) * grainAmount; 
            r += noise;
            g += noise;
            b += noise;
        }

        // Final clamp and assignment
        data[i] = clamp(r);
        data[i + 1] = clamp(g);
        data[i + 2] = clamp(b);
        // Alpha (data[i+3]) remains unchanged
    }

    // Put modified image data back
    ctx.putImageData(imageData, 0, 0);

    // 6. Vignette (applied post-pixel processing)
    if (vignetteStrength > 0 && vignetteStrength <= 1) {
        const centerX = width / 2;
        const centerY = height / 2;
        const maxRadius = Math.sqrt(centerX * centerX + centerY * centerY);
        
        // vignetteSoftness: 0.1 (harder edge, gradient near perimeter) to 1.0 (softer edge, gradient starts near center).
        // Clamp vignetteSoftness to a safe range to prevent extreme values for innerRadius.
        const effectiveSoftness = Math.min(Math.max(vignetteSoftness, 0.01), 0.99); 
        const innerRadius = maxRadius * (1 - effectiveSoftness); // Smaller softness -> larger innerRadius -> sharper vignette
                                                               // Larger softness -> smaller innerRadius -> wider vignette gradient
        
        const gradient = ctx.createRadialGradient(centerX, centerY, innerRadius, centerX, centerY, maxRadius);
        
        gradient.addColorStop(0, 'rgba(0,0,0,0)'); // Transparent center
        // Vignette color is black, strength controls its opacity at the edge
        gradient.addColorStop(1, `rgba(0,0,0,${vignetteStrength})`); 
        
        ctx.fillStyle = gradient;
        ctx.globalCompositeOperation = 'source-atop'; // Apply vignette on top of existing image content
        ctx.fillRect(0, 0, width, height);
        ctx.globalCompositeOperation = 'source-over'; // Reset composite operation
    }

    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 Atompunk Filter Effect Tool allows users to apply various retro-inspired visual effects to their images, emulating an Atompunk aesthetic. This tool offers customizable options, including selecting tint colors (such as Atompunk orange, teal, or yellow glow), adjusting tint strength, adding grain for a textured look, implementing vignette effects for a cinematic feel, and fine-tuning brightness, contrast, and saturation levels. Users can leverage this tool for enhancing digital art, creating visually appealing social media content, designing promotional materials, or transforming personal photos into stylized works reminiscent of vintage science fiction themes.

Leave a Reply

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