You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, swirlStrength = 30, centerFocus = 0.1, falloff = 1.5, quality = 5) {
// Parameter Coercion and Validation
swirlStrength = Number(swirlStrength);
if (isNaN(swirlStrength)) {
swirlStrength = 30; // Default value if input is not a valid number
}
centerFocus = Number(centerFocus);
if (isNaN(centerFocus)) {
centerFocus = 0.1; // Default value
}
centerFocus = Math.max(0, Math.min(1, centerFocus)); // Clamp between 0 and 1
falloff = Number(falloff);
if (isNaN(falloff) || falloff <= 0) { // Falloff must be positive
falloff = 1.5; // Default value
}
quality = Number(quality);
if (isNaN(quality)) {
quality = 5; // Default value
}
const numSamples = Math.max(1, Math.round(quality)); // Ensure at least 1 sample
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d', { willReadFrequently: true });
const imgWidth = originalImg.naturalWidth || originalImg.width;
const imgHeight = originalImg.naturalHeight || originalImg.height;
canvas.width = imgWidth;
canvas.height = imgHeight;
if (imgWidth === 0 || imgHeight === 0) {
// If image has no dimensions, return an empty canvas
return canvas;
}
try {
ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
} catch (e) {
console.error("Error drawing image to canvas. Ensure the image is loaded and not CORS-tainted.", e);
// Return the canvas, which might be blank or show a broken image placeholder if drawing failed.
return canvas;
}
const srcImageData = ctx.getImageData(0, 0, imgWidth, imgHeight);
const dstImageData = ctx.createImageData(imgWidth, imgHeight);
const dataSrc = srcImageData.data;
const dataDst = dstImageData.data;
const cx = imgWidth / 2.0;
const cy = imgHeight / 2.0;
const maxDist = Math.hypot(cx, cy); // Distance from center to a corner
// Helper function for Nearest Neighbor sampling
function getSrcPixelNN(srcPixelData, w, h, x, y) {
const ix = Math.max(0, Math.min(w - 1, Math.round(x)));
const iy = Math.max(0, Math.min(h - 1, Math.round(y)));
const i = (iy * w + ix) * 4;
return [srcPixelData[i], srcPixelData[i + 1], srcPixelData[i + 2], srcPixelData[i + 3]];
}
for (let y = 0; y < imgHeight; y++) {
for (let x = 0; x < imgWidth; x++) {
const relX = x - cx;
const relY = y - cy;
const dist = Math.hypot(relX, relY);
let currentPixelSwirlEffectRadius = 0;
const normDist = (maxDist === 0) ? 0 : dist / maxDist; // Normalized distance from center (0 to 1)
if (normDist > centerFocus) {
const focusRange = 1.0 - centerFocus;
if (focusRange > 1e-5) { // Avoid division by zero if centerFocus is very close to 1.0
let swirlRegionNormDist = (normDist - centerFocus) / focusRange;
swirlRegionNormDist = Math.max(0, Math.min(swirlRegionNormDist, 1.0)); // Clamp to [0, 1]
currentPixelSwirlEffectRadius = swirlStrength * Math.pow(swirlRegionNormDist, falloff);
}
}
const dstIdx = (y * imgWidth + x) * 4;
// If no swirl effect for this pixel, or it's at the exact center (where tangential vector is undefined)
if (currentPixelSwirlEffectRadius < 0.5 || dist < 1e-3) {
const srcIdx = dstIdx;
dataDst[dstIdx] = dataSrc[srcIdx];
dataDst[dstIdx + 1] = dataSrc[srcIdx + 1];
dataDst[dstIdx + 2] = dataSrc[srcIdx + 2];
dataDst[dstIdx + 3] = dataSrc[srcIdx + 3];
continue;
}
let rSum = 0, gSum = 0, bSum = 0, aSum = 0;
// Normalized Tangential vector: (-relY/dist, relX/dist)
// dist is guaranteed to be >= 1e-3 here, so division is safe.
const tx = -relY / dist;
const ty = relX / dist;
for (let i = 0; i < numSamples; i++) {
let sampleX = x;
let sampleY = y;
if (numSamples > 1) { // Only offset if more than one sample is taken
// Calculate sample position along the tangential blur line
// sampleRatio goes from 0 to 1
const sampleRatio = i / (numSamples - 1);
// offset makes samples spread from -radius/2 to +radius/2 around the current pixel
const offset = (sampleRatio - 0.5) * currentPixelSwirlEffectRadius;
sampleX = x + tx * offset;
sampleY = y + ty * offset;
}
const pixelValue = getSrcPixelNN(dataSrc, imgWidth, imgHeight, sampleX, sampleY);
rSum += pixelValue[0];
gSum += pixelValue[1];
bSum += pixelValue[2];
aSum += pixelValue[3];
}
dataDst[dstIdx] = rSum / numSamples;
dataDst[dstIdx + 1] = gSum / numSamples;
dataDst[dstIdx + 2] = bSum / numSamples;
dataDst[dstIdx + 3] = aSum / numSamples;
}
}
ctx.putImageData(dstImageData, 0, 0);
return canvas;
}
Apply Changes