/**
* @fileoverview LuminaJS Filters - Blur
* Applies a box blur effect to an image.
*/
/**
* Applies a box blur filter to a copy of the provided `ImageData`.
* This implementation uses a two-pass box blur algorithm (horizontal then vertical)
* for better performance.
*
* Performance notes:
* - Runtime cost grows with image dimensions and blur radius.
* - Large images can block the main thread during interactive use.
* - For responsive UIs, resize first (preview), then run full-resolution blur only on final export.
*
* @param {ImageData} imageData - The source pixel data.
* @param {number} radius - The blur radius (integer). Default is 1.
* @returns {ImageData} A new `ImageData` object with blur applied.
*
* @example
* const blurredData = blur(imageData, 3);
*/
export function blur(imageData, radius = 1) {
const width = imageData.width;
const height = imageData.height;
const input = imageData.data;
const output = new Uint8ClampedArray(input.length);
const temp = new Uint8ClampedArray(input.length);
radius = Math.max(0, Math.floor(radius));
if (radius === 0) {
return new ImageData(new Uint8ClampedArray(input), width, height);
}
// Horizontal pass
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
let r = 0,
g = 0,
b = 0,
a = 0;
let count = 0;
for (let dx = -radius; dx <= radius; dx++) {
const nx = x + dx;
if (nx >= 0 && nx < width) {
const offset = (y * width + nx) * 4;
r += input[offset];
g += input[offset + 1];
b += input[offset + 2];
a += input[offset + 3];
count++;
}
}
const offset = (y * width + x) * 4;
temp[offset] = r / count;
temp[offset + 1] = g / count;
temp[offset + 2] = b / count;
temp[offset + 3] = a / count;
}
}
// Vertical pass
for (let x = 0; x < width; x++) {
for (let y = 0; y < height; y++) {
let r = 0,
g = 0,
b = 0,
a = 0;
let count = 0;
for (let dy = -radius; dy <= radius; dy++) {
const ny = y + dy;
if (ny >= 0 && ny < height) {
const offset = (ny * width + x) * 4;
r += temp[offset];
g += temp[offset + 1];
b += temp[offset + 2];
a += temp[offset + 3];
count++;
}
}
const offset = (y * width + x) * 4;
output[offset] = r / count;
output[offset + 1] = g / count;
output[offset + 2] = b / count;
output[offset + 3] = a / count;
}
}
return new ImageData(output, width, height);
}