Please bookmark this page to avoid losing your image tool!

Image Punch And Pinch Effect Creator

(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 punch (bulge) or pinch (squeeze) distortion effect to an image.
 * The effect is centered at a specified point and contained within a given radius.
 *
 * @param {Image} originalImg The original javascript Image object to process.
 * @param {number} [amount=0.5] The strength and direction of the effect.
 *   Positive values create a "punch" or "bulge" effect (magnifying the center).
 *   Negative values create a "pinch" effect (shrinking the center).
 *   A value of 0 results in no change. The value must be greater than -1.
 *   Recommended range: -0.8 to 2.
 * @param {string|number} [centerXStr='50%'] The x-coordinate of the effect's center.
 *   Can be a number of pixels or a percentage string (e.g., "50%").
 * @param {string|number} [centerYStr='50%'] The y-coordinate of the effect's center.
 *   Can be a number of pixels or a percentage string (e.g., "50%").
 * @param {string|number} [radiusStr='50%'] The radius of the affected area.
 *   Can be a number of pixels or a percentage of the smaller image dimension.
 * @returns {HTMLCanvasElement} A new canvas element displaying the distorted image.
 */
function processImage(originalImg, amount = 0.5, centerXStr = '50%', centerYStr = '50%', radiusStr = '50%') {
    // 1. Setup canvas and context
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    const width = originalImg.width;
    const height = originalImg.height;
    canvas.width = width;
    canvas.height = height;

    // 2. Draw the original image to get its pixel data
    ctx.drawImage(originalImg, 0, 0);
    const srcData = ctx.getImageData(0, 0, width, height);
    const srcPixels = srcData.data;

    // 3. Create a destination ImageData object
    const destData = ctx.createImageData(width, height);
    const destPixels = destData.data;

    // 4. Parse parameters and resolve percentage values
    const parseValue = (val, max) => {
        if (typeof val === 'string' && val.endsWith('%')) {
            return (parseFloat(val) / 100) * max;
        }
        return parseFloat(val);
    };

    const centerX = parseValue(centerXStr, width);
    const centerY = parseValue(centerYStr, height);
    const radius = parseValue(radiusStr, Math.min(width, height));

    // The distortion formula uses pow(r, k). k must be > 0.
    // k is derived from amount, so we must clamp amount to be > -1.
    const clampedAmount = Math.max(-0.999, amount);

    // The exponent 'k' determines the mapping from destination radius to source radius.
    // For punch (magnify, amount > 0), we need k > 1.
    // For pinch (shrink, amount < 0), we need 0 < k < 1.
    // The mapping k = 1 + amount achieves this.
    const k = 1 + clampedAmount;

    // 5. Iterate over each destination pixel
    for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
            // Calculate vector from center to current pixel
            const dx = x - centerX;
            const dy = y - centerY;
            const distance = Math.sqrt(dx * dx + dy * dy);

            let sourceX = x;
            let sourceY = y;

            // Apply distortion only if the pixel is within the radius
            if (distance < radius) {
                // Normalize the distance to a value between 0 and 1
                const normalizedDistance = distance / radius;
                
                // Apply the power function to remap the distance
                const newNormalizedDistance = Math.pow(normalizedDistance, k);

                // Convert the new normalized distance back to pixel distance
                const newDistance = newNormalizedDistance * radius;
                
                // Find the ratio to scale the original vector
                const ratio = (distance === 0) ? 0 : newDistance / distance;

                // Calculate the source pixel coordinates by scaling the vector
                sourceX = centerX + dx * ratio;
                sourceY = centerY + dy * ratio;
            }

            // 6. Use bilinear interpolation to get the color from the source image
            const destIndex = (y * width + x) * 4;

            // Clamp coordinates to ensure they are within the image bounds for sampling
            const sx_clamped = Math.max(0, Math.min(width - 1.000001, sourceX));
            const sy_clamped = Math.max(0, Math.min(height - 1.000001, sourceY));

            const x_floor = Math.floor(sx_clamped);
            const y_floor = Math.floor(sy_clamped);
            const x_ceil = x_floor + 1;
            const y_ceil = y_floor + 1;

            const fx = sx_clamped - x_floor;
            const fy = sy_clamped - y_floor;
            const fx1 = 1 - fx;
            const fy1 = 1 - fy;

            const idx_tl = (y_floor * width + x_floor) * 4; // top-left
            const idx_tr = (y_floor * width + x_ceil) * 4;  // top-right
            const idx_bl = (y_ceil * width + x_floor) * 4;  // bottom-left
            const idx_br = (y_ceil * width + x_ceil) * 4;   // bottom-right

            // Weights for the four surrounding pixels
            const w_tl = fx1 * fy1;
            const w_tr = fx * fy1;
            const w_bl = fx1 * fy;
            const w_br = fx * fy;
            
            // Apply the weights to each channel (R, G, B, A)
            for (let i = 0; i < 4; i++) {
                destPixels[destIndex + i] = 
                    srcPixels[idx_tl + i] * w_tl +
                    srcPixels[idx_tr + i] * w_tr +
                    srcPixels[idx_bl + i] * w_bl +
                    srcPixels[idx_br + i] * w_br;
            }
        }
    }

    // 7. Put the new pixel data onto the canvas
    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 Punch and Pinch Effect Creator is a tool that allows users to apply distortion effects to images, creating either a ‘punch’ (bulge) effect or a ‘pinch’ (squeeze) effect. Users can specify the strength and direction of the effect, set the center point where the effect will be applied, and control the radius of the affected area. This tool is useful for enhancing images for artistic purposes, creating unique visual effects, or for use in graphic design projects where specific distortion effects are desired.

Leave a Reply

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