@thi.ng/text-canvas 2.3.8 → 2.4.2
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 +12 -1
- package/canvas.d.ts +16 -2
- package/canvas.js +43 -3
- package/image.d.ts +46 -2
- package/image.js +64 -3
- package/package.json +13 -12
- package/rect.d.ts +7 -0
- package/rect.js +12 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2022-
|
|
3
|
+
- **Last updated**: 2022-08-01T14:54:00Z
|
|
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
|
+
## [2.4.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/text-canvas@2.4.0) (2022-07-08)
|
|
13
|
+
|
|
14
|
+
#### 🚀 Features
|
|
15
|
+
|
|
16
|
+
- add canvasFromText(), update Canvas ([e8baa0b](https://github.com/thi-ng/umbrella/commit/e8baa0b))
|
|
17
|
+
- update deps
|
|
18
|
+
- add canvasFromText() factory fn
|
|
19
|
+
- add ICopy impl for Canvas
|
|
20
|
+
- add clearFormat() ([83f04cc](https://github.com/thi-ng/umbrella/commit/83f04cc))
|
|
21
|
+
- add blitMask() & docs ([a6cf74a](https://github.com/thi-ng/umbrella/commit/a6cf74a))
|
|
22
|
+
|
|
12
23
|
### [2.3.8](https://github.com/thi-ng/umbrella/tree/@thi.ng/text-canvas@2.3.8) (2022-06-28)
|
|
13
24
|
|
|
14
25
|
#### ♻️ Refactoring
|
package/canvas.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Fn0, IGrid2D, NumOrString } from "@thi.ng/api";
|
|
1
|
+
import { Fn0, ICopy, IGrid2D, NumOrString } from "@thi.ng/api";
|
|
2
2
|
import { ClipRect, StrokeStyle } from "./api.js";
|
|
3
|
-
export declare class Canvas implements IGrid2D<Uint32Array, number> {
|
|
3
|
+
export declare class Canvas implements ICopy<Canvas>, IGrid2D<Uint32Array, number> {
|
|
4
4
|
data: Uint32Array;
|
|
5
5
|
size: [number, number];
|
|
6
6
|
stride: [number, number];
|
|
@@ -13,6 +13,7 @@ export declare class Canvas implements IGrid2D<Uint32Array, number> {
|
|
|
13
13
|
get height(): number;
|
|
14
14
|
get offset(): number;
|
|
15
15
|
get dim(): 2;
|
|
16
|
+
copy(): Canvas;
|
|
16
17
|
order(): number[];
|
|
17
18
|
includes(d0: number, d1: number): boolean;
|
|
18
19
|
indexAt(d0: number, d1: number): number;
|
|
@@ -23,6 +24,19 @@ export declare class Canvas implements IGrid2D<Uint32Array, number> {
|
|
|
23
24
|
setAtUnsafe(x: number, y: number, col: number): boolean;
|
|
24
25
|
}
|
|
25
26
|
export declare const canvas: (width: number, height: number, format?: number, style?: StrokeStyle) => Canvas;
|
|
27
|
+
/**
|
|
28
|
+
* Creates and returns a new {@link Canvas} from given string/lines array and
|
|
29
|
+
* optional default `format` and/or initial `fill` value.
|
|
30
|
+
*
|
|
31
|
+
* @remarks
|
|
32
|
+
* The canvas will use the longest line width as its width and the length of the
|
|
33
|
+
* source array as height.
|
|
34
|
+
*
|
|
35
|
+
* @param lines
|
|
36
|
+
* @param format
|
|
37
|
+
* @param fill
|
|
38
|
+
*/
|
|
39
|
+
export declare const canvasFromText: (lines: string[], format?: number, fill?: NumOrString) => Canvas;
|
|
26
40
|
export declare const beginClip: (canvas: Canvas, x: number, y: number, w: number, h: number) => void;
|
|
27
41
|
export declare const endClip: (canvas: Canvas) => any;
|
|
28
42
|
export declare const withClip: (canvas: Canvas, x: number, y: number, w: number, h: number, fn: Fn0<any>) => void;
|
package/canvas.js
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
|
+
var Canvas_1;
|
|
1
2
|
import { __decorate } from "tslib";
|
|
2
3
|
import { nomixin } from "@thi.ng/api";
|
|
3
4
|
import { IGrid2DMixin } from "@thi.ng/api/mixins/igrid";
|
|
4
5
|
import { peek } from "@thi.ng/arrays/peek";
|
|
6
|
+
import { assert } from "@thi.ng/errors/assert";
|
|
5
7
|
import { clamp } from "@thi.ng/math/interval";
|
|
6
|
-
import { NONE } from "@thi.ng/text-format
|
|
8
|
+
import { NONE } from "@thi.ng/text-format";
|
|
9
|
+
import { map } from "@thi.ng/transducers/map";
|
|
10
|
+
import { max } from "@thi.ng/transducers/max";
|
|
11
|
+
import { transduce } from "@thi.ng/transducers/transduce";
|
|
7
12
|
import { STYLE_ASCII } from "./api.js";
|
|
8
13
|
import { charCode, intersectRect } from "./utils.js";
|
|
9
|
-
let Canvas = class Canvas {
|
|
14
|
+
let Canvas = Canvas_1 = class Canvas {
|
|
10
15
|
constructor(width, height, format = NONE, style = STYLE_ASCII) {
|
|
11
16
|
this.size = [width, height];
|
|
12
17
|
this.stride = [1, this.width];
|
|
@@ -29,6 +34,14 @@ let Canvas = class Canvas {
|
|
|
29
34
|
get dim() {
|
|
30
35
|
return 2;
|
|
31
36
|
}
|
|
37
|
+
copy() {
|
|
38
|
+
const res = new Canvas_1(this.width, this.height, this.format);
|
|
39
|
+
res.data.set(this.data);
|
|
40
|
+
res.stride = this.stride.slice();
|
|
41
|
+
res.styles = this.styles.slice();
|
|
42
|
+
res.clipRects = this.clipRects.slice();
|
|
43
|
+
return res;
|
|
44
|
+
}
|
|
32
45
|
// @ts-ignore mixin
|
|
33
46
|
order() { }
|
|
34
47
|
// @ts-ignore mixin
|
|
@@ -53,11 +66,38 @@ let Canvas = class Canvas {
|
|
|
53
66
|
__decorate([
|
|
54
67
|
nomixin
|
|
55
68
|
], Canvas.prototype, "setAt", null);
|
|
56
|
-
Canvas = __decorate([
|
|
69
|
+
Canvas = Canvas_1 = __decorate([
|
|
57
70
|
IGrid2DMixin
|
|
58
71
|
], Canvas);
|
|
59
72
|
export { Canvas };
|
|
60
73
|
export const canvas = (width, height, format, style) => new Canvas(width, height, format, style);
|
|
74
|
+
/**
|
|
75
|
+
* Creates and returns a new {@link Canvas} from given string/lines array and
|
|
76
|
+
* optional default `format` and/or initial `fill` value.
|
|
77
|
+
*
|
|
78
|
+
* @remarks
|
|
79
|
+
* The canvas will use the longest line width as its width and the length of the
|
|
80
|
+
* source array as height.
|
|
81
|
+
*
|
|
82
|
+
* @param lines
|
|
83
|
+
* @param format
|
|
84
|
+
* @param fill
|
|
85
|
+
*/
|
|
86
|
+
export const canvasFromText = (lines, format = NONE, fill) => {
|
|
87
|
+
const height = lines.length;
|
|
88
|
+
assert(height > 0, "require at least 1 line of text");
|
|
89
|
+
const width = transduce(map((x) => x.length), max(), lines);
|
|
90
|
+
const res = canvas(width, height, format);
|
|
91
|
+
fill !== undefined && res.data.fill(charCode(fill, format));
|
|
92
|
+
format <<= 16;
|
|
93
|
+
for (let y = 0; y < height; y++) {
|
|
94
|
+
const line = lines[y];
|
|
95
|
+
for (let x = 0, i = y * width, n = Math.min(width, line.length); x < n; x++, i++) {
|
|
96
|
+
res.data[i] = line.charCodeAt(x) | format;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return res;
|
|
100
|
+
};
|
|
61
101
|
export const beginClip = (canvas, x, y, w, h) => {
|
|
62
102
|
x |= 0;
|
|
63
103
|
y |= 0;
|
package/image.d.ts
CHANGED
|
@@ -1,7 +1,51 @@
|
|
|
1
|
-
import type { UIntArray } from "@thi.ng/api";
|
|
1
|
+
import type { NumOrString, UIntArray } from "@thi.ng/api";
|
|
2
2
|
import { ImageOpts } from "./api.js";
|
|
3
3
|
import { Canvas } from "./canvas.js";
|
|
4
|
-
export declare const blit: (
|
|
4
|
+
export declare const blit: (dest: Canvas, x: number, y: number, src: Canvas) => void;
|
|
5
|
+
/**
|
|
6
|
+
* Similar to {@link blit}. Pastes `src` {@link Canvas} into `dest` at given
|
|
7
|
+
* position and uses `mask` to exclude pixels from being copied (and therefore
|
|
8
|
+
* achieve a form of 1bit transparency, similar to GIFs), i.e. only non-`mask`
|
|
9
|
+
* pixels/chars will be copied. Supports region clipping.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* // source canvas
|
|
14
|
+
* const a = canvasFromText([
|
|
15
|
+
* "###==###",
|
|
16
|
+
* "##====##",
|
|
17
|
+
* "#======#",
|
|
18
|
+
* "##====##",
|
|
19
|
+
* "###==###",
|
|
20
|
+
* ]);
|
|
21
|
+
*
|
|
22
|
+
* // destination canvas (filled w/ "-")
|
|
23
|
+
* const b = canvas(12,7);
|
|
24
|
+
* clear(b, true, "-");
|
|
25
|
+
*
|
|
26
|
+
* // paste `a` several times into `b` using "#" as mask
|
|
27
|
+
* blitMask(b, -4, -2, a, "#"); // top-left (partially outside)
|
|
28
|
+
* blitMask(b, 2, 1, a, "#"); // center
|
|
29
|
+
* blitMask(b, 8, 4, a, "#"); // bottom-right (part outside)
|
|
30
|
+
*
|
|
31
|
+
* // show result
|
|
32
|
+
* console.log(formatCanvas(b))
|
|
33
|
+
* // ===---------
|
|
34
|
+
* // ==---==-----
|
|
35
|
+
* // =---====----
|
|
36
|
+
* // ---======---
|
|
37
|
+
* // ----====---=
|
|
38
|
+
* // -----==---==
|
|
39
|
+
* // ---------===
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @param dest
|
|
43
|
+
* @param x
|
|
44
|
+
* @param y
|
|
45
|
+
* @param src
|
|
46
|
+
* @param mask
|
|
47
|
+
*/
|
|
48
|
+
export declare const blitMask: (dest: Canvas, x: number, y: number, src: Canvas, mask?: NumOrString) => void;
|
|
5
49
|
export declare const resize: (canvas: Canvas, newWidth: number, newHeight: number) => void;
|
|
6
50
|
export declare const extract: (canvas: Canvas, x: number, y: number, w: number, h: number) => Canvas;
|
|
7
51
|
/**
|
package/image.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { blit1d } from "@thi.ng/arrays/blit";
|
|
1
2
|
import { peek } from "@thi.ng/arrays/peek";
|
|
2
3
|
import { isNumber } from "@thi.ng/checks/is-number";
|
|
3
4
|
import { clamp0 } from "@thi.ng/math/interval";
|
|
@@ -6,12 +7,12 @@ import { SHADES_BLOCK } from "./api.js";
|
|
|
6
7
|
import { canvas, Canvas } from "./canvas.js";
|
|
7
8
|
import { formatCanvas } from "./format.js";
|
|
8
9
|
import { charCode, intersectRect } from "./utils.js";
|
|
9
|
-
export const blit = (
|
|
10
|
+
export const blit = (dest, x, y, src) => {
|
|
10
11
|
x |= 0;
|
|
11
12
|
y |= 0;
|
|
12
13
|
const { data: sbuf, width: sw, height: sh } = src;
|
|
13
|
-
const { data: dbuf, width: dw } =
|
|
14
|
-
const { x1, y1, y2, w: iw, h: ih, } = intersectRect({ x1: x, y1: y, x2: x + sw, y2: y + sh, w: sw, h: sh }, peek(
|
|
14
|
+
const { data: dbuf, width: dw } = dest;
|
|
15
|
+
const { x1, y1, y2, w: iw, h: ih, } = intersectRect({ x1: x, y1: y, x2: x + sw, y2: y + sh, w: sw, h: sh }, peek(dest.clipRects));
|
|
15
16
|
if (!iw || !ih)
|
|
16
17
|
return;
|
|
17
18
|
const sx = clamp0(x1 - x);
|
|
@@ -22,6 +23,66 @@ export const blit = (canvas, x, y, src) => {
|
|
|
22
23
|
dbuf.set(sbuf.subarray(sidx, sidx + iw), didx);
|
|
23
24
|
}
|
|
24
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
* Similar to {@link blit}. Pastes `src` {@link Canvas} into `dest` at given
|
|
28
|
+
* position and uses `mask` to exclude pixels from being copied (and therefore
|
|
29
|
+
* achieve a form of 1bit transparency, similar to GIFs), i.e. only non-`mask`
|
|
30
|
+
* pixels/chars will be copied. Supports region clipping.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* // source canvas
|
|
35
|
+
* const a = canvasFromText([
|
|
36
|
+
* "###==###",
|
|
37
|
+
* "##====##",
|
|
38
|
+
* "#======#",
|
|
39
|
+
* "##====##",
|
|
40
|
+
* "###==###",
|
|
41
|
+
* ]);
|
|
42
|
+
*
|
|
43
|
+
* // destination canvas (filled w/ "-")
|
|
44
|
+
* const b = canvas(12,7);
|
|
45
|
+
* clear(b, true, "-");
|
|
46
|
+
*
|
|
47
|
+
* // paste `a` several times into `b` using "#" as mask
|
|
48
|
+
* blitMask(b, -4, -2, a, "#"); // top-left (partially outside)
|
|
49
|
+
* blitMask(b, 2, 1, a, "#"); // center
|
|
50
|
+
* blitMask(b, 8, 4, a, "#"); // bottom-right (part outside)
|
|
51
|
+
*
|
|
52
|
+
* // show result
|
|
53
|
+
* console.log(formatCanvas(b))
|
|
54
|
+
* // ===---------
|
|
55
|
+
* // ==---==-----
|
|
56
|
+
* // =---====----
|
|
57
|
+
* // ---======---
|
|
58
|
+
* // ----====---=
|
|
59
|
+
* // -----==---==
|
|
60
|
+
* // ---------===
|
|
61
|
+
* ```
|
|
62
|
+
*
|
|
63
|
+
* @param dest
|
|
64
|
+
* @param x
|
|
65
|
+
* @param y
|
|
66
|
+
* @param src
|
|
67
|
+
* @param mask
|
|
68
|
+
*/
|
|
69
|
+
export const blitMask = (dest, x, y, src, mask = 0x20) => {
|
|
70
|
+
x |= 0;
|
|
71
|
+
y |= 0;
|
|
72
|
+
const { data: sbuf, width: sw, height: sh } = src;
|
|
73
|
+
const { data: dbuf, width: dw } = dest;
|
|
74
|
+
const { x1, y1, y2, w: iw, h: ih, } = intersectRect({ x1: x, y1: y, x2: x + sw, y2: y + sh, w: sw, h: sh }, peek(dest.clipRects));
|
|
75
|
+
if (!iw || !ih)
|
|
76
|
+
return;
|
|
77
|
+
const sx = clamp0(x1 - x);
|
|
78
|
+
const sy = clamp0(y1 - y);
|
|
79
|
+
mask = charCode(mask, 0);
|
|
80
|
+
for (let yy = sy, dy = y1; dy < y2; yy++, dy++) {
|
|
81
|
+
let sidx = sx + yy * sw;
|
|
82
|
+
let didx = x1 + dy * dw;
|
|
83
|
+
blit1d(dbuf, didx, sbuf.subarray(sidx, sidx + iw), mask);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
25
86
|
export const resize = (canvas, newWidth, newHeight) => {
|
|
26
87
|
if (canvas.width === newWidth && canvas.height === newHeight)
|
|
27
88
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/text-canvas",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.2",
|
|
4
4
|
"description": "Text based canvas, drawing, tables with arbitrary formatting (incl. ANSI/HTML)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -34,23 +34,24 @@
|
|
|
34
34
|
"test": "testament test"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@thi.ng/api": "^8.3.
|
|
38
|
-
"@thi.ng/arrays": "^2.2
|
|
39
|
-
"@thi.ng/checks": "^3.2.
|
|
40
|
-
"@thi.ng/
|
|
41
|
-
"@thi.ng/
|
|
42
|
-
"@thi.ng/
|
|
43
|
-
"@thi.ng/
|
|
44
|
-
"@thi.ng/
|
|
37
|
+
"@thi.ng/api": "^8.3.9",
|
|
38
|
+
"@thi.ng/arrays": "^2.3.2",
|
|
39
|
+
"@thi.ng/checks": "^3.2.3",
|
|
40
|
+
"@thi.ng/errors": "^2.1.9",
|
|
41
|
+
"@thi.ng/geom-clip-line": "^2.1.20",
|
|
42
|
+
"@thi.ng/math": "^5.3.5",
|
|
43
|
+
"@thi.ng/strings": "^3.3.7",
|
|
44
|
+
"@thi.ng/text-format": "^1.2.2",
|
|
45
|
+
"@thi.ng/transducers": "^8.3.8"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
48
|
"@microsoft/api-extractor": "^7.25.0",
|
|
48
|
-
"@thi.ng/testament": "^0.2.
|
|
49
|
+
"@thi.ng/testament": "^0.2.10",
|
|
49
50
|
"rimraf": "^3.0.2",
|
|
50
51
|
"tools": "^0.0.1",
|
|
51
52
|
"tslib": "^2.4.0",
|
|
52
53
|
"typedoc": "^0.22.17",
|
|
53
|
-
"typescript": "^4.7.
|
|
54
|
+
"typescript": "^4.7.4"
|
|
54
55
|
},
|
|
55
56
|
"keywords": [
|
|
56
57
|
"4bit",
|
|
@@ -138,5 +139,5 @@
|
|
|
138
139
|
],
|
|
139
140
|
"year": 2020
|
|
140
141
|
},
|
|
141
|
-
"gitHead": "
|
|
142
|
+
"gitHead": "976ccd698cedaa60dcef2e69030a5eb98898cc4a\n"
|
|
142
143
|
}
|
package/rect.d.ts
CHANGED
|
@@ -10,6 +10,13 @@ import type { Canvas } from "./canvas.js";
|
|
|
10
10
|
* @param code -
|
|
11
11
|
*/
|
|
12
12
|
export declare const clear: (canvas: Canvas, reset?: boolean, code?: NumOrString) => void;
|
|
13
|
+
/**
|
|
14
|
+
* Clears or resets format of entire canvas.
|
|
15
|
+
*
|
|
16
|
+
* @param canvas -
|
|
17
|
+
* @param format -
|
|
18
|
+
*/
|
|
19
|
+
export declare const clearFormat: ({ data }: Canvas, format?: number) => void;
|
|
13
20
|
/**
|
|
14
21
|
* Fills given rect with char, taking currect clip rect and format into
|
|
15
22
|
* account.
|
package/rect.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { peek } from "@thi.ng/arrays/peek";
|
|
2
|
+
import { NONE } from "@thi.ng/text-format/api";
|
|
2
3
|
import { hline, vline } from "./hvline.js";
|
|
3
4
|
import { charCode } from "./utils.js";
|
|
4
5
|
/**
|
|
@@ -25,6 +26,17 @@ export const clear = (canvas, reset = false, code = 0x20) => {
|
|
|
25
26
|
canvas.data.fill(code);
|
|
26
27
|
}
|
|
27
28
|
};
|
|
29
|
+
/**
|
|
30
|
+
* Clears or resets format of entire canvas.
|
|
31
|
+
*
|
|
32
|
+
* @param canvas -
|
|
33
|
+
* @param format -
|
|
34
|
+
*/
|
|
35
|
+
export const clearFormat = ({ data }, format = NONE) => {
|
|
36
|
+
format <<= 16;
|
|
37
|
+
for (let i = data.length; i-- > 0;)
|
|
38
|
+
data[i] = (data[i] & 0xffff) | format;
|
|
39
|
+
};
|
|
28
40
|
/**
|
|
29
41
|
* Fills given rect with char, taking currect clip rect and format into
|
|
30
42
|
* account.
|