in src/canvastools/ts/CanvasTools/CanvasTools.Filter.ts [64:249]
export function BlurDiffFilter(factor: number): FilterFunction {
// http://blog.ivank.net/fastest-gaussian-blur.html
function boxesForGauss(sigma: number, n: number): number[] {
const wIdeal = Math.sqrt((12 * sigma * sigma / n) + 1); // Ideal averaging filter width
let wl = Math.floor(wIdeal);
if (wl % 2 === 0) {
wl--;
}
const wu = wl + 2;
const mIdeal = (12 * sigma * sigma - n * wl * wl - 4 * n * wl - 3 * n) / (-4 * wl - 4);
const m = Math.round(mIdeal);
// var sigmaActual = Math.sqrt( (m*wl*wl + (n-m)*wu*wu - n)/12 );
const sizes: number[] = [];
for (let i = 0; i < n; i++) {
sizes.push(i < m ? wl : wu);
}
return sizes;
}
function gaussBlur_4(scl: Uint8ClampedArray, tcl: Uint8ClampedArray, w: number, h: number, r: number) {
const bxs = boxesForGauss(r, 3);
boxBlur_4 (scl, tcl, w, h, (bxs[0] - 1) / 2);
boxBlur_4 (tcl, scl, w, h, (bxs[1] - 1) / 2);
boxBlur_4 (scl, tcl, w, h, (bxs[2] - 1) / 2);
}
function boxBlur_4(scl: Uint8ClampedArray, tcl: Uint8ClampedArray, w: number, h: number, r: number) {
for (let i = 0; i < scl.length; i++) {
tcl[i] = scl[i];
}
boxBlurH_4(tcl, scl, w, h, r);
boxBlurT_4(scl, tcl, w, h, r);
}
function boxBlurH_4(scl: Uint8ClampedArray, tcl: Uint8ClampedArray, w: number, h: number, r: number) {
const iarr = 1 / (r + r + 1);
for (let i = 0; i < h; i++) {
let ti = i * w;
let li = ti;
let ri = ti + r;
const fv = scl[ti];
const lv = scl[ti + w - 1];
let val = (r + 1) * fv;
for (let j = 0; j < r; j++) {
val += scl[ti + j];
}
for (let j = 0 ; j <= r ; j++) {
val += scl[ri++] - fv;
tcl[ti++] = Math.round(val * iarr);
}
for (let j = r + 1; j < w - r; j++) {
val += scl[ri++] - scl[li++];
tcl[ti++] = Math.round(val * iarr);
}
for (let j = w - r; j < w; j++) {
val += lv - scl[li++];
tcl[ti++] = Math.round(val * iarr);
}
}
}
function boxBlurT_4(scl: Uint8ClampedArray, tcl: Uint8ClampedArray, w: number, h: number, r: number) {
const iarr = 1 / (r + r + 1);
for (let i = 0; i < w; i++) {
let ti = i;
let li = ti;
let ri = ti + r * w;
const fv = scl[ti];
const lv = scl[ti + w * (h - 1)];
let val = (r + 1) * fv;
for (let j = 0; j < r; j++) {
val += scl[ti + j * w];
}
for (let j = 0; j <= r; j++) {
val += scl[ri] - fv;
tcl[ti] = Math.round(val * iarr);
ri += w;
ti += w;
}
for (let j = r + 1; j < h - r; j++) {
val += scl[ri] - scl[li];
tcl[ti] = Math.round(val * iarr);
li += w;
ri += w;
ti += w;
}
for (let j = h - r; j < h; j++) {
val += lv - scl[li];
tcl[ti] = Math.round(val * iarr);
li += w;
ti += w;
}
}
}
return (canvas: HTMLCanvasElement) => {
const context = canvas.getContext("2d");
const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
const buff = document.createElement("canvas");
buff.width = canvas.width;
buff.height = canvas.height;
const bludData = buff.getContext("2d").createImageData(buff.width, buff.height);
const idata = imageData.data;
const bdata = bludData.data;
const pixelsNumber = canvas.width * canvas.height;
const dataR = new Uint8ClampedArray(pixelsNumber);
const dataG = new Uint8ClampedArray(pixelsNumber);
const dataB = new Uint8ClampedArray(pixelsNumber);
const dataA = new Uint8ClampedArray(pixelsNumber);
for (let i = 0; i < pixelsNumber; i++) {
dataR[i] = idata[4 * i];
dataG[i] = idata[4 * i + 1];
dataB[i] = idata[4 * i + 2];
dataA[i] = idata[4 * i + 3];
}
const blurR = new Uint8ClampedArray(pixelsNumber);
const blurG = new Uint8ClampedArray(pixelsNumber);
const blurB = new Uint8ClampedArray(pixelsNumber);
const blurR2 = new Uint8ClampedArray(pixelsNumber);
const blurG2 = new Uint8ClampedArray(pixelsNumber);
const blurB2 = new Uint8ClampedArray(pixelsNumber);
// let blurA = new Uint8ClampedArray(pixelsNumber);
const halfFactor = factor / 2;
gaussBlur_4(dataR, blurR, buff.width, buff.height, halfFactor);
gaussBlur_4(dataG, blurG, buff.width, buff.height, halfFactor);
gaussBlur_4(dataB, blurB, buff.width, buff.height, halfFactor);
gaussBlur_4(dataR, blurR2, buff.width, buff.height, factor);
gaussBlur_4(dataG, blurG2, buff.width, buff.height, factor);
gaussBlur_4(dataB, blurB2, buff.width, buff.height, factor);
const alphaStep = 127 / factor;
for (let i = 0; i < pixelsNumber; i++) {
const dr = Math.abs(blurR2[i] - blurR[i]);
const dg = Math.abs(blurG2[i] - blurG[i]);
const db = Math.abs(blurB2[i] - blurB[i]);
// const d = 0.2126 * dr + 0.7152 * dg + 0.0722 * db;
const d = 0.2358 * dr + 0.0700 * dg + 0.6742 * db;
/* let dr = Math.abs(blurR2[i] - idata[4 * i + 0]);
let dg = Math.abs(blurG2[i] - idata[4 * i + 1]);
let db = Math.abs(blurB2[i] - idata[4 * i + 2]); */
// let d = 255 - Math.min(Math.round(Math.max(dr + dg + db - 16, 0)/8) * 16, 255);
/* bdata[4 * i + 0] = d;
bdata[4 * i + 1] = d;
bdata[4 * i + 2] = d; */
/* bdata[4 * i + 0] = (d < factor) ? Math.round(idata[4 * i + 0] / factor) * factor : idata[4 * i + 0];
bdata[4 * i + 1] = (d < factor) ? Math.round(idata[4 * i + 1] / factor) * factor : idata[4 * i + 1];
bdata[4 * i + 2] = (d < factor) ? Math.round(idata[4 * i + 2] / factor) * factor : idata[4 * i + 2]; */
/* bdata[4 * i + 0] = (dr >= 0.2126 * factor) ?
idata[4 * i + 0] : Math.round(idata[4 * i + 0] / factor) * factor;
bdata[4 * i + 1] = (dg >= 0.7152 * factor) ?
idata[4 * i + 1] : Math.round(idata[4 * i + 1] / factor) * factor;
bdata[4 * i + 2] = (db >= 0.0722 * factor) ?
idata[4 * i + 2] : Math.round(idata[4 * i + 2] / factor) * factor; */
const g = Math.round(0.2358 * idata[4 * i + 0] + 0.0700 * idata[4 * i + 1] + 0.6742 * idata[4 * i + 2]);
bdata[4 * i + 0] = (dr >= 0.2358 * halfFactor) ?
idata[4 * i + 0] : Math.round(g / factor) * factor;
bdata[4 * i + 1] = (dg >= 0.0700 * halfFactor) ?
idata[4 * i + 1] : Math.round(g / factor) * factor;
bdata[4 * i + 2] = (db >= 0.6742 * halfFactor) ?
idata[4 * i + 2] : Math.round(g / factor) * factor;
/* bdata[4 * i + 0] = Math.round(idata[4 * i + 0] / 8) * 8;
bdata[4 * i + 1] = Math.round(idata[4 * i + 1] / 8) * 8;
bdata[4 * i + 2] = Math.round(idata[4 * i + 2] / 8) * 8; */
bdata[4 * i + 3] = (d >= factor) ? 255 : 0 + Math.round(d * alphaStep);
}
buff.getContext("2d").putImageData(bludData, 0, 0);
return new Promise<HTMLCanvasElement>((resolve, reject) => {
return resolve(buff);
});
};
}