@thi.ng/geom-trace-bitmap 0.2.1 → 0.3.1

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-03-27T19:05:48Z
3
+ - **Last updated**: 2023-04-08T11:09:50Z
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.
@@ -9,6 +9,17 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
9
9
  **Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
10
10
  and/or version bumps of transitive dependencies.
11
11
 
12
+ ## [0.3.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/geom-trace-bitmap@0.3.0) (2023-04-08)
13
+
14
+ #### 🚀 Features
15
+
16
+ - add TraceOpts.max ([3b39d61](https://github.com/thi-ng/umbrella/commit/3b39d61))
17
+ - update TraceOpts.select() ([01b9e49](https://github.com/thi-ng/umbrella/commit/01b9e49))
18
+ - add point coords as 2nd select() arg
19
+ - update extractSegmentX/Y() ([274f71d](https://github.com/thi-ng/umbrella/commit/274f71d))
20
+ - update result to include unmatched points
21
+ - update tests
22
+
12
23
  ## [0.2.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/geom-trace-bitmap@0.2.0) (2023-03-25)
13
24
 
14
25
  #### 🚀 Features
package/README.md CHANGED
@@ -14,6 +14,7 @@ This project is part of the
14
14
  - [Related packages](#related-packages)
15
15
  - [Installation](#installation)
16
16
  - [Dependencies](#dependencies)
17
+ - [Usage examples](#usage-examples)
17
18
  - [API](#api)
18
19
  - [Basic usage](#basic-usage)
19
20
  - [Authors](#authors)
@@ -65,7 +66,7 @@ For Node.js REPL:
65
66
  const geomTraceBitmap = await import("@thi.ng/geom-trace-bitmap");
66
67
  ```
67
68
 
68
- Package sizes (brotli'd, pre-treeshake): ESM: 940 bytes
69
+ Package sizes (brotli'd, pre-treeshake): ESM: 988 bytes
69
70
 
70
71
  ## Dependencies
71
72
 
@@ -76,6 +77,18 @@ Package sizes (brotli'd, pre-treeshake): ESM: 940 bytes
76
77
  - [@thi.ng/pixel](https://github.com/thi-ng/umbrella/tree/develop/packages/pixel)
77
78
  - [@thi.ng/vectors](https://github.com/thi-ng/umbrella/tree/develop/packages/vectors)
78
79
 
80
+ ## Usage examples
81
+
82
+ Several demos in this repo's
83
+ [/examples](https://github.com/thi-ng/umbrella/tree/develop/examples)
84
+ directory are using this package.
85
+
86
+ A selection:
87
+
88
+ | Screenshot | Description | Live demo | Source |
89
+ |:--------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------|:---------------------------------------------------|:--------------------------------------------------------------------------------|
90
+ | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/trace-bitmap.jpg" width="240"/> | Multi-layer vectorization & dithering of bitmap images | [Demo](https://demo.thi.ng/umbrella/trace-bitmap/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/trace-bitmap) |
91
+
79
92
  ## API
80
93
 
81
94
  [Generated API docs](https://docs.thi.ng/umbrella/geom-trace-bitmap/)
package/api.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { FnU2, Predicate } from "@thi.ng/api";
2
- import type { GridIterator2D, PointTransform } from "@thi.ng/grid-iterators";
1
+ import type { Fn2, FnU2, Predicate } from "@thi.ng/api";
2
+ import type { GridCoord2D, GridIterator2D, PointTransform2D } from "@thi.ng/grid-iterators";
3
3
  import type { ReadonlyMat } from "@thi.ng/matrices";
4
4
  import type { IntBuffer } from "@thi.ng/pixel";
5
5
  export interface TraceOpts {
@@ -12,16 +12,26 @@ export interface TraceOpts {
12
12
  */
13
13
  img: IntBuffer;
14
14
  /**
15
- * Predicate function to determine if a pixel value is considered part of a
16
- * line.
15
+ * Predicate function to determine if a pixel position (or pixel value) is
16
+ * considered selectable (part of a line or point cloud). The function is
17
+ * being called with the pixel value and its coordinates.
18
+ *
19
+ * @param val
20
+ * @param p
17
21
  */
18
- select: Predicate<number>;
22
+ select: Fn2<number, GridCoord2D, boolean>;
19
23
  /**
20
- * Minimum length of line segments (in pixels).
24
+ * Minimum length of line segments (in consecutive pixels).
21
25
  *
22
26
  * @defaultValue 2
23
27
  */
24
28
  min?: number;
29
+ /**
30
+ * Maximum length of line segments (in consecutive pixels).
31
+ *
32
+ * @defaultValue Infinity
33
+ */
34
+ max?: number;
25
35
  /**
26
36
  * Clear value to replace extracted pixels with.
27
37
  *
@@ -80,7 +90,7 @@ export interface TraceDirImpl {
80
90
  * Optional point transform passed to {@link TraceDirImpl.order} (e.g. to
81
91
  * flip iteration order and therefore line direction)
82
92
  */
83
- tx?: PointTransform;
93
+ tx?: PointTransform2D;
84
94
  }
85
95
  export type BorderFn = FnU2<number, Predicate<[number, number]>>;
86
96
  //# sourceMappingURL=api.d.ts.map
package/extract.d.ts CHANGED
@@ -1,7 +1,9 @@
1
- import type { ReadonlyVec, VecPair } from "@thi.ng/vectors";
1
+ import type { ReadonlyVec, Vec, VecPair } from "@thi.ng/vectors";
2
2
  /**
3
3
  * Extracts horizontal line segments (along X-axis) from given point cloud
4
- * (assuming all points are aligned to a grid, e.g. pixel coords).
4
+ * (assuming all points are aligned to a grid, e.g. pixel coords). Returns
5
+ * object of `{segments, points}`, where `segments` contains all extracted
6
+ * segments and `points` all remaining/unmatched points.
5
7
  *
6
8
  * @remarks
7
9
  * The given point array will be sorted (in-place!). Line segments will be as
@@ -14,7 +16,10 @@ import type { ReadonlyVec, VecPair } from "@thi.ng/vectors";
14
16
  * @param pts
15
17
  * @param maxDist
16
18
  */
17
- export declare const extractSegmentsX: (pts: ReadonlyVec[], maxD?: number) => VecPair[];
19
+ export declare const extractSegmentsX: (pts: ReadonlyVec[], maxD?: number) => {
20
+ segments: VecPair[];
21
+ points: Vec[];
22
+ };
18
23
  /**
19
24
  * Similar to {@link extractSegmentsX}, but for extracting vertical line
20
25
  * segments (along Y-axis).
@@ -22,5 +27,8 @@ export declare const extractSegmentsX: (pts: ReadonlyVec[], maxD?: number) => Ve
22
27
  * @param pts
23
28
  * @param maxDist
24
29
  */
25
- export declare const extractSegmentsY: (pts: ReadonlyVec[], maxDist?: number) => VecPair[];
30
+ export declare const extractSegmentsY: (pts: ReadonlyVec[], maxDist?: number) => {
31
+ segments: VecPair[];
32
+ points: Vec[];
33
+ };
26
34
  //# sourceMappingURL=extract.d.ts.map
package/extract.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import { comparator2 } from "@thi.ng/vectors/compare";
2
2
  /**
3
3
  * Extracts horizontal line segments (along X-axis) from given point cloud
4
- * (assuming all points are aligned to a grid, e.g. pixel coords).
4
+ * (assuming all points are aligned to a grid, e.g. pixel coords). Returns
5
+ * object of `{segments, points}`, where `segments` contains all extracted
6
+ * segments and `points` all remaining/unmatched points.
5
7
  *
6
8
  * @remarks
7
9
  * The given point array will be sorted (in-place!). Line segments will be as
@@ -33,9 +35,12 @@ export const extractSegmentsY = (pts, maxDist = 5) => __extract(pts, maxDist, 0)
33
35
  * @internal
34
36
  */
35
37
  const __extract = (pts, maxD, order) => {
38
+ if (pts.length < 2)
39
+ return { segments: [], points: pts };
36
40
  const $ = order ? (p) => [p[1], p[0]] : (p) => p;
37
41
  pts = pts.sort(comparator2(order, order ^ 1));
38
42
  const segments = [];
43
+ const points = [];
39
44
  let [outer, inner] = $(pts[0]);
40
45
  let last = 0;
41
46
  for (let i = 1, n = pts.length - 1; i <= n; i++) {
@@ -45,6 +50,9 @@ const __extract = (pts, maxD, order) => {
45
50
  if (i - last > 1) {
46
51
  segments.push([pts[last], pts[i - 1]]);
47
52
  }
53
+ else {
54
+ points.push(pts[last]);
55
+ }
48
56
  last = i;
49
57
  }
50
58
  inner = p[1];
@@ -53,9 +61,12 @@ const __extract = (pts, maxD, order) => {
53
61
  if (i - last > 1) {
54
62
  segments.push([pts[last], pts[i - 1]]);
55
63
  }
64
+ else {
65
+ points.push(pts[last]);
66
+ }
56
67
  last = i;
57
68
  [outer, inner] = p;
58
69
  }
59
70
  }
60
- return segments;
71
+ return { segments, points };
61
72
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/geom-trace-bitmap",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "Bitmap image to hairline vector and point cloud conversions",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -34,20 +34,20 @@
34
34
  "test": "testament test"
35
35
  },
36
36
  "dependencies": {
37
- "@thi.ng/api": "^8.7.5",
38
- "@thi.ng/errors": "^2.2.14",
39
- "@thi.ng/grid-iterators": "^3.1.1",
40
- "@thi.ng/matrices": "^2.1.51",
41
- "@thi.ng/pixel": "^4.1.11",
42
- "@thi.ng/vectors": "^7.6.10"
37
+ "@thi.ng/api": "^8.8.0",
38
+ "@thi.ng/errors": "^2.2.15",
39
+ "@thi.ng/grid-iterators": "^4.0.1",
40
+ "@thi.ng/matrices": "^2.1.53",
41
+ "@thi.ng/pixel": "^4.2.1",
42
+ "@thi.ng/vectors": "^7.6.12"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@microsoft/api-extractor": "^7.34.4",
46
- "@thi.ng/testament": "^0.3.14",
46
+ "@thi.ng/testament": "^0.3.15",
47
47
  "rimraf": "^4.4.1",
48
48
  "tools": "^0.0.1",
49
49
  "typedoc": "^0.23.28",
50
- "typescript": "^5.0.2"
50
+ "typescript": "^5.0.4"
51
51
  },
52
52
  "keywords": [
53
53
  "bitmap",
@@ -100,5 +100,5 @@
100
100
  "status": "alpha",
101
101
  "year": 2022
102
102
  },
103
- "gitHead": "83b15b34326d480cbca0472b20390d4d3bbb792a\n"
103
+ "gitHead": "3a56bc490f1e68754762a503d06327b5b34ff7eb\n"
104
104
  }
package/trace.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { Fn, Predicate } from "@thi.ng/api";
2
- import type { GridIterOpts, PointTransform } from "@thi.ng/grid-iterators";
2
+ import type { GridIterOpts2D, PointTransform2D } from "@thi.ng/grid-iterators";
3
3
  import type { Vec, VecPair } from "@thi.ng/vectors";
4
4
  import type { TraceBitmapOpts, TraceOpts } from "./api.js";
5
5
  /**
@@ -30,7 +30,7 @@ export declare const traceBitmap: (opts: TraceBitmapOpts) => {
30
30
  * @param tx
31
31
  * @param acc
32
32
  */
33
- export declare const traceLines: (opts: TraceOpts, order: Fn<GridIterOpts, Iterable<[number, number]>>, border: Predicate<[number, number]>, tx: PointTransform, acc?: VecPair[]) => VecPair[];
33
+ export declare const traceLines: (opts: TraceOpts, order: Fn<GridIterOpts2D, Iterable<[number, number]>>, border: Predicate<[number, number]>, tx: PointTransform2D, acc?: VecPair[]) => VecPair[];
34
34
  /**
35
35
  * Extracts single pixels and stores their coordinates in `acc`.
36
36
  *
package/trace.js CHANGED
@@ -69,10 +69,11 @@ export const traceBitmap = (opts) => {
69
69
  * @param acc
70
70
  */
71
71
  export const traceLines = (opts, order, border, tx, acc = []) => {
72
- let { img, select, clear, last, min } = {
72
+ let { img, select, clear, last, min, max } = {
73
73
  clear: 0,
74
74
  last: true,
75
75
  min: 2,
76
+ max: Infinity,
76
77
  ...opts,
77
78
  };
78
79
  min--;
@@ -84,11 +85,11 @@ export const traceLines = (opts, order, border, tx, acc = []) => {
84
85
  img.setAtUnsafe(q[0], q[1], clear);
85
86
  };
86
87
  for (let p of order({ cols: img.width, rows: img.height, tx })) {
87
- const c = select(img.getAtUnsafe(p[0], p[1]));
88
+ const c = select(img.getAtUnsafe(p[0], p[1]), p);
88
89
  const isBorder = border(p);
89
90
  const n = curr.length;
90
91
  if (c) {
91
- if (isBorder) {
92
+ if (isBorder || n >= max) {
92
93
  if (n > 0) {
93
94
  if (prevBorder) {
94
95
  if (n > min)
@@ -133,7 +134,7 @@ export const tracePoints = ({ img, select, clear }, acc = []) => {
133
134
  if (clear === undefined)
134
135
  clear = 0;
135
136
  for (let i = 0, n = img.data.length, w = img.width; i < n; i++) {
136
- if (select(img.data[i])) {
137
+ if (select(img.data[i], [i % w, (i / w) | 0])) {
137
138
  acc.push([i % w, (i / w) | 0]);
138
139
  img.data[i] = clear;
139
140
  }