Encoder and decoder for the Wolt BlurHash algorithm that creates compact string representations of image placeholders.
npx @tessl/cli install tessl/npm-blurhash@2.0.0BlurHash is a TypeScript/JavaScript library that provides encoder and decoder implementations for the Wolt BlurHash algorithm. It creates compact string representations (20-30 characters) of image placeholders that can be used during image loading, offering a visually appealing alternative to empty boxes or loading spinners.
npm install blurhashimport { encode, decode, isBlurhashValid, ValidationError } from "blurhash";For CommonJS:
const { encode, decode, isBlurhashValid, ValidationError } = require("blurhash");import { encode, decode, isBlurhashValid } from "blurhash";
// Encoding: Convert image pixel data to blurhash string
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const blurhash = encode(imageData.data, imageData.width, imageData.height, 4, 4);
// Decoding: Convert blurhash string back to pixel data
const pixels = decode(blurhash, 32, 32);
const newCanvas = document.createElement("canvas");
const newCtx = newCanvas.getContext("2d");
const newImageData = new ImageData(pixels, 32, 32);
newCtx.putImageData(newImageData, 0, 0);
// Validation: Check if a blurhash string is valid
const validation = isBlurhashValid("LEHV6nWB2yk8pyo0adR*.7kCMdnj");
if (validation.result) {
console.log("Valid blurhash");
} else {
console.log("Invalid:", validation.errorReason);
}Encodes pixel data into a compact blurhash string representation.
/**
* Encodes pixel data into a blurhash string
* @param pixels - RGBA pixel data as Uint8ClampedArray
* @param width - Image width in pixels
* @param height - Image height in pixels
* @param componentX - Number of horizontal components (1-9)
* @param componentY - Number of vertical components (1-9)
* @returns Blurhash string representation
* @throws ValidationError if parameters are invalid
*/
function encode(
pixels: Uint8ClampedArray,
width: number,
height: number,
componentX: number,
componentY: number
): string;Usage Example:
import { encode } from "blurhash";
// Load image and get pixel data
const loadImage = async (src: string): Promise<HTMLImageElement> =>
new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = reject;
img.src = src;
});
const getImageData = (image: HTMLImageElement): ImageData => {
const canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
const context = canvas.getContext("2d");
context.drawImage(image, 0, 0);
return context.getImageData(0, 0, image.width, image.height);
};
const encodeImageToBlurhash = async (imageUrl: string): Promise<string> => {
const image = await loadImage(imageUrl);
const imageData = getImageData(image);
return encode(imageData.data, imageData.width, imageData.height, 4, 4);
};Decodes a blurhash string into pixel data for rendering.
/**
* Decodes a blurhash string into pixel data
* @param blurhash - Valid blurhash string
* @param width - Desired output width in pixels
* @param height - Desired output height in pixels
* @param punch - Optional contrast adjustment (defaults to 1)
* @returns Uint8ClampedArray containing RGBA pixel data
* @throws ValidationError if blurhash is invalid
*/
function decode(
blurhash: string,
width: number,
height: number,
punch?: number
): Uint8ClampedArray;Usage Example:
import { decode } from "blurhash";
// Decode blurhash to canvas
const renderBlurhash = (blurhash: string, width: number, height: number): HTMLCanvasElement => {
const pixels = decode(blurhash, width, height);
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext("2d");
const imageData = new ImageData(pixels, width, height);
ctx.putImageData(imageData, 0, 0);
return canvas;
};
// Usage
const canvas = renderBlurhash("LEHV6nWB2yk8pyo0adR*.7kCMdnj", 400, 300);
document.body.appendChild(canvas);Validates whether a string is a properly formatted blurhash.
/**
* Validates a blurhash string
* @param blurhash - String to validate
* @returns Validation result with boolean and optional error reason
*/
function isBlurhashValid(blurhash: string): { result: boolean; errorReason?: string };Usage Example:
import { isBlurhashValid } from "blurhash";
// Validate different blurhash strings
const valid = isBlurhashValid("LEHV6nWB2yk8pyo0adR*.7kCMdnj");
console.log(valid); // { result: true }
const invalid = isBlurhashValid("invalid");
console.log(invalid); // { result: false, errorReason: "The blurhash string must be at least 6 characters" }
const tooShort = isBlurhashValid("abc");
console.log(tooShort); // { result: false, errorReason: "The blurhash string must be at least 6 characters" }The library provides a custom error class for validation failures.
/**
* Custom error class thrown by encode/decode functions
* Extends the standard Error class
*/
class ValidationError extends Error {
constructor(message: string);
name: "ValidationError";
message: string;
}Usage Example:
import { encode, decode, ValidationError } from "blurhash";
try {
// This will throw ValidationError due to invalid component values
const hash = encode(pixels, 100, 100, 0, 0); // componentX and componentY must be 1-9
} catch (error) {
if (error instanceof ValidationError) {
console.error("Validation failed:", error.message);
} else {
console.error("Unexpected error:", error);
}
}
try {
// This will throw ValidationError due to invalid blurhash
const pixels = decode("invalid", 100, 100);
} catch (error) {
if (error instanceof ValidationError) {
console.error("Decode failed:", error.message);
}
}The library enforces the following validation rules:
width * height * 4 (RGBA format)4 + 2 * componentX * componentYThe library works in all modern browsers that support:
Uint8ClampedArrayImageData (for canvas integration)CommonJS and ES module formats are provided for maximum compatibility across different JavaScript environments and build systems.