imagescript 1.2.8 → 1.2.15
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 +223 -0
- package/ImageScript.js +60 -192
- package/LICENSE +619 -0
- package/README.md +17 -16
- package/bench/_.mjs +166 -0
- package/bench/all.mjs +4 -0
- package/bench/blur.mjs +59 -0
- package/bench/flip.mjs +63 -0
- package/bench/overlay.mjs +35 -0
- package/bench/package.json +7 -0
- package/bench/readme.md +64 -0
- package/bench/resize.mjs +52 -0
- package/codecs/LICENSE +21 -0
- package/codecs/lib.d.ts +50 -0
- package/codecs/lib.js +6 -0
- package/codecs/lib.mjs +1 -0
- package/codecs/node/bin/arm64-darwin.node +0 -0
- package/{node → codecs/node/bin}/arm64-linux.node +0 -0
- package/codecs/node/bin/x64-darwin.node +0 -0
- package/{node → codecs/node/bin}/x64-linux.node +0 -0
- package/{node → codecs/node/bin}/x64-win32.node +0 -0
- package/codecs/node/index.js +3 -0
- package/codecs/node/index.mjs +6 -0
- package/codecs/package.json +14 -0
- package/codecs/readme.md +38 -0
- package/{wasm/simd.wasm → codecs/tests/gif.js} +0 -0
- package/{wasm/unknown.wasm → codecs/tests/jpeg.js} +0 -0
- package/codecs/tests/png.js +0 -0
- package/codecs/tests/results/gif/1024.nis.gif +0 -0
- package/codecs/tests/results/gif/1024.skyra.gif +0 -0
- package/codecs/tests/results/gif/256.nis.gif +0 -0
- package/codecs/tests/results/gif/256.skyra.gif +0 -0
- package/codecs/tests/results/jpeg/256.jpegjs.jpeg +0 -0
- package/codecs/tests/results/jpeg/256.nis.jpeg +0 -0
- package/codecs/tests/results/jpeg/256.sharp.jpeg +0 -0
- package/codecs/tests/results/jpeg/512.jpegjs.jpeg +0 -0
- package/codecs/tests/results/jpeg/512.nis.jpeg +0 -0
- package/codecs/tests/results/jpeg/512.sharp.jpeg +0 -0
- package/codecs/tests/results/jpeg/64.jpegjs.jpeg +0 -0
- package/codecs/tests/results/jpeg/64.nis.jpeg +0 -0
- package/codecs/tests/results/jpeg/64.sharp.jpeg +0 -0
- package/codecs/tests/results/png/256.jis.png +0 -0
- package/codecs/tests/results/png/256.nis.png +0 -0
- package/codecs/tests/results/png/256.sharp.png +0 -0
- package/codecs/tests/results/png/256.upng.png +0 -0
- package/codecs/tests/results/png/512.jis.png +0 -0
- package/codecs/tests/results/png/512.nis.png +0 -0
- package/codecs/tests/results/png/512.sharp.png +0 -0
- package/codecs/tests/results/png/512.upng.png +0 -0
- package/codecs/tests/results/png/64.jis.png +0 -0
- package/codecs/tests/results/png/64.nis.png +0 -0
- package/codecs/tests/results/png/64.sharp.png +0 -0
- package/codecs/tests/results/png/64.upng.png +0 -0
- package/codecs/tests/webp.js +0 -0
- package/codecs/wasm/bin/codecs.wasm +0 -0
- package/codecs/wasm/bin/simd.wasm +0 -0
- package/codecs/wasm/bundle/browser.js +1 -0
- package/codecs/wasm/index.js +1 -0
- package/codecs/wasm/index.mjs +1 -0
- package/package.json +17 -4
- package/png/README.md +1 -0
- package/png/src/{crc.js → crc.mjs} +0 -0
- package/png/src/{mem.js → mem.mjs} +0 -0
- package/png/src/{png.js → png.mjs} +3 -3
- package/png/src/{zlib.js → zlib.mjs} +0 -0
- package/tsconfig.json +21 -0
- package/v2/framebuffer.js +94 -115
- package/v2/framebuffer.mjs +9 -10
- package/v2/framebuffer.rs +1264 -0
- package/v2/index.js +1 -1
- package/v2/ops/{blur.js → blur.mjs} +0 -0
- package/v2/ops/{color.js → color.mjs} +0 -0
- package/v2/ops/{crop.js → crop.mjs} +0 -0
- package/v2/ops/{fill.js → fill.mjs} +0 -0
- package/v2/ops/{flip.js → flip.mjs} +0 -0
- package/v2/ops/index.mjs +9 -0
- package/v2/ops/{iterator.js → iterator.mjs} +6 -6
- package/v2/ops/overlay.mjs +63 -0
- package/v2/ops/{resize.js → resize.mjs} +3 -3
- package/v2/ops/{rotate.js → rotate.mjs} +8 -9
- package/v2/util/{mem.js → mem.mjs} +3 -5
- package/wasm/any/font.wasm +0 -0
- package/wasm/any/png.wasm +0 -0
- package/wasm/node/png.js +49 -0
- package/node/arm64-darwin.node +0 -0
- package/node/index.js +0 -7
- package/node/x64-darwin.node +0 -0
- package/v2/ops/index.js +0 -9
- package/v2/ops/overlay.js +0 -55
- package/wasm/node.js +0 -23
- package/wasm/web.js +0 -10
package/bench/_.mjs
ADDED
|
@@ -0,0 +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;
|
|
166
|
+
}
|
package/bench/all.mjs
ADDED
package/bench/blur.mjs
ADDED
|
@@ -0,0 +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
|
+
}));
|
|
59
|
+
}
|
package/bench/flip.mjs
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
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: 'flip horizontal (256)',
|
|
23
|
+
|
|
24
|
+
results: {
|
|
25
|
+
jimp: sync(1e4, () => images.jimp.flip(true, false)),
|
|
26
|
+
imagescript: sync(1e4, () => images.v2.flip('horizontal')),
|
|
27
|
+
sharp: await async(1e4, () => images.sharp.flip().toBuffer()),
|
|
28
|
+
'image-rs (wasm)': sync(1e4, () => images.imagers.flip_horizontal()),
|
|
29
|
+
'imagescript-rs (wasm)': sync(1e4, () => v2_wasm.flip_horizontal(images.v2_wasm)),
|
|
30
|
+
},
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
images.v2_wasm.drop();
|
|
34
|
+
images.imagers.drop();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
{
|
|
38
|
+
const rgba = new Uint8Array(4 * 256 * 256).map((_, i) => i % 256);
|
|
39
|
+
|
|
40
|
+
const images = {
|
|
41
|
+
v2: new v2(256, 256, rgba),
|
|
42
|
+
imagers: imagers.framebuffer.from(256, 256, rgba),
|
|
43
|
+
v2_wasm: v2_wasm.framebuffer.from(256, 256, rgba),
|
|
44
|
+
sharp: sharp(rgba, { raw: { width: 256, height: 256, channels: 4 } }),
|
|
45
|
+
jimp: await new Promise(r => new jimp({ width: 256, height: 256, data: rgba }, (_, i) => r(i))),
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
console.log(format({
|
|
49
|
+
percentiles: false,
|
|
50
|
+
title: 'flip vertical (256)',
|
|
51
|
+
|
|
52
|
+
results: {
|
|
53
|
+
jimp: sync(1e4, () => images.jimp.flip(false, true)),
|
|
54
|
+
imagescript: sync(1e4, () => images.v2.flip('vertical')),
|
|
55
|
+
sharp: await async(1e4, () => images.sharp.flop().toBuffer()),
|
|
56
|
+
'image-rs (wasm)': sync(1e4, () => images.imagers.flip_vertical()),
|
|
57
|
+
'imagescript-rs (wasm)': sync(1e4, () => v2_wasm.flip_vertical(images.v2_wasm)),
|
|
58
|
+
},
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
images.v2_wasm.drop();
|
|
62
|
+
images.imagers.drop();
|
|
63
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
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: 'overlay(256x256)',
|
|
23
|
+
|
|
24
|
+
results: {
|
|
25
|
+
jimp: sync(1e4, () => images.jimp.composite(images.jimp, 0, 0)),
|
|
26
|
+
imagescript: sync(1e4, () => images.v2.overlay(images.v2, 0, 0)),
|
|
27
|
+
'image-rs (wasm)': sync(1e4, () => images.imagers.overlay(images.imagers, 0, 0)),
|
|
28
|
+
'imagescript-rs (wasm)': sync(1e4, () => v2_wasm.overlay(images.v2_wasm, images.v2_wasm, 0, 0)),
|
|
29
|
+
sharp: await async(1e4, () => images.sharp.composite([{ input: rgba, raw: { width: 256, height: 256, channels: 4 } }]).toBuffer()),
|
|
30
|
+
},
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
images.v2_wasm.drop();
|
|
34
|
+
images.imagers.drop();
|
|
35
|
+
}
|
package/bench/readme.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
these benchmarks are purely for v2 progress tracking
|
|
2
|
+
|
|
3
|
+
`node all.mjs`
|
|
4
|
+
```js
|
|
5
|
+
resize linear (256 -> 1024)
|
|
6
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
7
|
+
│ imagescript │ 19,503,902 ns/iter (18,861,626..27,912,168 ns/iter) │
|
|
8
|
+
│ imagescript-rs (wasm) │ 17,713,101 ns/iter (17,476,625..23,760,793 ns/iter) │
|
|
9
|
+
└─────────────────────────────────────────────────────────────────────────────┘
|
|
10
|
+
resize cubic (256 -> 1024)
|
|
11
|
+
┌────────────────────────────────────────────────────────────────────────────────┐
|
|
12
|
+
│ imagescript │ 235,246,467 ns/iter (229,790,251..354,907,209 ns/iter) │
|
|
13
|
+
│ sharp │ 14,342,381 ns/iter (10,830,958..39,727,583 ns/iter) │
|
|
14
|
+
│ imagescript-rs (wasm) │ 63,684,581 ns/iter (62,884,708..75,180,751 ns/iter) │
|
|
15
|
+
└────────────────────────────────────────────────────────────────────────────────┘
|
|
16
|
+
flip horizontal (256)
|
|
17
|
+
┌─────────────────────────────────────────────────────────────────────────────────┐
|
|
18
|
+
│ jimp │ 1,259,846 ns/iter (1,209,542..2,151,208 ns/iter) │
|
|
19
|
+
│ imagescript │ 26,333 ns/iter (24,626..93,501 ns/iter) │
|
|
20
|
+
│ sharp │ 24,134,341 ns/iter (274,959..210,144,563,500 ns/iter) │
|
|
21
|
+
│ image-rs (wasm) │ 43,797 ns/iter (43,501..74,293 ns/iter) │
|
|
22
|
+
│ imagescript-rs (wasm) │ 14,309 ns/iter (13,959..49,333 ns/iter) │
|
|
23
|
+
└─────────────────────────────────────────────────────────────────────────────────┘
|
|
24
|
+
flip vertical (256)
|
|
25
|
+
┌───────────────────────────────────────────────────────────────────────────┐
|
|
26
|
+
│ jimp │ 1,281,557 ns/iter (1,223,292..7,604,917 ns/iter) │
|
|
27
|
+
│ imagescript │ 54,151 ns/iter (53,333..89,959 ns/iter) │
|
|
28
|
+
│ sharp │ 2,552,946 ns/iter (513,959..10,188,876 ns/iter) │
|
|
29
|
+
│ image-rs (wasm) │ 30,475 ns/iter (30,167..88,250 ns/iter) │
|
|
30
|
+
│ imagescript-rs (wasm) │ 13,747 ns/iter (13,542..27,042 ns/iter) │
|
|
31
|
+
└───────────────────────────────────────────────────────────────────────────┘
|
|
32
|
+
overlay(256x256)
|
|
33
|
+
┌─────────────────────────────────────────────────────────────────────────────────┐
|
|
34
|
+
│ jimp │ 3,428,386 ns/iter (3,372,335..5,125,459 ns/iter) │
|
|
35
|
+
│ imagescript │ 259,099 ns/iter (256,583..310,334 ns/iter) │
|
|
36
|
+
│ image-rs (wasm) │ 541,678 ns/iter (533,166..1,509,710 ns/iter) │
|
|
37
|
+
│ imagescript-rs (wasm) │ 143,653 ns/iter (137,293..1,242,793 ns/iter) │
|
|
38
|
+
│ sharp │ 28,689,423 ns/iter (1,837,000..210,144,590,042 ns/iter) │
|
|
39
|
+
└─────────────────────────────────────────────────────────────────────────────────┘
|
|
40
|
+
resize nearest (256 -> 1024)
|
|
41
|
+
┌───────────────────────────────────────────────────────────────────────────────┐
|
|
42
|
+
│ imagescript │ 1,452,792 ns/iter (1,327,334..13,043,958 ns/iter) │
|
|
43
|
+
│ jimp │ 6,053,008 ns/iter (5,835,042..9,540,835 ns/iter) │
|
|
44
|
+
│ sharp │ 6,209,299 ns/iter (2,089,376..15,344,367,876 ns/iter) │
|
|
45
|
+
│ image-rs (wasm) │ 4,823,582 ns/iter (4,809,042..7,176,000 ns/iter) │
|
|
46
|
+
│ imagescript-rs (wasm) │ 600,103 ns/iter (597,042..802,751 ns/iter) │
|
|
47
|
+
└───────────────────────────────────────────────────────────────────────────────┘
|
|
48
|
+
blur (5.0f/256x256)
|
|
49
|
+
┌─────────────────────────────────────────────────────────────────────────────────┐
|
|
50
|
+
│ jimp │ 3,752,613 ns/iter (3,338,751..17,802,125 ns/iter) │
|
|
51
|
+
│ imagescript │ 1,982,010 ns/iter (1,935,459..2,907,833 ns/iter) │
|
|
52
|
+
│ sharp │ 36,079,515 ns/iter (2,465,000..210,155,512,001 ns/iter) │
|
|
53
|
+
│ image-rs (wasm) │ 6,050,020 ns/iter (6,037,125..8,032,876 ns/iter) │
|
|
54
|
+
│ imagescript-rs (wasm) │ 1,288,080 ns/iter (1,263,834..1,699,542 ns/iter) │
|
|
55
|
+
└─────────────────────────────────────────────────────────────────────────────────┘
|
|
56
|
+
blur (5.0f/1024x1024)
|
|
57
|
+
┌───────────────────────────────────────────────────────────────────────────────┐
|
|
58
|
+
│ jimp │ 105,250,057 ns/iter (89,942,042..302,817,625 ns/iter) │
|
|
59
|
+
│ imagescript │ 31,996,324 ns/iter (31,372,417..101,801,209 ns/iter) │
|
|
60
|
+
│ sharp │ 20,019,663 ns/iter (18,547,168..66,675,542 ns/iter) │
|
|
61
|
+
│ image-rs (wasm) │ 97,924,025 ns/iter (96,879,584..158,598,250 ns/iter) │
|
|
62
|
+
│ imagescript-rs (wasm) │ 20,960,014 ns/iter (20,533,709..104,136,960 ns/iter) │
|
|
63
|
+
└───────────────────────────────────────────────────────────────────────────────┘
|
|
64
|
+
```
|
package/bench/resize.mjs
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
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
|
+
const rgba = new Uint8Array(4 * 256 * 256).map((_, i) => i % 256);
|
|
9
|
+
|
|
10
|
+
const images = {
|
|
11
|
+
v2: () => new v2(256, 256, rgba),
|
|
12
|
+
v2_wasm: v2_wasm.framebuffer.from(256, 256, rgba),
|
|
13
|
+
imagers: imagers.framebuffer.from(256, 256, rgba),
|
|
14
|
+
sharp: sharp(rgba, { raw: { width: 256, height: 256, channels: 4 } }),
|
|
15
|
+
jimp: await new Promise(r => new jimp({ width: 256, height: 256, data: rgba }, (_, i) => r(i))),
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
console.log(format({
|
|
19
|
+
percentiles: false,
|
|
20
|
+
title: 'resize linear (256 -> 1024)',
|
|
21
|
+
|
|
22
|
+
results: {
|
|
23
|
+
// others don't have linear
|
|
24
|
+
imagescript: sync(1e3, () => images.v2().resize('linear', 1024, 1024)),
|
|
25
|
+
'imagescript-rs (wasm)': sync(1e3, () => v2_wasm.resize(images.v2_wasm, 'linear', 1024, 1024).drop()),
|
|
26
|
+
},
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
console.log(format({
|
|
30
|
+
percentiles: false,
|
|
31
|
+
title: 'resize cubic (256 -> 1024)',
|
|
32
|
+
|
|
33
|
+
results: {
|
|
34
|
+
// others don't have cubic
|
|
35
|
+
imagescript: sync(1e3, () => images.v2().resize('cubic', 1024, 1024)),
|
|
36
|
+
sharp: await async(1e3, () => images.sharp.resize(1024, 1024, { kernel: 'cubic' }).toBuffer()),
|
|
37
|
+
'imagescript-rs (wasm)': sync(1e3, () => v2_wasm.resize(images.v2_wasm, 'cubic', 1024, 1024).drop()),
|
|
38
|
+
},
|
|
39
|
+
}));
|
|
40
|
+
|
|
41
|
+
console.log(format({
|
|
42
|
+
percentiles: false,
|
|
43
|
+
title: 'resize nearest (256 -> 1024)',
|
|
44
|
+
|
|
45
|
+
results: {
|
|
46
|
+
imagescript: sync(1e4, () => images.v2().resize('nearest', 1024, 1024)),
|
|
47
|
+
jimp: sync(1e4, () => images.jimp.resize(1024, 1024, jimp.RESIZE_NEAREST_NEIGHBOR)),
|
|
48
|
+
sharp: await async(1e4, () => images.sharp.resize(1024, 1024, { kernel: 'nearest' }).toBuffer()),
|
|
49
|
+
'image-rs (wasm)': sync(1e4, () => imagers.resize(images.imagers, 'nearest', 1024, 1024).drop()),
|
|
50
|
+
'imagescript-rs (wasm)': sync(1e4, () => v2_wasm.resize(images.v2_wasm, 'nearest', 1024, 1024).drop()),
|
|
51
|
+
},
|
|
52
|
+
}));
|
package/codecs/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021-present matmen, evanwashere
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/codecs/lib.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
declare module '@imagescript/codecs' {
|
|
2
|
+
type wah = { width: number, height: number };
|
|
3
|
+
type jpeg_encode_options = wah & { quality?: number };
|
|
4
|
+
type webp_encode_options = wah & { quality?: number };
|
|
5
|
+
|
|
6
|
+
type png_encode_options = wah & {
|
|
7
|
+
compression?: 'fast' | 'best' | 'default',
|
|
8
|
+
filter?: 'up' | 'sub' | 'none' | 'paeth' | 'average',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type gif_frame_options = wah & {
|
|
12
|
+
x?: number,
|
|
13
|
+
y?: number,
|
|
14
|
+
delay?: number,
|
|
15
|
+
speed?: number,
|
|
16
|
+
colors?: number,
|
|
17
|
+
quality?: number,
|
|
18
|
+
dispose?: 'any' | 'keep' | 'previous' | 'background',
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class gif_encoder {
|
|
23
|
+
width: number;
|
|
24
|
+
height: number;
|
|
25
|
+
|
|
26
|
+
constructor(width: number, height: number): this;
|
|
27
|
+
add(buffer: ArrayBufferView, options: gif_frame_options): void;
|
|
28
|
+
finish(options: { repeat?: number, comment: string, application?: string }): Uint8Array;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
export interface gif {
|
|
33
|
+
encoder: gif_encoder,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface png {
|
|
37
|
+
encode(buffer: ArrayBufferView, options: png_encode_options): Uint8Array,
|
|
38
|
+
encode_async(buffer: ArrayBufferView, options: png_encode_options): Promise<Uint8Array>,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface jpeg {
|
|
42
|
+
encode(buffer: ArrayBufferView, options: png_encode_options): Uint8Array,
|
|
43
|
+
encode_async(buffer: ArrayBufferView, options: png_encode_options): Promise<Uint8Array>,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface webp {
|
|
47
|
+
encode(buffer: ArrayBufferView, options: png_encode_options): Uint8Array,
|
|
48
|
+
encode_async(buffer: ArrayBufferView, options: png_encode_options): Promise<Uint8Array>,
|
|
49
|
+
}
|
|
50
|
+
}
|
package/codecs/lib.js
ADDED
package/codecs/lib.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import lib from './lib.js';
|
|
Binary file
|
|
File without changes
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"license": "MIT",
|
|
3
|
+
"main": "lib.js",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"types": "lib.d.ts",
|
|
6
|
+
"name": "@imagescript/codecs",
|
|
7
|
+
"description": "fast codecs bindings for node and browsers",
|
|
8
|
+
"author": "imagescript (https://github.com/matmen/imagescript)",
|
|
9
|
+
"bugs": { "url": "https://github.com/matmen/imagescript/issues" },
|
|
10
|
+
"homepage": "https://github.com/matmen/ImageScript/blob/master/codecs/readme.md",
|
|
11
|
+
"repository": { "type": "git", "url": "git+https://github.com/matmen/imagescript.git" },
|
|
12
|
+
"exports": { ".": [{ "import": "./lib.mjs", "require": "./lib.js" }, "./lib.js"], "./*": "./*" },
|
|
13
|
+
"keywords": ["png", "jpg", "gif", "jpeg", "webp", "fast", "wasm", "codecs", "native", "bindings"]
|
|
14
|
+
}
|
package/codecs/readme.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# fast codecs bindings for node and browsers
|
|
2
|
+
|
|
3
|
+
`npm i @imagescript/codecs`
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
import { png } from '@imagescript/codecs';
|
|
7
|
+
|
|
8
|
+
const rgba = new Uint32Array(256 * 256);
|
|
9
|
+
const image = png.encode(rgba, { width: 256, height: 256 });
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## supported platforms
|
|
13
|
+
| | node@10 | node@12 | node@14 | node@16 |
|
|
14
|
+
| ---------------- | ------- | ------- | ------- | ------- |
|
|
15
|
+
| wasm32 | ✕ | ✕ | ✕ | ✕ |
|
|
16
|
+
| macos x64 | ✓ | ✓ | ✓ | ✓ |
|
|
17
|
+
| macos arm64 | ✓ | ✓ | ✓ | ✓ |
|
|
18
|
+
| windows x64 | ✓ | ✓ | ✓ | ✓ |
|
|
19
|
+
| linux x64 gnu | ✓ | ✓ | ✓ | ✓ |
|
|
20
|
+
| linux arm64 gnu | ✓ | ✓ | ✓ | ✓ |
|
|
21
|
+
|
|
22
|
+
you can force usage of wasm by setting `CODECS_FORCE_WASM` env variable
|
|
23
|
+
|
|
24
|
+
for deno and browsers use `@imagescript/codecs/wasm/bundle/browser.js` [cdn](https://unpkg.com/@imagescript/codecs/wasm/bundle/browser.js)
|
|
25
|
+
|
|
26
|
+
## benchmarks
|
|
27
|
+
|
|
28
|
+
image used for benchmarks: `new framebuffer(width, height).fill((x, y) => x * y)`
|
|
29
|
+
|
|
30
|
+

|
|
31
|
+
|
|
32
|
+

|
|
33
|
+
|
|
34
|
+

|
|
35
|
+
|
|
36
|
+
## License
|
|
37
|
+
|
|
38
|
+
MIT © [evan](https://github.com/evanwashere) [matmen](https://github.com/matmen)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|