You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, lensCenterXRatio = 0.5, lensCenterYRatio = 0.5, lensStrength = 0.3, lensRadiusRatio = 0.4) {
// Ensure parameters are numbers
lensCenterXRatio = Number(lensCenterXRatio);
lensCenterYRatio = Number(lensCenterYRatio);
lensStrength = Number(lensStrength);
lensRadiusRatio = Number(lensRadiusRatio);
const width = originalImg.naturalWidth || originalImg.width;
const height = originalImg.naturalHeight || originalImg.height;
// Create a canvas to draw the original image and get its pixel data
// This step is necessary because we need pixel-level access to the original image.
const inputCanvas = document.createElement('canvas');
inputCanvas.width = width;
inputCanvas.height = height;
const inputCtx = inputCanvas.getContext('2d', { willReadFrequently: true }); // Hint for optimization
inputCtx.drawImage(originalImg, 0, 0, width, height);
let inputImageData;
try {
inputImageData = inputCtx.getImageData(0, 0, width, height);
} catch (e) {
console.error("Error getting image data from input canvas. This can happen due to CORS restrictions if the image is from a different origin and the canvas becomes tainted.", e);
// Fallback: return a new canvas with the original image drawn, if processing fails.
const fallbackCanvas = document.createElement('canvas');
fallbackCanvas.width = width;
fallbackCanvas.height = height;
const fallbackCtx = fallbackCanvas.getContext('2d');
fallbackCtx.drawImage(originalImg, 0, 0, width, height);
return fallbackCanvas;
}
const inputData = inputImageData.data;
// Create the output canvas
const outputCanvas = document.createElement('canvas');
outputCanvas.width = width;
outputCanvas.height = height;
const outputCtx = outputCanvas.getContext('2d');
const outputImageData = outputCtx.createImageData(width, height);
const outputData = outputImageData.data;
const centerX = width * lensCenterXRatio;
const centerY = height * lensCenterYRatio;
const minDimension = Math.min(width, height);
const radius = minDimension * lensRadiusRatio;
// If radius is 0 or negative, or strength is 0, there's no visual effect.
// In this case, draw the original image onto the output canvas and return it.
if (radius <= 0 || lensStrength === 0) {
outputCtx.drawImage(originalImg, 0, 0, width, height);
return outputCanvas;
}
// Power for the falloff of the lens effect.
// 1.0 means linear falloff, 2.0 means quadratic (effect more concentrated at center).
const pullEffectFalloffPower = 1.0;
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const dx = x - centerX; // Vector from lens center to current pixel
const dy = y - centerY;
const distanceSq = dx * dx + dy * dy; // Squared distance
let sourceX = x; // Coords of the pixel to sample from the original image
let sourceY = y;
// Check if the current pixel (x,y) is within the lens's radius of influence
if (distanceSq < radius * radius) {
const distance = Math.sqrt(distanceSq); // Actual distance
if (distance === 0) {
// If at the exact center of the lens, sample from the center.
sourceX = centerX;
sourceY = centerY;
} else {
// Normalized distance from center (0.0 at center, 1.0 at radius edge)
const normDist = distance / radius;
// Calculate the "pull" amount.
// This is strongest at the center (max `lensStrength`) and zero at the edge of the radius.
// A positive `lensStrength` "pulls" the image, resembling gravitational lensing (pinch).
// A negative `lensStrength` "pushes" (bulge/magnification).
const pullAmount = lensStrength * Math.pow(1.0 - normDist, pullEffectFalloffPower);
// Calculate the scaling factor for the radial vector (dx, dy).
// A scaleFactor > 1.0 means sampling from further out from the lens center (pinch effect).
// A scaleFactor < 1.0 means sampling from closer to the lens center (bulge effect).
const scaleFactor = 1.0 + pullAmount;
sourceX = centerX + dx * scaleFactor;
sourceY = centerY + dy * scaleFactor;
}
}
// Determine the source pixel using nearest neighbor sampling.
// Clamp coordinates to be within the image boundaries.
const sx = Math.max(0, Math.min(width - 1, Math.round(sourceX)));
const sy = Math.max(0, Math.min(height - 1, Math.round(sourceY)));
const inputIndex = (sy * width + sx) * 4; // Index for inputImageData array
const outputIndex = (y * width + x) * 4; // Index for outputImageData array
// Copy pixel data (R, G, B, A) from source to target
outputData[outputIndex] = inputData[inputIndex];
outputData[outputIndex + 1] = inputData[inputIndex + 1];
outputData[outputIndex + 2] = inputData[inputIndex + 2];
outputData[outputIndex + 3] = inputData[inputIndex + 3];
}
}
// Write the modified pixel data to the output canvas
outputCtx.putImageData(outputImageData, 0, 0);
return outputCanvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Image Gravitational Lens Filter Effect Tool allows users to apply a gravitational lensing effect to images. This tool can simulate the visual distortion seen in astronomical images, where gravity alters the path of light. By adjusting parameters such as the lens center, strength, and radius, users can create unique artistic effects for photography, graphic design, or educational purposes. It’s useful for artists looking to add depth to their images or for anyone attempting to create visually striking alterations to their pictures.