Please bookmark this page to avoid losing your image tool!

90s Analog Security Camera Aesthetic Image Filter

(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,
    pixelation = "2",
    brightness = "1.2",
    contrast = "1.2",
    noiseIntensity = "35",
    rgbShiftAmount = "4",
    glitchIntensity = "15",
    vignetteIntensity = "0.7",
    colorTint = "grayscale", // options: "none", "amber", "green", "blue", "grayscale"
    timestamp = "1998-05-12 14:32:01 PLAY",
    showRec = "true"
) {
    // Parse parameters
    const pix = Math.max(1, parseInt(pixelation) || 2);
    const b = parseFloat(brightness) || 1.2;
    const c = parseFloat(contrast) || 1.2;
    const noiseAmt = parseFloat(noiseIntensity) || 35;
    const shiftOrig = parseFloat(rgbShiftAmount) || 4;
    const glitchAmt = parseFloat(glitchIntensity) || 15;
    const vigAmt = parseFloat(vignetteIntensity) || 0.7;
    const isRec = String(showRec).toLowerCase() === 'true' || showRec === '1';
    const tint = String(colorTint).toLowerCase();

    // Canvas setup
    const width = originalImg.width;
    const height = originalImg.height;
    
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d');

    // 1. Pixelation Phase
    const miniCanvas = document.createElement('canvas');
    miniCanvas.width = Math.ceil(width / pix);
    miniCanvas.height = Math.ceil(height / pix);
    const miniCtx = miniCanvas.getContext('2d');
    miniCtx.drawImage(originalImg, 0, 0, miniCanvas.width, miniCanvas.height);

    const midCanvas = document.createElement('canvas');
    midCanvas.width = width;
    midCanvas.height = height;
    const midCtx = midCanvas.getContext('2d');
    midCtx.imageSmoothingEnabled = false;
    midCtx.drawImage(miniCanvas, 0, 0, width, height);

    // 2. VHS Glitch Phase (Horizontal shifts)
    const offCanvas = document.createElement('canvas');
    offCanvas.width = width;
    offCanvas.height = height;
    const offCtx = offCanvas.getContext('2d');
    
    // Fill black background in case glitch leaves transparent gaps
    offCtx.fillStyle = 'black';
    offCtx.fillRect(0, 0, width, height);

    let yOffset = 0;
    while (yOffset < height) {
        let sliceHeight = Math.random() * (height * 0.05) + (height * 0.01);
        if (yOffset + sliceHeight > height) sliceHeight = height - yOffset;
        
        let xOffset = 0;
        // Apply random intense glitch to ~15% of slices
        if (Math.random() < 0.15) {
            xOffset = (Math.random() - 0.5) * glitchAmt * (width / 500);
        }
        
        offCtx.drawImage(
            midCanvas, 
            0, yOffset, width, sliceHeight, 
            xOffset, yOffset, width, sliceHeight
        );
        yOffset += sliceHeight;
    }

    // 3. Pixel Manipulation (RGB Shift, Noise, Brightness, Contrast, Tint)
    const imgData = offCtx.getImageData(0, 0, width, height);
    const data = imgData.data;
    const outData = new Uint8ClampedArray(data.length);
    
    // Scale shift relative to image width so it has consistent effect
    const shiftPix = Math.floor(shiftOrig * Math.max(1, width / 1000));

    for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
            const i = (y * width + x) * 4;
            
            // Chromatic aberration (RGB shift)
            const iRed = (y * width + Math.max(0, x - shiftPix)) * 4;
            const iBlue = (y * width + Math.min(width - 1, x + shiftPix)) * 4;
            
            let red = data[iRed];
            let green = data[i + 1];
            let blue = data[iBlue + 2];
            
            // Brightness & Contrast
            red = ((red * b) - 128) * c + 128;
            green = ((green * b) - 128) * c + 128;
            blue = ((blue * b) - 128) * c + 128;
            
            // Static Noise
            const noise = (Math.random() - 0.5) * noiseAmt * 2;
            red += noise;
            green += noise;
            blue += noise;
            
            // Color Tint
            if (tint !== 'none') {
                const luma = 0.299 * red + 0.587 * green + 0.114 * blue;
                if (tint === 'amber') {
                    red = luma * 1.2;
                    green = luma * 0.9;
                    blue = luma * 0.2;
                } else if (tint === 'green') {
                    red = luma * 0.2;
                    green = luma * 1.2;
                    blue = luma * 0.2;
                } else if (tint === 'blue') {
                    red = luma * 0.3;
                    green = luma * 0.5;
                    blue = luma * 1.3;
                } else { // grayscale
                    red = luma;
                    green = luma;
                    blue = luma;
                }
            }
            
            outData[i] = red;
            outData[i + 1] = green;
            outData[i + 2] = blue;
            outData[i + 3] = 255; // fully opaque
        }
    }
    
    const newImgData = new ImageData(outData, width, height);
    ctx.putImageData(newImgData, 0, 0);

    // 4. CRT Scanlines
    ctx.fillStyle = 'rgba(0, 0, 0, 0.25)';
    for (let y = 0; y < height; y += 4) {
        ctx.fillRect(0, y, width, 2);
    }
    
    // 5. VHS Bottom Tracking Distortions
    ctx.fillStyle = 'rgba(255, 255, 255, 0.07)';
    for(let i = 0; i < 8; i++) {
        let trackY = height - Math.random() * (height * 0.15);
        let trackH = Math.random() * 6 + 1;
        ctx.fillRect(0, trackY, width, trackH);
    }

    // 6. Vignette Effect
    const cx = width / 2;
    const cy = height / 2;
    const maxRadius = Math.max(cx, cy) * 1.2;
    const gradient = ctx.createRadialGradient(cx, cy, maxRadius * 0.4, cx, cy, maxRadius);
    gradient.addColorStop(0, 'rgba(0,0,0,0)');
    gradient.addColorStop(1, `rgba(0,0,0,${Math.min(1, vigAmt)})`);
    ctx.fillStyle = gradient;
    ctx.fillRect(0, 0, width, height);

    // 7. Security Overlay (Timestamp & REC)
    const fontSize = Math.max(16, Math.floor(height * 0.04));
    ctx.font = `bold ${fontSize}px "Courier New", Courier, monospace`;
    ctx.textBaseline = 'middle';
    
    // Text styling (glow/shadow to make it readable)
    ctx.shadowColor = 'rgba(0,0,0,0.8)';
    ctx.shadowBlur = 4;
    ctx.shadowOffsetX = 2;
    ctx.shadowOffsetY = 2;
    ctx.fillStyle = 'white';
    
    const paddingX = Math.max(10, Math.floor(width * 0.05));
    const paddingY = Math.max(10, Math.floor(height * 0.05));

    // Draw Timestamp (Bottom Left)
    if (timestamp && timestamp.trim() !== '') {
        ctx.fillText(timestamp, paddingX, height - paddingY - fontSize / 2);
    }

    // Draw REC indicator (Top Right)
    if (isRec) {
        const recText = "REC";
        const recWidth = ctx.measureText(recText).width;
        const textX = width - paddingX - recWidth;
        const textY = paddingY + fontSize / 2;
        
        ctx.fillText(recText, textX, textY);
        
        // Red flashing dot (simulated as static on photo)
        const dotRadius = fontSize * 0.3;
        ctx.fillStyle = '#ff0000';
        ctx.shadowColor = 'rgba(255,0,0,0.8)'; // Red glow
        ctx.shadowBlur = 8;
        ctx.beginPath();
        ctx.arc(textX - dotRadius * 2, textY, dotRadius, 0, Math.PI * 2);
        ctx.fill();
    }

    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

This tool applies a vintage 90s-style analog security camera aesthetic to your images. It simulates a retro surveillance look by incorporating effects such as pixelation, VHS-style glitches, chromatic aberration (RGB shift), static noise, and CRT scanlines. Users can customize the appearance with various color tints—including amber, green, blue, or grayscale—and adjust settings for brightness, contrast, and vignette intensity. The tool also adds authentic security overlays like a customizable timestamp and a recording indicator. This is ideal for creators looking to add a lo-fi, nostalgic, or found-footage atmosphere to photos for social media, digital art, or cinematic storytelling.

Leave a Reply

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