img
bun add @stopcock/imgPixel-level image manipulation on raw RGBA buffers. Filters, convolution, resize, crop, the usual. All parameterised functions are dual-form, so they work in pipe point-free.
import { create, grayscale, blur, resize, brightness } from '@stopcock/img'
pipe( create(800, 600), grayscale, blur(3), brightness(40), resize(400, 300),)Real-world patterns
Section titled “Real-world patterns”Thumbnail generation pipeline
Section titled “Thumbnail generation pipeline”import { pipe } from '@stopcock/fp'import { fromRGBA, resize, sharpen, contrast } from '@stopcock/img'
const thumbnail = (data: Uint8ClampedArray, w: number, h: number) => pipe( fromRGBA(data, w, h), resize(200, 200), sharpen, // sharpen after downscale to recover detail contrast(30), // slight contrast boost)Batch image filter
Section titled “Batch image filter”import { pipe, A } from '@stopcock/fp'import { fromRGBA, grayscale, sepia, brightness } from '@stopcock/img'
const vintage = (img: Image) => pipe(img, grayscale, sepia, brightness(1.1))
const processed = A.map(images, vintage)Edge detection for feature extraction
Section titled “Edge detection for feature extraction”import { grayscale, gaussianBlur, edgeDetect } from '@stopcock/img'
const edges = pipe( image, grayscale, // convert to single channel gaussianBlur(2), // smooth out noise edgeDetect, // Sobel operator)type Pixel = [r: number, g: number, b: number, a: number] // 0-255 eachtype Image = { width: number height: number data: Uint8ClampedArray // RGBA pixel data}Creation
Section titled “Creation”create(width: number, height: number): Imageclone(img: Image): ImagefromRGBA(data: Uint8ClampedArray, width: number, height: number): ImageColor conversion
Section titled “Color conversion”rgbToHsl(r: number, g: number, b: number): [h: number, s: number, l: number]hslToRgb(h: number, s: number, l: number): [r: number, g: number, b: number]rgbToGray(r: number, g: number, b: number): numbergrayscale(img: Image): ImageFilters
Section titled “Filters”All parameterised filters are dual-form: brightness(img, 40) or brightness(40) for pipe.
brightness(img: Image, amount: number): Imagecontrast(img: Image, amount: number): Imageinvert(img: Image): Imagethreshold(img: Image, value: number): Imagesepia(img: Image): Imagesaturate(img: Image, factor: number): ImageConvolution
Section titled “Convolution”Dual-form where there are parameters. convolve, blur, gaussianBlur, sharpen all work in pipe.
convolve(img: Image, kernel: number[][], divisor?: number): Imageblur(img: Image, radius: number): ImagegaussianBlur(img: Image, radius: number, sigma?: number): Imagesharpen(img: Image, amount?: number): ImageedgeDetect(img: Image): ImageTransforms
Section titled “Transforms”resize and crop are dual-form. flipH, flipV, rotate90 are arity-1 so they already work point-free.
resize(img: Image, width: number, height: number): Imagecrop(img: Image, x: number, y: number, w: number, h: number): ImageflipH(img: Image): ImageflipV(img: Image): Imagerotate90(img: Image): ImageHistogram
Section titled “Histogram”histogram(img: Image): { r: number[]; g: number[]; b: number[] }equalize(img: Image): ImageAnalysis
Section titled “Analysis”For detecting structure in edge-detected / thresholded images.
houghLines(img: Image, options?: HoughOptions): DetectedLine[]lineToEndpoints(line: DetectedLine, width: number, height: number): [Point, Point]connectedComponents(img: Image): ComponentResulthoughLines finds straight lines using the Hough transform. Feed it a thresholded edge image and it returns lines sorted by vote count. houghLines is dual-form.
connectedComponents labels contiguous foreground regions and returns their area, centroid, and bounding box. Good for finding blobs (obstructions, objects) after thresholding.
type DetectedLine = { rho: number; theta: number; votes: number }type Component = { id: number; area: number; centroid: { x: number; y: number }; bbox: { x: number; y: number; w: number; h: number } }type ComponentResult = { labels: Int32Array; width: number; height: number; components: Component[] }