Please bookmark this page to avoid losing your image tool!

Image Durability Test 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.
async function processImage(originalImg, intensity = "50", damageType = "all") {
    let level = parseFloat(intensity);
    if (isNaN(level)) level = 50;
    level = Math.max(0, Math.min(100, level));

    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    canvas.width = Math.max(1, originalImg.width);
    canvas.height = Math.max(1, originalImg.height);

    // Fill white background to handle transparent images
    ctx.fillStyle = '#ffffff';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.drawImage(originalImg, 0, 0);

    const loadImage = (url) => new Promise((resolve) => {
        const img = new Image();
        img.onload = () => resolve(img);
        img.src = url;
    });

    // 1. Digital Damage (Generation Loss & Glitches)
    if (damageType === "all" || damageType === "digital") {
        const passes = Math.floor((level / 100) * 8); // MAX 8 passes
        for (let i = 0; i < passes; i++) {
            const quality = Math.max(0.01, 0.3 - (level / 100) * 0.25);
            const dataUrl = canvas.toDataURL('image/jpeg', quality);
            const tempImg = await loadImage(dataUrl);
            ctx.drawImage(tempImg, 0, 0);
        }

        const glitchLines = Math.floor(level / 2);
        for (let i = 0; i < glitchLines; i++) {
            const y = Math.random() * canvas.height;
            const h = Math.random() * (canvas.height * 0.05) + 2;
            const shiftX = (Math.random() - 0.5) * (level / 100) * canvas.width * 0.15;
            
            const slice = ctx.getImageData(0, y, canvas.width, h);
            
            const tmpCanvas = document.createElement('canvas');
            tmpCanvas.width = canvas.width;
            tmpCanvas.height = h;
            const tCtx = tmpCanvas.getContext('2d');
            tCtx.putImageData(slice, 0, 0);

            ctx.fillStyle = Math.random() > 0.5 ? '#000000' : '#ffffff';
            ctx.fillRect(0, y, canvas.width, h);
            ctx.drawImage(tmpCanvas, shiftX, y);
            
            if (Math.random() > 0.5) {
                ctx.fillStyle = Math.random() > 0.5 ? 'rgba(255,0,0,0.3)' : 'rgba(0,255,255,0.3)';
                ctx.globalCompositeOperation = 'screen';
                ctx.fillRect(Math.max(0, shiftX), y, canvas.width, h);
                ctx.globalCompositeOperation = 'source-over';
            }
        }
    }

    // 2. Physical Damage (Cracks, Scratches, Dirt)
    if (damageType === "all" || damageType === "physical") {
        const area = canvas.width * canvas.height;
        
        // Scratches
        const scratchCount = (level / 100) * (area / 10000); 
        for (let i = 0; i < scratchCount; i++) {
            ctx.beginPath();
            let x = Math.random() * canvas.width;
            let y = Math.random() * canvas.height;
            ctx.moveTo(x, y);
            let len = Math.random() * 100 + 10;
            let angle = Math.random() * Math.PI * 2;
            let pX = x + Math.cos(angle) * len;
            let pY = y + Math.sin(angle) * len;
            
            let steps = Math.floor(len / 5);
            for(let j = 0; j < steps; j++) {
                x += (pX - x) / (steps - j) + (Math.random() - 0.5) * 5;
                y += (pY - y) / (steps - j) + (Math.random() - 0.5) * 5;
                ctx.lineTo(x, y);
            }

            ctx.strokeStyle = `rgba(0,0,0,${Math.random() * 0.4 + 0.1})`;
            ctx.lineWidth = Math.random() * 2 + 1;
            ctx.stroke();
            
            ctx.strokeStyle = `rgba(255,255,255,${Math.random() * 0.5 + 0.2})`;
            ctx.lineWidth = ctx.lineWidth / 2;
            ctx.stroke();
        }

        // Cracks
        const crackCount = Math.floor(level / 25);
        for (let c = 0; c < crackCount; c++) {
            const impactX = Math.random() * canvas.width;
            const impactY = Math.random() * canvas.height;
            const rays = Math.floor(Math.random() * 5) + 5; 

            for (let r = 0; r < rays; r++) {
                let x = impactX;
                let y = impactY;
                let angle = (Math.PI * 2 / rays) * r + (Math.random() - 0.5);
                let length = (Math.random() * 0.5 + 0.5) * Math.max(canvas.width, canvas.height);
                
                ctx.beginPath();
                ctx.moveTo(x, y);
                
                let currentLen = 0;
                while (currentLen < length) {
                    let step = Math.random() * 30 + 10;
                    currentLen += step;
                    angle += (Math.random() - 0.5) * 0.8; 
                    x += Math.cos(angle) * step;
                    y += Math.sin(angle) * step;
                    ctx.lineTo(x, y);
                    
                    if (Math.random() < 0.3) {
                        let bx = x;
                        let by = y;
                        let bangle = angle + (Math.random() > 0.5 ? 1 : -1) * (0.5 + Math.random());
                        let bstep = Math.random() * 60 + 20;
                        ctx.moveTo(x, y);
                        
                        let cx = bx, cy = by;
                        for(let k = 0; k < 3; k++) {
                            cx += Math.cos(bangle) * (bstep / 3);
                            cy += Math.sin(bangle) * (bstep / 3);
                            bangle += (Math.random() - 0.5) * 0.5;
                            ctx.lineTo(cx, cy);
                        }
                        ctx.moveTo(x, y); 
                    }
                }
                
                ctx.strokeStyle = 'rgba(0, 0, 0, 0.6)';
                ctx.lineWidth = 1.5;
                ctx.stroke();
                
                ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
                ctx.lineWidth = 0.5;
                ctx.stroke();
            }
        }
        
        // Dirt Splatters
        const stainCount = (level / 100) * (area / 15000);
        for (let i = 0; i < stainCount; i++) {
            let cx = Math.random() * canvas.width;
            let cy = Math.random() * canvas.height;
            let r = Math.random() * 20 + 5;
            
            ctx.beginPath();
            ctx.arc(cx, cy, r, 0, Math.PI * 2);
            ctx.fillStyle = `rgba(50, 40, 30, ${Math.random() * 0.5 * (level / 100)})`;
            ctx.fill();
            
            let splatterCount = Math.random() * 5;
            for(let s = 0; s < splatterCount; s++) {
                ctx.beginPath();
                let sx = cx + (Math.random() - 0.5) * r * 3;
                let sy = cy + (Math.random() - 0.5) * r * 3;
                let sr = Math.random() * r * 0.3;
                ctx.arc(sx, sy, sr, 0, Math.PI * 2);
                ctx.fill();
            }
        }
    }

    // 3. Time Damage (Fading, Sepia, Noise, Vignette)
    if (damageType === "all" || damageType === "time") {
        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
        const data = imageData.data;
        const fadeStrength = (level / 100) * 0.8; 
        const noiseStrength = (level / 100) * 80;

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

            // Aging fade/sepia tint
            let gray = 0.3 * r + 0.59 * g + 0.11 * b;
            data[i]     = r + ((gray + 40) - r) * fadeStrength; 
            data[i + 1] = g + ((gray + 20) - g) * fadeStrength; 
            data[i + 2] = b + ((gray - 10) - b) * fadeStrength; 

            // Add grain/noise
            if (noiseStrength > 0) {
                let noise = (Math.random() - 0.5) * noiseStrength;
                data[i]   = Math.min(255, Math.max(0, data[i] + noise));
                data[i+1] = Math.min(255, Math.max(0, data[i+1] + noise));
                data[i+2] = Math.min(255, Math.max(0, data[i+2] + noise));
            }
        }
        ctx.putImageData(imageData, 0, 0);

        if (level > 0) {
            const cx = canvas.width / 2;
            const cy = canvas.height / 2;
            const maxRadius = Math.sqrt(cx * cx + cy * cy);
            const gradientRadius = maxRadius * Math.max(0.1, 1 - (level / 100) * 0.6);
            
            const gradient = ctx.createRadialGradient(cx, cy, gradientRadius, cx, cy, maxRadius);
            gradient.addColorStop(0, 'rgba(0,0,0,0)');
            gradient.addColorStop(1, `rgba(0,0,0,${(level / 100) * 0.9})`);
            
            ctx.fillStyle = gradient;
            ctx.fillRect(0, 0, canvas.width, canvas.height);
        }
    }

    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 Durability Test Tool simulates various types of wear and tear on an image to mimic aging, physical damage, or digital corruption. Users can apply different categories of effects, including digital glitches and generation loss, physical attributes like scratches, cracks, and dirt splatters, or temporal effects such as fading, sepia tones, noise, and vignetting. This tool is useful for graphic designers creating vintage aesthetics, digital artists experimenting with glitch art, or developers testing how image assets appear under degraded conditions.

Leave a Reply

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