Please bookmark this page to avoid losing your image tool!

Image Blown Glass Filter Effect 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, strength = 20, scale = 50) {
    const width = originalImg.width;
    const height = originalImg.height;

    // Handle cases where image might not be loaded or has no dimensions
    if (width === 0 || height === 0) {
        const emptyCanvas = document.createElement('canvas');
        emptyCanvas.width = width;
        emptyCanvas.height = height;
        // Optionally draw the (empty) image if context is available
        // const ctx = emptyCanvas.getContext('2d');
        // if (ctx) ctx.drawImage(originalImg, 0, 0);
        return emptyCanvas;
    }

    // Ensure scale is positive to avoid division by zero or negative scales.
    const effectiveScale = Math.max(1, scale);

    // Create a source canvas to get ImageData from originalImg
    const srcCanvas = document.createElement('canvas');
    srcCanvas.width = width;
    srcCanvas.height = height;
    const srcCtx = srcCanvas.getContext('2d');

    if (!srcCtx) {
        console.error("Could not get 2D context for source canvas. Aborting.");
        // Return a canvas with the original image drawn as a fallback
        const fallbackCanvas = document.createElement('canvas');
        fallbackCanvas.width = width;
        fallbackCanvas.height = height;
        const fbCtx = fallbackCanvas.getContext('2d');
        if (fbCtx) fbCtx.drawImage(originalImg, 0, 0, width, height);
        return fallbackCanvas;
    }

    srcCtx.drawImage(originalImg, 0, 0, width, height);
    
    let srcImageData;
    try {
        srcImageData = srcCtx.getImageData(0, 0, width, height);
    } catch (e) {
        console.error("Could not get ImageData from source canvas. This might be due to cross-origin restrictions if the image is not hosted on the same domain.", e);
        // Fallback: return a canvas with the original image drawn
        const fallbackCanvas = document.createElement('canvas');
        fallbackCanvas.width = width;
        fallbackCanvas.height = height;
        const fbCtx = fallbackCanvas.getContext('2d');
        if (fbCtx) fbCtx.drawImage(originalImg, 0, 0, width, height);
        return fallbackCanvas;
    }
    const srcData = srcImageData.data;

    // Create the displacement grid
    // The grid should be large enough to cover all lookups.
    // gx2 can go up to ceil(width/effectiveScale), gy2 up to ceil(height/effectiveScale).
    // So grid dimensions need to be ceil(dim/effectiveScale) + 1.
    const gridW = Math.ceil(width / effectiveScale) + 1;
    const gridH = Math.ceil(height / effectiveScale) + 1;
    
    const displacementGrid = [];
    for (let gy = 0; gy < gridH; gy++) {
        const row = [];
        for (let gx = 0; gx < gridW; gx++) {
            // Store random displacement factors in [-1, 1) range
            row.push([(Math.random() - 0.5) * 2, (Math.random() - 0.5) * 2]); 
        }
        displacementGrid.push(row);
    }

    // Create destination canvas and ImageData
    const destCanvas = document.createElement('canvas');
    destCanvas.width = width;
    destCanvas.height = height;
    const destCtx = destCanvas.getContext('2d');

    if (!destCtx) {
        console.error("Could not get 2D context for destination canvas. Aborting.");
        // Fallback: return a canvas with the original image drawn
        const fallbackCanvas = document.createElement('canvas');
        fallbackCanvas.width = width;
        fallbackCanvas.height = height;
        const fbCtx = fallbackCanvas.getContext('2d');
        if (fbCtx) fbCtx.drawImage(originalImg, 0, 0, width, height);
        return fallbackCanvas;
    }

    const destImageData = destCtx.createImageData(width, height);
    const destData = destImageData.data;

    for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
            const normalizedX = x / effectiveScale;
            const normalizedY = y / effectiveScale;

            const gx1 = Math.floor(normalizedX);
            const gy1 = Math.floor(normalizedY);
            const gx2 = gx1 + 1;
            const gy2 = gy1 + 1;

            const fracX = normalizedX - gx1;
            const fracY = normalizedY - gy1;

            // Values from the displacement grid
            // (gx1, gy1) (gx2, gy1)
            // (gx1, gy2) (gx2, gy2)
            const d11 = displacementGrid[gy1][gx1]; 
            const d21 = displacementGrid[gy1][gx2]; 
            const d12 = displacementGrid[gy2][gx1]; 
            const d22 = displacementGrid[gy2][gx2]; 

            // Bilinear interpolation for X displacement factor
            const dxTop = d11[0] * (1 - fracX) + d21[0] * fracX;
            const dxBottom = d12[0] * (1 - fracX) + d22[0] * fracX;
            const interpolatedDxFactor = dxTop * (1 - fracY) + dxBottom * fracY;

            // Bilinear interpolation for Y displacement factor
            const dyTop = d11[1] * (1 - fracX) + d21[1] * fracX;
            const dyBottom = d12[1] * (1 - fracX) + d22[1] * fracX;
            const interpolatedDyFactor = dyTop * (1 - fracY) + dyBottom * fracY;

            const finalDisplacementX = interpolatedDxFactor * strength;
            const finalDisplacementY = interpolatedDyFactor * strength;

            let srcX = Math.round(x + finalDisplacementX);
            let srcY = Math.round(y + finalDisplacementY);

            // Clamp source coordinates to be within image bounds
            srcX = Math.max(0, Math.min(width - 1, srcX));
            srcY = Math.max(0, Math.min(height - 1, srcY));

            const srcIndex = (srcY * width + srcX) * 4;
            const destIndex = (y * width + x) * 4;

            destData[destIndex]     = srcData[srcIndex];     // R
            destData[destIndex + 1] = srcData[srcIndex + 1]; // G
            destData[destIndex + 2] = srcData[srcIndex + 2]; // B
            destData[destIndex + 3] = srcData[srcIndex + 3]; // A
        }
    }

    destCtx.putImageData(destImageData, 0, 0);
    return destCanvas;
}

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 Blown Glass Filter Effect Tool allows users to apply a unique blown glass effect to their images. By adjusting parameters like strength and scale, users can manipulate the aesthetic quality of their pictures, creating dynamic and visually appealing glass-like distortions. This tool is ideal for graphic designers, artists, or anyone looking to enhance their photos for social media, presentations, or personal projects. With the ease of use provided by this web tool, anyone can transform their images into captivating pieces that mimic the appearance of colored glass.

Leave a Reply

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