Skip to content

Commit

Permalink
refactor(pixel): convert resize() into class method
Browse files Browse the repository at this point in the history
- move `IntSampler`, `FloatSampler` types to api.ts
- migrate `resize()` to `PackedBuffer.resize()`
- replace `PackedBuffer.downsample()` w/ new `PackedBuffer.scale()`
- update resize filter arg to also accept custom sampler
  • Loading branch information
postspectacular committed Mar 17, 2021
1 parent 25bcd83 commit 1c4dcaa
Show file tree
Hide file tree
Showing 10 changed files with 73 additions and 84 deletions.
Binary file modified assets/pixel/resize-bicubic.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/pixel/resize-bilinear.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/pixel/resize-nearest.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions packages/pixel/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ sampler(-1.1, 0.5).toString(16)
// 'ff79643a'

// resize image to 1024x256 using bicubic sampling
const img = resize(src, 1024, 256, "cubic");
const img = src.resize(1024, 256, "cubic");
```

| Filter | |
Expand Down Expand Up @@ -259,7 +259,7 @@ yarn add @thi.ng/pixel
<script src="https://unpkg.com/@thi.ng/pixel/lib/index.umd.js" crossorigin></script>
```

Package sizes (gzipped, pre-treeshake): ESM: 8.17 KB / CJS: 8.45 KB / UMD: 8.20 KB
Package sizes (gzipped, pre-treeshake): ESM: 8.19 KB / CJS: 8.47 KB / UMD: 8.22 KB

## Dependencies

Expand Down
5 changes: 5 additions & 0 deletions packages/pixel/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
Fn2,
Fn3,
FnN,
FnU2,
IObjectOf,
NumericArray,
TypedArray,
Expand Down Expand Up @@ -439,3 +440,7 @@ export interface NormalMapOpts {
*/
z: number;
}

export type IntSampler = FnU2<number>;

export type FloatSampler = FnU2<number, FloatArray>;
1 change: 0 additions & 1 deletion packages/pixel/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ export * from "./dither";
export * from "./float";
export * from "./normal-map";
export * from "./packed";
export * from "./resize";
export * from "./sample";
export * from "./utils";

