Please bookmark this page to avoid losing your image tool!

Image Rashed Pinch And Bulge Strength Analyzer

(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.
/**
 * Applies a radial pinch or bulge distortion to an image.
 * This function simulates a lens effect, magnifying (bulge) or minifying (pinch)
 * the area within a specified circle.
 *
 * @param {Image} originalImg The original Image object to process.
 * @param {number} [strength=0.5] The strength of the distortion. Positive values (0 to 1) create a bulge,
 *   while negative values (0 to -1) create a pinch. 0 means no effect. Values are clamped to [-1, 1].
 * @param {number} [radius=-1] The radius of the circular area of effect in pixels.
 *   If a non-positive value is provided, a default radius is calculated to cover the entire image from the center point.
 * @param {number} [centerX=0.5] The horizontal center of the effect, as a ratio of the image's width (0.0 to 1.0).
 * @param {number} [centerY=0.5] The vertical center of the effect, as a ratio of the image's height (0.0 to 1.0).
 * @returns {HTMLCanvasElement} A new canvas element with the distorted image.
 */
function processImage(originalImg, strength = 0.5, radius = -1, centerX = 0.5, centerY = 0.5) {
    const canvas = document.createElement('canvas');
    // Using { willReadFrequently: true } can optimize repeated calls to getImageData on some browsers
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

    const width = originalImg.naturalWidth;
    const height = originalImg.naturalHeight;
    canvas.width = width;
    canvas.height = height;

    ctx.drawImage(originalImg, 0, 0, width, height);

    // If image is not loaded or has no dimensions, return the canvas as is
    if (width === 0 || height === 0) {
        return canvas;
    }

    const srcDataObj = ctx.getImageData(0, 0, width, height);
    const srcData = srcDataObj.data;
    const dstDataObj = ctx.createImageData(width, height);
    const dstData = dstDataObj.data;

    const cx = width * centerX;
    const cy = height * centerY;

    let effectRadius = radius;
    // If radius is not provided or non-positive, calculate a default
    if (effectRadius <= 0) {
        // Default radius is the distance from the center to the furthest corner
        const dx_to_edge = Math.max(cx, width - cx);
        const dy_to_edge = Math.max(cy, height - cy);
        effectRadius = Math.sqrt(dx_to_edge ** 2 + dy_to_edge ** 2);
    }

    // A radius of 0 means no area is affected, so we can return early
    if (effectRadius === 0) {
        return canvas;
    }

    // Clamp strength to the range [-1, 1] for predictable behavior
    const s = Math.max(-1, Math.min(1, strength));
    
    // Bail out if strength is 0, as there's no effect to apply
    if (s === 0) {
        return canvas;
    }

    const PI_2 = Math.PI / 2;

    // A helper function to sample a color value from the source data using bilinear interpolation.
    // This produces smoother results than nearest-neighbor sampling.
    const getInterpolatedValue = (data, w, h, x, y, channel) => {
        const x_low = Math.floor(x);
        const y_low = Math.floor(y);
        const x_high = x_low + 1;
        const y_high = y_low + 1;

        const x_weight = x - x_low;
        const y_weight = y - y_low;

        // A nested helper to get a single pixel component, clamping coordinates to be within bounds.
        const getClamped = (x_coord, y_coord) => {
            const clampedX = Math.max(0, Math.min(w - 1, x_coord));
            const clampedY = Math.max(0, Math.min(h - 1, y_coord));
            return data[((clampedY * w) + clampedX) * 4 + channel];
        };

        const tl = getClamped(x_low, y_low);   // top-left
        const tr = getClamped(x_high, y_low);  // top-right
        const bl = getClamped(x_low, y_high);  // bottom-left
        const br = getClamped(x_high, y_high); // bottom-right

        const top = tl * (1 - x_weight) + tr * x_weight;
        const bottom = bl * (1 - x_weight) + br * x_weight;
        
        return top * (1 - y_weight) + bottom * y_weight;
    };


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

            const dx = x - cx;
            const dy = y - cy;
            const distance = Math.sqrt(dx * dx + dy * dy);

            let srcX = x;
            let srcY = y;
            
            // Only apply the effect within the radius
            if (distance < effectRadius) {
                const angle = Math.atan2(dy, dx);
                let newDist;
                const rd = distance; // current radius in destination

                if (s > 0) { // Bulge effect
                    // Map destination radius to source radius using an arcsin curve for a fisheye effect
                    const rs_bulge = effectRadius * Math.asin(rd / effectRadius) / PI_2;
                    // Interpolate between no effect (rd) and full effect (rs_bulge)
                    newDist = rd * (1 - s) + rs_bulge * s;
                } else { // Pinch effect (s < 0)
                    // Map destination radius to source radius using a sin curve
                    const rs_pinch = effectRadius * Math.sin(rd * PI_2 / effectRadius);
                    const strength_pinch = -s; // Make strength positive for interpolation [0, 1]
                    // Interpolate between no effect (rd) and full effect (rs_pinch)
                    newDist = rd * (1 - strength_pinch) + rs_pinch * strength_pinch;
                }
                
                // Convert polar coordinates back to cartesian for the source pixel
                srcX = cx + newDist * Math.cos(angle);
                srcY = cy + newDist * Math.sin(angle);
            }

            const dstIdx = (y * width + x) * 4;
            // Get the interpolated color from the source and apply it to the destination
            dstData[dstIdx]     = getInterpolatedValue(srcData, width, height, srcX, srcY, 0); // R
            dstData[dstIdx + 1] = getInterpolatedValue(srcData, width, height, srcX, srcY, 1); // G
            dstData[dstIdx + 2] = getInterpolatedValue(srcData, width, height, srcX, srcY, 2); // B
            dstData[dstIdx + 3] = getInterpolatedValue(srcData, width, height, srcX, srcY, 3); // A
        }
    }

    ctx.putImageData(dstDataObj, 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 Rashed Pinch and Bulge Strength Analyzer is a tool that applies radial pinch or bulge distortions to images, simulating a lens effect. Users can control the strength and radius of the distortion, allowing for creative manipulation of the image’s appearance. This tool can be used for artistic photography, graphic design, and to create unique visual effects for images, making it beneficial for artists, designers, and content creators looking to enhance their visual projects.

Leave a Reply

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