• Public
  • Public/Protected
  • All



npm versionnpm downloads Twitter Follow

This project is part of the @thi.ng/umbrella monorepo.


Typed array backed, integer and floating point pixel buffers w/ customizable formats, blitting, dithering, conversions.


  • Buffer creation from HTML image elements w/ opt resize & format conversion (browser only)
  • Buffer-to-buffer blitting w/ automatic format conversion
  • Buffer-to-canvas blitting
  • Buffer-to-buffer blending w/ Porter-Duff operators
  • Pre/post-multiply alpha
  • Region / sub-image extraction
  • Single-channel manipulation / extraction / replacement / conversion
  • Inversion
  • XY pixel accessors
  • 10 packed integer and 4 floating point preset formats (see table below)
  • Ordered dithering w/ customizable Bayer matrix size and target color steps (int formats only)
  • Declarative custom format & optimized code generation
  • HTML canvas creation & ImageData utilities

WIP features

  • Accessors for normalized channel value
  • Pre/Post-multipy (only if alpha is available)
  • Re-add strided float buffers / formats
  • Dithering
  • Readonly texture sampling abstraction
    • Wrap-around behaviors
    • Filtered access (bilinear interpolation)

Packed integer pixel formats

All packed integer formats use the canvas native ABGR 32bit format as common intermediate for conversions. During conversion to ABGR, channels with sizes smaller than 8 bits will be scaled appropriately to ensure an as full-range and as linear as possible mapping. E.g. a 4 bit channel will be scaled by 255 / 15 = 17.

Format specs can freely control channel layout within current limits:

  • Channel sizes: 1 - 32 bits.
  • Storage: 8, 16 or 32 bits per pixel

New formats can be defined via defPackedFormat().

Format IDBits per pixelDescription
ALPHA888 bit channel (alpha only)
GRAY888 bit single channel (grayscale conv)
GRAY_ALPHA8168 bit single channel (grayscale conv), 8 bit alpha
GRAY161616 bit single channel (grayscale conv)
GRAY_ALPHA163216 bit single channel (grayscale conv), 16 bit alpha
ARGB4444164 channels @ 4 bits each
ARGB1555165 bits each for RGB, 1 bit alpha
RGB565165 bits red, 6 bits green, 5 bits blue
RGB88832 (24 effective)3 channels @ 8 bits each
ARGB8888324 channels @ 8 bits each
BGR88832 (24 effective)3 channels @ 8 bits each
ABGR8888324 channels @ 8 bits each
  • ALPHA8 is mapped from/to ABGR alpha channel
  • GRAY8/16, GRAY_ALPHA8/16 compute grayscale/luminance when converting from ABGR and in return produce grayscale ABGR
  • In all built-in formats supporting it, the alpha channel always occupies the most-significant bits (up to format size)

Floating point pixel formats

Strided floating point format presets for use with floatBuffer(). New formats can be defined via defFloatFormat().

Format IDChannel countDescription
FLOAT_GRAY1Single channel / grayscale
FLOAT_GRAY_ALPHA2Grayscale and alpha channel
FLOAT_RGB3Red, Green, Blue
FLOAT_RGBA4Red, Green, Blue, Alpha
  • All color channels are unclamped (but can be clamped via buf.clamp()). For conversion to packed int formats assumed to contain normalized data (i.e. [0..1] interval)
  • Conversion between float formats is currently unsupported


STABLE - used in production

Search or submit any issues for this package

Support packages

Related packages


yarn add @thi.ng/pixel
// ES module
<script type="module" src="https://unpkg.com/@thi.ng/pixel?module" crossorigin></script>

// UMD
<script src="https://unpkg.com/@thi.ng/pixel/lib/index.umd.js" crossorigin></script>

Package sizes (gzipped, pre-treeshake): ESM: 5.35 KB / CJS: 5.57 KB / UMD: 5.52 KB


Usage examples

Several demos in this repo's /examples directory are using this package.

A selection:

ScreenshotDescriptionLive demoSource
Interactive image processing (adaptive threshold)DemoSource
Pixel buffer manipulationsDemoSource
Interactive pixel sorting tool using thi.ng/color & thi.ng/pixelDemoSource
Port-Duff image compositing / alpha blendingDemoSource
Fork-join worker-based raymarch rendererDemoSource
Textmode image warping w/ 16bit color outputDemoSource
Minimal multi-pass / GPGPU exampleDemoSource


Generated API docs

import * as pix from "@thi.ng/pixel";
import { SRC_OVER_I } from "@thi.ng/porter-duff";

import IMG from "../assets/haystack.jpg";
import LOGO from "../assets/logo-64.png";

    .all([IMG, LOGO].map(pix.imagePromise))
    .then(([img, logo]) => {

        // init 16 bit packed RGB pixel buffer from image (resized to 256x256)
        const buf = pix.PackedBuffer.fromImage(img, pix.RGB565, 256, 256);

        // create grayscale buffer for logo and use Porter-Duff operator to
        // composite with main image. Since the logo has transparency, we need
        // to premultiply alpha first...
        pix.PackedBuffer.fromImage(logo, pix.GRAY_ALPHA88)
            .blend(SRC_OVER_I, buf, {
                dx: 10,
                dy: 10

        // extract sub-image
        const region = buf.getRegion(32, 96, 128, 64);
        // copy region back at new position
        region.blit(buf, { dx: 96, dy: 32 });

        // or alternatively blit buf into itself
        // buf.blit(buf, { dx: 96, dy: 32, sx: 32, sy: 96, w: 128, h: 64 });

        // create html canvas
        // (returns obj of canvas & 2d context)
        const ctx = pix.canvas2d(buf.width, buf.height * 3);

        // write pixel buffer to canvas

        // manipulate single color channel (here red)
        const id = 0;
        // obtain channel & invert
        const ch = buf.getChannel(id).invert();
        // create dot pattern
        for (let y = 0; y < ch.height; y += 2) {
            for (let x = (y >> 1) & 1; x < ch.width; x += 2) {
                ch.setAt(x, y, 0xff);
        // replace original channel
        buf.setChannel(id, ch);

        // write pixel buffer to new position
        buf.blitCanvas(ctx.canvas, 0, buf.height);

        // create & write grayscale version
        buf.as(GRAY8).blitCanvas(ctx.canvas, 0, buf.height * 2);


TODO see examples & source comments for now


Karsten Schmidt

If this project contributes to an academic publication, please cite it as:

  title = "@thi.ng/pixel",
  author = "Karsten Schmidt",
  note = "https://thi.ng/pixel",
  year = 2019


© 2019 - 2021 Karsten Schmidt // Apache Software License 2.0

Generated using TypeDoc