Expand Down
49 changes: 29 additions & 20 deletions packages/pixel/src/packed.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import {
assert,
Fn,
ICopy,
IEmpty,
typedArray,
UIntArray,
uintTypeForBits,
} from "@thi.ng/api";
import { isNumber } from "@thi.ng/checks";
import { isNumber, isString } from "@thi.ng/checks";
import {
isPremultipliedInt,
postmultiplyInt,
Expand All @@ -17,6 +18,8 @@ import {
BayerSize,
BlendFnInt,
BlitOpts,
Filter,
IntSampler,
IPixelBuffer,
Lane,
PackedChannel,
Expand All @@ -28,6 +31,7 @@ import { compileGrayFromABGR, compileGrayToABGR } from "./codegen";
import { defBayer } from "./dither";
import { ABGR8888 } from "./format/abgr8888";
import { defPackedFormat } from "./format/packed-format";
import { defSampler } from "./sample";
import {
clampRegion,
ensureChannel,
Expand Down Expand Up @@ -425,27 +429,32 @@ export class PackedBuffer
}

/**
* Returns new buffer of downscaled version (by given integer factor) using
* simple nearest neighbor sampling.
* Returns scaled version of this buffer using given sampler or filter
* (default: `"linear"`) for interpolation. Syntax sugar for
* {@link PackedBuffer.resize}.
*
* @param res
* @param scale
*/
downsample(res: number) {
res |= 0;
const { width, height, pixels: sbuf } = this;
const dest = new PackedBuffer(
(width / res) | 0,
(height / res) | 0,
this.format
);
const { width: dwidth, height: dheight, pixels: dbuf } = dest;
for (let y = 0, i = 0; y < dheight; y++) {
for (
let x = 0, j = y * res * width;
x < dwidth;
x++, i++, j += res
) {
dbuf[i] = sbuf[j];
scale(scale: number, sampler: IntSampler | Filter = "linear") {
assert(scale > 0, `scale must be > 0`);
return this.resize(this.width * scale, this.height * scale, sampler);
}

resize(w: number, h: number, sampler: IntSampler | Filter = "linear") {
w |= 0;
h |= 0;
assert(w > 0 && h > 0, `target width & height must be > 0`);
const dest = packedBuffer(w, h, this.format);
const dpix = dest.pixels;
const scaleX = w > 0 ? this.width / w : 0;
const scaleY = h > 0 ? this.height / h : 0;
sampler = isString(sampler)
? defSampler(this, sampler, "repeat")
: sampler;
for (let y = 0, i = 0; y < h; y++) {
const yy = y * scaleY;
for (let x = 0; x < w; x++, i++) {
dpix[i] = sampler(x * scaleX, yy);
}
}
return dest;
Expand Down
22 changes: 0 additions & 22 deletions packages/pixel/src/resize.ts

This file was deleted.

74 changes: 36 additions & 38 deletions packages/pixel/src/sample.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import {
assert,
FloatArray,
Fn,
FnU2,
IObjectOf,
NumericArray,
} from "@thi.ng/api";
import { clamp, fmod, fract, mixBilinear, mixBicubic } from "@thi.ng/math";
import type { Filter, IPixelBuffer, Wrap } from "./api";
import { assert, Fn, IObjectOf, NumericArray } from "@thi.ng/api";
import { clamp, fmod, fract, mixBicubic, mixBilinear } from "@thi.ng/math";
import type {
Filter,
FloatSampler,
IntSampler,
IPixelBuffer,
Wrap,
} from "./api";
import type { FloatBuffer } from "./float";
import type { PackedBuffer } from "./packed";

type IntSampler = FnU2<number>;
type FloatSampler = FnU2<number, FloatArray>;

export function defSampler(
src: PackedBuffer,
filter?: Filter,
Expand Down Expand Up @@ -188,7 +184,9 @@ const mixBicubicChan = (
u: number,
v: number,
i: number,
s = 4
s = 4,
min = 0,
max = 255
) =>
clamp(
mixBicubic(
Expand All @@ -211,14 +209,14 @@ const mixBicubicChan = (
u,
v
),
0,
255
min,
max
);

const bicubicABGR = (src: PackedBuffer, sample: IntSampler): IntSampler => {
const { fromABGR, toABGR } = src.format;
const buf32 = new Uint32Array(16);
const buf8 = new Uint8Array(buf32.buffer);
const u32 = new Uint32Array(16);
const u8 = new Uint8Array(u32.buffer);
return (x, y) => {
x -= 0.5;
y -= 0.5;
Expand All @@ -230,28 +228,28 @@ const bicubicABGR = (src: PackedBuffer, sample: IntSampler): IntSampler => {
const y3 = y + 2;
const u = fract(x);
const v = fract(y);
buf32[0] = toABGR(sample(x1, y1));
buf32[1] = toABGR(sample(x, y1));
buf32[2] = toABGR(sample(x2, y1));
buf32[3] = toABGR(sample(x3, y1));
buf32[4] = toABGR(sample(x1, y));
buf32[5] = toABGR(sample(x, y));
buf32[6] = toABGR(sample(x2, y));
buf32[7] = toABGR(sample(x3, y));
buf32[8] = toABGR(sample(x1, y2));
buf32[9] = toABGR(sample(x, y2));
buf32[10] = toABGR(sample(x2, y2));
buf32[11] = toABGR(sample(x3, y2));
buf32[12] = toABGR(sample(x1, y3));
buf32[13] = toABGR(sample(x, y3));
buf32[14] = toABGR(sample(x2, y3));
buf32[15] = toABGR(sample(x3, y3));
u32[0] = toABGR(sample(x1, y1));
u32[1] = toABGR(sample(x, y1));
u32[2] = toABGR(sample(x2, y1));
u32[3] = toABGR(sample(x3, y1));
u32[4] = toABGR(sample(x1, y));
u32[5] = toABGR(sample(x, y));
u32[6] = toABGR(sample(x2, y));
u32[7] = toABGR(sample(x3, y));
u32[8] = toABGR(sample(x1, y2));
u32[9] = toABGR(sample(x, y2));
u32[10] = toABGR(sample(x2, y2));
u32[11] = toABGR(sample(x3, y2));
u32[12] = toABGR(sample(x1, y3));
u32[13] = toABGR(sample(x, y3));
u32[14] = toABGR(sample(x2, y3));
u32[15] = toABGR(sample(x3, y3));
return (
fromABGR(
(mixBicubicChan(buf8, u, v, 3) << 24) |
(mixBicubicChan(buf8, u, v, 2) << 16) |
(mixBicubicChan(buf8, u, v, 1) << 8) |
mixBicubicChan(buf8, u, v, 0)
mixBicubicChan(u8, u, v, 0) |
(mixBicubicChan(u8, u, v, 1) << 8) |
(mixBicubicChan(u8, u, v, 2) << 16) |
(mixBicubicChan(u8, u, v, 3) << 24)
) >>> 0
);
};
Expand Down
2 changes: 1 addition & 1 deletion packages/pixel/tpl.readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ sampler(-1.1, 0.5).toString(16)
// 'ff79643a'

// resize image to 1024x256 using bicubic sampling
const img = resize(src, 1024, 256, "cubic");
const img = src.resize(1024, 256, "cubic");
```

| Filter | |
Expand Down

0 comments on commit 1c4dcaa

Please sign in to comment.