You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, strength = 0.1) {
const canvas = document.createElement('canvas');
// Use willReadFrequently hint for contexts we'll use getImageData on.
const ctx = canvas.getContext('2d', { willReadFrequently: false }); // Main canvas for output
const width = originalImg.naturalWidth || originalImg.width;
const height = originalImg.naturalHeight || originalImg.height;
canvas.width = width;
canvas.height = height;
if (width === 0 || height === 0) {
// Handles invalid image dimensions like 0x0.
// Returns an empty canvas of the correct size.
return canvas;
}
// Draw the original image onto a temporary canvas to get its ImageData.
// This is crucial as originalImg might be an HTMLImageElement that isn't on a canvas yet.
// It also handles various image types that can be drawn to a canvas.
const tempCanvas = document.createElement('canvas');
tempCanvas.width = width;
tempCanvas.height = height;
// The temporary context will be read from via getImageData.
const tempCtx = tempCanvas.getContext('2d', { willReadFrequently: true });
tempCtx.drawImage(originalImg, 0, 0, width, height);
let srcImageData;
try {
srcImageData = tempCtx.getImageData(0, 0, width, height);
} catch (e) {
// This can happen due to tainted canvas if image is cross-origin.
// Log error and return original image drawn on canvas as fallback.
console.error("Error getting ImageData from temporary canvas: ", e);
ctx.drawImage(originalImg, 0, 0, width, height);
return canvas;
}
const srcData = srcImageData.data;
const destImageData = ctx.createImageData(width, height);
const destData = destImageData.data;
const centerX = width / 2;
const centerY = height / 2;
// If strength is 0, distortionFactor becomes 1. sourceX_exact = x, sourceY_exact = y.
// This means the image is unchanged. Optimize for this common case.
if (strength === 0) {
destImageData.data.set(srcData); // Copy data directly
ctx.putImageData(destImageData, 0, 0);
return canvas;
}
// Normalization factor:
// Using Math.max ensures that normalized coordinates nx, ny are generally within [-1, 1]
// for one dimension if the image is not square. The radius r_sq will be based on this.
// Other choices (e.g., Math.min, or geometric mean, or diagonal) would scale `strength` differently.
const normFactor = Math.max(centerX, centerY);
if (normFactor === 0) { // Avoid division by zero if centerX/Y are 0 (e.g. 1x1 image where center is 0.5)
// For a 1x1 image, normFactor would be 0.5. This check is mostly for W=0 or H=0 cases already handled.
destImageData.data.set(srcData);
ctx.putImageData(destImageData, 0, 0);
return canvas;
}
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const dx = x - centerX; // Distance from center for current destination pixel
const dy = y - centerY;
// Normalized coordinates (nx, ny)
// Have values typically between -1 and 1, depending on normFactor and aspect ratio
const nx = dx / normFactor;
const ny = dy / normFactor;
const r_sq = nx * nx + ny * ny; // Squared normalized radial distance
// Distortion factor calculation:
// For barrel distortion (wide-angle effect), strength > 0.
// For pincushion distortion, strength < 0.
// This formula maps a destination pixel (dx, dy relative to center)
// to a source pixel by scaling its distance from the center.
// If strength > 0, distortionFactor > 1, so source pixel is further from center.
// This pulls pixels from outer regions of source to inner regions of destination,
// creating a 'bulge' or magnification in the center and compression at edges.
const distortionFactor = 1 + strength * r_sq;
// Calculate exact source coordinates by applying the distortionFactor
// to the original distances from the center (dx, dy)
const sourceX_exact = centerX + dx * distortionFactor;
const sourceY_exact = centerY + dy * distortionFactor;
const destIdx = (y * width + x) * 4; // Index for the destination pixel array
// Check if the calculated source coordinates are within the bounds of the source image
if (sourceX_exact >= 0 && sourceX_exact < width &&
sourceY_exact >= 0 && sourceY_exact < height) {
// Bilinear interpolation for smooth sampling
// Clamp coordinates to avoid issues at the very edges for interpolation window
const clampedSourceX = Math.max(0, Math.min(width - 1.0000001, sourceX_exact));
const clampedSourceY = Math.max(0, Math.min(height - 1.0000001, sourceY_exact));
const x1 = Math.floor(clampedSourceX);
const y1 = Math.floor(clampedSourceY);
// Ensure x2, y2 are within image bounds for memory access
const x2 = Math.min(x1 + 1, width - 1);
const y2 = Math.min(y1 + 1, height - 1);
const fracX = clampedSourceX - x1; // Fractional part for x
const fracY = clampedSourceY - y1; // Fractional part for y
// Indices for the four neighboring pixels in the source data array
const idxP11 = (y1 * width + x1) * 4; // Top-left
const idxP21 = (y1 * width + x2) * 4; // Top-right
const idxP12 = (y2 * width + x1) * 4; // Bottom-left
const idxP22 = (y2 * width + x2) * 4; // Bottom-right
// Interpolate R, G, B, A channels
for (let c = 0; c < 4; c++) {
const p11 = srcData[idxP11 + c];
const p21 = srcData[idxP21 + c];
const p12 = srcData[idxP12 + c];
const p22 = srcData[idxP22 + c];
destData[destIdx + c] =
p11 * (1 - fracX) * (1 - fracY) + // Contribution from P11
p21 * fracX * (1 - fracY) + // Contribution from P21
p12 * (1 - fracX) * fracY + // Contribution from P12
p22 * fracX * fracY; // Contribution from P22
}
} else {
// Source coordinates are outside the image bounds.
// Make these pixels transparent black.
destData[destIdx] = 0; // R
destData[destIdx + 1] = 0; // G
destData[destIdx + 2] = 0; // B
destData[destIdx + 3] = 0; // A (transparent)
}
}
}
// Put the processed image data onto the main 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 Wide-Angle Lens Perspective Filter Effect Tool allows users to apply a wide-angle lens effect to their images, simulating the distortion typically seen in wide-angle photography. By adjusting the strength of the effect, users can enhance the central focus of an image while creating a bulging or expansive perspective at the edges. This tool is useful for photographers and graphic designers looking to create dynamic visual effects, enhance landscape and architectural images, or add artistic flair to their photos.