Please bookmark this page to avoid losing your image tool!

LCD Monitor Failure Image Analyzer

(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, severity = 5, hasPhysicalDamage = 1, colorCorruption = 1) {
    // Coerce parameters to numbers and bound safely
    severity = Math.max(0, Math.min(20, Number(severity)));
    hasPhysicalDamage = Number(hasPhysicalDamage);
    colorCorruption = Number(colorCorruption);

    // Setup Canvas
    const canvas = document.createElement('canvas');
    const w = originalImg.width || originalImg.naturalWidth;
    const h = originalImg.height || originalImg.naturalHeight;
    canvas.width = w;
    canvas.height = h;
    const ctx = canvas.getContext('2d', { willReadFrequently: true });
    
    // Draw original image
    ctx.drawImage(originalImg, 0, 0, w, h);

    let impactX = -1;
    let impactY = -1;

    // 1. Simulate Physical Damage Layer (Broken Glass & Liquid Crystal Leak)
    if (hasPhysicalDamage === 1) {
        // Decide a random point of impact for the monitor screen break
        impactX = Math.floor(w * (0.2 + Math.random() * 0.6));
        impactY = Math.floor(h * (0.2 + Math.random() * 0.6));

        // Draw the primary liquid crystal "bleed" (a jagged, dark blob)
        ctx.fillStyle = '#0a0a0f';
        ctx.beginPath();
        for (let angle = 0; angle < Math.PI * 2; angle += 0.15) {
            const radius = Math.min(w, h) * (0.02 + Math.random() * 0.08);
            const x = impactX + Math.cos(angle) * radius;
            const y = impactY + Math.sin(angle) * radius;
            if (angle === 0) ctx.moveTo(x, y);
            else ctx.lineTo(x, y);
        }
        ctx.fill();

        // Draw crystal leakage branches radiating from the crack
        for (let i = 0; i < 15; i++) {
            ctx.beginPath();
            ctx.moveTo(impactX, impactY);
            let currX = impactX;
            let currY = impactY;
            const angleBase = (Math.PI * 2 / 15) * i + (Math.random() - 0.5);
            ctx.strokeStyle = '#050508';
            
            // Random walk outward to create jagged fracture lines
            for (let j = 0; j < 12; j++) {
                const step = Math.min(w, h) * (0.02 + Math.random() * 0.04);
                const angle = angleBase + (Math.random() - 0.5) * 1.5;
                currX += Math.cos(angle) * step;
                currY += Math.sin(angle) * step;
                ctx.lineTo(currX, currY);
                ctx.lineWidth = Math.max(1, 4 - j * 0.3);
                ctx.stroke();
                ctx.beginPath();
                ctx.moveTo(currX, currY);
            }
        }

        // Introduce bright vertical "ribbon sync" failure lines directly over the physical break
        const syncColors = ['#ff0000', '#00ff00', '#0000ff', '#00ffff', '#ff00ff', '#ffff00', '#ffffff', '#000000'];
        
        for(let c = 0; c < 8; c++) {
            const color = syncColors[Math.floor(Math.random() * syncColors.length)];
            ctx.fillStyle = color;
            const glWidth = Math.random() * 4 + 1;
            const glX = impactX + (Math.random() - 0.5) * 40;
            ctx.fillRect(glX, 0, glWidth, h);
        }
        
        // Horizontal sync freeze below the line of impact (classic broken panel artifact)
        ctx.fillStyle = 'rgba(255, 255, 255, 0.15)'; 
        ctx.fillRect(0, impactY, w, h - impactY);
        
        for(let c = 0; c < 4; c++) {
            const color = syncColors[Math.floor(Math.random() * syncColors.length)];
            ctx.fillStyle = color;
            const glHeight = Math.random() * 3 + 1;
            const glY = impactY + (Math.random() - 0.5) * 30;
            ctx.fillRect(0, glY, w, glHeight);
        }
    }

    // 2. Fetch pixels to create Logic Board / Timing Controller (T-CON) failures
    const imgData = ctx.getImageData(0, 0, w, h);
    const data = imgData.data;
    const srcData = new Uint8ClampedArray(data); // Immutable copy for referencing original pixels during shifts

    // Chromatic aberration / Ghosting severity
    const shiftAmount = Math.floor(severity * (w * 0.003));

    // Generate corrupted "T-CON bands" (areas where screen processes colors incorrectly)
    const tconBands = [];
    if (colorCorruption === 1) {
        const numBands = Math.floor(severity * 1.5);
        for(let i=0; i<numBands; i++) {
            tconBands.push({
                yStart: Math.random() * h,
                height: Math.random() * (h * 0.15),
                type: Math.floor(Math.random() * 3) // 0: color inverted, 1: bit-crushed/solarized, 2: drop channel
            });
        }
    }

    // Process Pixels
    for (let y = 0; y < h; y++) {
        // Determine whether the current line falls within a T-CON failing band
        let activeBand = null;
        for (let b = 0; b < tconBands.length; b++) {
            if (y >= tconBands[b].yStart && y < tconBands[b].yStart + tconBands[b].height) {
                activeBand = tconBands[b];
                break;
            }
        }

        // Horizontal Sync loss (wavy line jitter based on severity)
        let rowOffset = 0;
        if (severity > 3 && Math.random() < 0.03) {
            rowOffset = Math.floor((Math.random() - 0.5) * severity * 4);
        }

        for (let x = 0; x < w; x++) {
            const i = (y * w + x) * 4;

            // Chromatic separation / ghosting offset by row
            let srcX_R = Math.min(w - 1, Math.max(0, x + shiftAmount + rowOffset));
            let srcX_B = Math.min(w - 1, Math.max(0, x - shiftAmount + rowOffset));
            let srcX_G = Math.min(w - 1, Math.max(0, x + rowOffset));

            const iR = (y * w + srcX_R) * 4;
            const iG = (y * w + srcX_G) * 4;
            const iB = (y * w + srcX_B) * 4;

            let r = srcData[iR];
            let g = srcData[iG + 1];
            let b = srcData[iB + 2];

            // Apply T-Con Board Colorspace Corruption
            if (activeBand) {
                if (activeBand.type === 0) {
                    // Color Inversion
                    r = 255 - r;
                    g = 255 - g;
                    b = 255 - b;
                } else if (activeBand.type === 1) {
                    // Solarization Wrap-around 
                    r = r > 127 ? 255 - r : r;
                    g = g > 127 ? 255 - g : g;
                    b = b > 127 ? 255 - b : b;
                } else if (activeBand.type === 2) {
                    // Color Channel Loss (Classic dying cable look)
                    if (x % 3 === 0) r = 0;
                    if (x % 3 === 1) g = 0;
                    if (x % 3 === 2) b = 0;
                }
            }

            // LCD Panel Subpixel Matrix Interference (Scanline effect)
            if (y % 3 === 0) {
                r = r * 0.8;
                g = g * 0.8;
                b = b * 0.8;
            }
            
            // Image Retention / Posterization in the lower section if physically damaged
            if (hasPhysicalDamage === 1 && y > impactY + 30) {
                const reduce = 32; // Color crushing constraint
                r = Math.floor(r / reduce) * reduce;
                g = Math.floor(g / reduce) * reduce;
                b = Math.floor(b / reduce) * reduce;
            }

            data[i] = r;
            data[i + 1] = g;
            data[i + 2] = b;
            // leave alpha channel unmodified to preserve transparency format boundaries
        }
    }

    // 3. Isolated Stuck & Dead Subpixels 
    const totalPixels = w * h;
    const numDead = Math.floor(totalPixels * (severity * 0.00015));
    const pureColors = [
        [255, 0, 0], [0, 255, 0], [0, 0, 255], [0, 0, 0], [255, 255, 255], [0, 255, 255], [255, 0, 255]
    ];
    for (let p = 0; p < numDead; p++) {
        const dx = Math.floor(Math.random() * w);
        const dy = Math.floor(Math.random() * h);
        const i = (dy * w + dx) * 4;
        const c = pureColors[Math.floor(Math.random() * pureColors.length)];
        data[i] = c[0];
        data[i+1] = c[1];
        data[i+2] = c[2];
        data[i+3] = 255; 
    }

    // 4. Random Thin Ribbon Cable Synchronization Streaks (Vertical)
    const numRibbons = Math.floor(severity * 3);
    for (let l = 0; l < numRibbons; l++) {
        const rx = Math.floor(Math.random() * w);
        const rWidth = Math.floor(Math.random() * 3) + 1;
        const c = pureColors[Math.floor(Math.random() * pureColors.length)];
        const yStart = Math.random() > 0.4 ? 0 : Math.floor(Math.random() * h);
        const yEnd = Math.random() > 0.4 ? h : Math.floor(Math.random() * h + yStart);
        
        for (let ry = yStart; ry < yEnd; ry++) {
            if (ry >= h) continue;
            for (let rw = 0; rw < rWidth; rw++) {
                if (rx + rw >= w) continue;
                const i = (ry * w + (rx + rw)) * 4;
                data[i] = c[0];
                data[i+1] = c[1];
                data[i+2] = c[2];
                data[i+3] = 255;
            }
        }
    }

    // Embed all modifications
    ctx.putImageData(imgData, 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 LCD Monitor Failure Image Analyzer is a simulation tool designed to overlay various types of display malfunctions onto an uploaded image. It can emulate physical hardware damage, such as cracked glass, liquid crystal bleeding, and impact fractures, as well as electronic failures like color corruption, T-CON board errors, chromatic aberration, and sync loss. Users can also simulate technical artifacts like stuck/dead subpixels and vertical ribbon cable interference. This tool is useful for digital artists looking to create realistic damaged screen effects, educators demonstrating hardware failure modes, or filmmakers needing assets for visual effects (VFX) and concept art.

Leave a Reply

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