@thi.ng/pixel-dither 1.1.88 → 1.1.90

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2023-12-03T12:13:31Z
3
+ - **Last updated**: 2023-12-11T10:07:09Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
package/api.js CHANGED
@@ -1 +0,0 @@
1
- export {};
package/atkinson.js CHANGED
@@ -1,14 +1,9 @@
1
- /**
2
- * (Bill) Atkinson dither kernel
3
- *
4
- * @remarks
5
- * References:
6
- * - https://beyondloom.com/blog/dither.html
7
- * - https://tannerhelland.com/2012/12/28/dithering-eleven-algorithms-source-code.html
8
- */
9
- export const ATKINSON = {
10
- ox: [1, 2, -1, 0, 1, 0],
11
- oy: [0, 0, 1, 1, 1, 2],
12
- weights: [1, 1, 1, 1, 1, 1],
13
- shift: 3,
1
+ const ATKINSON = {
2
+ ox: [1, 2, -1, 0, 1, 0],
3
+ oy: [0, 0, 1, 1, 1, 2],
4
+ weights: [1, 1, 1, 1, 1, 1],
5
+ shift: 3
6
+ };
7
+ export {
8
+ ATKINSON
14
9
  };
package/burkes.js CHANGED
@@ -1,13 +1,9 @@
1
- /**
2
- * Burkes dither kernel (similar/improved version of {@link STUCKI}).
3
- *
4
- * @remarks
5
- * References:
6
- * - https://tannerhelland.com/2012/12/28/dithering-eleven-algorithms-source-code.html
7
- */
8
- export const BURKES = {
9
- ox: [1, 2, -2, -1, 0, 1, 2],
10
- oy: [0, 0, 1, 1, 1, 1, 1],
11
- weights: [8, 4, 2, 4, 8, 4, 2],
12
- shift: 5,
1
+ const BURKES = {
2
+ ox: [1, 2, -2, -1, 0, 1, 2],
3
+ oy: [0, 0, 1, 1, 1, 1, 1],
4
+ weights: [8, 4, 2, 4, 8, 4, 2],
5
+ shift: 5
6
+ };
7
+ export {
8
+ BURKES
13
9
  };
package/diffusion.js CHANGED
@@ -1,28 +1,24 @@
1
- /**
2
- * Basic 1D (row-based) error diffusion.
3
- */
4
- export const DIFFUSION_ROW = {
5
- ox: [1],
6
- oy: [0],
7
- weights: [1],
8
- shift: 0,
9
- // x2: width - 1,
1
+ const DIFFUSION_ROW = {
2
+ ox: [1],
3
+ oy: [0],
4
+ weights: [1],
5
+ shift: 0
6
+ // x2: width - 1,
10
7
  };
11
- /**
12
- * Basic 1D (column-based) error diffusion.
13
- */
14
- export const DIFFUSION_COLUMN = {
15
- ox: [0],
16
- oy: [1],
17
- weights: [1],
18
- shift: 0,
8
+ const DIFFUSION_COLUMN = {
9
+ ox: [0],
10
+ oy: [1],
11
+ weights: [1],
12
+ shift: 0
19
13
  };
20
- /**
21
- * Basic 2D error diffusion
22
- */
23
- export const DIFFUSION_2D = {
24
- ox: [1, 0],
25
- oy: [0, 1],
26
- weights: [1, 1],
27
- shift: 1,
14
+ const DIFFUSION_2D = {
15
+ ox: [1, 0],
16
+ oy: [0, 1],
17
+ weights: [1, 1],
18
+ shift: 1
19
+ };
20
+ export {
21
+ DIFFUSION_2D,
22
+ DIFFUSION_COLUMN,
23
+ DIFFUSION_ROW
28
24
  };
package/dither.js CHANGED
@@ -1,47 +1,40 @@
1
1
  import { range } from "@thi.ng/pixel/range";
2
- /**
3
- * Generic kernel-based dithering. Takes a {@link DitherKernelFactory} and
4
- * integer pixel buffer (multiple channels supported). Applies dithering to all
5
- * (or configured) channels using provided options. Returns modified pixel
6
- * buffer.
7
- *
8
- * @param kernel -
9
- * @param img -
10
- * @param opts -
11
- */
12
- export const ditherWith = (kernel, img, opts) => {
13
- const { channels, bleed, threshold } = {
14
- bleed: 1,
15
- threshold: 0.5,
16
- ...opts,
17
- };
18
- const { format, width, height } = img;
19
- const { ox, oy, weights, shift } = kernel;
20
- let p, err;
21
- for (let cid of channels || range(format.channels.length)) {
22
- const cimg = img.getChannel(cid);
23
- const chan = format.channels[cid];
24
- const $thresh = chan.num * threshold;
25
- const $max = chan.mask0;
26
- const data = new Int32Array(cimg.data);
27
- for (let y = 0; y < height; y++) {
28
- for (let x = 0, i = x + y * width; x < width; x++, i++) {
29
- p = data[i] < $thresh ? 0 : $max;
30
- err = (data[i] - p) * bleed;
31
- data[i] = p;
32
- if (!err)
33
- continue;
34
- for (let j = ox.length; j-- > 0;) {
35
- const xx = x + ox[j];
36
- const yy = y + oy[j];
37
- if (yy >= 0 && yy < height && xx >= 0 && xx < width) {
38
- data[yy * width + xx] += (err * weights[j]) >> shift;
39
- }
40
- }
41
- }
2
+ const ditherWith = (kernel, img, opts) => {
3
+ const { channels, bleed, threshold } = {
4
+ bleed: 1,
5
+ threshold: 0.5,
6
+ ...opts
7
+ };
8
+ const { format, width, height } = img;
9
+ const { ox, oy, weights, shift } = kernel;
10
+ let p, err;
11
+ for (let cid of channels || range(format.channels.length)) {
12
+ const cimg = img.getChannel(cid);
13
+ const chan = format.channels[cid];
14
+ const $thresh = chan.num * threshold;
15
+ const $max = chan.mask0;
16
+ const data = new Int32Array(cimg.data);
17
+ for (let y = 0; y < height; y++) {
18
+ for (let x = 0, i = x + y * width; x < width; x++, i++) {
19
+ p = data[i] < $thresh ? 0 : $max;
20
+ err = (data[i] - p) * bleed;
21
+ data[i] = p;
22
+ if (!err)
23
+ continue;
24
+ for (let j = ox.length; j-- > 0; ) {
25
+ const xx = x + ox[j];
26
+ const yy = y + oy[j];
27
+ if (yy >= 0 && yy < height && xx >= 0 && xx < width) {
28
+ data[yy * width + xx] += err * weights[j] >> shift;
29
+ }
42
30
  }
43
- cimg.data.set(data);
44
- img.setChannel(cid, cimg);
31
+ }
45
32
  }
46
- return img;
33
+ cimg.data.set(data);
34
+ img.setChannel(cid, cimg);
35
+ }
36
+ return img;
37
+ };
38
+ export {
39
+ ditherWith
47
40
  };
@@ -1,14 +1,9 @@
1
- /**
2
- * Floyd-Steinberg dither kernel.
3
- *
4
- * @remarks
5
- * References:
6
- * - https://en.wikipedia.org/wiki/Floyd%E2%80%93Steinberg_dithering
7
- * - https://tannerhelland.com/2012/12/28/dithering-eleven-algorithms-source-code.html
8
- */
9
- export const FLOYD_STEINBERG = {
10
- ox: [1, -1, 0, 1],
11
- oy: [0, 1, 1, 1],
12
- weights: [7, 3, 5, 1],
13
- shift: 4,
1
+ const FLOYD_STEINBERG = {
2
+ ox: [1, -1, 0, 1],
3
+ oy: [0, 1, 1, 1],
4
+ weights: [7, 3, 5, 1],
5
+ shift: 4
6
+ };
7
+ export {
8
+ FLOYD_STEINBERG
14
9
  };
package/jarvis.js CHANGED
@@ -2,17 +2,12 @@ const A = 64 / 48;
2
2
  const B = 3 * A;
3
3
  const C = 5 * A;
4
4
  const D = 7 * A;
5
- /**
6
- * Jarvis-Judice-Ninke dither kernel.
7
- *
8
- * @remarks
9
- * References:
10
- * - https://en.wikipedia.org/wiki/Error_diffusion#minimized_average_error
11
- * - https://tannerhelland.com/2012/12/28/dithering-eleven-algorithms-source-code.html
12
- */
13
- export const JARVIS_JUDICE_NINKE = {
14
- ox: [1, 2, -2, -1, 0, 1, 2, -2, -1, 0, 1, 2],
15
- oy: [0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
16
- weights: [D, C, B, C, D, C, B, A, B, C, B, A],
17
- shift: 6,
5
+ const JARVIS_JUDICE_NINKE = {
6
+ ox: [1, 2, -2, -1, 0, 1, 2, -2, -1, 0, 1, 2],
7
+ oy: [0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
8
+ weights: [D, C, B, C, D, C, B, A, B, C, B, A],
9
+ shift: 6
10
+ };
11
+ export {
12
+ JARVIS_JUDICE_NINKE
18
13
  };
package/ordered.js CHANGED
@@ -1,91 +1,53 @@
1
1
  import { isNumber } from "@thi.ng/checks/is-number";
2
2
  import { clamp } from "@thi.ng/math/interval";
3
3
  const init = (x, y, size, val, step, mat) => {
4
- if (size === 1) {
5
- !mat[y] && (mat[y] = []);
6
- mat[y][x] = val;
7
- return mat;
8
- }
9
- size >>= 1;
10
- const step4 = step << 2;
11
- init(x, y, size, val, step4, mat);
12
- init(x + size, y + size, size, val + step, step4, mat);
13
- init(x + size, y, size, val + step * 2, step4, mat);
14
- init(x, y + size, size, val + step * 3, step4, mat);
4
+ if (size === 1) {
5
+ !mat[y] && (mat[y] = []);
6
+ mat[y][x] = val;
15
7
  return mat;
8
+ }
9
+ size >>= 1;
10
+ const step4 = step << 2;
11
+ init(x, y, size, val, step4, mat);
12
+ init(x + size, y + size, size, val + step, step4, mat);
13
+ init(x + size, y, size, val + step * 2, step4, mat);
14
+ init(x, y + size, size, val + step * 3, step4, mat);
15
+ return mat;
16
16
  };
17
- /**
18
- * Creates a Bayer matrix of given kernel size (power of 2) for ordered
19
- * dithering and use with {@link ditherPixels}
20
- *
21
- * @remarks
22
- * Reference:
23
- * - https://en.wikipedia.org/wiki/Ordered_dithering
24
- *
25
- * @param size -
26
- */
27
- export const defBayer = (size) => ({
28
- mat: init(0, 0, size, 0, 1, []),
29
- invSize: 1 / (size * size),
30
- mask: size - 1,
17
+ const defBayer = (size) => ({
18
+ mat: init(0, 0, size, 0, 1, []),
19
+ invSize: 1 / (size * size),
20
+ mask: size - 1
31
21
  });
32
- /**
33
- * Single-channel/value ordered dither using provided Bayer matrix.
34
- *
35
- * @param mat - matrix
36
- * @param dsteps - number of dest colors
37
- * @param drange - dest color range
38
- * @param srange - src color range
39
- * @param x - x pos
40
- * @param y - y pos
41
- * @param val - src value
42
- *
43
- * @internal
44
- */
45
22
  const orderedDither1 = ({ mat, mask, invSize }, dsteps, drange, srange, x, y, val) => {
46
- val =
47
- (dsteps * (val / srange) + mat[y & mask][x & mask] * invSize - 0.5) | 0;
48
- dsteps--;
49
- return clamp(val, 0, dsteps) * ((drange - 1) / dsteps);
23
+ val = dsteps * (val / srange) + mat[y & mask][x & mask] * invSize - 0.5 | 0;
24
+ dsteps--;
25
+ return clamp(val, 0, dsteps) * ((drange - 1) / dsteps);
50
26
  };
51
- /**
52
- * Applies in-place, ordered dithering using provided dither matrix
53
- * (or matrix size) and desired number of dither levels, optionally
54
- * specified individually (per channel). Each channel is be
55
- * processed independently. Channels can be excluded from dithering
56
- * by setting their target colors to zero or negative numbers.
57
- *
58
- * @remarks
59
- * A `size` of 1 will result in simple posterization of each
60
- * channel. The `numColors` value(s) MUST be in the `[0 ..
61
- * numColorsInChannel]` interval.
62
- *
63
- * Also see: {@link defBayer}
64
- *
65
- * @param img - pixel buffer
66
- * @param size - bayer dither matrix/size
67
- * @param numColors - num target colors/steps
68
- */
69
- export const orderedDither = (img, size, numColors) => {
70
- const { data, format, width } = img;
71
- const steps = isNumber(numColors)
72
- ? new Array(format.channels.length).fill(numColors)
73
- : numColors;
74
- const mat = isNumber(size) ? defBayer(size) : size;
75
- for (let i = 0, n = data.length, nc = format.channels.length, x = 0, y = 0; i < n; i++) {
76
- let col = data[i];
77
- for (let j = 0; j < nc; j++) {
78
- const ch = format.channels[j];
79
- const num = ch.num;
80
- const cs = steps[j];
81
- cs > 0 &&
82
- (col = ch.setInt(col, orderedDither1(mat, cs, num, num, x, y, ch.int(col))));
83
- }
84
- data[i] = col;
85
- if (++x === width) {
86
- x = 0;
87
- y++;
88
- }
27
+ const orderedDither = (img, size, numColors) => {
28
+ const { data, format, width } = img;
29
+ const steps = isNumber(numColors) ? new Array(format.channels.length).fill(numColors) : numColors;
30
+ const mat = isNumber(size) ? defBayer(size) : size;
31
+ for (let i = 0, n = data.length, nc = format.channels.length, x = 0, y = 0; i < n; i++) {
32
+ let col = data[i];
33
+ for (let j = 0; j < nc; j++) {
34
+ const ch = format.channels[j];
35
+ const num = ch.num;
36
+ const cs = steps[j];
37
+ cs > 0 && (col = ch.setInt(
38
+ col,
39
+ orderedDither1(mat, cs, num, num, x, y, ch.int(col))
40
+ ));
41
+ }
42
+ data[i] = col;
43
+ if (++x === width) {
44
+ x = 0;
45
+ y++;
89
46
  }
90
- return img;
47
+ }
48
+ return img;
49
+ };
50
+ export {
51
+ defBayer,
52
+ orderedDither
91
53
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/pixel-dither",
3
- "version": "1.1.88",
3
+ "version": "1.1.90",
4
4
  "description": "Extensible image dithering w/ various algorithm presets",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -24,7 +24,9 @@
24
24
  "author": "Karsten Schmidt (https://thi.ng)",
25
25
  "license": "Apache-2.0",
26
26
  "scripts": {
27
- "build": "yarn clean && tsc --declaration",
27
+ "build": "yarn build:esbuild && yarn build:decl",
28
+ "build:decl": "tsc --declaration --emitDeclarationOnly",
29
+ "build:esbuild": "esbuild --format=esm --platform=neutral --target=es2022 --tsconfig=tsconfig.json --outdir=. src/**/*.ts",
28
30
  "clean": "rimraf --glob '*.js' '*.d.ts' '*.map' doc",
29
31
  "doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts",
30
32
  "doc:ae": "mkdir -p .ae/doc .ae/temp && api-extractor run --local --verbose",
@@ -33,13 +35,13 @@
33
35
  "test": "bun test"
34
36
  },
35
37
  "dependencies": {
36
- "@thi.ng/checks": "^3.4.10",
37
- "@thi.ng/math": "^5.7.5",
38
- "@thi.ng/pixel": "^5.0.2"
38
+ "@thi.ng/checks": "^3.4.12",
39
+ "@thi.ng/math": "^5.7.7",
40
+ "@thi.ng/pixel": "^5.0.4"
39
41
  },
40
42
  "devDependencies": {
41
43
  "@microsoft/api-extractor": "^7.38.3",
42
- "@thi.ng/testament": "^0.4.3",
44
+ "esbuild": "^0.19.8",
43
45
  "rimraf": "^5.0.5",
44
46
  "tools": "^0.0.1",
45
47
  "typedoc": "^0.25.4",
@@ -104,5 +106,5 @@
104
106
  "parent": "@thi.ng/pixel",
105
107
  "year": 2021
106
108
  },
107
- "gitHead": "04d1de79f256d7a53c6b5fd157b37f49bc88e11d\n"
109
+ "gitHead": "5e7bafedfc3d53bc131469a28de31dd8e5b4a3ff\n"
108
110
  }
package/sierra2.js CHANGED
@@ -1,13 +1,9 @@
1
- /**
2
- * (Frankie) Sierra's 2-row dither kernel.
3
- *
4
- * @remarks
5
- * References:
6
- * - https://tannerhelland.com/2012/12/28/dithering-eleven-algorithms-source-code.html
7
- */
8
- export const SIERRA2 = {
9
- ox: [1, 2, -2, -1, 0, 1, 2],
10
- oy: [0, 0, 1, 1, 1, 1, 1],
11
- weights: [4, 3, 1, 2, 3, 2, 1],
12
- shift: 4,
1
+ const SIERRA2 = {
2
+ ox: [1, 2, -2, -1, 0, 1, 2],
3
+ oy: [0, 0, 1, 1, 1, 1, 1],
4
+ weights: [4, 3, 1, 2, 3, 2, 1],
5
+ shift: 4
6
+ };
7
+ export {
8
+ SIERRA2
13
9
  };
package/stucki.js CHANGED
@@ -2,16 +2,12 @@ const A = 64 / 42;
2
2
  const B = 2 * A;
3
3
  const C = 4 * A;
4
4
  const D = 8 * A;
5
- /**
6
- * Stucki dither kernel (similar/improved version of {@link JARVIS_JUDICE_NINKE}).
7
- *
8
- * @remarks
9
- * References:
10
- * - https://tannerhelland.com/2012/12/28/dithering-eleven-algorithms-source-code.html
11
- */
12
- export const STUCKI = {
13
- ox: [1, 2, -2, -1, 0, 1, 2, -2, -1, 0, 1, 2],
14
- oy: [0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
15
- weights: [D, C, B, C, D, C, B, A, B, C, B, A],
16
- shift: C,
5
+ const STUCKI = {
6
+ ox: [1, 2, -2, -1, 0, 1, 2, -2, -1, 0, 1, 2],
7
+ oy: [0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
8
+ weights: [D, C, B, C, D, C, B, A, B, C, B, A],
9
+ shift: C
10
+ };
11
+ export {
12
+ STUCKI
17
13
  };
package/threshold.js CHANGED
@@ -1,9 +1,9 @@
1
- /**
2
- * Basic 1x1 thresold dither kernel
3
- */
4
- export const THRESHOLD = {
5
- ox: [],
6
- oy: [],
7
- weights: [],
8
- shift: 0,
1
+ const THRESHOLD = {
2
+ ox: [],
3
+ oy: [],
4
+ weights: [],
5
+ shift: 0
6
+ };
7
+ export {
8
+ THRESHOLD
9
9
  };