
glur is a Vanilla JavaScript Gaussian blur library that applies fast blur processing to RGBA Canvas image data using an IIR (Infinite Impulse Response) filter.
The library reads the pixel buffer from a canvas ImageData object, blurs it in place, and lets you write the result back to the canvas with putImageData.
You can use it to build a photo blur slider, generate background blur for a modal overlay, or run an unsharp mask pass on an image before export.
Features:
- Applies Gaussian blur to RGBA image buffers.
- Processes Canvas ImageData arrays in place.
- Handles 16-bit grayscale pixel buffers.
- Uses a pure JavaScript IIR filter.
- Supports browser module usage through an ESM CDN import.
Use Cases:
- Blur uploaded image previews before export.
- Add adjustable blur controls to a Canvas editor.
- Process thumbnails in a Web Worker.
- Blur a grayscale mask for sharpening or glow effects.
How To Use It:
Installation
Install glur with NPM and import the functions you need:
# NPM $ npm install glur
import { blurRGBA, blurMono16 } from 'glur';You can also import it via a CDN.
<script type="module">
import { blurRGBA, blurMono16 } from 'https://cdn.jsdelivr.net/npm/[email protected]/lib/index.mjs';
// your code here
</script>Basic glur Example With Canvas ImageData
Use this example when you need the shortest working Canvas blur setup.
<canvas id="blur-preview" width="640" height="360"></canvas>
<script type="module">
import { blurRGBA } from 'https://cdn.jsdelivr.net/npm/[email protected]/+esm';
const canvas = document.querySelector('#blur-preview');
const ctx = canvas.getContext('2d');
const photo = new Image();
// Use a same-origin image file for direct Canvas pixel access.
photo.src = '/images/sample-landscape.jpg';
photo.onload = () => {
// Draw the image before reading pixel data from the canvas.
ctx.drawImage(photo, 0, 0, canvas.width, canvas.height);
// Read RGBA pixels as a Uint8ClampedArray.
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
// Blur the pixel buffer in place.
blurRGBA(imageData.data, imageData.width, imageData.height, 12);
// Write the blurred pixels back to the canvas.
ctx.putImageData(imageData, 0, 0);
};
</script>
Interactive Blur Radius Slider
This can be useful when you want users to preview different blur strengths in an image editor, avatar cropper, or product image tool.
<label for="blur-radius">Blur radius</label>
<input id="blur-radius" type="range" min="0" max="40" value="8" step="1">
<canvas id="product-preview" width="720" height="405"></canvas>
<script type="module">
import { blurRGBA } from 'glur';
const radiusInput = document.querySelector('#blur-radius');
const canvas = document.querySelector('#product-preview');
const ctx = canvas.getContext('2d');
const productImage = new Image();
// Use your own image path here.
productImage.src = '/assets/demo-product.jpg';
// Wait until the browser can decode the image.
await productImage.decode();
function renderBlur(radius) {
// Redraw the original image before each new blur pass.
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(productImage, 0, 0, canvas.width, canvas.height);
// Create a fresh ImageData object for this radius value.
const frame = ctx.getImageData(0, 0, canvas.width, canvas.height);
// Convert the slider value to a number before passing it to glur.
blurRGBA(frame.data, frame.width, frame.height, Number(radius));
// Replace the canvas pixels with the blurred version.
ctx.putImageData(frame, 0, 0);
}
radiusInput.addEventListener('input', (event) => {
// Update the preview when the user moves the slider.
renderBlur(event.currentTarget.value);
});
// Render the initial preview.
renderBlur(radiusInput.value);
</script>
Run Image Blur In A Web Worker
Use a Web Worker when you blur large images and want to keep the main UI responsive.
// main.js
const canvas = document.querySelector('#editor-canvas');
const ctx = canvas.getContext('2d');
const blurWorker = new Worker(new URL('./blur-worker.js', import.meta.url), {
type: 'module'
});
document.querySelector('#apply-blur').addEventListener('click', () => {
// Read the current canvas pixels.
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
// Transfer the pixel buffer to the worker.
blurWorker.postMessage(
{
imageData,
radius: 18
},
[imageData.data.buffer]
);
});
blurWorker.addEventListener('message', (event) => {
// Draw the processed pixels after the worker finishes.
ctx.putImageData(event.data.imageData, 0, 0);
});
// blur-worker.js
import { blurRGBA } from 'glur';
self.addEventListener('message', (event) => {
const { imageData, radius } = event.data;
// Mutate the RGBA buffer inside the worker thread.
blurRGBA(imageData.data, imageData.width, imageData.height, radius);
// Send the processed buffer back to the main thread.
self.postMessage(
{
imageData
},
[imageData.data.buffer]
);
});
Blur A 16 Bit Grayscale Buffer
This example works best when your image pipeline needs a blurred brightness channel or grayscale mask.
import { blurMono16 } from 'glur';
const canvas = document.querySelector('#mask-canvas');
const ctx = canvas.getContext('2d');
const source = ctx.getImageData(0, 0, canvas.width, canvas.height);
const width = source.width;
const height = source.height;
// Create one grayscale value per pixel.
const brightnessMask = new Uint16Array(width * height);
for (let i = 0; i < source.data.length; i += 4) {
const pixelIndex = i / 4;
// Read RGB values from the Canvas ImageData buffer.
const red = source.data[i];
const green = source.data[i + 1];
const blue = source.data[i + 2];
// Convert 8 bit brightness to the 16 bit range.
brightnessMask[pixelIndex] = Math.round(
(red * 0.299 + green * 0.587 + blue * 0.114) * 257
);
}
// Blur the grayscale buffer in place.
blurMono16(brightnessMask, width, height, 10);
// Copy the blurred brightness values back into the visible image.
for (let i = 0; i < source.data.length; i += 4) {
const pixelIndex = i / 4;
// Convert the 16 bit blurred value back to 8 bit.
const value = Math.round(brightnessMask[pixelIndex] / 257);
source.data[i] = value;
source.data[i + 1] = value;
source.data[i + 2] = value;
}
// Keep the original alpha channel and update the canvas.
ctx.putImageData(source, 0, 0);
Implementation Tips
Remote images need CORS headers before getImageData() can read Canvas pixels. Set image.crossOrigin = 'anonymous' before assigning image.src, and serve the image from a domain that sends the proper CORS header.
blurRGBA() and blurMono16() mutate the input array in place. Clone the original ImageData first if your editor needs undo, reset, side by side previews, or non destructive filters.
Call the blur function after the image finishes loading. image.decode() gives module based code a clean async path for this step.
A radius value of 0 exits early. Very small positive values below 0.5 use 0.5 during filter coefficient calculation.
Configuration Options
glur does not use a configuration object. Pass these parameters directly to the API functions.
src(Uint8ClampedArray | Uint8Array): Supplies RGBA image data forblurRGBA(). glur mutates this array in place.src(Uint16Array): Supplies grayscale 16 bit image data forblurMono16(). glur mutates this array in place.width(number): Sets the image width in pixels.height(number): Sets the image height in pixels.radius(number): Sets the blur radius.0skips processing.
API Methods
// Blur RGBA image data in place. blurRGBA(src, width, height, radius); // Blur a 16 bit grayscale image buffer in place. blurMono16(src, width, height, radius);
Alternatives:
- Fast Gaussian Blur For Canvas – StackBlur.js
- A JS Library For Blur Effect On Images – blurify.js
- Create Dreamy Blur Effects With The BlurJS Library
- Create Smooth Image Loading Transitions With Blurry Image Loader
FAQs:
Q: Why does my canvas look unchanged after I call blurRGBA()?
A: blurRGBA() changes the array in memory. Call ctx.putImageData(imageData, 0, 0) after the blur call.
Q: Why does getImageData() throw a security error?
A: The image likely comes from another domain. Use CORS enabled image hosting and set crossOrigin before assigning the image URL.
Q: Can I use glur in React, Vue, or Svelte?
A: Yes. Run it after the image loads and after the canvas element exists. In React, place the Canvas logic inside an effect that reads a ref.
Q: Does glur replace CSS filter: blur()?
A: No. CSS blur changes visual rendering for DOM elements. glur changes pixel data inside typed arrays.







