Please bookmark this page to avoid losing your image tool!

Image Glitch Filter Application

(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, intensity = 20, slices = 10, channelShiftMaxOffset = 5) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    const w = originalImg.naturalWidth;
    const h = originalImg.naturalHeight;

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

    // If the image has no dimensions (e.g., not loaded or 0x0), return an empty canvas.
    if (w === 0 || h === 0) {
        return canvas;
    }

    // Helper function for random integers (inclusive)
    function getRandomInt(min, max) {
        min = Math.ceil(min);
        max = Math.floor(max);
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    // Draw original image onto the canvas
    ctx.drawImage(originalImg, 0, 0, w, h);

    // Normalize intensity to a factor between 0 and 1
    const glitchFactor = Math.max(0, Math.min(1, intensity / 100));

    // If intensity is 0, no glitch effects are applied.
    // The canvas already has the original image drawn.
    if (glitchFactor === 0) {
        return canvas;
    }

    // --- 1. Slicing and Shifting Effect ---
    // Number of slices increases with intensity and the 'slices' parameter.
    const numSlices = Math.floor(slices * glitchFactor * 1.5); 
    for (let i = 0; i < numSlices; i++) {
        const startY = Math.random() * h; // Random Y position to start the slice
        
        // Slice height: 1px to 10% of image height, scaled by (0.5 + glitchFactor)
        // This means higher intensity can lead to larger slice heights.
        let sliceHeight = Math.max(1, Math.random() * (h * 0.1) * (0.5 + glitchFactor));
        
        // Adjust sliceHeight if it goes beyond canvas boundary from startY
        if (startY + sliceHeight > h) {
            sliceHeight = h - startY;
        }
        
        // If sliceHeight becomes zero or negative (e.g., startY is at the very bottom), skip this iteration.
        if (sliceHeight <= 0) {
            continue;
        }

        // Horizontal offset: up to +/-30% of width, scaled by intensity.
        const offsetX = (Math.random() - 0.5) * (w * 0.6) * glitchFactor; 
        
        try {
            // Get the pixel data for the slice from the current canvas state
            const sliceData = ctx.getImageData(0, startY, w, sliceHeight);
            // Draw the slice back onto the canvas at the new (horizontally shifted) position
            ctx.putImageData(sliceData, offsetX, startY);
        } catch (e) {
            // Log error if getImageData or putImageData fails, though protections above should minimize this.
            // console.warn("Error in slicing effect:", e);
        }
    }

    // --- 2. Channel Shift Effect ---
    // The maximum pixel offset for channel shifting is scaled by intensity and channelShiftMaxOffset.
    const actualChannelShiftOffset = Math.floor(channelShiftMaxOffset * (0.5 + glitchFactor));
    if (glitchFactor > 0 && actualChannelShiftOffset > 0) {
        const imageData = ctx.getImageData(0, 0, w, h);
        const data = imageData.data;
        // Create a copy of the current pixel data to source from (avoids self-interference during shifting)
        const sourceDataCopy = new Uint8ClampedArray(data);

        // Probability for a scanline to be RGB-shifted: ranges from 5% to 30% based on intensity.
        const shiftLineProbability = 0.05 + glitchFactor * 0.25; 

        for (let y = 0; y < h; y++) {
            // Randomly decide if this line should be shifted
            if (Math.random() < shiftLineProbability) {
                // Determine random offsets for R, G, B channels for this line
                const rOffset = getRandomInt(-actualChannelShiftOffset, actualChannelShiftOffset);
                const gOffset = getRandomInt(-actualChannelShiftOffset, actualChannelShiftOffset);
                const bOffset = getRandomInt(-actualChannelShiftOffset, actualChannelShiftOffset);

                for (let x = 0; x < w; x++) {
                    const idx = (y * w + x) * 4; // Current pixel's R index

                    // Calculate source X coordinates for R, G, B channels, clamped to image bounds
                    const rOrigX = Math.max(0, Math.min(w - 1, x + rOffset));
                    const gOrigX = Math.max(0, Math.min(w - 1, x + gOffset));
                    const bOrigX = Math.max(0, Math.min(w - 1, x + bOffset));

                    // Calculate source indices in the copied data array
                    const rSrcIdx = (y * w + rOrigX) * 4;
                    const gSrcIdx = (y * w + gOrigX) * 4;
                    const bSrcIdx = (y * w + bOrigX) * 4;

                    // Set new pixel data from shifted channels using the source copy
                    data[idx]     = sourceDataCopy[rSrcIdx];         // Red channel
                    data[idx + 1] = sourceDataCopy[gSrcIdx + 1];     // Green channel
                    data[idx + 2] = sourceDataCopy[bSrcIdx + 2];     // Blue channel
                    // Alpha channel is taken from the original pixel's location (no shift)
                    data[idx + 3] = sourceDataCopy[idx + 3];         
                }
            }
        }
        // Write the modified pixel data back to the canvas
        ctx.putImageData(imageData, 0, 0);
    }
    
    // --- 3. Scanlines Effect (subtle) ---
    // Add scanlines if intensity is moderately high (e.g., > 15%).
    if (glitchFactor > 0.15) { 
        // Scanline "density" (gap between lines): Denser for higher intensity.
        // Ranges roughly from 2 to 7px.
        const scanlineDensity = getRandomInt(2, 4) + Math.floor((1 - glitchFactor) * 3); 
        // Scanline opacity: from 3% to 10% based on intensity.
        const scanlineOpacity = 0.03 + glitchFactor * 0.07; 
        
        ctx.fillStyle = `rgba(0, 0, 0, ${scanlineOpacity})`; // Dark scanlines
        for (let y = 0; y < h; y += scanlineDensity) {
            ctx.fillRect(0, y, w, 1); // Draw a 1px high dark line
        }
    }

    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 Glitch Filter Application allows users to apply glitch effects to their images, transforming them into unique and artistic visuals. By adjusting parameters such as intensity, the number of slices, and channel shifting, users can create a variety of distorted looks reminiscent of digital errors or retro aesthetics. This tool can be useful for graphic designers, digital artists, or anyone looking to add a creative twist to their images for use in personal projects, social media, or multimedia presentations.

Leave a Reply

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