Skip to content

Instantly share code, notes, and snippets.

@Sphinxxxx
Created December 22, 2022 22:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Sphinxxxx/2da469152a8f3afa715e6cb3a75d3a71 to your computer and use it in GitHub Desktop.
Save Sphinxxxx/2da469152a8f3afa715e6cb3a75d3a71 to your computer and use it in GitHub Desktop.
StackBlur on grayscale data (from https://github.com/flozz/StackBlur)
const stackGray = (function() {
const mulTable = [
512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292,
512, 454, 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292,
273, 512, 482, 454, 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259,
496, 475, 456, 437, 420, 404, 388, 374, 360, 347, 335, 323, 312, 302, 292,
282, 273, 265, 512, 497, 482, 468, 454, 441, 428, 417, 405, 394, 383, 373,
364, 354, 345, 337, 328, 320, 312, 305, 298, 291, 284, 278, 271, 265, 259,
507, 496, 485, 475, 465, 456, 446, 437, 428, 420, 412, 404, 396, 388, 381,
374, 367, 360, 354, 347, 341, 335, 329, 323, 318, 312, 307, 302, 297, 292,
287, 282, 278, 273, 269, 265, 261, 512, 505, 497, 489, 482, 475, 468, 461,
454, 447, 441, 435, 428, 422, 417, 411, 405, 399, 394, 389, 383, 378, 373,
368, 364, 359, 354, 350, 345, 341, 337, 332, 328, 324, 320, 316, 312, 309,
305, 301, 298, 294, 291, 287, 284, 281, 278, 274, 271, 268, 265, 262, 259,
257, 507, 501, 496, 491, 485, 480, 475, 470, 465, 460, 456, 451, 446, 442,
437, 433, 428, 424, 420, 416, 412, 408, 404, 400, 396, 392, 388, 385, 381,
377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344, 341, 338, 335, 332,
329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297, 294, 292,
289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259
];
const shgTable = [
9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17,
17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
];
class BlurStack {
constructor () {
this.r = 0;
this.next = null;
}
}
function processChannel (pixels, topX, topY, width, height, radius) {
const div = 2 * radius + 1;
const widthMinus1 = width - 1;
const heightMinus1 = height - 1;
const radiusPlus1 = radius + 1;
const sumFactor = radiusPlus1 * (radiusPlus1 + 1) / 2;
const stackStart = new BlurStack();
let stack = stackStart;
let stackEnd;
for (let i = 1; i < div; i++) {
stack = stack.next = new BlurStack();
if (i === radiusPlus1) {
stackEnd = stack;
}
}
stack.next = stackStart;
let stackIn = null,
stackOut = null,
yw = 0,
yi = 0;
const mulSum = mulTable[radius];
const shgSum = shgTable[radius];
for (let y = 0; y < height; y++) {
stack = stackStart;
const pr = pixels[yi];
for (let i = 0; i < radiusPlus1; i++) {
stack.r = pr;
stack = stack.next;
}
let rInSum = 0,
rOutSum = radiusPlus1 * pr,
rSum = sumFactor * pr;
for (let i = 1; i < radiusPlus1; i++) {
const p = yi + ((widthMinus1 < i ? widthMinus1 : i) /*<< 2*/);
const r = pixels[p];
const rbs = radiusPlus1 - i;
rSum += (stack.r = r) * rbs;
rInSum += r;
stack = stack.next;
}
stackIn = stackStart;
stackOut = stackEnd;
for (let x = 0; x < width; x++) {
pixels[yi] = ((rSum * mulSum) >> shgSum);
rSum -= rOutSum;
rOutSum -= stackIn.r;
let p = x + radius + 1;
p = (yw + (p < widthMinus1
? p
: widthMinus1)) /*<< 2*/;
rInSum += (stackIn.r = pixels[p]);
rSum += rInSum;
stackIn = stackIn.next;
const r = stackOut.r;
rOutSum += r;
rInSum -= r;
stackOut = stackOut.next;
yi += 1 /*4*/;
}
yw += width;
}
for (let x = 0; x < width; x++) {
yi = x /*<< 2*/;
let pr = pixels[yi],
rOutSum = radiusPlus1 * pr,
rSum = sumFactor * pr;
stack = stackStart;
for (let i = 0; i < radiusPlus1; i++) {
stack.r = pr;
stack = stack.next;
}
let yp = width;
let rInSum = 0;
for (let i = 1; i <= radius; i++) {
yi = (yp + x) /*<< 2*/;
const rbs = radiusPlus1 - i;
rSum += (stack.r = (pr = pixels[yi])) * rbs;
rInSum += pr;
stack = stack.next;
if (i < heightMinus1) {
yp += width;
}
}
yi = x;
stackIn = stackStart;
stackOut = stackEnd;
for (let y = 0; y < height; y++) {
let p = yi /*<< 2*/;
pixels[p] = ((rSum * mulSum) >> shgSum);
rSum -= rOutSum;
rOutSum -= stackIn.r;
p = (x + (
((p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1) *
width
)) /*<< 2*/;
rSum += (rInSum += (stackIn.r = pixels[p]));
stackIn = stackIn.next;
rOutSum += (pr = stackOut.r);
rInSum -= pr;
stackOut = stackOut.next;
yi += width;
}
}
return pixels;
}
return processChannel;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment