Please bookmark this page to avoid losing your image tool!

Photo Weather Damage 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, sepiaIntensity = 0.7, noiseAmount = 25, vignetteStrength = 0.7, vignetteFalloff = 0.5, brightnessShift = -10, contrastFactor = 0.9, scratchDensity = 0.00005, scratchOpacity = 0.2, dustDensity = 0.0002, dustOpacity = 0.3) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d', { willReadFrequently: true }); // Optimization hint for repeated getImageData/putImageData

    const w = originalImg.naturalWidth || originalImg.width;
    const h = originalImg.naturalHeight || originalImg.height;
    canvas.width = w;
    canvas.height = h;

    // If image dimensions are zero, return an empty canvas
    if (w === 0 || h === 0) {
        return canvas;
    }

    ctx.drawImage(originalImg, 0, 0, w, h);

    const imageData = ctx.getImageData(0, 0, w, h);
    const data = imageData.data;
    const centerX = w / 2;
    const centerY = h / 2;
    // Max distance from center to a corner, for vignette normalization
    const maxDist = Math.sqrt(centerX * centerX + centerY * centerY);

    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 & Contrast
        // Apply brightness shift
        r += brightnessShift;
        g += brightnessShift;
        b += brightnessShift;

        // Apply contrast (pivot around 127.5)
        r = ((r / 255 - 0.5) * contrastFactor + 0.5) * 255;
        g = ((g / 255 - 0.5) * contrastFactor + 0.5) * 255;
        b = ((b / 255 - 0.5) * contrastFactor + 0.5) * 255;
        
        r = Math.max(0, Math.min(255, r));
        g = Math.max(0, Math.min(255, g));
        b = Math.max(0, Math.min(255, b));

        // 2. Sepia
        if (sepiaIntensity > 0) {
            const origR = r, origG = g, origB = b;
            const sr = (origR * 0.393) + (origG * 0.769) + (origB * 0.189);
            const sg = (origR * 0.349) + (origG * 0.686) + (origB * 0.168);
            const sb = (origR * 0.272) + (origG * 0.534) + (origB * 0.131);

            r = origR * (1 - sepiaIntensity) + sr * sepiaIntensity;
            g = origG * (1 - sepiaIntensity) + sg * sepiaIntensity;
            b = origB * (1 - sepiaIntensity) + sb * sepiaIntensity;
            
            r = Math.max(0, Math.min(255, r));
            g = Math.max(0, Math.min(255, g));
            b = Math.max(0, Math.min(255, b));
        }
        
        // 3. Noise
        if (noiseAmount > 0) {
            const noise = (Math.random() - 0.5) * noiseAmount; // Noise range: -noiseAmount/2 to +noiseAmount/2
            r += noise;
            g += noise;
            b += noise;
            
            r = Math.max(0, Math.min(255, r));
            g = Math.max(0, Math.min(255, g));
            b = Math.max(0, Math.min(255, b));
        }

        // 4. Vignette
        if (vignetteStrength > 0 && maxDist > 0) {
            const x = (i / 4) % w;
            const y = Math.floor((i / 4) / w);
            const dx = x - centerX;
            const dy = y - centerY;
            const dist = Math.sqrt(dx * dx + dy * dy);
            
            const normalizedDist = dist / maxDist;
            // vignetteFalloff: 0.1 (wide bright area) to 2 (small bright area)
            // Power curve for falloff: lower falloff value means slower darkening from center.
            const vgnFactor = Math.pow(normalizedDist, vignetteFalloff); 
            const reduction = vignetteStrength * vgnFactor;
            
            r *= (1 - reduction);
            g *= (1 - reduction);
            b *= (1 - reduction);
            
            r = Math.max(0, Math.min(255, r)); // Clamp again after vignette
            g = Math.max(0, Math.min(255, g));
            b = Math.max(0, Math.min(255, b));
        }

        data[i] = r;
        data[i + 1] = g;
        data[i + 2] = b;
    }
    ctx.putImageData(imageData, 0, 0);

    // 5. Scratches (Drawn on top of pixel manipulations)
    if (scratchDensity > 0 && scratchOpacity > 0) {
        const numScratches = Math.floor(w * h * scratchDensity);
        
        // Lighter scratches
        ctx.strokeStyle = `rgba(220, 220, 220, ${scratchOpacity * 0.7})`;
        for (let k = 0; k < numScratches / 2; k++) {
            ctx.lineWidth = Math.random() * 1.0 + 0.5; // Width: 0.5px to 1.5px
            const x1 = Math.random() * w;
            const y1 = Math.random() * h;
            const len = (0.05 + Math.random() * 0.15) * Math.min(w, h); // Length: 5% to 20% of min image dimension
            const angle = Math.random() * Math.PI * 2;
            const x2 = x1 + Math.cos(angle) * len;
            const y2 = y1 + Math.sin(angle) * len;
            
            ctx.beginPath();
            ctx.moveTo(x1, y1);
            ctx.lineTo(x2, y2);
            ctx.stroke();
        }
        
        // Darker scratches
        ctx.strokeStyle = `rgba(30, 30, 30, ${scratchOpacity})`; 
        for (let k = 0; k < numScratches / 2; k++) {
            ctx.lineWidth = Math.random() * 0.6 + 0.2; // Width: 0.2px to 0.8px
            const x1 = Math.random() * w;
            const y1 = Math.random() * h;
            const len = (0.03 + Math.random() * 0.12) * Math.min(w, h); // Length: 3% to 15% of min image dimension
            const angle = Math.random() * Math.PI * 2;
            const x2 = x1 + Math.cos(angle) * len;
            const y2 = y1 + Math.sin(angle) * len;

            ctx.beginPath();
            ctx.moveTo(x1, y1);
            ctx.lineTo(x2, y2);
            ctx.stroke();
        }
    }
    
    // 6. Dust (Drawn on top)
    if (dustDensity > 0 && dustOpacity > 0) {
        const numDustParticles = Math.floor(w * h * dustDensity);
        for (let k = 0; k < numDustParticles; k++) {
            const x = Math.random() * w;
            const y = Math.random() * h;
            const size = Math.random() * 1.5 + 0.5; // Dust particle size: 0.5px to 2px
            // Dust color: 60% light specks, 40% dark specks
            const colorVal = Math.random() > 0.4 ? Math.floor(Math.random() * 55) + 200 : Math.floor(Math.random() * 100);
            // Vary opacity slightly per particle
            const particleOpacity = dustOpacity * (Math.random() * 0.5 + 0.5); // 50% to 100% of base dustOpacity
            ctx.fillStyle = `rgba(${colorVal}, ${colorVal}, ${colorVal}, ${particleOpacity})`;
            ctx.fillRect(x - size / 2, y - size / 2, size, size); // Center the particle
        }
    }

    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 Photo Weather Damage Filter Effect Tool allows users to apply a variety of effects to images, simulating the appearance of weathering and aging. This tool can enhance photos by adding sepia tones, adjusting brightness and contrast, incorporating visual noise, and creating a vignette effect. Additionally, it can overlay scratches and dust to give a vintage or distressed look. It is ideal for users looking to create artistic renditions of their photos, restore old images with a weathered appearance, or simply add creative effects for digital art projects.

Leave a Reply

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