From a70b3c133ebb3ff897d92200b150b2db3be9d458 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 16 Mar 2022 13:44:43 +0100 Subject: [PATCH] feat(pixel): buffer method additions, internal checks - add FloatBuffer.premultiply/postmultiply() - add Int/FloatBuffer.fill() --- packages/pixel/src/checks.ts | 4 +++ packages/pixel/src/float.ts | 47 ++++++++++++++++++++++++++++++++++-- packages/pixel/src/int.ts | 21 ++++++++++------ 3 files changed, 62 insertions(+), 10 deletions(-) diff --git a/packages/pixel/src/checks.ts b/packages/pixel/src/checks.ts index f6b6a3c664..68b9e1106d 100644 --- a/packages/pixel/src/checks.ts +++ b/packages/pixel/src/checks.ts @@ -20,3 +20,7 @@ export const ensureChannel = (fmt: IntFormat | FloatFormat, id: number) => { /** @internal */ export const ensureSingleChannel = (fmt: IntFormat | FloatFormat) => assert(fmt.channels.length === 1, `require single channel buffer`); + +/** @internal */ +export const ensureAlpha = (fmt: IntFormat | FloatFormat) => + assert(!!fmt.alpha, "missing alpha channel"); diff --git a/packages/pixel/src/float.ts b/packages/pixel/src/float.ts index e0fda56e67..26a0dba607 100644 --- a/packages/pixel/src/float.ts +++ b/packages/pixel/src/float.ts @@ -5,6 +5,7 @@ import { isNumber } from "@thi.ng/checks/is-number"; import { isString } from "@thi.ng/checks/is-string"; import { assert } from "@thi.ng/errors/assert"; import { clamp01 } from "@thi.ng/math/interval"; +import { postmultiply, premultiply } from "@thi.ng/porter-duff/premultiply"; import type { BlendFnFloat, BlitOpts, @@ -61,8 +62,8 @@ export function floatBuffer(...args: any[]) { * @remarks * See {@link FloatBuffer.as} for reverse operation. * - * @param src - - * @param fmt - + * @param src - + * @param fmt - */ export const floatBufferFromInt = ( src: IntBuffer, @@ -371,6 +372,44 @@ export class FloatBuffer return this; } + fill(x: NumericArray) { + assert( + x.length <= this.format.channels.length, + `fill value has too many channels` + ); + const { + data, + stride: [stride], + } = this; + for (let i = 0, n = data.length; i < n; i += stride) { + data.set(x, i); + } + } + + premultiply() { + this.ensureRGBA(); + const { + data, + stride: [stride], + } = this; + for (let i = 0, n = data.length; i < n; i += stride) { + premultiply(null, data.subarray(i, i + stride)); + } + return this; + } + + postmultiply() { + this.ensureRGBA(); + const { + data, + stride: [stride], + } = this; + for (let i = 0, n = data.length; i < n; i += stride) { + postmultiply(null, data.subarray(i, i + stride)); + } + return this; + } + clamp() { const data = this.data; for (let i = data.length; i-- > 0; ) { @@ -479,4 +518,8 @@ export class FloatBuffer `dest buffer format must be same as src` ); } + + protected ensureRGBA() { + assert(this.format === FLOAT_RGBA, "require FLOAT_RGBA format"); + } } diff --git a/packages/pixel/src/int.ts b/packages/pixel/src/int.ts index 3ca510fdc6..05589aba79 100644 --- a/packages/pixel/src/int.ts +++ b/packages/pixel/src/int.ts @@ -26,7 +26,7 @@ import { Lane, } from "./api.js"; import { canvasPixels, imageCanvas } from "./canvas.js"; -import { ensureChannel, ensureSize } from "./checks.js"; +import { ensureAlpha, ensureChannel, ensureSize } from "./checks.js"; import { ABGR8888 } from "./format/abgr8888.js"; import { defIntFormat } from "./format/int-format.js"; import { @@ -72,10 +72,10 @@ export function intBuffer(...args: any[]) { * Creates a new pixel buffer from given HTML image element with optional * support for format conversion (default: {@link ABGR8888} & resizing. * - * @param img - - * @param fmt - - * @param width - - * @param height - + * @param img - + * @param fmt - + * @param width - + * @param height - */ export const intBufferFromImage = ( img: HTMLImageElement, @@ -88,8 +88,8 @@ export const intBufferFromImage = ( * Creates a new pixel buffer from given HTML canvas element with optional * support for format conversion (default: {@link ABGR8888}. * - * @param canvas - - * @param fmt - + * @param canvas - + * @param fmt - */ export const intBufferFromCanvas = ( canvas: HTMLCanvasElement, @@ -374,6 +374,7 @@ export class IntBuffer } premultiply() { + ensureAlpha(this.format); __transformABGR(this.data, this.format, premultiplyInt); return this; } @@ -402,6 +403,10 @@ export class IntBuffer return this; } + fill(x: number) { + this.data.fill(x); + } + /** * Flips image vertically. */ @@ -425,7 +430,7 @@ export class IntBuffer * (default: `"linear"`) for interpolation. Syntax sugar for * {@link IntBuffer.resize}. * - * @param scale - + * @param scale - */ scale(scale: number, sampler: IntSampler | Filter = "linear") { assert(scale > 0, `scale must be > 0`);