|
export function blur(values, r) { |
|
if (!((r = +r) >= 0)) throw new RangeError("invalid r"); |
|
let length = values.length; |
|
if (!((length = Math.floor(length)) >= 0)) throw new RangeError("invalid length"); |
|
if (!length || !r) return values; |
|
const blur = blurf(r); |
|
const temp = values.slice(); |
|
blur(values, temp, 0, length, 1); |
|
blur(temp, values, 0, length, 1); |
|
blur(values, temp, 0, length, 1); |
|
return values; |
|
} |
|
|
|
export const blur2 = Blur2(blurf); |
|
|
|
export const blurImage = Blur2(blurfImage); |
|
|
|
function Blur2(blur) { |
|
return function(data, rx, ry = rx) { |
|
if (!((rx = +rx) >= 0)) throw new RangeError("invalid rx"); |
|
if (!((ry = +ry) >= 0)) throw new RangeError("invalid ry"); |
|
let {data: values, width, height} = data; |
|
if (!((width = Math.floor(width)) >= 0)) throw new RangeError("invalid width"); |
|
if (!((height = Math.floor(height !== undefined ? height : values.length / width)) >= 0)) throw new RangeError("invalid height"); |
|
if (!width || !height || (!rx && !ry)) return data; |
|
const blurx = rx && blur(rx); |
|
const blury = ry && blur(ry); |
|
const temp = values.slice(); |
|
if (blurx && blury) { |
|
blurh(blurx, temp, values, width, height); |
|
blurh(blurx, values, temp, width, height); |
|
blurh(blurx, temp, values, width, height); |
|
blurv(blury, values, temp, width, height); |
|
blurv(blury, temp, values, width, height); |
|
blurv(blury, values, temp, width, height); |
|
} else if (blurx) { |
|
blurh(blurx, values, temp, width, height); |
|
blurh(blurx, temp, values, width, height); |
|
blurh(blurx, values, temp, width, height); |
|
} else if (blury) { |
|
blurv(blury, values, temp, width, height); |
|
blurv(blury, temp, values, width, height); |
|
blurv(blury, values, temp, width, height); |
|
} |
|
return data; |
|
}; |
|
} |
|
|
|
function blurh(blur, T, S, w, h) { |
|
for (let y = 0, n = w * h; y < n;) { |
|
blur(T, S, y, y += w, 1); |
|
} |
|
} |
|
|
|
function blurv(blur, T, S, w, h) { |
|
for (let x = 0, n = w * h; x < w; ++x) { |
|
blur(T, S, x, x + n, w); |
|
} |
|
} |
|
|
|
function blurfImage(radius) { |
|
const blur = blurf(radius); |
|
return (T, S, start, stop, step) => { |
|
start <<= 2, stop <<= 2, step <<= 2; |
|
blur(T, S, start + 0, stop + 0, step); |
|
blur(T, S, start + 1, stop + 1, step); |
|
blur(T, S, start + 2, stop + 2, step); |
|
blur(T, S, start + 3, stop + 3, step); |
|
}; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function blurf(radius) { |
|
const radius0 = Math.floor(radius); |
|
if (radius0 === radius) return bluri(radius); |
|
const t = radius - radius0; |
|
const w = 2 * radius + 1; |
|
return (T, S, start, stop, step) => { |
|
if (!((stop -= step) >= start)) return; |
|
let sum = radius0 * S[start]; |
|
const s0 = step * radius0; |
|
const s1 = s0 + step; |
|
for (let i = start, j = start + s0; i < j; i += step) { |
|
sum += S[Math.min(stop, i)]; |
|
} |
|
for (let i = start, j = stop; i <= j; i += step) { |
|
sum += S[Math.min(stop, i + s0)]; |
|
T[i] = (sum + t * (S[Math.max(start, i - s1)] + S[Math.min(stop, i + s1)])) / w; |
|
sum -= S[Math.max(start, i - s0)]; |
|
} |
|
}; |
|
} |
|
|
|
|
|
function bluri(radius) { |
|
const w = 2 * radius + 1; |
|
return (T, S, start, stop, step) => { |
|
if (!((stop -= step) >= start)) return; |
|
let sum = radius * S[start]; |
|
const s = step * radius; |
|
for (let i = start, j = start + s; i < j; i += step) { |
|
sum += S[Math.min(stop, i)]; |
|
} |
|
for (let i = start, j = stop; i <= j; i += step) { |
|
sum += S[Math.min(stop, i + s)]; |
|
T[i] = sum / w; |
|
sum -= S[Math.max(start, i - s)]; |
|
} |
|
}; |
|
} |
|
|