Skip to content

Instantly share code, notes, and snippets.

@padenot
Created June 25, 2014 09:08
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 padenot/882805ee8458d691953c to your computer and use it in GitHub Desktop.
Save padenot/882805ee8458d691953c to your computer and use it in GitHub Desktop.
fast black and white gaussian blur on canvas in js
/* 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