Please bookmark this page to avoid losing your image tool!

Image Steampunk 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, sepiaParam = "0.7", contrastParam = "1.3", noiseParam = "15", vignettePowerParam = "0.6", vignetteCoverageParam = "0.5") {
    // Convert string parameters to their appropriate numeric types
    const sepiaAmount = parseFloat(sepiaParam);
    const contrastValue = parseFloat(contrastParam);
    const noiseIntensity = parseInt(noiseParam, 10); // Explicitly use radix 10 for parseInt
    const vignettePower = parseFloat(vignettePowerParam);
    const vignetteCoverage = parseFloat(vignetteCoverageParam);

    const canvas = document.createElement('canvas');
    // Use { willReadFrequently: true } for potential performance optimization if supported
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

    const imgWidth = originalImg.naturalWidth || originalImg.width;
    const imgHeight = originalImg.naturalHeight || originalImg.height;

    canvas.width = imgWidth;
    canvas.height = imgHeight;

    // Handle cases where the image might not be loaded or has no dimensions
    if (imgWidth === 0 || imgHeight === 0) {
        // Optionally, log a warning or draw an error message on the canvas
        // console.warn("Image has zero width or height.");
        return canvas; // Return empty (or minimally setup) canvas
    }

    // Draw the original image onto the canvas
    ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
    
    // Get image data to manipulate pixels.
    // This can throw a security error if the image is cross-origin and the canvas becomes tainted.
    let imageData;
    try {
        imageData = ctx.getImageData(0, 0, imgWidth, imgHeight);
    } catch (e) {
        console.error("Could not getImageData from canvas. Likely a cross-origin image security issue.", e);
        // Fallback: return the canvas with the original image drawn, and perhaps an error message.
        // For a visual cue, you could draw an error message on the canvas itself.
        ctx.font = "16px Arial";
        ctx.fillStyle = "red";
        ctx.textAlign = "center";
        ctx.fillText("Error: Could not process image (cross-origin issue?).", imgWidth / 2, imgHeight / 2);
        return canvas;
    }
    
    const pixels = imageData.data;
    const centerX = imgWidth / 2.0;
    const centerY = imgHeight / 2.0;

    // Iterate over each pixel (RGBA components)
    for (let i = 0; i < pixels.length; i += 4) {
        let r = pixels[i];
        let g = pixels[i+1];
        let b = pixels[i+2];
        // Alpha channel (pixels[i+3]) is generally not modified for this effect

        // 1. Desaturation and Tinting for Steampunk look
        if (sepiaAmount > 0) {
            // Calculate luminance (brightness) of the pixel
            const lum = 0.299 * r + 0.587 * g + 0.114 * b;
            
            // Desaturate: sepiaAmount an Dcontrols blend between original color and its luminance
            // A portion of sepiaAmount (e.g., 70%) determines the desaturation strength
            const desaturationLevel = sepiaAmount * 0.7; 
            r = r * (1 - desaturationLevel) + lum * desaturationLevel;
            g = g * (1 - desaturationLevel) + lum * desaturationLevel;
            b = b * (1 - desaturationLevel) + lum * desaturationLevel;

            // Apply a steampunk tint (bronze/copper/brass tones)
            // The strength of this tint is also influenced by sepiaAmount
            const tintStrengthFactor = sepiaAmount; 
            r = r + 30 * tintStrengthFactor; // Add red/orange component
            g = g + 15 * tintStrengthFactor; // Add a smaller green/yellow component
            b = b - 20 * tintStrengthFactor; // Reduce blue component to make it warmer/browner
        }
        
        // Clamp color values after sepia/tint to stay within [0, 255]
        r = Math.min(255, Math.max(0, r));
        g = Math.min(255, Math.max(0, g));
        b = Math.min(255, Math.max(0, b));

        // 2. Contrast Adjustment
        if (contrastValue !== 1.0) {
            // Standard contrast formula: NewColor = ((OldColor/255 - 0.5) * ContrastFactor + 0.5) * 255
            // ContrastValue: 1.0 = no change, >1.0 = increase contrast, <1.0 = decrease.
            r = ((r / 255.0 - 0.5) * contrastValue + 0.5) * 255.0;
            g = ((g / 255.0 - 0.5) * contrastValue + 0.5) * 255.0;
            b = ((b / 255.0 - 0.5) * contrastValue + 0.5) * 255.0;
        }
        
        // Clamp after contrast
        r = Math.min(255, Math.max(0, r));
        g = Math.min(255, Math.max(0, g));
        b = Math.min(255, Math.max(0, b));
        
        // 3. Noise (Grain)
        if (noiseIntensity > 0) {
            // Add random noise (positive or negative) to each channel
            const noise = (Math.random() - 0.5) * noiseIntensity;
            r += noise;
            g += noise;
            b += noise;
        }
        
        // Clamp after noise
        r = Math.min(255, Math.max(0, r));
        g = Math.min(255, Math.max(0, g));
        b = Math.min(255, Math.max(0, b));

        // 4. Vignette Effect
        // Apply only if vignette parameters are set to create an effect and image dimensions are valid
        if (vignettePower > 0 && vignetteCoverage > 0 && imgWidth > 0 && imgHeight > 0) {
            const currentX = (i / 4) % imgWidth;
            const currentY = Math.floor((i / 4) / imgWidth);

            // Calculate normalized distance components from the center (-1 to 1 range)
            // This creates an elliptical vignette shape that matches the image aspect ratio
            const dx_norm = (currentX - centerX) / centerX; 
            const dy_norm = (currentY - centerY) / centerY; 
            
            // Calculate combined normalized distance from center (0 at center, ~1 at corners)
            let dist = Math.sqrt(dx_norm * dx_norm + dy_norm * dy_norm);
            // Further normalize dist to be reliably within 0-1 (1 at corners)
            dist = Math.min(dist / Math.sqrt(2.0), 1.0); 

            let vignetteEffect = 1.0; // Default: no change
            
            // brightRadius: normalized radius of the central fully bright area (0 to 1)
            // vignetteCoverage = 0: brightRadius = 1 (vignette only at extreme edges/corners)
            // vignetteCoverage = 1: brightRadius = 0 (vignette effect starts from the very center)
            const brightRadius = 1.0 - vignetteCoverage;

            if (dist > brightRadius) {
                // Pixel is in the vignette falloff zone.
                // Calculate falloff intensity (0 to 1) within the vignette band.
                // The width of the vignette band (normalized) is effectively 'vignetteCoverage'.
                let falloff = (dist - brightRadius) / (vignetteCoverage + 0.00001); // Add epsilon to avoid division by zero
                falloff = Math.min(1.0, Math.max(0.0, falloff)); // Clamp falloff to 0-1 range

                // vignettePower determines maximum darkness (0=no darkening, 1=edges can become black)
                vignetteEffect = 1.0 - falloff * vignettePower;
            }
            
            // Apply vignette darkening
            r *= vignetteEffect;
            g *= vignetteEffect;
            b *= vignetteEffect;
        }

        // Final assignment of possibly modified and clamped color values to pixel data
        pixels[i] = r; // r is already clamped
        pixels[i+1] = g; // g is already clamped
        pixels[i+2] = b; // b is already clamped
    }

    // Write the modified pixel data back to 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 Steampunk Filter Effect Tool allows users to apply a steampunk aesthetic to their images, transforming them with a unique combination of sepia tones, contrast adjustments, noise effects, and vignette detailing. This tool is ideal for artists, designers, or anyone looking to enhance their photos with a vintage, retro-futuristic style. Whether for social media posts, graphic design projects, or personal artwork, this filter can help achieve a distinct and creative visual appeal.

Leave a Reply

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