Created
December 22, 2022 22:49
-
-
Save Sphinxxxx/2da469152a8f3afa715e6cb3a75d3a71 to your computer and use it in GitHub Desktop.
StackBlur on grayscale data (from https://github.com/flozz/StackBlur)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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