Please bookmark this page to avoid losing your image tool!

Image Pinch, Bulge, Swirl, And Fisheye Effects 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, effect = 'pinch', strength = 0.5, radius = 0.5) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d', { willReadFrequently: true });
    const width = originalImg.width;
    const height = originalImg.height;
    canvas.width = width;
    canvas.height = height;

    ctx.drawImage(originalImg, 0, 0, width, height);
    const sourceData = ctx.getImageData(0, 0, width, height);
    const destData = ctx.createImageData(width, height);

    const centerX = width / 2;
    const centerY = height / 2;

    /**
     * Performs bilinear interpolation to find the color of a non-integer coordinate.
     * @param {ImageData} imgData The source image data.
     * @param {number} x The x-coordinate.
     * @param {number} y The y-coordinate.
     * @returns {Uint8ClampedArray} An array containing [r, g, b, a] for the interpolated pixel.
     */
    function getBilinearPixel(imgData, x, y) {
        const x1 = Math.floor(x);
        const y1 = Math.floor(y);

        // Check if the coordinates are out of bounds
        if (x1 < 0 || x1 >= width - 1 || y1 < 0 || y1 >= height - 1) {
            // Return a default color (e.g., transparent black) for out-of-bounds pixels
            const safeX = Math.max(0, Math.min(width - 1, Math.floor(x)));
            const safeY = Math.max(0, Math.min(height - 1, Math.floor(y)));
            const i = (safeY * width + safeX) * 4;
            return sourceData.data.slice(i, i+4);
        }
        
        const x2 = x1 + 1;
        const y2 = y1 + 1;

        const i1 = (y1 * width + x1) * 4;
        const i2 = (y1 * width + x2) * 4;
        const i3 = (y2 * width + x1) * 4;
        const i4 = (y2 * width + x2) * 4;

        const xFrac = x - x1;
        const yFrac = y - y1;
        const xFracInv = 1 - xFrac;
        const yFracInv = 1 - yFrac;
        
        const out = new Uint8ClampedArray(4);

        for (let i = 0; i < 4; i++) { // R, G, B, A
            const c1 = imgData.data[i1 + i];
            const c2 = imgData.data[i2 + i];
            const c3 = imgData.data[i3 + i];
            const c4 = imgData.data[i4 + i];

            const top = c1 * xFracInv + c2 * xFrac;
            const bottom = c3 * xFracInv + c4 * xFrac;
            out[i] = top * yFracInv + bottom * yFrac;
        }
        return out;
    }

    for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
            let sourceX = x;
            let sourceY = y;

            const dx = x - centerX;
            const dy = y - centerY;
            const dist = Math.sqrt(dx * dx + dy * dy);
            const angle = Math.atan2(dy, dx);
            
            switch (effect) {
                case 'pinch':
                case 'bulge': {
                    const actualRadius = radius * Math.min(width, height);
                    if (dist < actualRadius) {
                        // For bulge, amount is positive; for pinch, it's negative.
                        // strength is assumed to be [0, 1].
                        const amount = (effect === 'pinch' ? -strength : strength);
                        // Using an inverse function to map destination pixels to source pixels
                        const power = 1.0 - amount;
                        if (power !== 0) { // Avoid division by zero
                            const sourceRadius = actualRadius * Math.pow(dist / actualRadius, 1.0 / power);
                            sourceX = centerX + sourceRadius * Math.cos(angle);
                            sourceY = centerY + sourceRadius * Math.sin(angle);
                        }
                    }
                    break;
                }
                case 'swirl': {
                    const actualRadius = radius * Math.min(width, height);
                    if (dist < actualRadius) {
                        const factor = 1.0 - (dist / actualRadius);
                        // Strength parameter interpreted as number of full rotations
                        const maxAngle = strength * 2 * Math.PI; 
                        // The swirl angle decreases with distance from the center
                        const swirlAngle = maxAngle * factor * factor; // Use factor^2 for smoother falloff
                        
                        // Inverse mapping: find the source angle for the destination pixel
                        const sourceAngle = angle - swirlAngle; 

                        sourceX = centerX + dist * Math.cos(sourceAngle);
                        sourceY = centerY + dist * Math.sin(sourceAngle);
                    }
                    break;
                }
                case 'fisheye': {
                    // Fisheye is a strong bulge effect over the whole image
                    const maxDist = Math.sqrt(centerX * centerX + centerY * centerY);
                     // strength is assumed to be [0, 1]
                    const amount = strength;
                    const power = 1.0 - amount;

                    if (power > 0.001) { // Avoid power being zero or negative for stability
                         const sourceRadius = maxDist * Math.pow(dist / maxDist, 1.0 / power);
                         sourceX = centerX + sourceRadius * Math.cos(angle);
                         sourceY = centerY + sourceRadius * Math.sin(angle);
                    }
                    // If strength is too high, we default to the original pixel
                    break;
                }
            }

            const color = getBilinearPixel(sourceData, sourceX, sourceY);
            const index = (y * width + x) * 4;
            destData.data.set(color, index);
        }
    }

    ctx.putImageData(destData, 0, 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 Pinch, Bulge, Swirl, and Fisheye Effects Tool allows users to apply various distortion effects to images. It supports effects such as pinch, bulge, swirl, and fisheye, enabling creative image manipulation. Users can adjust the strength and radius of these effects, making it suitable for enhancing photos, creating artistic compositions, or experimenting with visual designs. This tool is useful for graphic designers, social media content creators, and anyone looking to add unique visual elements to their images.

Leave a Reply

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