Please bookmark this page to avoid losing your image tool!

Image VHS Effect With Inscription 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, inscriptionText = 'REC ● 01:23:45', fontSize = 24, fontColor = '#ffcc00', fontName = 'VCR OSD Mono') {
    /**
     * Dynamically loads a font from Google Fonts.
     * @param {string} name - The name of the font.
     * @param {string} url - The URL of the font file (e.g., woff2).
     * @returns {Promise<boolean>} - A promise that resolves to true if the font is loaded, false otherwise.
     */
    async function loadFont(name, url) {
        if (document.fonts.check(`1em "${name}"`)) {
            return true;
        }
        try {
            const fontFace = new FontFace(name, `url(${url})`);
            await fontFace.load();
            document.fonts.add(fontFace);
            return true;
        } catch (error) {
            console.error(`Font "${name}" could not be loaded from ${url}.`, error);
            return false;
        }
    }

    // 1. Load the special VCR font. Fallback to a generic monospace if it fails.
    const fontUrl = 'https://fonts.gstatic.com/s/vcrosdmono/v19/q5uDsoiL2nreB2nK9I4v-22hsvBlZA.woff2';
    const fontLoaded = await loadFont(fontName, fontUrl);
    if (!fontLoaded) {
        fontName = 'monospace'; // Fallback font
    }

    // 2. Setup canvas
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d', { willReadFrequently: true });
    const width = originalImg.naturalWidth;
    const height = originalImg.naturalHeight;
    canvas.width = width;
    canvas.height = height;

    // Draw the original image to the canvas
    ctx.drawImage(originalImg, 0, 0, width, height);

    // Get the pixel data from the canvas
    const originalImageData = ctx.getImageData(0, 0, width, height);
    const originalData = originalImageData.data;
    const vhsImageData = ctx.createImageData(width, height);
    const vhsData = vhsImageData.data;

    // 3. Apply Chromatic Aberration & Noise in a single pass for efficiency
    const aberrationAmount = 4; // in pixels
    const noiseAmount = 35; // intensity from 0-255

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

            // Chromatic Aberration: get R from a left-shifted pixel and B from a right-shifted pixel
            const redX = Math.max(0, x - aberrationAmount);
            const blueX = Math.min(width - 1, x + aberrationAmount);
            const redIndex = (y * width + redX) * 4;
            const blueIndex = (y * width + blueX) * 4;

            const r = originalData[redIndex];
            const g = originalData[i + 1];
            const b = originalData[blueIndex + 2];
            
            // Add random noise
            const noise = (Math.random() - 0.5) * noiseAmount;

            // Assign new pixel values, clamping them between 0 and 255
            vhsData[i] = Math.max(0, Math.min(255, r + noise));
            vhsData[i + 1] = Math.max(0, Math.min(255, g + noise));
            vhsData[i + 2] = Math.max(0, Math.min(255, b + noise));
            vhsData[i + 3] = originalData[i + 3]; // Keep original alpha
        }
    }

    // Put the VHS-effect pixel data back onto the canvas
    ctx.putImageData(vhsImageData, 0, 0);

    // 4. Apply random horizontal glitch/jitter effect
    const glitchLines = Math.floor(height * 0.04); // Glitch about 4% of the lines
    for (let i = 0; i < glitchLines; i++) {
        const y = Math.floor(Math.random() * height);
        const h = Math.floor(Math.random() * 10) + 1; // Slice height: 1 to 10 pixels
        
        if (y + h > height) continue;
        
        const xOffset = (Math.random() - 0.5) * (width * 0.1); // Shift up to 10% of width
        
        try {
           const sliceData = ctx.getImageData(0, y, width, h);
           ctx.putImageData(sliceData, xOffset, y);
        } catch (e) {
            // This can fail on tainted canvases (e.g., with cross-origin images)
            console.warn("Could not apply glitch effect due to canvas security restrictions.");
            break; // Stop trying if we hit a security wall
        }
    }
    
    // 5. Apply semi-transparent scanlines
    ctx.fillStyle = 'rgba(10, 10, 10, 0.2)';
    for (let i = 0; i < height; i += 3) {
        ctx.fillRect(0, i, width, 1.5);
    }
    
    // 6. Draw the inscription text
    ctx.font = `${fontSize}px "${fontName}"`;
    ctx.fillStyle = fontColor;
    ctx.textAlign = 'left';
    ctx.textBaseline = 'top';

    // Add a shadow to make the text pop, mimicking CRT glow
    ctx.shadowColor = 'rgba(0, 0, 0, 0.7)';
    ctx.shadowBlur = 6;
    ctx.shadowOffsetX = 2;
    ctx.shadowOffsetY = 2;

    const padding = fontSize * 0.8;
    ctx.fillText(inscriptionText, padding, padding);

    // Reset shadow for any subsequent drawing on this context if it were to be reused
    ctx.shadowColor = 'transparent';
    ctx.shadowBlur = 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 Image VHS Effect With Inscription Tool allows users to apply a vintage VHS effect to their images, enhancing them with a nostalgic aesthetic. This tool modifies images by adding chromatic aberration, random noise, horizontal glitches, and semi-transparent scanlines to create an authentic retro video look. Users can also add customizable text inscriptions, such as timestamps or labels, using a specific font reminiscent of old VHS tape recordings. This tool is ideal for creating retro-themed graphics, enhancing video stills, or simply adding a creative touch to images for social media posts, presentations, or personal projects.

Leave a Reply

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