imagescript 1.2.15 → 1.2.17
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/ImageScript.d.ts +233 -223
- package/ImageScript.js +1658 -1646
- package/LICENSE +12 -619
- package/LICENSE.AGPL-3.0 +619 -0
- package/LICENSE.MIT +19 -0
- package/README.md +51 -46
- package/bench/_.mjs +165 -165
- package/bench/all.mjs +3 -3
- package/bench/blur.mjs +58 -58
- package/bench/flip.mjs +62 -62
- package/bench/overlay.mjs +34 -34
- package/bench/package.json +6 -6
- package/bench/readme.md +63 -63
- package/bench/resize.mjs +51 -51
- package/codecs/LICENSE +20 -20
- package/codecs/lib.d.ts +49 -49
- package/codecs/lib.js +5 -5
- package/codecs/node/index.js +2 -2
- package/codecs/node/index.mjs +5 -5
- package/codecs/package.json +13 -13
- package/codecs/readme.md +37 -37
- package/package.json +41 -41
- package/png/node.js +1137 -1137
- package/png/src/crc.mjs +48 -48
- package/png/src/mem.mjs +23 -23
- package/png/src/png.mjs +254 -254
- package/png/src/zlib.mjs +617 -617
- package/tsconfig.json +21 -21
- package/utils/mem.js +25 -25
- package/v2/codecs/magic.js +24 -24
- package/v2/framebuffer.d.ts +66 -66
- package/v2/framebuffer.js +2352 -2352
- package/v2/framebuffer.mjs +125 -125
- package/v2/framebuffer.rs +1263 -1263
- package/v2/index.d.ts +83 -83
- package/v2/index.js +260 -260
- package/v2/ops/blur.mjs +302 -302
- package/v2/ops/color.mjs +276 -276
- package/v2/ops/crop.mjs +63 -63
- package/v2/ops/fill.mjs +32 -32
- package/v2/ops/flip.mjs +32 -32
- package/v2/ops/index.mjs +8 -8
- package/v2/ops/iterator.mjs +33 -33
- package/v2/ops/overlay.mjs +62 -62
- package/v2/ops/resize.mjs +165 -165
- package/v2/ops/rotate.mjs +116 -116
- package/v2/util/mem.mjs +23 -23
- package/wasm/node/font.js +141 -141
- package/wasm/node/gif.js +76 -76
- package/wasm/node/jpeg.js +91 -91
- package/wasm/node/png.js +49 -49
- package/wasm/node/svg.js +55 -55
- package/wasm/node/tiff.js +46 -46
package/README.md
CHANGED
|
@@ -1,46 +1,51 @@
|
|
|
1
|
-
# ImageScript
|
|
2
|
-
##### zero-dependency JavaScript image manipulation
|
|
3
|
-
[](https://discord.gg/8hPrwAH)
|
|
4
|
-
[](https://imagescript.matmen.dev/)
|
|
5
|
-
[](https://github.com/matmen/ImageScript)
|
|
6
|
-
[](https://deno.land/x/imagescript)
|
|
7
|
-
[](https://www.npmjs.com/package/imagescript)
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
**ImageScript** is a zero-dependency alternative to common JavaScript bitmap image manipulation tools. It can achieve
|
|
12
|
-
much more performant results by utilizing lower-level memory access, less memory copying and WebAssembly / native
|
|
13
|
-
binaries for decoding and encoding.
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
### Features
|
|
18
|
-
|
|
19
|
-
- [Decoding images](https://imagescript.matmen.dev/Image.html#.decode)
|
|
20
|
-
- PNGs (grayscale, RGB, indexed colors) with and without alpha channels
|
|
21
|
-
- JPEGs (grayscale, RGB, CMYK)
|
|
22
|
-
- TIFFs
|
|
23
|
-
- [Decoding GIFs](https://imagescript.matmen.dev/GIF.html#.decode)
|
|
24
|
-
- [Rendering SVGs](https://imagescript.matmen.dev/Image.html#.renderSVG)
|
|
25
|
-
- [Rendering vector fonts](https://imagescript.matmen.dev/Image.html#.renderText)
|
|
26
|
-
- Image manipulation functions ([crop](https://imagescript.matmen.dev/Image.html#crop)
|
|
27
|
-
, [rotate](https://imagescript.matmen.dev/Image.html#rotate)
|
|
28
|
-
, [composite](https://imagescript.matmen.dev/Image.html#composite), ...)
|
|
29
|
-
- Color manipulation functions ([invert](https://imagescript.matmen.dev/Image.html##invert)
|
|
30
|
-
, [hueShift](https://imagescript.matmen.dev/Image.html##hueshift), ...)
|
|
31
|
-
- Color information functions ([averageColor](https://imagescript.matmen.dev/Image.html#averageColor)
|
|
32
|
-
, [dominantColor](https://imagescript.matmen.dev/Image.html#dominantColor), ...)
|
|
33
|
-
- Encoding images as [PNGs](https://imagescript.matmen.dev/Image.html#encode)
|
|
34
|
-
, [JPEGs](https://imagescript.matmen.dev/Image.html#encodejpeg)
|
|
35
|
-
, [WEBPs](https://imagescript.matmen.dev/Image.html#encodeWEBP)
|
|
36
|
-
and [GIFs](https://imagescript.matmen.dev/GIF.html#encode)
|
|
37
|
-
|
|
38
|
-
---
|
|
39
|
-
|
|
40
|
-
### Example
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
1
|
+
# ImageScript
|
|
2
|
+
##### zero-dependency JavaScript image manipulation
|
|
3
|
+
[](https://discord.gg/8hPrwAH)
|
|
4
|
+
[](https://imagescript.matmen.dev/)
|
|
5
|
+
[](https://github.com/matmen/ImageScript)
|
|
6
|
+
[](https://deno.land/x/imagescript)
|
|
7
|
+
[](https://www.npmjs.com/package/imagescript)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
**ImageScript** is a zero-dependency alternative to common JavaScript bitmap image manipulation tools. It can achieve
|
|
12
|
+
much more performant results by utilizing lower-level memory access, less memory copying and WebAssembly / native
|
|
13
|
+
binaries for decoding and encoding.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
- [Decoding images](https://imagescript.matmen.dev/Image.html#.decode)
|
|
20
|
+
- PNGs (grayscale, RGB, indexed colors) with and without alpha channels
|
|
21
|
+
- JPEGs (grayscale, RGB, CMYK)
|
|
22
|
+
- TIFFs
|
|
23
|
+
- [Decoding GIFs](https://imagescript.matmen.dev/GIF.html#.decode)
|
|
24
|
+
- [Rendering SVGs](https://imagescript.matmen.dev/Image.html#.renderSVG)
|
|
25
|
+
- [Rendering vector fonts](https://imagescript.matmen.dev/Image.html#.renderText)
|
|
26
|
+
- Image manipulation functions ([crop](https://imagescript.matmen.dev/Image.html#crop)
|
|
27
|
+
, [rotate](https://imagescript.matmen.dev/Image.html#rotate)
|
|
28
|
+
, [composite](https://imagescript.matmen.dev/Image.html#composite), ...)
|
|
29
|
+
- Color manipulation functions ([invert](https://imagescript.matmen.dev/Image.html##invert)
|
|
30
|
+
, [hueShift](https://imagescript.matmen.dev/Image.html##hueshift), ...)
|
|
31
|
+
- Color information functions ([averageColor](https://imagescript.matmen.dev/Image.html#averageColor)
|
|
32
|
+
, [dominantColor](https://imagescript.matmen.dev/Image.html#dominantColor), ...)
|
|
33
|
+
- Encoding images as [PNGs](https://imagescript.matmen.dev/Image.html#encode)
|
|
34
|
+
, [JPEGs](https://imagescript.matmen.dev/Image.html#encodejpeg)
|
|
35
|
+
, [WEBPs](https://imagescript.matmen.dev/Image.html#encodeWEBP)
|
|
36
|
+
and [GIFs](https://imagescript.matmen.dev/GIF.html#encode)
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
### Example
|
|
41
|
+
|
|
42
|
+
Check out one of these examples:
|
|
43
|
+
* **NodeJS**: [README image generation](https://github.com/matmen/ImageScript/blob/master/tests/readme.js)
|
|
44
|
+
* **Deno**: [README image generation](https://github.com/matmen/ImageScript/blob/deno/tests/readme.js)
|
|
45
|
+
* **Browser**: [Grayscale Conversion Example Page](https://github.com/matmen/ImageScript/blob/browser/example/index.html) (via CDN)
|
|
46
|
+
|
|
47
|
+
[](https://github.com/matmen/ImageScript/blob/master/tests/readme.js)
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
If you have any additional questions, feel free to join the [discord support server](https://discord.gg/8hPrwAH).
|
package/bench/_.mjs
CHANGED
|
@@ -1,166 +1,166 @@
|
|
|
1
|
-
// https://gist.github.com/evanwashere/7ee592870e46f80405b9776dcd56e1e8#file-bench-js
|
|
2
|
-
|
|
3
|
-
const now = performance.now.bind(performance);
|
|
4
|
-
|
|
5
|
-
function sort(a, b) {
|
|
6
|
-
if (a > b) return 1;
|
|
7
|
-
if (a < b) return -1;
|
|
8
|
-
|
|
9
|
-
return 0;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
function stats(n, avg, min, max, jit, all) {
|
|
13
|
-
return {
|
|
14
|
-
min: Math.ceil(min * 1e6),
|
|
15
|
-
max: Math.ceil(max * 1e6),
|
|
16
|
-
avg: Math.ceil(avg / n * 1e6),
|
|
17
|
-
jit: jit.map(x => Math.ceil(x * 1e6)),
|
|
18
|
-
'50th': Math.ceil(1e6 * all[Math.ceil(n * (50 / 100)) - 1]),
|
|
19
|
-
'75th': Math.ceil(1e6 * all[Math.ceil(n * (75 / 100)) - 1]),
|
|
20
|
-
'99th': Math.ceil(1e6 * all[Math.ceil(n * (99 / 100)) - 1]),
|
|
21
|
-
'99.5th': Math.ceil(1e6 * all[Math.ceil(n * (99.5 / 100)) - 1]),
|
|
22
|
-
'99.9th': Math.ceil(1e6 * all[Math.ceil(n * (99.9 / 100)) - 1]),
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function sync(n, fn) {
|
|
27
|
-
let avg = 0;
|
|
28
|
-
let min = Infinity;
|
|
29
|
-
let max = -Infinity;
|
|
30
|
-
const all = new Array(n);
|
|
31
|
-
const jit = new Array(10);
|
|
32
|
-
|
|
33
|
-
warmup: {
|
|
34
|
-
let offset = 0;
|
|
35
|
-
let iterations = 10;
|
|
36
|
-
while (iterations--) {
|
|
37
|
-
const t1 = now();
|
|
38
|
-
|
|
39
|
-
fn();
|
|
40
|
-
jit[offset++] = now() - t1;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
iterations = 1e3 - 10;
|
|
44
|
-
while (iterations--) fn();
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
measure: {
|
|
48
|
-
let offset = 0;
|
|
49
|
-
let iterations = n;
|
|
50
|
-
while (iterations--) {
|
|
51
|
-
const t1 = now();
|
|
52
|
-
|
|
53
|
-
fn();
|
|
54
|
-
const t2 = now() - t1;
|
|
55
|
-
if (t2 < min) min = t2;
|
|
56
|
-
if (t2 > max) max = t2;
|
|
57
|
-
avg += (all[offset++] = t2);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
all.sort(sort);
|
|
62
|
-
return stats(n, avg, min, max, jit, all);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export async function async(n, fn) {
|
|
66
|
-
let avg = 0;
|
|
67
|
-
let min = Infinity;
|
|
68
|
-
let max = -Infinity;
|
|
69
|
-
const all = new Array(n);
|
|
70
|
-
const jit = new Array(10);
|
|
71
|
-
|
|
72
|
-
warmup: {
|
|
73
|
-
let offset = 0;
|
|
74
|
-
let iterations = 10;
|
|
75
|
-
while (iterations--) {
|
|
76
|
-
const t1 = now();
|
|
77
|
-
|
|
78
|
-
await fn();
|
|
79
|
-
jit[offset++] = now() - t1;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
iterations = 1e3 - 10;
|
|
83
|
-
while (iterations--) await fn();
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
measure: {
|
|
87
|
-
let offset = 0;
|
|
88
|
-
let iterations = n;
|
|
89
|
-
while (iterations--) {
|
|
90
|
-
const t1 = now();
|
|
91
|
-
|
|
92
|
-
await fn();
|
|
93
|
-
const t2 = now() - t1;
|
|
94
|
-
if (t2 < min) min = t2;
|
|
95
|
-
if (t2 > max) max = t2;
|
|
96
|
-
avg += (all[offset++] = t2);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
all.sort(sort);
|
|
101
|
-
return stats(n, avg, min, max, jit, all);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export function format({ results, title = '', unit = 'ns', percentiles = true }) {
|
|
105
|
-
const h = '─';
|
|
106
|
-
const v = '│';
|
|
107
|
-
|
|
108
|
-
let s = '';
|
|
109
|
-
unit = `${unit}/iter`;
|
|
110
|
-
const rk = Object.keys(results);
|
|
111
|
-
const rv = Object.values(results);
|
|
112
|
-
const ra = rv.map(x => x.avg.toLocaleString('en-us'));
|
|
113
|
-
const r50 = rv.map(x => x['50th'].toLocaleString('en-us'));
|
|
114
|
-
const r75 = rv.map(x => x['75th'].toLocaleString('en-us'));
|
|
115
|
-
const r99 = rv.map(x => x['99th'].toLocaleString('en-us'));
|
|
116
|
-
const r995 = rv.map(x => x['99.5th'].toLocaleString('en-us'));
|
|
117
|
-
const r999 = rv.map(x => x['99.9th'].toLocaleString('en-us'));
|
|
118
|
-
const rmm = rv.map(x => [x.min.toLocaleString('en-us'), x.max.toLocaleString('en-us')]);
|
|
119
|
-
|
|
120
|
-
const us = unit.length;
|
|
121
|
-
const rks = Math.max(...rk.map(x => x.length));
|
|
122
|
-
const ras = Math.max(...ra.map(x => x.length));
|
|
123
|
-
const r50s = Math.max(...r50.map(x => x.length));
|
|
124
|
-
const r75s = Math.max(...r75.map(x => x.length));
|
|
125
|
-
const r99s = Math.max(...r99.map(x => x.length));
|
|
126
|
-
const r995s = Math.max(...r995.map(x => x.length));
|
|
127
|
-
const r999s = Math.max(...r999.map(x => x.length));
|
|
128
|
-
const rmns = Math.max(...rmm.map(x => x[0].length));
|
|
129
|
-
const rmxs = Math.max(...rmm.map(x => x[1].length));
|
|
130
|
-
|
|
131
|
-
const bks = 1 + rks + 1;
|
|
132
|
-
const b50s = 1 + r50s + 1 + us + 1;
|
|
133
|
-
const b75s = 1 + r75s + 1 + us + 1;
|
|
134
|
-
const b99s = 1 + r99s + 1 + us + 1;
|
|
135
|
-
const b995s = 1 + r995s + 1 + us + 1;
|
|
136
|
-
const b999s = 1 + r999s + 1 + us + 1;
|
|
137
|
-
const bimms = 1 + rmns + 2 + rmxs + 1 + us + 1;
|
|
138
|
-
const bas = 1 + (ras + 1 + us) + 1 + bimms + 1;
|
|
139
|
-
const ls = 1 + bks + 1 + bas + 1 + b50s + 1 + b75s + 1 + b99s + 1 + b995s + 1 + b999s + 1;
|
|
140
|
-
|
|
141
|
-
if (!percentiles) s += title ? ` ${title}` : '';
|
|
142
|
-
|
|
143
|
-
else {
|
|
144
|
-
s += ' '.repeat(3 + bks + bas);
|
|
145
|
-
s += '┌' + h.repeat(ls - 4 - bks - bas) + '┐';
|
|
146
|
-
s += '\n' + ` ${title.padEnd(2 + bks + bas, ' ')}`;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (percentiles) s += v
|
|
150
|
-
+ '50th'.padEnd((b50s + 4) / 2, ' ').padStart(b50s, ' ') + v
|
|
151
|
-
+ '75th'.padEnd((b75s + 4) / 2, ' ').padStart(b75s, ' ') + v
|
|
152
|
-
+ '99th'.padEnd((b99s + 4) / 2, ' ').padStart(b99s, ' ') + v
|
|
153
|
-
+ '99.5th'.padEnd((b995s + 6) / 2, ' ').padStart(b995s, ' ') + v
|
|
154
|
-
+ '99.9th'.padEnd((b999s + 6) / 2, ' ').padStart(b999s, ' ') + v;
|
|
155
|
-
|
|
156
|
-
s += (title || percentiles ? '\n' : '') + '┌' + h.repeat(1 + bks + bas) + '┐' + (percentiles ? '├' + h.repeat(ls - 4 - bks - bas) + '┤' : '');
|
|
157
|
-
|
|
158
|
-
for (let i = 0; i < rk.length; i++) {
|
|
159
|
-
s += '\n' + v + ` ${rk[i].padEnd(rks, ' ')} ` + v + ` ${ra[i].padStart(ras, ' ')} ${unit} ${`(${rmm[i][0]}..${rmm[i][1]} ${unit})`.padStart(bimms, ' ')} ` + v
|
|
160
|
-
if (percentiles) s += v + ` ${r50[i].padStart(r50s, ' ')} ${unit} ` + v + ` ${r75[i].padStart(r75s, ' ')} ${unit} ` + v + ` ${r99[i].padStart(r99s, ' ')} ${unit} ` + v + ` ${r995[i].padStart(r995s, ' ')} ${unit} ` + v + ` ${r999[i].padStart(r999s, ' ')} ${unit} ` + v;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
s += '\n' + '└' + h.repeat(1 + bks + bas) + '┘' + (percentiles ? '└' + h.repeat(ls - 4 - bks - bas) + '┘' : '');
|
|
164
|
-
|
|
165
|
-
return s;
|
|
1
|
+
// https://gist.github.com/evanwashere/7ee592870e46f80405b9776dcd56e1e8#file-bench-js
|
|
2
|
+
|
|
3
|
+
const now = performance.now.bind(performance);
|
|
4
|
+
|
|
5
|
+
function sort(a, b) {
|
|
6
|
+
if (a > b) return 1;
|
|
7
|
+
if (a < b) return -1;
|
|
8
|
+
|
|
9
|
+
return 0;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
function stats(n, avg, min, max, jit, all) {
|
|
13
|
+
return {
|
|
14
|
+
min: Math.ceil(min * 1e6),
|
|
15
|
+
max: Math.ceil(max * 1e6),
|
|
16
|
+
avg: Math.ceil(avg / n * 1e6),
|
|
17
|
+
jit: jit.map(x => Math.ceil(x * 1e6)),
|
|
18
|
+
'50th': Math.ceil(1e6 * all[Math.ceil(n * (50 / 100)) - 1]),
|
|
19
|
+
'75th': Math.ceil(1e6 * all[Math.ceil(n * (75 / 100)) - 1]),
|
|
20
|
+
'99th': Math.ceil(1e6 * all[Math.ceil(n * (99 / 100)) - 1]),
|
|
21
|
+
'99.5th': Math.ceil(1e6 * all[Math.ceil(n * (99.5 / 100)) - 1]),
|
|
22
|
+
'99.9th': Math.ceil(1e6 * all[Math.ceil(n * (99.9 / 100)) - 1]),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function sync(n, fn) {
|
|
27
|
+
let avg = 0;
|
|
28
|
+
let min = Infinity;
|
|
29
|
+
let max = -Infinity;
|
|
30
|
+
const all = new Array(n);
|
|
31
|
+
const jit = new Array(10);
|
|
32
|
+
|
|
33
|
+
warmup: {
|
|
34
|
+
let offset = 0;
|
|
35
|
+
let iterations = 10;
|
|
36
|
+
while (iterations--) {
|
|
37
|
+
const t1 = now();
|
|
38
|
+
|
|
39
|
+
fn();
|
|
40
|
+
jit[offset++] = now() - t1;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
iterations = 1e3 - 10;
|
|
44
|
+
while (iterations--) fn();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
measure: {
|
|
48
|
+
let offset = 0;
|
|
49
|
+
let iterations = n;
|
|
50
|
+
while (iterations--) {
|
|
51
|
+
const t1 = now();
|
|
52
|
+
|
|
53
|
+
fn();
|
|
54
|
+
const t2 = now() - t1;
|
|
55
|
+
if (t2 < min) min = t2;
|
|
56
|
+
if (t2 > max) max = t2;
|
|
57
|
+
avg += (all[offset++] = t2);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
all.sort(sort);
|
|
62
|
+
return stats(n, avg, min, max, jit, all);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function async(n, fn) {
|
|
66
|
+
let avg = 0;
|
|
67
|
+
let min = Infinity;
|
|
68
|
+
let max = -Infinity;
|
|
69
|
+
const all = new Array(n);
|
|
70
|
+
const jit = new Array(10);
|
|
71
|
+
|
|
72
|
+
warmup: {
|
|
73
|
+
let offset = 0;
|
|
74
|
+
let iterations = 10;
|
|
75
|
+
while (iterations--) {
|
|
76
|
+
const t1 = now();
|
|
77
|
+
|
|
78
|
+
await fn();
|
|
79
|
+
jit[offset++] = now() - t1;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
iterations = 1e3 - 10;
|
|
83
|
+
while (iterations--) await fn();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
measure: {
|
|
87
|
+
let offset = 0;
|
|
88
|
+
let iterations = n;
|
|
89
|
+
while (iterations--) {
|
|
90
|
+
const t1 = now();
|
|
91
|
+
|
|
92
|
+
await fn();
|
|
93
|
+
const t2 = now() - t1;
|
|
94
|
+
if (t2 < min) min = t2;
|
|
95
|
+
if (t2 > max) max = t2;
|
|
96
|
+
avg += (all[offset++] = t2);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
all.sort(sort);
|
|
101
|
+
return stats(n, avg, min, max, jit, all);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function format({ results, title = '', unit = 'ns', percentiles = true }) {
|
|
105
|
+
const h = '─';
|
|
106
|
+
const v = '│';
|
|
107
|
+
|
|
108
|
+
let s = '';
|
|
109
|
+
unit = `${unit}/iter`;
|
|
110
|
+
const rk = Object.keys(results);
|
|
111
|
+
const rv = Object.values(results);
|
|
112
|
+
const ra = rv.map(x => x.avg.toLocaleString('en-us'));
|
|
113
|
+
const r50 = rv.map(x => x['50th'].toLocaleString('en-us'));
|
|
114
|
+
const r75 = rv.map(x => x['75th'].toLocaleString('en-us'));
|
|
115
|
+
const r99 = rv.map(x => x['99th'].toLocaleString('en-us'));
|
|
116
|
+
const r995 = rv.map(x => x['99.5th'].toLocaleString('en-us'));
|
|
117
|
+
const r999 = rv.map(x => x['99.9th'].toLocaleString('en-us'));
|
|
118
|
+
const rmm = rv.map(x => [x.min.toLocaleString('en-us'), x.max.toLocaleString('en-us')]);
|
|
119
|
+
|
|
120
|
+
const us = unit.length;
|
|
121
|
+
const rks = Math.max(...rk.map(x => x.length));
|
|
122
|
+
const ras = Math.max(...ra.map(x => x.length));
|
|
123
|
+
const r50s = Math.max(...r50.map(x => x.length));
|
|
124
|
+
const r75s = Math.max(...r75.map(x => x.length));
|
|
125
|
+
const r99s = Math.max(...r99.map(x => x.length));
|
|
126
|
+
const r995s = Math.max(...r995.map(x => x.length));
|
|
127
|
+
const r999s = Math.max(...r999.map(x => x.length));
|
|
128
|
+
const rmns = Math.max(...rmm.map(x => x[0].length));
|
|
129
|
+
const rmxs = Math.max(...rmm.map(x => x[1].length));
|
|
130
|
+
|
|
131
|
+
const bks = 1 + rks + 1;
|
|
132
|
+
const b50s = 1 + r50s + 1 + us + 1;
|
|
133
|
+
const b75s = 1 + r75s + 1 + us + 1;
|
|
134
|
+
const b99s = 1 + r99s + 1 + us + 1;
|
|
135
|
+
const b995s = 1 + r995s + 1 + us + 1;
|
|
136
|
+
const b999s = 1 + r999s + 1 + us + 1;
|
|
137
|
+
const bimms = 1 + rmns + 2 + rmxs + 1 + us + 1;
|
|
138
|
+
const bas = 1 + (ras + 1 + us) + 1 + bimms + 1;
|
|
139
|
+
const ls = 1 + bks + 1 + bas + 1 + b50s + 1 + b75s + 1 + b99s + 1 + b995s + 1 + b999s + 1;
|
|
140
|
+
|
|
141
|
+
if (!percentiles) s += title ? ` ${title}` : '';
|
|
142
|
+
|
|
143
|
+
else {
|
|
144
|
+
s += ' '.repeat(3 + bks + bas);
|
|
145
|
+
s += '┌' + h.repeat(ls - 4 - bks - bas) + '┐';
|
|
146
|
+
s += '\n' + ` ${title.padEnd(2 + bks + bas, ' ')}`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (percentiles) s += v
|
|
150
|
+
+ '50th'.padEnd((b50s + 4) / 2, ' ').padStart(b50s, ' ') + v
|
|
151
|
+
+ '75th'.padEnd((b75s + 4) / 2, ' ').padStart(b75s, ' ') + v
|
|
152
|
+
+ '99th'.padEnd((b99s + 4) / 2, ' ').padStart(b99s, ' ') + v
|
|
153
|
+
+ '99.5th'.padEnd((b995s + 6) / 2, ' ').padStart(b995s, ' ') + v
|
|
154
|
+
+ '99.9th'.padEnd((b999s + 6) / 2, ' ').padStart(b999s, ' ') + v;
|
|
155
|
+
|
|
156
|
+
s += (title || percentiles ? '\n' : '') + '┌' + h.repeat(1 + bks + bas) + '┐' + (percentiles ? '├' + h.repeat(ls - 4 - bks - bas) + '┤' : '');
|
|
157
|
+
|
|
158
|
+
for (let i = 0; i < rk.length; i++) {
|
|
159
|
+
s += '\n' + v + ` ${rk[i].padEnd(rks, ' ')} ` + v + ` ${ra[i].padStart(ras, ' ')} ${unit} ${`(${rmm[i][0]}..${rmm[i][1]} ${unit})`.padStart(bimms, ' ')} ` + v
|
|
160
|
+
if (percentiles) s += v + ` ${r50[i].padStart(r50s, ' ')} ${unit} ` + v + ` ${r75[i].padStart(r75s, ' ')} ${unit} ` + v + ` ${r99[i].padStart(r99s, ' ')} ${unit} ` + v + ` ${r995[i].padStart(r995s, ' ')} ${unit} ` + v + ` ${r999[i].padStart(r999s, ' ')} ${unit} ` + v;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
s += '\n' + '└' + h.repeat(1 + bks + bas) + '┘' + (percentiles ? '└' + h.repeat(ls - 4 - bks - bas) + '┘' : '');
|
|
164
|
+
|
|
165
|
+
return s;
|
|
166
166
|
}
|
package/bench/all.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import './flip.mjs';
|
|
2
|
-
import './blur.mjs';
|
|
3
|
-
import './resize.mjs';
|
|
1
|
+
import './flip.mjs';
|
|
2
|
+
import './blur.mjs';
|
|
3
|
+
import './resize.mjs';
|
|
4
4
|
import './overlay.mjs';
|
package/bench/blur.mjs
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
import { sync, async, format } from './_.mjs';
|
|
2
|
-
|
|
3
|
-
import jimp from 'jimp';
|
|
4
|
-
import sharp from 'sharp';
|
|
5
|
-
import v2 from '../v2/framebuffer.mjs';
|
|
6
|
-
import * as imagers from '@evan/wasm/target/image/node.mjs';
|
|
7
|
-
import * as v2_wasm from '@evan/wasm/target/imagescript/node.mjs';
|
|
8
|
-
|
|
9
|
-
{
|
|
10
|
-
const rgba = new Uint8Array(4 * 256 * 256).map((_, i) => i % 256);
|
|
11
|
-
|
|
12
|
-
const images = {
|
|
13
|
-
v2: new v2(256, 256, rgba),
|
|
14
|
-
imagers: imagers.framebuffer.from(256, 256, rgba),
|
|
15
|
-
v2_wasm: () => v2_wasm.framebuffer.from(256, 256, rgba),
|
|
16
|
-
sharp: sharp(rgba, { raw: { width: 256, height: 256, channels: 4 } }),
|
|
17
|
-
jimp: await new Promise(r => new jimp({ width: 256, height: 256, data: rgba }, (_, i) => r(i))),
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
console.log(format({
|
|
21
|
-
percentiles: false,
|
|
22
|
-
title: 'blur (5.0f/256x256)',
|
|
23
|
-
|
|
24
|
-
results: {
|
|
25
|
-
jimp: sync(1e4, () => images.jimp.clone().blur(5)),
|
|
26
|
-
imagescript: sync(1e4, () => images.v2.clone().blur('gaussian')),
|
|
27
|
-
sharp: await async(1e4, () => images.sharp.clone().blur(5).toBuffer()),
|
|
28
|
-
'image-rs (wasm)': sync(1e4, () => imagers.blur(images.imagers, 5).drop()),
|
|
29
|
-
'imagescript-rs (wasm)': sync(1e4, () => { let i = images.v2_wasm(); v2_wasm.blur(i, 5); i.drop() }),
|
|
30
|
-
},
|
|
31
|
-
}));
|
|
32
|
-
|
|
33
|
-
images.imagers.drop();
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
{
|
|
37
|
-
const rgba = new Uint8Array(4 * 1024 * 1024).map((_, i) => i % 256);
|
|
38
|
-
|
|
39
|
-
const images = {
|
|
40
|
-
v2: new v2(1024, 1024, rgba),
|
|
41
|
-
imagers: imagers.framebuffer.from(1024, 1024, rgba),
|
|
42
|
-
v2_wasm: () => v2_wasm.framebuffer.from(1024, 1024, rgba),
|
|
43
|
-
sharp: sharp(rgba, { raw: { width: 1024, height: 1024, channels: 4 } }),
|
|
44
|
-
jimp: await new Promise(r => new jimp({ width: 1024, height: 1024, data: rgba }, (_, i) => r(i))),
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
console.log(format({
|
|
48
|
-
percentiles: false,
|
|
49
|
-
title: 'blur (5.0f/1024x1024)',
|
|
50
|
-
|
|
51
|
-
results: {
|
|
52
|
-
jimp: sync(1e4, () => images.jimp.clone().blur(5)),
|
|
53
|
-
imagescript: sync(1e4, () => images.v2.clone().blur('gaussian')),
|
|
54
|
-
sharp: await async(1e4, () => images.sharp.clone().blur(5).toBuffer()),
|
|
55
|
-
'image-rs (wasm)': sync(1e4, () => imagers.blur(images.imagers, 5).drop()),
|
|
56
|
-
'imagescript-rs (wasm)': sync(1e4, () => { let i = images.v2_wasm(); v2_wasm.blur(i, 5); i.drop() }),
|
|
57
|
-
},
|
|
58
|
-
}));
|
|
1
|
+
import { sync, async, format } from './_.mjs';
|
|
2
|
+
|
|
3
|
+
import jimp from 'jimp';
|
|
4
|
+
import sharp from 'sharp';
|
|
5
|
+
import v2 from '../v2/framebuffer.mjs';
|
|
6
|
+
import * as imagers from '@evan/wasm/target/image/node.mjs';
|
|
7
|
+
import * as v2_wasm from '@evan/wasm/target/imagescript/node.mjs';
|
|
8
|
+
|
|
9
|
+
{
|
|
10
|
+
const rgba = new Uint8Array(4 * 256 * 256).map((_, i) => i % 256);
|
|
11
|
+
|
|
12
|
+
const images = {
|
|
13
|
+
v2: new v2(256, 256, rgba),
|
|
14
|
+
imagers: imagers.framebuffer.from(256, 256, rgba),
|
|
15
|
+
v2_wasm: () => v2_wasm.framebuffer.from(256, 256, rgba),
|
|
16
|
+
sharp: sharp(rgba, { raw: { width: 256, height: 256, channels: 4 } }),
|
|
17
|
+
jimp: await new Promise(r => new jimp({ width: 256, height: 256, data: rgba }, (_, i) => r(i))),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
console.log(format({
|
|
21
|
+
percentiles: false,
|
|
22
|
+
title: 'blur (5.0f/256x256)',
|
|
23
|
+
|
|
24
|
+
results: {
|
|
25
|
+
jimp: sync(1e4, () => images.jimp.clone().blur(5)),
|
|
26
|
+
imagescript: sync(1e4, () => images.v2.clone().blur('gaussian')),
|
|
27
|
+
sharp: await async(1e4, () => images.sharp.clone().blur(5).toBuffer()),
|
|
28
|
+
'image-rs (wasm)': sync(1e4, () => imagers.blur(images.imagers, 5).drop()),
|
|
29
|
+
'imagescript-rs (wasm)': sync(1e4, () => { let i = images.v2_wasm(); v2_wasm.blur(i, 5); i.drop() }),
|
|
30
|
+
},
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
images.imagers.drop();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
{
|
|
37
|
+
const rgba = new Uint8Array(4 * 1024 * 1024).map((_, i) => i % 256);
|
|
38
|
+
|
|
39
|
+
const images = {
|
|
40
|
+
v2: new v2(1024, 1024, rgba),
|
|
41
|
+
imagers: imagers.framebuffer.from(1024, 1024, rgba),
|
|
42
|
+
v2_wasm: () => v2_wasm.framebuffer.from(1024, 1024, rgba),
|
|
43
|
+
sharp: sharp(rgba, { raw: { width: 1024, height: 1024, channels: 4 } }),
|
|
44
|
+
jimp: await new Promise(r => new jimp({ width: 1024, height: 1024, data: rgba }, (_, i) => r(i))),
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
console.log(format({
|
|
48
|
+
percentiles: false,
|
|
49
|
+
title: 'blur (5.0f/1024x1024)',
|
|
50
|
+
|
|
51
|
+
results: {
|
|
52
|
+
jimp: sync(1e4, () => images.jimp.clone().blur(5)),
|
|
53
|
+
imagescript: sync(1e4, () => images.v2.clone().blur('gaussian')),
|
|
54
|
+
sharp: await async(1e4, () => images.sharp.clone().blur(5).toBuffer()),
|
|
55
|
+
'image-rs (wasm)': sync(1e4, () => imagers.blur(images.imagers, 5).drop()),
|
|
56
|
+
'imagescript-rs (wasm)': sync(1e4, () => { let i = images.v2_wasm(); v2_wasm.blur(i, 5); i.drop() }),
|
|
57
|
+
},
|
|
58
|
+
}));
|
|
59
59
|
}
|