![@thi.ng/pixel](https://media.thi.ng/umbrella/banners-20230807/thing-pixel.svg?fdc39d3a)
![Mastodon Follow](https://img.shields.io/mastodon/follow/109331703950160316?domain=https%3A%2F%2Fmastodon.thi.ng&style=social)
[!NOTE]
This is one of 199 standalone projects, maintained as part
of the @thi.ng/umbrella monorepo
and anti-framework.
🚀 Please help me to work full-time on these projects by sponsoring me on
GitHub. Thank you! ❤️
About
Typedarray integer & float pixel buffers w/ customizable formats, blitting, drawing, convolution.
[!IMPORTANT]
In July 2024 this package was restructured and split-up to extract some
features into smaller more focused packages:
- Buffer creation from HTML image elements or canvas w/ opt resize & format
conversion (browser only)
- 12 packed integer and 6 floating point preset formats (see table below)
- Palette-based indexed pixel formats
- Buffer-to-buffer blitting w/ automatic format conversion
- Buffer-to-canvas blitting (incl. offscreen canvas support)
- Buffer-to-buffer blending w/ Porter-Duff
operators
- Pre/post-multiply alpha
- Region / sub-image extraction
- Single-channel manipulation / extraction / replacement / conversion
- Accessors for normalized channel value
- Image sampling & filtered resizing
- Filters: nearest neighbor, bilinear, bicubic
- Wrap behaviors: clamp, wrap, repeat
- Invert image
- XY coordinate-based pixel & channel-only accessors (w/ optional bounds checking)
- Declarative custom pixel formats with optimized code generation
- HTML canvas creation &
ImageData
utilities
Integer pixel formats
All 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
Custom formats can be defined via
defIntFormat()
.
Format ID | Bits per pixel | Description |
---|
ALPHA8 | 8 | 8 bit channel (alpha only) |
GRAY8 | 8 | 8 bit single channel (grayscale conv) |
GRAY_ALPHA8 | 16 | 8 bit single channel (grayscale conv), 8 bit alpha |
GRAY16 | 16 | 16 bit single channel (grayscale conv) |
GRAY_ALPHA16 | 32 | 16 bit single channel (grayscale conv), 16 bit alpha |
ARGB4444 | 16 | 4 channels @ 4 bits each |
ARGB1555 | 16 | 5 bits each for RGB, 1 bit alpha |
RGB565 | 16 | 5 bits red, 6 bits green, 5 bits blue |
RGB888 | 32 (24 effective) | 3 channels @ 8 bits each |
ARGB8888 | 32 | 4 channels @ 8 bits each |
BGR888 | 32 (24 effective) | 3 channels @ 8 bits each |
ABGR8888 | 32 | 4 channels @ 8 bits each |
ALPHA8
is mapped from/to ABGR alpha channelGRAY8/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)
Indexed, palette-based pixel formats
Instead of storing colors directly for each pixel, palette-based formats are
supported which only store a color index per pixel (e.g. as is done for GIF
and/or indexed PNG formats). These formats can be created via the
defIndexed()
family of
functions.
Floating point pixel formats
Strided floating point format presets for use with
floatBuffer()
.
New formats can be defined via
defFloatFormat()
.
Format ID | Channel count | Description |
---|
FLOAT_GRAY | 1 | Single channel / grayscale |
FLOAT_GRAY_ALPHA | 2 | Grayscale and alpha channel |
FLOAT_GRAY_RANGE | 1 | Grayscale (user defined value range) |
FLOAT_NORMAL | 3 | Normal map (signed values) |
FLOAT_RGB | 3 | Red, Green, Blue |
FLOAT_RGBA | 4 | Red, 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, with exception of FLOAT_NORMAL
which uses [-1..1] range) - Conversion between float formats is currently unsupported
Filtered image sampling and resizing
Available (and optimized) for both integer & floating point formats, image
samplers can be created with the following filters & wrap modes:
Filters
"nearest"
- nearest neighbor"linear"
- bilinear interpolation"cubic"
- bicubic interpolation
Wrap mode
"clamp"
- outside values return 0"wrap"
- infinite tiling"repeat"
- edge pixels are repeated
import { intBuffer, defSampler, ABGR8888 } from "@thi.ng/pixel";
const src = intBuffer(4, 4, ABGR8888);
src.forEach((_,i) => 0xff000000 | Math.random() * 0xffffff);
const sampler = defSampler(src, "linear", "repeat");
sampler(-1.1, 0.5).toString(16)
const img = src.resize(1024, 256, "cubic");
Filter | |
---|
"nearest" | ![resized image w/ nearest neighbor sampling](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/pixel/resize-nearest.png) |
"linear" | ![resized image w/ bilinear sampling](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/pixel/resize-bilinear.jpg) |
"cubic" | ![resized image w/ bicubic sampling](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/pixel/resize-bicubic.jpg) |
Status
STABLE - used in production
Search or submit any issues for this package
Support packages
Related packages
- @thi.ng/color - Array-based color types, CSS parsing, conversions, transformations, declarative theme generation, gradients, presets
- @thi.ng/porter-duff - Porter-Duff operators for packed ints & float-array alpha compositing
- @thi.ng/rasterize - Headless 2D shape drawing, filling & rasterization for arbitrary targets/purposes (no canvas required)
- @thi.ng/shader-ast - DSL to define shader code in TypeScript and cross-compile to GLSL, JS and other targets
- @thi.ng/webgl - WebGL & GLSL abstraction layer
Installation
yarn add @thi.ng/pixel
ESM import:
import * as pix from "@thi.ng/pixel";
Browser ESM import:
<script type="module" src="https://esm.run/@thi.ng/pixel"></script>
JSDelivr documentation
For Node.js REPL:
const pix = await import("@thi.ng/pixel");
Package sizes (brotli'd, pre-treeshake): ESM: 7.35 KB
Dependencies
Note: @thi.ng/api is in most cases a type-only import (not used at runtime)
Usage examples
26 projects in this repo's
/examples
directory are using this package:
Screenshot | Description | Live demo | Source |
---|
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/adaptive-threshold.png) | Interactive image processing (adaptive threshold) | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/ascii-raymarch.jpg) | ASCII art raymarching with thi.ng/shader-ast & thi.ng/text-canvas | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/blurhash.jpg) | Interactive & reactive image blurhash generator | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/dominant-colors.png) | Color palette generation via dominant color extraction from uploaded images | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/geom-terrain-viz.jpg) | 2.5D hidden line visualization of digital elevation files (DEM) | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/ifs-fractal.jpg) | Barnsley fern IFS fractal renderer | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/pixel/pixel-basics.png) | Pixel buffer manipulations | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/pixel-colormatrix.jpg) | Matrix-based image color adjustments | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/pixel-dither.jpg) | Showcase of various dithering algorithms | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/pixel-gradients.jpg) | Randomized 4-point 2D color gradient image generator | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/pixel-indexed.jpg) | Image dithering and remapping using indexed palettes | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/pixel-normal-map.jpg) | Normal map creation/conversion basics | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/pixel-sorting.png) | Interactive pixel sorting tool using thi.ng/color & thi.ng/pixel | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/pixel-waveform.jpg) | RGB waveform image analysis | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/poisson-image.avif) | Image-based Poisson-disk sampling | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/porter-duff/porter-duff2.png) | Port-Duff image compositing / alpha blending | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/rasterize-blend.jpg) | Steering behavior drawing with alpha-blended shapes | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/rdom-formgen.jpg) | Basic usage of the declarative rdom-forms generator | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/related-images.jpg) | Responsive image gallery with tag-based Jaccard similarity ranking | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/scenegraph-image.png) | 2D scenegraph & image map based geometry manipulation | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/shader-ast-tunnel.jpg) | WebGL & Canvas2D textured tunnel shader | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/shader-ast-workers.jpg) | Fork-join worker-based raymarch renderer (JS/CPU only) | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/text-canvas-image.png) | Textmode image warping w/ 16bit color output | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/trace-bitmap.jpg) | Multi-layer vectorization & dithering of bitmap images | Demo | Source |
![](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/unbiased-normals.png) | Visual comparison of biased vs. unbiased normal vectors projected on the surface of a sphere | Demo | Source |
| Minimal multi-pass / GPGPU example | Demo | Source |
API
Generated API docs
import * as pix from "@thi.ng/pixel";
import { SRC_OVER_I } from "@thi.ng/porter-duff";
import { pixelCanvas2d } from "@thi.ng/canvas";
import IMG from "../assets/haystack.jpg";
import LOGO from "../assets/logo-64.png";
const [img, logo] = await Promise.all([IMG, LOGO].map((x) => imageFromURL(x)));
const buf = intBufferFromImage(img, RGB565, 256, 256);
intBufferFromImage(logo, GRAY_ALPHA8).premultiply().blend(SRC_OVER_I, buf, {
dx: 10,
dy: 10,
});
const region = buf.getRegion(32, 96, 128, 64)!;
region.blit(buf, { dx: 96, dy: 32 });
const { canvas } = pixelCanvas2d(buf.width, buf.height * 3, document.body);
buf.blitCanvas(canvas);
const id = 0;
const ch = buf.getChannel(id).invert();
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);
}
}
buf.setChannel(id, ch);
buf.blitCanvas(canvas, { y: buf.height });
buf.as(GRAY8).blitCanvas(canvas, { y: buf.height * 2 });
Authors
If this project contributes to an academic publication, please cite it as:
@misc{thing-pixel,
title = "@thi.ng/pixel",
author = "Karsten Schmidt and others",
note = "https://thi.ng/pixel",
year = 2019
}
License
© 2019 - 2024 Karsten Schmidt // Apache License 2.0