You can edit the below JavaScript code to customize the image tool.
async function processImage(originalImg, spinAngleDegreesStr = "10", numSamplesStr = "10", centerXPercentStr = "50", centerYPercentStr = "50") {
// Parameter parsing
const spinAngleDegrees = Number(spinAngleDegreesStr);
// Ensure numSamples is an integer and at least 1.
// Math.floor is important if numSamplesStr could be "10.5" etc.
const numSamples = Math.max(1, Math.floor(Number(numSamplesStr)));
const centerXPercent = Number(centerXPercentStr);
const centerYPercent = Number(centerYPercentStr);
// Image and canvas setup
const width = originalImg.width;
const height = originalImg.height;
// Handle 0-dimension images (e.g. if originalImg failed to load)
if (width === 0 || height === 0) {
const zeroCanvas = document.createElement('canvas');
zeroCanvas.width = width; // which is 0
zeroCanvas.height = height; // which is 0
return zeroCanvas;
}
const outputCanvas = document.createElement('canvas');
outputCanvas.width = width;
outputCanvas.height = height;
// Note: { willReadFrequently: true } is a hint for optimization if available in browser.
const outputCtx = outputCanvas.getContext('2d', { willReadFrequently: true });
const spinAngleRad = spinAngleDegrees * (Math.PI / 180);
// Optimization: If spinAngle is 0 or numSamples is 1, the image is effectively unchanged.
// In these cases, we can just draw the original image to the output canvas and return.
if (spinAngleRad === 0 || numSamples === 1) {
outputCtx.drawImage(originalImg, 0, 0, width, height);
return outputCanvas;
}
// Create a temporary canvas to draw the original image and access its pixel data.
// This is necessary because getImageData can only be called on a canvas context.
const inputCanvas = document.createElement('canvas');
inputCanvas.width = width;
inputCanvas.height = height;
const inputCtx = inputCanvas.getContext('2d', { willReadFrequently: true });
inputCtx.drawImage(originalImg, 0, 0, width, height);
let imageData;
try {
imageData = inputCtx.getImageData(0, 0, width, height);
} catch (e) {
// This error can occur if the image is cross-origin and the canvas becomes "tainted",
// preventing pixel data extraction due to security restrictions.
console.error("Error getting image data for Image Spin Blur Filter:", e);
// Fallback: draw the original image to the output canvas. The filter won't be applied.
outputCtx.drawImage(originalImg, 0, 0, width, height);
return outputCanvas;
}
const data = imageData.data; // Pixel data from the original image
// Create ImageData for the output canvas to hold the processed pixels.
const outputImageData = outputCtx.createImageData(width, height);
const outputData = outputImageData.data; // Pixel data for the new image
// Calculate the center of the spin in absolute pixel coordinates.
const cx = (centerXPercent / 100) * width;
const cy = (centerYPercent / 100) * height;
// Iterate over each pixel of the destination image.
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const currentPixelOutputIndex = (y * width + x) * 4; // Index for R, G, B, A components
let rSum = 0, gSum = 0, bSum = 0, aSum = 0; // Accumulators for color components
// Vector from the spin center to the current pixel (x,y).
const dx = x - cx;
const dy = y - cy;
// Distance (radius) of the current pixel from the spin center.
const radius = Math.sqrt(dx * dx + dy * dy);
// Original angle of the current pixel relative to the spin center.
// Math.atan2 handles all quadrants and case (0,0) (returns 0).
const originalAngle = Math.atan2(dy, dx);
// Collect samples along the circular arc for the current pixel.
// Since numSamples >= 2 here (due to early exit), numSamples-1 is safe (>=1).
for (let i = 0; i < numSamples; i++) {
// 't' interpolates from 0 to 1 across the samples.
const t = i / (numSamples - 1);
// Calculate the angle offset for this sample.
// This distributes samples symmetrically from -spinAngleRad/2 to +spinAngleRad/2
// relative to the originalAngle.
const currentAngleOffset = (t - 0.5) * spinAngleRad;
const sampleAngle = originalAngle + currentAngleOffset;
// Calculate the coordinates of the source pixel to sample using polar to cartesian conversion.
const sx_float = cx + radius * Math.cos(sampleAngle);
const sy_float = cy + radius * Math.sin(sampleAngle);
// Clamp coordinates to be within image bounds and round to the nearest integer pixel.
// This is a simple nearest-neighbor sampling.
const sx = Math.max(0, Math.min(width - 1, Math.round(sx_float)));
const sy = Math.max(0, Math.min(height - 1, Math.round(sy_float)));
const samplePixelIndex = (sy * width + sx) * 4; // Index for R, G, B, A components in source data
// Accumulate color and alpha values from the sampled pixel.
rSum += data[samplePixelIndex];
gSum += data[samplePixelIndex + 1];
bSum += data[samplePixelIndex + 2];
aSum += data[samplePixelIndex + 3];
}
// Average the accumulated values and assign to the output pixel.
outputData[currentPixelOutputIndex] = rSum / numSamples;
outputData[currentPixelOutputIndex + 1] = gSum / numSamples;
outputData[currentPixelOutputIndex + 2] = bSum / numSamples;
outputData[currentPixelOutputIndex + 3] = aSum / numSamples;
}
}
// Put the processed pixel data onto 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 Spin Blur Filter is a web-based tool that allows users to apply a dynamic spin blur effect to their images. By adjusting parameters such as the angle of blur, number of samples for smoothness, and the center point of rotation, users can create artistic effects that convey motion or focus. This tool is ideal for graphic designers, photographers, and creative individuals looking to enhance their images with a unique visual style, making it suitable for use in digital artworks, promotional materials, and social media content.