Created
June 25, 2014 09:08
-
-
Save padenot/882805ee8458d691953c to your computer and use it in GitHub Desktop.
fast black and white gaussian blur on canvas in js
This file contains 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
/* vertical blur of blur_px. for efficiency, we copy a vertical | |
* line to a buffer so that access are made in a cache efficient | |
* manner */ | |
function vblur(b, blur_px) { | |
var buf = new Uint8ClampedArray(h * 4); | |
for (var vertical = 0; vertical < w; vertical++) { | |
copy_vertical_in_buffer(b, vertical, buf); | |
blur_scanline(buf, 0, h, blur_px); | |
copy_buffer_in_vertical(b, vertical, buf); | |
} | |
} | |
/* box blur, operate on a scanline */ | |
function blur_scanline(b, offset, len, blur_px) { | |
var x = offset; | |
var avg = 0; | |
// XXX distinguish left and right lobe if blur_px is odd | |
var hb = Math.floor(blur_px / 2); | |
// fill kernel: first pixel | |
for (var i = 0; i < hb; i++) { | |
avg += b[i * 4]; | |
} | |
b[x] = b[x+1] = b[x+2] = avg / hb; | |
x+=4; | |
// left lobe | |
for (var i = 0; i < hb; i++) { | |
avg += b[x + hb * 4]; | |
b[x] = b[x+1] = b[x+2] = avg / (hb + 1 + i); | |
x += 4; | |
} | |
// process most of the scanline | |
for (var i = 0; i < len - hb - hb - 1; i++) { | |
avg += b[x + hb * 4]; | |
avg -= b[x - hb * 4]; | |
b[x] = b[x+1] = b[x+2] = avg / blur_px; | |
x += 4; | |
} | |
// flush kernel | |
for (var i = 0; i < hb; i++) { | |
avg -= b[x - hb * 4]; | |
b[x] = b[x+1] = b[x+2] = avg / (blur_px - i - 1); | |
x += 4; | |
} | |
return x; | |
} | |
/* horizontal blur */ | |
function hblur(b, blur_px) { | |
var x = 0; | |
for (var scanline = 0; scanline < h; scanline++) { | |
x = blur_scanline(b, x, w, blur_px); | |
} | |
} | |
/* copy a vertical line of pixel from the image to a linear buffer */ | |
function copy_vertical_in_buffer(b, scanline, buffer) { | |
for (var i = 0; i < buffer.length; i+=4) { | |
buffer[i] = b[4 * (scanline + i / 4* w)]; | |
buffer[i+1] = b[4 * (scanline + i / 4* w) + 1]; | |
buffer[i+2] = b[4 * (scanline + i / 4* w) + 2]; | |
buffer[i+3] = b[4 * (scanline + i / 4* w) + 3]; | |
} | |
} | |
/* copy back a buffer to a vertical line */ | |
function copy_buffer_in_vertical(b, scanline, buffer) { | |
for (var i = 0; i < buffer.length; i+=4) { | |
b[scanline * 4 + i / 4 * w * 4] = buffer[i]; | |
b[scanline * 4 + i / 4 * w * 4 + 1] = buffer[i+1]; | |
b[scanline * 4 + i / 4 * w * 4 + 2] = buffer[i+2]; | |
b[scanline * 4 + i / 4 * w * 4 + 3] = buffer[i+3]; | |
} | |
} | |
/* function to call | |
* b: buffer, result of getImageData().data | |
* blur_px: number of pixels to blur | |
* we need three passes to approximate a gaussian blur to | |
* 97%. Maybe only one or two passes works for your use case. */ | |
function gaussian_blur(b, blur_px) { | |
for (var i = 0; i < 3; i++) { | |
hblur(b, blur_px); | |
vblur(b, blur_px); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment