A high-performance implementation of hierarchical agglomerative clustering (HAC), optimized for speed and scalability. This package uses WebAssembly (WASM) to accelerate computation, making it suitable for large datasets and real-time clustering tasks in the browser or Node.js environments.
It includes an interface for performing image clustering, palette extraction, and color quantization directly on raw image data, making it a powerful tool for graphics processing, image analysis, and visual data simplification.
- β Extract clustering information from image data
- π¨ Generate color palettes from raw images or clustering
- βοΈ Quantize images using clustering or palette data
- πΉοΈ Async interface with lazy WASM initialization
- πΎ Works with
Uint8Array,Uint8ClampedArray, andImageDatainputs (rgborrgba) - π¦ TypeScript declarations included
npm install agglomerative-clusteringAll functions that accept an image accept any of the following input types:
// Plain raw RGBA buffer β format defaults to 'rgba'
Uint8Array
// Browser Canvas ImageData β always treated as 'rgba'
ImageData
// Explicit format object β use this for 'rgb' data or Uint8ClampedArray buffers
{ data: Uint8Array | Uint8ClampedArray, format: 'rgb' | 'rgba' }The three quantize* functions mirror the input type in their return value: passing a Uint8Array returns a Uint8Array, passing an ImageData returns an ImageData, and passing an object returns an object with the same format.
import { quantize } from 'agglomerative-clustering';
import sharp from 'sharp';
async function loadImage(path) {
const { data, info } = await sharp(path).raw().ensureAlpha().toBuffer({ resolveWithObject: true });
return { width: info.width, height: info.height, data: new Uint8Array(data.buffer) };
}
async function saveImage(path, width, height, data) {
await sharp(data, { raw: { width, height, channels: 4 } }).toFile(path);
}
(async () => {
const k = 8;
const { width, height, data } = await loadImage('example.png');
// Quantize β result is the same type as the input (Uint8Array here)
const processed = await quantize(data, k);
await saveImage('example_quantized.png', width, height, Buffer.from(processed));
})();import { quantize } from 'agglomerative-clustering';
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
// Pass ImageData directly β result is a new ImageData with the same dimensions
const result = await quantize(imageData, 8);
ctx.putImageData(result, 0, 0);import { getClustering, getPaletteFromClustering, quantizeWithClustering } from 'agglomerative-clustering';
const data = new Uint8Array(/* raw rgba bytes */);
// Compute clustering once
const clustering = await getClustering(data);
// Derive different palette sizes without recomputing the clustering
const palette4 = await getPaletteFromClustering(clustering, 4);
const palette16 = await getPaletteFromClustering(clustering, 16);
// Quantize using the precomputed clustering
const quantized = await quantizeWithClustering(data, clustering, 8);Pre-initializes the WASM module. All other functions call this lazily, so explicit use is optional β useful for warming up the module before processing a batch of images.
Computes a compact hierarchical clustering from the image's color histogram. The result can be passed to getPaletteFromClustering or quantizeWithClustering to avoid redundant work.
Returns a palette of up to k colors as a flat RGB byte array (k * 3 bytes).
Derives a palette of up to k colors from a precomputed clustering.
Quantizes the image to at most k colors. Return type matches the input type.
Quantizes using a precomputed clustering. Return type matches the input type.
Quantizes using an already-computed palette. Return type matches the input type.