You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, strength = 0.2) {
const W = originalImg.width;
const H = originalImg.height;
const canvas = document.createElement('canvas');
canvas.width = W;
canvas.height = H;
// The { willReadFrequently: true } hint can improve performance on some browsers for getImageData/putImageData operations.
const ctx = canvas.getContext('2d', { willReadFrequently: true });
// Draw the original image onto the canvas initially to access its pixel data.
ctx.drawImage(originalImg, 0, 0, W, H);
const srcImageData = ctx.getImageData(0, 0, W, H);
const srcData = srcImageData.data;
// Create a new ImageData object for the destination pixels.
const destImageData = ctx.createImageData(W, H);
const destData = destImageData.data;
const centerX = W / 2;
const centerY = H / 2;
// Ensure strength is a number.
strength = Number(strength);
if (isNaN(strength)) {
strength = 0.2; // Default strength if input is invalid
}
// Helper function to get a pixel (R,G,B,A) from image data.
// Coordinates are floored and clamped to image boundaries.
function getPixel(x_in, y_in, data, Dwidth, Dheight) {
const x = Math.max(0, Math.min(Dwidth - 1, Math.floor(x_in)));
const y = Math.max(0, Math.min(Dheight - 1, Math.floor(y_in)));
const i = (y * Dwidth + x) * 4;
return [data[i], data[i+1], data[i+2], data[i+3]];
}
// Helper function for bilinear interpolation.
function getPixelBilinear(x, y, data, Dwidth, Dheight) {
// Handle cases where x or y are exactly at the width/height boundary for correct fx, fy.
const x_eff = (x >= Dwidth -1e-9) ? Dwidth - 1.000001 : Math.max(0,x) ; // Ensure x is within [0, Dwidth-epsilon)
const y_eff = (y >= Dheight -1e-9) ? Dheight - 1.000001 : Math.max(0,y) ; // Ensure y is within [0, Dheight-epsilon)
const x1 = Math.floor(x_eff);
const y1 = Math.floor(y_eff);
const x2 = x1 + 1;
const y2 = y1 + 1;
// Get the four neighboring pixels. getPixel handles boundary clamping.
const P11 = getPixel(x1, y1, data, Dwidth, Dheight);
const P21 = getPixel(x2, y1, data, Dwidth, Dheight);
const P12 = getPixel(x1, y2, data, Dwidth, Dheight);
const P22 = getPixel(x2, y2, data, Dwidth, Dheight);
const fx = x_eff - x1; // Fractional part of x
const fy = y_eff - y1; // Fractional part of y
const fx1 = 1 - fx;
const fy1 = 1 - fy;
// Interpolate R, G, B, A channels
const R = P11[0]*fx1*fy1 + P21[0]*fx*fy1 + P12[0]*fx1*fy + P22[0]*fx*fy;
const G = P11[1]*fx1*fy1 + P21[1]*fx*fy1 + P12[1]*fx1*fy + P22[1]*fx*fy;
const B = P11[2]*fx1*fy1 + P21[2]*fx*fy1 + P12[2]*fx1*fy + P22[2]*fx*fy;
const A = P11[3]*fx1*fy1 + P21[3]*fx*fy1 + P12[3]*fx1*fy + P22[3]*fx*fy;
return [R,G,B,A];
}
// Iterate over each pixel in the destination image.
for (let j = 0; j < H; j++) { // Current row (y-coordinate)
for (let i = 0; i < W; i++) { // Current column (x-coordinate)
const destIdx = (j * W + i) * 4; // Index for the destination pixel array
// Normalized coordinates relative to the center.
// dx_norm, dy_norm range from -1 to 1.
const dx_norm = (i - centerX) / centerX;
const dy_norm = (j - centerY) / centerY;
// If W or H is 1, centerX or centerY would be 0.5. Division is fine.
// No need to check for W/H=0 as Image objects have W,H >= 1.
// 'Elliptical' squared radial distance from center.
// r_sq_geom can be up to 2.0 at the corners (if dx_norm=1, dy_norm=1).
const r_sq_geom = dx_norm * dx_norm + dy_norm * dy_norm;
// Barrel distortion factor.
// strength > 0: bulge out (barrel)
// strength < 0: squeeze in (pincushion)
// factor = 1 means no change in radius proportion.
const factor = 1.0 - strength * r_sq_geom;
// Calculate source normalized coordinates by scaling from the center.
const src_dx_norm = dx_norm * factor;
const src_dy_norm = dy_norm * factor;
// Convert normalized source coordinates back to absolute pixel coordinates.
// srcX = centerX + src_dx_norm * centerX = centerX * (1 + src_dx_norm)
const srcX = centerX * (1 + src_dx_norm);
const srcY = centerY * (1 + src_dy_norm);
// Get the color from the source image using bilinear interpolation.
// The srcX, srcY coordinates are guaranteed by the formula to be within
// the logical bounds [0,W] and [0,H] for reasonable strength values.
// getPixelBilinear and getPixel handle clamping for edge cases.
const color = getPixelBilinear(srcX, srcY, srcData, W, H);
destData[destIdx] = color[0]; // R
destData[destIdx + 1] = color[1]; // G
destData[destIdx + 2] = color[2]; // B
destData[destIdx + 3] = color[3]; // A
}
}
// Put the modified pixel data back onto the canvas.
ctx.putImageData(destImageData, 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!
The Image Stadium View Filter Effect tool applies a distortion effect to images, simulating a stadium view by bulging or squeezing the image based on a strength parameter. This tool can be used for enhancing photos, creating artistic effects for social media posts, or preparing images for promotional materials by giving them a dynamic, curved appearance. Adjusting the strength of the effect allows users to customize the intensity of the distortion to achieve their desired look.