Please bookmark this page to avoid losing your image tool!

CCTV Style Image Effect 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.
async function processImage(originalImg, level = 'medium') {
    const w = originalImg.naturalWidth || originalImg.width;
    const h = originalImg.naturalHeight || originalImg.height;

    if (!w || !h) {
        throw new Error("Invalid image dimensions.");
    }

    let pixelHeight, brightness, blurAmount, motionOffset, noiseLevel, jpegQuality, scanlineAlpha;

    // Define CCTV severity levels parameters
    switch (level.toLowerCase()) {
        case 'mild':
            pixelHeight = 240;
            brightness = 80;
            blurAmount = 2; // px
            motionOffset = Math.max(3, w * 0.015);
            noiseLevel = 30;
            jpegQuality = 0.4;
            scanlineAlpha = 0.15;
            break;
        case 'harsh':
            pixelHeight = 96;
            brightness = 40;
            blurAmount = 8;
            motionOffset = Math.max(15, w * 0.05);
            noiseLevel = 90;
            jpegQuality = 0.05; // Extreme compression artifacts
            scanlineAlpha = 0.4;
            break;
        case 'medium':
        default:
            pixelHeight = 144;
            brightness = 60;
            blurAmount = 5;
            motionOffset = Math.max(8, w * 0.03);
            noiseLevel = 60;
            jpegQuality = 0.15;
            scanlineAlpha = 0.25;
            break;
    }

    // 1. Lower Resolution (Downscale)
    const scale = Math.min(1.0, pixelHeight / h);
    const smW = Math.max(1, Math.floor(w * scale));
    const smH = Math.max(1, Math.floor(h * scale));

    const smallCanvas = document.createElement('canvas');
    smallCanvas.width = smW;
    smallCanvas.height = smH;
    const smCtx = smallCanvas.getContext('2d');
    smCtx.imageSmoothingEnabled = true;
    smCtx.drawImage(originalImg, 0, 0, smW, smH);

    // 2. Setup Main Canvas
    const canvas = document.createElement('canvas');
    canvas.width = w;
    canvas.height = h;
    const ctx = canvas.getContext('2d');

    // Turn off image smoothing during upscale to create harsh NEAREST-NEIGHBOR pixelation
    ctx.imageSmoothingEnabled = false;

    // Apply baseline dark lighting and core blur
    ctx.filter = `brightness(${brightness}%) blur(${blurAmount}px)`;

    // Apply Motion Blur: Draw the small canvas upscaled multiple times thinly with an offset scatter
    const motionSteps = 6;
    ctx.globalAlpha = 1.0 / motionSteps;
    for (let i = 0; i < motionSteps; i++) {
        // Compute offset horizontally along an assumed movement vector
        const dx = (i - Math.floor(motionSteps / 2)) * (motionOffset / motionSteps);
        const dy = dx * 0.1; // Minimal vertical drift
        ctx.drawImage(smallCanvas, 0, 0, smW, smH, dx, dy, w, h);
    }

    // Reset properties
    ctx.filter = 'none';
    ctx.globalAlpha = 1.0;

    // 3. Compression Artifacts (JPEG encoding/decoding technique to recreate macro-blocks naturally)
    const dataUrl = canvas.toDataURL('image/jpeg', jpegQuality);
    const jpegImg = await new Promise((resolve) => {
        const img = new Image();
        img.onload = () => resolve(img);
        img.onerror = () => resolve(canvas); // Fallback to current canvas data
        img.src = dataUrl;
    });

    ctx.clearRect(0, 0, w, h);
    ctx.imageSmoothingEnabled = false;
    ctx.drawImage(jpegImg, 0, 0, w, h);

    // 4. Heavy Noise Application (Manual additive normal-distributed static)
    const imgData = ctx.getImageData(0, 0, w, h);
    const data = imgData.data;

    for (let i = 0; i < data.length; i += 4) {
        // Fast approximation of normally distributed random number logic
        const randNormal = (Math.random() + Math.random() + Math.random() - 1.5) * 2;
        const uniformNoise = randNormal * noiseLevel;

        // Apply noise and clamp limits between 0-255 using Math max/min
        data[i] = Math.max(0, Math.min(255, data[i] + uniformNoise));         // R
        data[i + 1] = Math.max(0, Math.min(255, data[i + 1] + uniformNoise)); // G
        data[i + 2] = Math.max(0, Math.min(255, data[i + 2] + uniformNoise)); // B
        // Alpha (data[i + 3]) is left untouched
    }
    ctx.putImageData(imgData, 0, 0);

    // 5. Scan Lines
    const maxScanlines = 600;
    const scanlineCount = Math.min(h, maxScanlines);
    const lineThickness = Math.max(1, Math.floor(h / scanlineCount));
    const lineGap = lineThickness * 2;

    ctx.fillStyle = `rgba(0, 0, 0, ${scanlineAlpha})`;
    for (let y = 0; y < h; y += lineGap) {
        ctx.fillRect(0, y, w, lineThickness);
    }

    // 6. Generic CCTV Overlay UI Overlay (Text Date / Time)
    const fontSize = Math.max(12, Math.floor(Math.min(w, h) * 0.04));
    ctx.font = `${fontSize}px "Courier New", Courier, monospace`;
    ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
    ctx.textBaseline = "top";
    
    // Top-Left "REC" with Record Dot
    ctx.fillText("REC ●", w * 0.04, h * 0.04);

    // Bottom-Left Simulated Timestamp
    const now = new Date();
    const yyyy = now.getFullYear();
    const mm = String(now.getMonth() + 1).padStart(2, '0');
    const dd = String(now.getDate()).padStart(2, '0');
    const hh = String(now.getHours()).padStart(2, '0');
    const min = String(now.getMinutes()).padStart(2, '0');
    const ss = String(now.getSeconds()).padStart(2, '0');
    
    ctx.textBaseline = "bottom";
    ctx.fillText(`CAM-01  ${yyyy}-${mm}-${dd} ${hh}:${min}:${ss}`, w * 0.04, h * 0.96);

    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 CCTV Style Image Effect Generator applies a variety of visual filters to photos to make them look like footage from a security camera. The tool simulates low-resolution pixelation, motion blur, digital noise, and JPEG compression artifacts. It also adds authentic stylistic elements such as scan lines and a surveillance-style interface overlay including a ‘REC’ indicator and a real-time timestamp. Users can choose between different intensity levels—mild, medium, or harsh—to customize the severity of the effect. This tool is ideal for digital artists, filmmakers, or content creators looking to add a gritty, realistic security camera aesthetic to their visual projects.

Leave a Reply

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