Please bookmark this page to avoid losing your image tool!

Realistic Enterprise CCTV Surveillance Footage Generator

(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, cameraIdentifier = "CAM 04 - MAIN LOBBY", noiseLvl = "25", compressionBlockiness = "3", lensDistortion = "0.15") {
    // Parse numerical parameters
    const noiseLevel = parseFloat(noiseLvl) || 25;
    const blockiness = parseFloat(compressionBlockiness) || 3;
    const distK = parseFloat(lensDistortion) || 0.15;

    // Create main canvas
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d", { willReadFrequently: true });

    // Limit maximum dimension to 1280px to ensure good performance during pixel manipulation
    const MAX_DIM = 1280;
    let w = originalImg.width;
    let h = originalImg.height;

    if (w > MAX_DIM || h > MAX_DIM) {
        const ratio = Math.min(MAX_DIM / w, MAX_DIM / h);
        w = Math.floor(w * ratio);
        h = Math.floor(h * ratio);
    } else {
        w = Math.floor(w);
        h = Math.floor(h);
    }

    canvas.width = w;
    canvas.height = h;

    // 1. Draw original image with ghosting to simulate low-framerate motion blur
    ctx.globalAlpha = 0.6;
    ctx.drawImage(originalImg, 0, 0, w, h);
    ctx.globalAlpha = 0.2;
    ctx.drawImage(originalImg, 3, 0, w, h); // Shifted right
    ctx.drawImage(originalImg, -2, 2, w, h); // Shifted bottom-left
    ctx.globalAlpha = 1.0;

    // 2. Pixel manipulation for surveillance filter effects
    const imgData = ctx.getImageData(0, 0, w, h);
    const data = imgData.data;
    const outData = new Uint8ClampedArray(data.length);

    const cx = w / 2;
    const cy = h / 2;

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

            // Normalize coords for wide-angle barrel distortion
            let nx = (x - cx) / cx;
            let ny = (y - cy) / cy;
            let r2 = nx * nx + ny * ny;
            
            // Apply radial distortion factor
            let f = 1 + distK * r2;
            let sx = Math.floor(nx * f * cx + cx);
            let sy = Math.floor(ny * f * cy + cy);

            // Slight offset for red channel to simulate chromatic aberration of cheap lenses
            let srx = Math.floor(nx * (f + 0.015) * cx + cx);

            if (sx >= 0 && sx < w && sy >= 0 && sy < h) {
                let srcIdx = (sy * w + sx) * 4;
                let srcRIdx = (sy * w + Math.max(0, Math.min(w - 1, srx))) * 4;

                let r = data[srcRIdx]; // Chromatic aberration Red
                let g = data[srcIdx + 1];
                let b = data[srcIdx + 2];

                // Desaturate to mimic cheap CMOS sensors in low/indoor light
                let gray = r * 0.299 + g * 0.587 + b * 0.114;
                r = r * 0.25 + gray * 0.75;
                g = g * 0.25 + gray * 0.75;
                b = b * 0.25 + gray * 0.75;

                // Color tint (slightly washed out fluorescent green/blue)
                r *= 0.90;
                g *= 1.02;
                b *= 0.95;

                // Add sensor noise
                let noise = (Math.random() - 0.5) * noiseLevel;
                r += noise;
                g += noise;
                b += noise;

                // Subtle analog scanlines (darken every few rows)
                if (y % 4 < 2) {
                    r *= 0.92;
                    g *= 0.92;
                    b *= 0.92;
                }

                outData[destIdx] = r;
                outData[destIdx + 1] = g;
                outData[destIdx + 2] = b;
                outData[destIdx + 3] = 255;
            } else {
                // Out of bounds rendered as black for fisheye border effect
                outData[destIdx] = 0;
                outData[destIdx + 1] = 0;
                outData[destIdx + 2] = 0;
                outData[destIdx + 3] = 255;
            }
        }
    }

    // Apply modified pixels back to the main canvas
    data.set(outData);
    ctx.putImageData(imgData, 0, 0);

    // 3. Add H.264 artifacting/blockiness by harsh downscaling and upscaling
    if (blockiness > 1.0) {
        const smallCanvas = document.createElement("canvas");
        smallCanvas.width = Math.max(1, Math.floor(w / blockiness));
        smallCanvas.height = Math.max(1, Math.floor(h / blockiness));
        const sCtx = smallCanvas.getContext("2d");
        
        // Draw normal to small canvas
        sCtx.imageSmoothingEnabled = true;
        sCtx.drawImage(canvas, 0, 0, smallCanvas.width, smallCanvas.height);

        // Draw scaled up to main canvas using nearest-neighbor (pixelated)
        ctx.imageSmoothingEnabled = false;
        ctx.drawImage(smallCanvas, 0, 0, w, h);
        ctx.imageSmoothingEnabled = true;
    }

    // 4. Heavy vignette overlay (darkening corners)
    const vignette = ctx.createRadialGradient(cx, cy, Math.min(cx, cy) * 0.3, cx, cy, Math.max(cx, cy) * 1.1);
    vignette.addColorStop(0, "rgba(0,0,0,0)");
    vignette.addColorStop(1, "rgba(0,0,0,0.85)");
    ctx.fillStyle = vignette;
    ctx.fillRect(0, 0, w, h);

    // 5. OSD (On-Screen Display) overlays for realism
    const pad = (num) => num.toString().padStart(2, "0");
    const now = new Date();
    const timestampStr = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`;

    const fontSize = Math.max(14, Math.floor(h * 0.035));
    ctx.font = `bold ${fontSize}px "Courier New", Courier, monospace`;
    ctx.textBaseline = "top";

    // Helper to draw realistic typical CCTV text (white with black outline)
    function drawOSDText(text, x, y, align = "left") {
        ctx.textAlign = align;
        ctx.lineWidth = Math.max(2, Math.floor(fontSize * 0.15));
        ctx.strokeStyle = "rgba(0, 0, 0, 0.8)";
        ctx.strokeText(text, x, y);
        ctx.fillStyle = "rgba(245, 245, 245, 0.95)";
        ctx.fillText(text, x, y);
    }

    // Top-left: Timestamp
    drawOSDText(timestampStr, Math.floor(w * 0.02), Math.floor(h * 0.02), "left");

    // Top-right: Camera Name / Location
    drawOSDText(cameraIdentifier, Math.floor(w * 0.98), Math.floor(h * 0.02), "right");

    // Bottom-left: Recording Indicator (fake blinking)
    if (Math.random() > 0.3) {
        let recX = Math.floor(w * 0.02);
        let recY = Math.floor(h * 0.98) - fontSize;
        
        ctx.textAlign = "left";
        ctx.lineWidth = Math.max(2, Math.floor(fontSize * 0.15));
        
        // Draw red dot
        ctx.beginPath();
        let dotCenterY = recY + (fontSize * 0.5);
        ctx.arc(recX + (fontSize * 0.4), dotCenterY, fontSize * 0.35, 0, Math.PI * 2);
        ctx.fillStyle = "rgba(220, 20, 20, 0.95)";
        ctx.fill();
        ctx.strokeStyle = "rgba(0, 0, 0, 0.8)";
        ctx.stroke();

        // Draw "REC" text
        drawOSDText("REC", recX + fontSize * 1.1, recY, "left");
    }

    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 transforms standard images into realistic enterprise CCTV surveillance footage. It applies a variety of visual effects to mimic security camera aesthetics, including barrel lens distortion, chromatic aberration, sensor noise, and desaturation. Users can customize the output by adjusting noise levels, compression blockiness, and lens distortion. Additionally, the tool adds realistic on-screen display (OSD) elements such as timestamps, camera identifiers, and a recording indicator. This tool is ideal for filmmakers, content creators, or game developers looking to add authentic security footage visuals to their projects.

Leave a Reply

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