forked from external-repos/squoosh
Compare commits
44 Commits
libsquoosh
...
preprocess
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ed26ec70c | ||
|
|
73b3fd0ef3 | ||
|
|
ad6f91692f | ||
|
|
7918938d8a | ||
|
|
543c2e73fb | ||
|
|
8c5b4f33bf | ||
|
|
066e9acf93 | ||
|
|
44de57a92a | ||
|
|
33347951d7 | ||
|
|
c459319b21 | ||
|
|
588ec61543 | ||
|
|
82914f9cde | ||
|
|
37f4d753f9 | ||
|
|
ce3d94297d | ||
|
|
76ef6294f3 | ||
|
|
50bc8e4106 | ||
|
|
1b8f051438 | ||
|
|
cf894b7d19 | ||
|
|
d1d181fccd | ||
|
|
a65bbdf811 | ||
|
|
7de8fa9da3 | ||
|
|
646747b039 | ||
|
|
a2fb7a38cd | ||
|
|
81890e972b | ||
|
|
c2aa35aa02 | ||
|
|
c6d936cd49 | ||
|
|
60b79da936 | ||
|
|
dbd80f15eb | ||
|
|
ed3c79894d | ||
|
|
213028cfdd | ||
|
|
952aea049d | ||
|
|
e3b053db12 | ||
|
|
b8574b228a | ||
|
|
ee8ea539e7 | ||
|
|
a7a991ae45 | ||
|
|
32232c7f0b | ||
|
|
bb78632cf5 | ||
|
|
68cd15bd14 | ||
|
|
bde3a93b6e | ||
|
|
7aeef5ff37 | ||
|
|
0ee234f03b | ||
|
|
8105633ca6 | ||
|
|
46764f3375 | ||
|
|
0371cfd292 |
44
README.md
44
README.md
@@ -1,42 +1,36 @@
|
|||||||
# [Squoosh]!
|
# [Squoosh]!
|
||||||
|
|
||||||
[Squoosh] is an image compression web app that reduces image sizes through numerous formats.
|
[Squoosh] is an image compression web app that allows you to dive into the advanced options provided
|
||||||
|
by various image compressors.
|
||||||
|
|
||||||
# API & CLI
|
# API & CLI
|
||||||
|
|
||||||
Squoosh has [an API](https://github.com/GoogleChromeLabs/squoosh/tree/dev/libsquoosh) and [a CLI](https://github.com/GoogleChromeLabs/squoosh/tree/dev/cli) to compress many images at once.
|
Squoosh now has [an API](https://github.com/GoogleChromeLabs/squoosh/tree/dev/libsquoosh) and [a CLI](https://github.com/GoogleChromeLabs/squoosh/tree/dev/cli) that allows you to compress many images at once.
|
||||||
|
|
||||||
# Privacy
|
# Privacy
|
||||||
|
|
||||||
Squoosh does not send your image to a server. All image compression processes locally.
|
Google Analytics is used to record the following:
|
||||||
|
|
||||||
However, Squoosh utilizes Google Analytics to collect the following:
|
- [Basic visit data](https://support.google.com/analytics/answer/6004245?ref_topic=2919631).
|
||||||
|
- Before and after image size once an image is downloaded. These values are rounded to the nearest
|
||||||
|
kilobyte.
|
||||||
|
- If install is available, when Squoosh is installed, and what method was used to install Squoosh.
|
||||||
|
|
||||||
- [Basic visitor data](https://support.google.com/analytics/answer/6004245?ref_topic=2919631).
|
Image compression is handled locally; no additional data is sent to the server.
|
||||||
- The before and after image size value.
|
|
||||||
- If Squoosh PWA, the type of Squoosh installation.
|
|
||||||
- If Squoosh PWA, the installation time and date.
|
|
||||||
|
|
||||||
# Developing
|
# Building locally
|
||||||
|
|
||||||
To develop for Squoosh:
|
Clone the repo, and:
|
||||||
|
|
||||||
1. Clone the repository
|
```sh
|
||||||
1. To install node packages, run:
|
npm install
|
||||||
```sh
|
npm run build
|
||||||
npm install
|
```
|
||||||
```
|
|
||||||
1. Then build the app by running:
|
|
||||||
```sh
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
1. After building, start the development server by running:
|
|
||||||
```sh
|
|
||||||
npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
# Contributing
|
You can run the development server with:
|
||||||
|
|
||||||
Squoosh is an open-source project that appreciates all community involvement. To contribute to the project, follow the [contribute guide](/CONTRIBUTING.md).
|
```sh
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
[squoosh]: https://squoosh.app
|
[squoosh]: https://squoosh.app
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ Options:
|
|||||||
-h, --help display help for command
|
-h, --help display help for command
|
||||||
```
|
```
|
||||||
|
|
||||||
The default values for each `config` option can be found in the [`codecs.ts`][codecs.ts] file under `defaultEncoderOptions`. Every unspecified value will use the default value specified here. _Better documentation is needed here._
|
The default values for each `config` option can be found in the [`codecs.js`][codecs.js] file under `defaultEncoderOptions`. Every unspecified value will use the default value specified here. _Better documentation is needed here._
|
||||||
|
|
||||||
## Auto optimizer
|
## Auto optimizer
|
||||||
|
|
||||||
@@ -55,5 +55,5 @@ $ npx @squoosh/cli --wp2 auto test.png
|
|||||||
```
|
```
|
||||||
|
|
||||||
[squoosh]: https://squoosh.app
|
[squoosh]: https://squoosh.app
|
||||||
[codecs.ts]: https://github.com/GoogleChromeLabs/squoosh/blob/dev/libsquoosh/src/codecs.ts
|
[codecs.js]: https://github.com/GoogleChromeLabs/squoosh/blob/dev/libsquoosh/src/codecs.js
|
||||||
[butteraugli]: https://github.com/google/butteraugli
|
[butteraugli]: https://github.com/google/butteraugli
|
||||||
|
|||||||
36
cli/package-lock.json
generated
36
cli/package-lock.json
generated
@@ -1,15 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "@squoosh/cli",
|
"name": "@squoosh/cli",
|
||||||
"version": "0.7.2",
|
"version": "0.7.0",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@squoosh/cli",
|
"name": "@squoosh/cli",
|
||||||
"version": "0.7.2",
|
"version": "0.7.0",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@squoosh/lib": "^0.4.0",
|
"@squoosh/lib": "^0.2.0",
|
||||||
"commander": "^7.2.0",
|
"commander": "^7.2.0",
|
||||||
"json5": "^2.2.0",
|
"json5": "^2.2.0",
|
||||||
"kleur": "^4.1.4",
|
"kleur": "^4.1.4",
|
||||||
@@ -18,21 +18,14 @@
|
|||||||
"bin": {
|
"bin": {
|
||||||
"cli": "src/index.js",
|
"cli": "src/index.js",
|
||||||
"squoosh-cli": "src/index.js"
|
"squoosh-cli": "src/index.js"
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": " ^12.20.2 || ^14.13.1 || ^16.0.0 "
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@squoosh/lib": {
|
"node_modules/@squoosh/lib": {
|
||||||
"version": "0.4.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@squoosh/lib/-/lib-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@squoosh/lib/-/lib-0.2.0.tgz",
|
||||||
"integrity": "sha512-O1LyugWLZjMI4JZeZMA5vzfhfPjfMZXH5/HmVkRagP8B70wH3uoR7tjxfGNdSavey357MwL8YJDxbGwBBdHp7Q==",
|
"integrity": "sha512-zKId9h/LzEnCdoOGnIgjzvqbk5g2aHgfEqgKQ+S+r5K3TasgD/DAsT6r7v6gXft1ao0f/00CTcwIp1KviWTQbw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"wasm-feature-detect": "^1.2.11",
|
|
||||||
"web-streams-polyfill": "^3.0.3"
|
"web-streams-polyfill": "^3.0.3"
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": " ^12.5.0 || ^14.0.0 || ^16.0.0 "
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ansi-regex": {
|
"node_modules/ansi-regex": {
|
||||||
@@ -330,11 +323,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||||
},
|
},
|
||||||
"node_modules/wasm-feature-detect": {
|
|
||||||
"version": "1.2.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.2.11.tgz",
|
|
||||||
"integrity": "sha512-HUqwaodrQGaZgz1lZaNioIkog9tkeEJjrM3eq4aUL04whXOVDRc/o2EGb/8kV0QX411iAYWEqq7fMBmJ6dKS6w=="
|
|
||||||
},
|
|
||||||
"node_modules/wcwidth": {
|
"node_modules/wcwidth": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
|
||||||
@@ -354,11 +342,10 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@squoosh/lib": {
|
"@squoosh/lib": {
|
||||||
"version": "0.4.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@squoosh/lib/-/lib-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@squoosh/lib/-/lib-0.2.0.tgz",
|
||||||
"integrity": "sha512-O1LyugWLZjMI4JZeZMA5vzfhfPjfMZXH5/HmVkRagP8B70wH3uoR7tjxfGNdSavey357MwL8YJDxbGwBBdHp7Q==",
|
"integrity": "sha512-zKId9h/LzEnCdoOGnIgjzvqbk5g2aHgfEqgKQ+S+r5K3TasgD/DAsT6r7v6gXft1ao0f/00CTcwIp1KviWTQbw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"wasm-feature-detect": "^1.2.11",
|
|
||||||
"web-streams-polyfill": "^3.0.3"
|
"web-streams-polyfill": "^3.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -591,11 +578,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||||
},
|
},
|
||||||
"wasm-feature-detect": {
|
|
||||||
"version": "1.2.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.2.11.tgz",
|
|
||||||
"integrity": "sha512-HUqwaodrQGaZgz1lZaNioIkog9tkeEJjrM3eq4aUL04whXOVDRc/o2EGb/8kV0QX411iAYWEqq7fMBmJ6dKS6w=="
|
|
||||||
},
|
|
||||||
"wcwidth": {
|
"wcwidth": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
|
||||||
|
|||||||
@@ -1,14 +1,9 @@
|
|||||||
{
|
{
|
||||||
"name": "@squoosh/cli",
|
"name": "@squoosh/cli",
|
||||||
"version": "0.7.2",
|
"version": "0.7.0",
|
||||||
"description": "A CLI for Squoosh",
|
"description": "A CLI for Squoosh",
|
||||||
"public": true,
|
"public": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"homepage": "https://github.com/GoogleChromeLabs/squoosh",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/GoogleChromeLabs/squoosh.git"
|
|
||||||
},
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"squoosh-cli": "src/index.js",
|
"squoosh-cli": "src/index.js",
|
||||||
"@squoosh/cli": "src/index.js"
|
"@squoosh/cli": "src/index.js"
|
||||||
@@ -19,11 +14,8 @@
|
|||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "Google Chrome Developers <chromium-dev@google.com>",
|
"author": "Google Chrome Developers <chromium-dev@google.com>",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
|
||||||
"node": " ^12.20.2 || ^14.13.1 || ^16.0.0 "
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@squoosh/lib": "^0.4.0",
|
"@squoosh/lib": "^0.2.0",
|
||||||
"commander": "^7.2.0",
|
"commander": "^7.2.0",
|
||||||
"json5": "^2.2.0",
|
"json5": "^2.2.0",
|
||||||
"kleur": "^4.1.4",
|
"kleur": "^4.1.4",
|
||||||
|
|||||||
@@ -75,7 +75,9 @@ async function getInputFiles(paths) {
|
|||||||
|
|
||||||
for (const inputPath of paths) {
|
for (const inputPath of paths) {
|
||||||
const files = (await fsp.lstat(inputPath)).isDirectory()
|
const files = (await fsp.lstat(inputPath)).isDirectory()
|
||||||
? (await fsp.readdir(inputPath, {withFileTypes: true})).filter(dirent => dirent.isFile()).map(dirent => path.join(inputPath, dirent.name))
|
? (await fsp.readdir(inputPath, { withFileTypes: true }))
|
||||||
|
.filter((dirent) => dirent.isFile())
|
||||||
|
.map((dirent) => path.join(inputPath, dirent.name))
|
||||||
: [inputPath];
|
: [inputPath];
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
try {
|
try {
|
||||||
@@ -177,8 +179,8 @@ async function processFiles(files) {
|
|||||||
jobsFinished++;
|
jobsFinished++;
|
||||||
const outputPath = path.join(
|
const outputPath = path.join(
|
||||||
program.opts().outputDir,
|
program.opts().outputDir,
|
||||||
path.basename(originalFile, path.extname(originalFile)) +
|
program.opts().suffix +
|
||||||
program.opts().suffix
|
path.basename(originalFile, path.extname(originalFile)),
|
||||||
);
|
);
|
||||||
for (const output of Object.values(image.encodedWith)) {
|
for (const output of Object.values(image.encodedWith)) {
|
||||||
const outputFile = `${outputPath}.${(await output).extension}`;
|
const outputFile = `${outputPath}.${(await output).extension}`;
|
||||||
|
|||||||
@@ -10,16 +10,13 @@ export CODEC_DIR = node_modules/libavif
|
|||||||
export BUILD_DIR = node_modules/build
|
export BUILD_DIR = node_modules/build
|
||||||
export LIBAOM_DIR = node_modules/libaom
|
export LIBAOM_DIR = node_modules/libaom
|
||||||
|
|
||||||
override CFLAGS += "-Wno-unused-macros"
|
|
||||||
export
|
|
||||||
|
|
||||||
OUT_ENC_JS = enc/avif_enc.js
|
OUT_ENC_JS = enc/avif_enc.js
|
||||||
OUT_NODE_ENC_JS = enc/avif_node_enc.js
|
OUT_NODE_ENC_JS = enc/avif_node_enc.js
|
||||||
OUT_ENC_MT_JS = enc/avif_enc_mt.js
|
OUT_ENC_MT_JS = enc/avif_enc_mt.js
|
||||||
OUT_NODE_ENC_MT_JS = enc/avif_node_enc_mt.js
|
|
||||||
OUT_DEC_JS = dec/avif_dec.js
|
OUT_DEC_JS = dec/avif_dec.js
|
||||||
OUT_NODE_DEC_JS = dec/avif_node_dec.js
|
OUT_NODE_DEC_JS = dec/avif_node_dec.js
|
||||||
|
|
||||||
|
OUT_ENC_CPP = enc/avif_enc.cpp
|
||||||
OUT_ENC_CPP = enc/avif_enc.cpp
|
OUT_ENC_CPP = enc/avif_enc.cpp
|
||||||
OUT_DEC_CPP = dec/avif_dec.cpp
|
OUT_DEC_CPP = dec/avif_dec.cpp
|
||||||
ENVIRONMENT = worker
|
ENVIRONMENT = worker
|
||||||
@@ -28,9 +25,9 @@ HELPER_MAKEFLAGS := -f helper.Makefile
|
|||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
|
|
||||||
all: $(OUT_ENC_JS) $(OUT_DEC_JS) $(OUT_ENC_MT_JS) $(OUT_NODE_ENC_JS) $(OUT_NODE_ENC_MT_JS) $(OUT_NODE_DEC_JS)
|
all: $(OUT_ENC_JS) $(OUT_DEC_JS) $(OUT_ENC_MT_JS) $(OUT_NODE_ENC_JS) $(OUT_NODE_DEC_JS)
|
||||||
|
|
||||||
$(OUT_NODE_ENC_JS) $(OUT_NODE_ENC_MT_JS): ENVIRONMENT=node
|
$(OUT_NODE_ENC_JS): ENVIRONMENT=node
|
||||||
$(OUT_NODE_ENC_JS) $(OUT_ENC_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt
|
$(OUT_NODE_ENC_JS) $(OUT_ENC_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt
|
||||||
$(MAKE) \
|
$(MAKE) \
|
||||||
$(HELPER_MAKEFLAGS) \
|
$(HELPER_MAKEFLAGS) \
|
||||||
@@ -44,7 +41,7 @@ $(OUT_NODE_ENC_JS) $(OUT_ENC_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(L
|
|||||||
ENVIRONMENT=$(ENVIRONMENT) \
|
ENVIRONMENT=$(ENVIRONMENT) \
|
||||||
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_DECODE=0"
|
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_DECODE=0"
|
||||||
|
|
||||||
$(OUT_ENC_MT_JS) $(OUT_NODE_ENC_MT_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt
|
$(OUT_ENC_MT_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt
|
||||||
$(MAKE) \
|
$(MAKE) \
|
||||||
$(HELPER_MAKEFLAGS) \
|
$(HELPER_MAKEFLAGS) \
|
||||||
OUT_JS=$@ \
|
OUT_JS=$@ \
|
||||||
@@ -89,7 +86,4 @@ $(LIBAOM_DIR)/CMakeLists.txt: $(LIBAOM_PACKAGE)
|
|||||||
clean:
|
clean:
|
||||||
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_ENC_JS) clean
|
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_ENC_JS) clean
|
||||||
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_ENC_MT_JS) clean
|
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_ENC_MT_JS) clean
|
||||||
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_ENC_NODE_JS) clean
|
|
||||||
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_ENC_NODE_MT_JS) clean
|
|
||||||
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_DEC_JS) clean
|
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_DEC_JS) clean
|
||||||
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_DEV_NODE_JS) clean
|
|
||||||
|
|||||||
43
codecs/avif/dec/avif_dec.js
generated
43
codecs/avif/dec/avif_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
43
codecs/avif/dec/avif_node_dec.js
generated
43
codecs/avif/dec/avif_node_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
49
codecs/avif/enc/avif_enc.js
generated
49
codecs/avif/enc/avif_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
82
codecs/avif/enc/avif_enc_mt.js
generated
82
codecs/avif/enc/avif_enc_mt.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
2
codecs/avif/enc/avif_enc_mt.worker.js
generated
2
codecs/avif/enc/avif_enc_mt.worker.js
generated
@@ -1 +1 @@
|
|||||||
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./avif_enc_mt.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,0,0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./avif_enc_mt.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,/*isMainBrowserThread=*/0,/*isMainRuntimeThread=*/0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
||||||
|
|||||||
48
codecs/avif/enc/avif_node_enc.js
generated
48
codecs/avif/enc/avif_node_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
16
codecs/avif/enc/avif_node_enc_mt.js
generated
16
codecs/avif/enc/avif_node_enc_mt.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
1
codecs/avif/enc/avif_node_enc_mt.worker.js
generated
1
codecs/avif/enc/avif_node_enc_mt.worker.js
generated
@@ -1 +0,0 @@
|
|||||||
"use strict";var Module={};if(typeof process==="object"&&typeof process.versions==="object"&&typeof process.versions.node==="string"){var nodeWorkerThreads=require("worker_threads");var parentPort=nodeWorkerThreads.parentPort;parentPort.on("message",function(data){onmessage({data:data})});var nodeFS=require("fs");Object.assign(global,{self:global,require:require,Module:Module,location:{href:__filename},Worker:nodeWorkerThreads.Worker,importScripts:function(f){(0,eval)(nodeFS.readFileSync(f,"utf8"))},postMessage:function(msg){parentPort.postMessage(msg)},performance:global.performance||{now:function(){return Date.now()}}})}var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./avif_node_enc_mt.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,0,0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
FROM emscripten/emsdk:2.0.23
|
FROM emscripten/emsdk:2.0.21
|
||||||
RUN apt-get update && apt-get install -qqy autoconf libtool pkg-config
|
RUN apt-get update && apt-get install -qqy autoconf libtool pkg-config
|
||||||
ENV CFLAGS "-O3 -flto"
|
ENV CFLAGS "-O3 -flto"
|
||||||
ENV CXXFLAGS "${CFLAGS} -std=c++17"
|
ENV CXXFLAGS "${CFLAGS} -std=c++17"
|
||||||
ENV LDFLAGS "${CFLAGS} \
|
ENV LDFLAGS "${CFLAGS} \
|
||||||
|
--closure 1 \
|
||||||
-s FILESYSTEM=0 \
|
-s FILESYSTEM=0 \
|
||||||
-s PTHREAD_POOL_SIZE=navigator.hardwareConcurrency \
|
-s PTHREAD_POOL_SIZE=navigator.hardwareConcurrency \
|
||||||
-s ALLOW_MEMORY_GROWTH=1 \
|
-s ALLOW_MEMORY_GROWTH=1 \
|
||||||
-s TEXTDECODER=2 \
|
-s TEXTDECODER=2 \
|
||||||
-s NODEJS_CATCH_EXIT=0 -s NODEJS_CATCH_REJECTION=0 \
|
|
||||||
"
|
"
|
||||||
# Build and cache standard libraries with these flags + Embind.
|
# Build and cache standard libraries with these flags + Embind.
|
||||||
RUN emcc ${CXXFLAGS} ${LDFLAGS} --bind -xc++ /dev/null -o /dev/null
|
RUN emcc ${CXXFLAGS} ${LDFLAGS} --bind -xc++ /dev/null -o /dev/null
|
||||||
|
|||||||
41
codecs/imagequant/imagequant.js
generated
41
codecs/imagequant/imagequant.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
41
codecs/imagequant/imagequant_node.js
generated
41
codecs/imagequant/imagequant_node.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1,5 +1,5 @@
|
|||||||
CODEC_URL = https://github.com/libjxl/libjxl.git
|
CODEC_URL = https://gitlab.com/wg1/jpeg-xl.git
|
||||||
CODEC_VERSION = v0.5
|
CODEC_VERSION = ab7c5e9b6795134377aa4846ceaae2c5bc504f76
|
||||||
CODEC_DIR = node_modules/jxl
|
CODEC_DIR = node_modules/jxl
|
||||||
CODEC_BUILD_ROOT := $(CODEC_DIR)/build
|
CODEC_BUILD_ROOT := $(CODEC_DIR)/build
|
||||||
CODEC_MT_BUILD_DIR := $(CODEC_BUILD_ROOT)/mt
|
CODEC_MT_BUILD_DIR := $(CODEC_BUILD_ROOT)/mt
|
||||||
|
|||||||
42
codecs/jxl/dec/jxl_dec.js
generated
42
codecs/jxl/dec/jxl_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
42
codecs/jxl/dec/jxl_node_dec.js
generated
42
codecs/jxl/dec/jxl_node_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -10,13 +10,15 @@ using namespace emscripten;
|
|||||||
thread_local const val Uint8Array = val::global("Uint8Array");
|
thread_local const val Uint8Array = val::global("Uint8Array");
|
||||||
|
|
||||||
struct JXLOptions {
|
struct JXLOptions {
|
||||||
int effort;
|
// 1 = slowest
|
||||||
|
// 7 = fastest
|
||||||
|
int speed;
|
||||||
float quality;
|
float quality;
|
||||||
bool progressive;
|
bool progressive;
|
||||||
int epf;
|
int epf;
|
||||||
|
int nearLossless;
|
||||||
bool lossyPalette;
|
bool lossyPalette;
|
||||||
size_t decodingSpeedTier;
|
size_t decodingSpeedTier;
|
||||||
float photonNoiseIso;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
val encode(std::string image, int width, int height, JXLOptions options) {
|
val encode(std::string image, int width, int height, JXLOptions options) {
|
||||||
@@ -31,20 +33,15 @@ val encode(std::string image, int width, int height, JXLOptions options) {
|
|||||||
pool_ptr = &pool;
|
pool_ptr = &pool;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size_t st = 10 - options.effort;
|
|
||||||
cparams.speed_tier = jxl::SpeedTier(st);
|
|
||||||
|
|
||||||
cparams.epf = options.epf;
|
cparams.epf = options.epf;
|
||||||
|
cparams.speed_tier = static_cast<jxl::SpeedTier>(options.speed);
|
||||||
|
cparams.near_lossless = options.nearLossless;
|
||||||
cparams.decoding_speed_tier = options.decodingSpeedTier;
|
cparams.decoding_speed_tier = options.decodingSpeedTier;
|
||||||
cparams.photon_noise_iso = options.photonNoiseIso;
|
|
||||||
|
|
||||||
if (options.lossyPalette) {
|
if (options.lossyPalette) {
|
||||||
cparams.lossy_palette = true;
|
cparams.lossy_palette = true;
|
||||||
cparams.palette_colors = 0;
|
cparams.palette_colors = 0;
|
||||||
cparams.options.predictor = jxl::Predictor::Zero;
|
cparams.options.predictor = jxl::Predictor::Zero;
|
||||||
// Near-lossless assumes -R 0
|
|
||||||
cparams.responsive = 0;
|
|
||||||
cparams.modular_mode = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float quality = options.quality;
|
float quality = options.quality;
|
||||||
@@ -80,6 +77,12 @@ val encode(std::string image, int width, int height, JXLOptions options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cparams.near_lossless) {
|
||||||
|
// Near-lossless assumes -R 0
|
||||||
|
cparams.responsive = 0;
|
||||||
|
cparams.modular_mode = true;
|
||||||
|
}
|
||||||
|
|
||||||
io.metadata.m.SetAlphaBits(8);
|
io.metadata.m.SetAlphaBits(8);
|
||||||
if (!io.metadata.size.Set(width, height)) {
|
if (!io.metadata.size.Set(width, height)) {
|
||||||
return val::null();
|
return val::null();
|
||||||
@@ -107,12 +110,12 @@ val encode(std::string image, int width, int height, JXLOptions options) {
|
|||||||
|
|
||||||
EMSCRIPTEN_BINDINGS(my_module) {
|
EMSCRIPTEN_BINDINGS(my_module) {
|
||||||
value_object<JXLOptions>("JXLOptions")
|
value_object<JXLOptions>("JXLOptions")
|
||||||
.field("effort", &JXLOptions::effort)
|
.field("speed", &JXLOptions::speed)
|
||||||
.field("quality", &JXLOptions::quality)
|
.field("quality", &JXLOptions::quality)
|
||||||
.field("progressive", &JXLOptions::progressive)
|
.field("progressive", &JXLOptions::progressive)
|
||||||
|
.field("nearLossless", &JXLOptions::nearLossless)
|
||||||
.field("lossyPalette", &JXLOptions::lossyPalette)
|
.field("lossyPalette", &JXLOptions::lossyPalette)
|
||||||
.field("decodingSpeedTier", &JXLOptions::decodingSpeedTier)
|
.field("decodingSpeedTier", &JXLOptions::decodingSpeedTier)
|
||||||
.field("photonNoiseIso", &JXLOptions::photonNoiseIso)
|
|
||||||
.field("epf", &JXLOptions::epf);
|
.field("epf", &JXLOptions::epf);
|
||||||
|
|
||||||
function("encode", &encode);
|
function("encode", &encode);
|
||||||
|
|||||||
4
codecs/jxl/enc/jxl_enc.d.ts
vendored
4
codecs/jxl/enc/jxl_enc.d.ts
vendored
@@ -1,11 +1,11 @@
|
|||||||
export interface EncodeOptions {
|
export interface EncodeOptions {
|
||||||
effort: number;
|
speed: number;
|
||||||
quality: number;
|
quality: number;
|
||||||
progressive: boolean;
|
progressive: boolean;
|
||||||
epf: number;
|
epf: number;
|
||||||
|
nearLossless: number;
|
||||||
lossyPalette: boolean;
|
lossyPalette: boolean;
|
||||||
decodingSpeedTier: number;
|
decodingSpeedTier: number;
|
||||||
photonNoiseIso: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface JXLModule extends EmscriptenWasm.Module {
|
export interface JXLModule extends EmscriptenWasm.Module {
|
||||||
|
|||||||
55
codecs/jxl/enc/jxl_enc.js
generated
55
codecs/jxl/enc/jxl_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
91
codecs/jxl/enc/jxl_enc_mt.js
generated
91
codecs/jxl/enc/jxl_enc_mt.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
2
codecs/jxl/enc/jxl_enc_mt.worker.js
generated
2
codecs/jxl/enc/jxl_enc_mt.worker.js
generated
@@ -1 +1 @@
|
|||||||
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./jxl_enc_mt.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,0,0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./jxl_enc_mt.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,/*isMainBrowserThread=*/0,/*isMainRuntimeThread=*/0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
||||||
|
|||||||
91
codecs/jxl/enc/jxl_enc_mt_simd.js
generated
91
codecs/jxl/enc/jxl_enc_mt_simd.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
2
codecs/jxl/enc/jxl_enc_mt_simd.worker.js
generated
2
codecs/jxl/enc/jxl_enc_mt_simd.worker.js
generated
@@ -1 +1 @@
|
|||||||
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./jxl_enc_mt_simd.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,0,0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./jxl_enc_mt_simd.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,/*isMainBrowserThread=*/0,/*isMainRuntimeThread=*/0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
||||||
|
|||||||
56
codecs/jxl/enc/jxl_node_enc.js
generated
56
codecs/jxl/enc/jxl_node_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
43
codecs/mozjpeg/dec/mozjpeg_node_dec.js
generated
43
codecs/mozjpeg/dec/mozjpeg_node_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -158,11 +158,6 @@ val encode(std::string image_in, int image_width, int image_height, MozJpegOptio
|
|||||||
if (!opts.auto_subsample && opts.color_space == JCS_YCbCr) {
|
if (!opts.auto_subsample && opts.color_space == JCS_YCbCr) {
|
||||||
cinfo.comp_info[0].h_samp_factor = opts.chroma_subsample;
|
cinfo.comp_info[0].h_samp_factor = opts.chroma_subsample;
|
||||||
cinfo.comp_info[0].v_samp_factor = opts.chroma_subsample;
|
cinfo.comp_info[0].v_samp_factor = opts.chroma_subsample;
|
||||||
|
|
||||||
if (opts.chroma_subsample > 2) {
|
|
||||||
// Otherwise encoding fails.
|
|
||||||
jpeg_c_set_int_param(&cinfo, JINT_DC_SCAN_OPT_MODE, 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!opts.baseline && opts.progressive) {
|
if (!opts.baseline && opts.progressive) {
|
||||||
|
|||||||
45
codecs/mozjpeg/enc/mozjpeg_enc.js
generated
45
codecs/mozjpeg/enc/mozjpeg_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
45
codecs/mozjpeg/enc/mozjpeg_node_enc.js
generated
45
codecs/mozjpeg/enc/mozjpeg_node_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
@@ -53,11 +53,7 @@ where
|
|||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn decode(mut data: &[u8]) -> ImageData {
|
pub fn decode(mut data: &[u8]) -> ImageData {
|
||||||
let mut decoder = png::Decoder::new(&mut data);
|
let mut decoder = png::Decoder::new(&mut data);
|
||||||
decoder.set_transformations(
|
decoder.set_transformations(png::Transformations::EXPAND);
|
||||||
png::Transformations::EXPAND | // Turn paletted images into RGB
|
|
||||||
png::Transformations::PACKING | // Turn images <8bit to 8bit
|
|
||||||
png::Transformations::STRIP_16, // Turn 16bit into 8 bit
|
|
||||||
);
|
|
||||||
let (info, mut reader) = decoder.read_info().unwrap_throw();
|
let (info, mut reader) = decoder.read_info().unwrap_throw();
|
||||||
let num_pixels = (info.width * info.height) as usize;
|
let num_pixels = (info.width * info.height) as usize;
|
||||||
let mut buf = vec![0; num_pixels * 4];
|
let mut buf = vec![0; num_pixels * 4];
|
||||||
|
|||||||
4
codecs/resize/pkg/squoosh_resize.d.ts
generated
vendored
4
codecs/resize/pkg/squoosh_resize.d.ts
generated
vendored
@@ -9,9 +9,9 @@
|
|||||||
* @param {number} typ_idx
|
* @param {number} typ_idx
|
||||||
* @param {boolean} premultiply
|
* @param {boolean} premultiply
|
||||||
* @param {boolean} color_space_conversion
|
* @param {boolean} color_space_conversion
|
||||||
* @returns {Uint8ClampedArray}
|
* @returns {Uint8Array}
|
||||||
*/
|
*/
|
||||||
export function resize(input_image: Uint8Array, input_width: number, input_height: number, output_width: number, output_height: number, typ_idx: number, premultiply: boolean, color_space_conversion: boolean): Uint8ClampedArray;
|
export function resize(input_image: Uint8Array, input_width: number, input_height: number, output_width: number, output_height: number, typ_idx: number, premultiply: boolean, color_space_conversion: boolean): Uint8Array;
|
||||||
|
|
||||||
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
||||||
|
|
||||||
|
|||||||
16
codecs/resize/pkg/squoosh_resize.js
generated
16
codecs/resize/pkg/squoosh_resize.js
generated
@@ -26,16 +26,8 @@ function getInt32Memory0() {
|
|||||||
return cachegetInt32Memory0;
|
return cachegetInt32Memory0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let cachegetUint8ClampedMemory0 = null;
|
function getArrayU8FromWasm0(ptr, len) {
|
||||||
function getUint8ClampedMemory0() {
|
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len);
|
||||||
if (cachegetUint8ClampedMemory0 === null || cachegetUint8ClampedMemory0.buffer !== wasm.memory.buffer) {
|
|
||||||
cachegetUint8ClampedMemory0 = new Uint8ClampedArray(wasm.memory.buffer);
|
|
||||||
}
|
|
||||||
return cachegetUint8ClampedMemory0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getClampedArrayU8FromWasm0(ptr, len) {
|
|
||||||
return getUint8ClampedMemory0().subarray(ptr / 1, ptr / 1 + len);
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param {Uint8Array} input_image
|
* @param {Uint8Array} input_image
|
||||||
@@ -46,7 +38,7 @@ function getClampedArrayU8FromWasm0(ptr, len) {
|
|||||||
* @param {number} typ_idx
|
* @param {number} typ_idx
|
||||||
* @param {boolean} premultiply
|
* @param {boolean} premultiply
|
||||||
* @param {boolean} color_space_conversion
|
* @param {boolean} color_space_conversion
|
||||||
* @returns {Uint8ClampedArray}
|
* @returns {Uint8Array}
|
||||||
*/
|
*/
|
||||||
export function resize(input_image, input_width, input_height, output_width, output_height, typ_idx, premultiply, color_space_conversion) {
|
export function resize(input_image, input_width, input_height, output_width, output_height, typ_idx, premultiply, color_space_conversion) {
|
||||||
try {
|
try {
|
||||||
@@ -56,7 +48,7 @@ export function resize(input_image, input_width, input_height, output_width, out
|
|||||||
wasm.resize(retptr, ptr0, len0, input_width, input_height, output_width, output_height, typ_idx, premultiply, color_space_conversion);
|
wasm.resize(retptr, ptr0, len0, input_width, input_height, output_width, output_height, typ_idx, premultiply, color_space_conversion);
|
||||||
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
||||||
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
||||||
var v1 = getClampedArrayU8FromWasm0(r0, r1).slice();
|
var v1 = getArrayU8FromWasm0(r0, r1).slice();
|
||||||
wasm.__wbindgen_free(r0, r1 * 1);
|
wasm.__wbindgen_free(r0, r1 * 1);
|
||||||
return v1;
|
return v1;
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Binary file not shown.
7
codecs/resize/pkg/squoosh_resize_bg.wasm.d.ts
generated
vendored
7
codecs/resize/pkg/squoosh_resize_bg.wasm.d.ts
generated
vendored
@@ -1,7 +0,0 @@
|
|||||||
/* tslint:disable */
|
|
||||||
/* eslint-disable */
|
|
||||||
export const memory: WebAssembly.Memory;
|
|
||||||
export function resize(a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number): void;
|
|
||||||
export function __wbindgen_add_to_stack_pointer(a: number): number;
|
|
||||||
export function __wbindgen_malloc(a: number): number;
|
|
||||||
export function __wbindgen_free(a: number, b: number): void;
|
|
||||||
@@ -8,7 +8,6 @@ use cfg_if::cfg_if;
|
|||||||
use resize::Pixel;
|
use resize::Pixel;
|
||||||
use resize::Type;
|
use resize::Type;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use wasm_bindgen::Clamped;
|
|
||||||
|
|
||||||
mod srgb;
|
mod srgb;
|
||||||
use srgb::{linear_to_srgb, Clamp};
|
use srgb::{linear_to_srgb, Clamp};
|
||||||
@@ -67,7 +66,7 @@ pub fn resize(
|
|||||||
typ_idx: usize,
|
typ_idx: usize,
|
||||||
premultiply: bool,
|
premultiply: bool,
|
||||||
color_space_conversion: bool,
|
color_space_conversion: bool,
|
||||||
) -> Clamped<Vec<u8>> {
|
) -> Vec<u8> {
|
||||||
let typ = match typ_idx {
|
let typ = match typ_idx {
|
||||||
0 => Type::Triangle,
|
0 => Type::Triangle,
|
||||||
1 => Type::Catrom,
|
1 => Type::Catrom,
|
||||||
@@ -92,7 +91,7 @@ pub fn resize(
|
|||||||
typ,
|
typ,
|
||||||
);
|
);
|
||||||
resizer.resize(input_image.as_slice(), output_image.as_mut_slice());
|
resizer.resize(input_image.as_slice(), output_image.as_mut_slice());
|
||||||
return Clamped(output_image);
|
return output_image;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, we convert to f32 images to keep the
|
// Otherwise, we convert to f32 images to keep the
|
||||||
@@ -139,5 +138,5 @@ pub fn resize(
|
|||||||
.clamp(0.0, 255.0) as u8;
|
.clamp(0.0, 255.0) as u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Clamped(output_image);
|
return output_image;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
This codec currently needs monkey-patching of Emscripten
|
|
||||||
|
|
||||||
```
|
|
||||||
$ docker run --rm -it -v $(PWD):/src squoosh-cpp "/bin/bash"
|
|
||||||
# cat << EOF | patch /emsdk/upstream/emscripten/system/lib/dlmalloc.c
|
|
||||||
659c659
|
|
||||||
< #define MALLOC_ALIGNMENT ((size_t)(2 * sizeof(void *)))
|
|
||||||
---
|
|
||||||
> #define MALLOC_ALIGNMENT ((size_t)(16U))
|
|
||||||
EOF
|
|
||||||
# emcc --clear-cache
|
|
||||||
# /emsdk/upstream/emscripten/embuilder build libdlmalloc --force
|
|
||||||
# emmake make
|
|
||||||
```
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "avif",
|
"name": "avif",
|
||||||
"type": "module",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "../build-cpp.sh"
|
"build": "../build-cpp.sh"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,19 +5,12 @@
|
|||||||
using namespace emscripten;
|
using namespace emscripten;
|
||||||
using namespace butteraugli;
|
using namespace butteraugli;
|
||||||
|
|
||||||
#define GAMMA 2.2
|
|
||||||
|
|
||||||
static float SrgbToLinear[256];
|
|
||||||
|
|
||||||
inline void gammaLookupTable() {
|
|
||||||
SrgbToLinear[0] = 0;
|
|
||||||
for (int i = 1; i < 256; ++i) {
|
|
||||||
SrgbToLinear[i] = static_cast<float>(255.0 * pow(i / 255.0, GAMMA));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Turns an interleaved RGBA buffer into 4 planes for each color channel
|
// Turns an interleaved RGBA buffer into 4 planes for each color channel
|
||||||
void planarize(std::vector<ImageF>& img, const uint8_t* rgba, int width, int height) {
|
void planarize(std::vector<ImageF>& img,
|
||||||
|
const uint8_t* rgba,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
float gamma = 2.2) {
|
||||||
assert(img.size() == 0);
|
assert(img.size() == 0);
|
||||||
img.push_back(ImageF(width, height));
|
img.push_back(ImageF(width, height));
|
||||||
img.push_back(ImageF(width, height));
|
img.push_back(ImageF(width, height));
|
||||||
@@ -29,10 +22,10 @@ void planarize(std::vector<ImageF>& img, const uint8_t* rgba, int width, int hei
|
|||||||
float* const row_b = img[2].Row(y);
|
float* const row_b = img[2].Row(y);
|
||||||
float* const row_a = img[3].Row(y);
|
float* const row_a = img[3].Row(y);
|
||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
row_r[x] = SrgbToLinear[rgba[(y * width + x) * 4 + 0]];
|
row_r[x] = 255.0 * pow(rgba[(y * width + x) * 4 + 0] / 255.0, gamma);
|
||||||
row_g[x] = SrgbToLinear[rgba[(y * width + x) * 4 + 1]];
|
row_g[x] = 255.0 * pow(rgba[(y * width + x) * 4 + 1] / 255.0, gamma);
|
||||||
row_b[x] = SrgbToLinear[rgba[(y * width + x) * 4 + 2]];
|
row_b[x] = 255.0 * pow(rgba[(y * width + x) * 4 + 2] / 255.0, gamma);
|
||||||
row_a[x] = SrgbToLinear[rgba[(y * width + x) * 4 + 3]];
|
row_a[x] = 255.0 * pow(rgba[(y * width + x) * 4 + 3] / 255.0, gamma);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,7 +37,6 @@ class VisDiff {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
VisDiff(std::string ref_img, int width, int height) {
|
VisDiff(std::string ref_img, int width, int height) {
|
||||||
gammaLookupTable();
|
|
||||||
planarize(this->ref_img, (uint8_t*)ref_img.c_str(), width, height);
|
planarize(this->ref_img, (uint8_t*)ref_img.c_str(), width, height);
|
||||||
this->width = width;
|
this->width = width;
|
||||||
this->height = height;
|
this->height = height;
|
||||||
|
|||||||
55
codecs/visdif/visdif.js
generated
55
codecs/visdif/visdif.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
41
codecs/webp/dec/webp_dec.js
generated
41
codecs/webp/dec/webp_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
41
codecs/webp/dec/webp_node_dec.js
generated
41
codecs/webp/dec/webp_node_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
45
codecs/webp/enc/webp_enc.js
generated
45
codecs/webp/enc/webp_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
45
codecs/webp/enc/webp_enc_simd.js
generated
45
codecs/webp/enc/webp_enc_simd.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
44
codecs/webp/enc/webp_node_enc.js
generated
44
codecs/webp/enc/webp_node_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
42
codecs/wp2/dec/wp2_dec.js
generated
42
codecs/wp2/dec/wp2_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
41
codecs/wp2/dec/wp2_node_dec.js
generated
41
codecs/wp2/dec/wp2_node_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
46
codecs/wp2/enc/wp2_enc.js
generated
46
codecs/wp2/enc/wp2_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
79
codecs/wp2/enc/wp2_enc_mt.js
generated
79
codecs/wp2/enc/wp2_enc_mt.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
2
codecs/wp2/enc/wp2_enc_mt.worker.js
generated
2
codecs/wp2/enc/wp2_enc_mt.worker.js
generated
@@ -1 +1 @@
|
|||||||
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./wp2_enc_mt.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,0,0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./wp2_enc_mt.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,/*isMainBrowserThread=*/0,/*isMainRuntimeThread=*/0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
||||||
|
|||||||
79
codecs/wp2/enc/wp2_enc_mt_simd.js
generated
79
codecs/wp2/enc/wp2_enc_mt_simd.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
2
codecs/wp2/enc/wp2_enc_mt_simd.worker.js
generated
2
codecs/wp2/enc/wp2_enc_mt_simd.worker.js
generated
@@ -1 +1 @@
|
|||||||
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./wp2_enc_mt_simd.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,0,0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./wp2_enc_mt_simd.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,/*isMainBrowserThread=*/0,/*isMainRuntimeThread=*/0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
||||||
|
|||||||
46
codecs/wp2/enc/wp2_node_enc.js
generated
46
codecs/wp2/enc/wp2_node_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -77,7 +77,9 @@ export default function entryDataPlugin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return JSON.stringify(
|
return JSON.stringify(
|
||||||
getDependencies(chunks, chunk).map((filename) => fileNameToURL(filename)),
|
getDependencies(chunks, chunk).map((filename) =>
|
||||||
|
fileNameToURL(filename),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const imagePath = 'path/to/image.png';
|
|||||||
const image = imagePool.ingestImage(imagePath);
|
const image = imagePool.ingestImage(imagePath);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `ingestImage` function can take anything the node [`readFile`][readfile] function can take, including a buffer and `FileHandle`.
|
The `ingestImage` function can take anything the node [`readFile`][readfile] function can take, uncluding a buffer and `FileHandle`.
|
||||||
|
|
||||||
The returned `image` object is a representation of the original image, that you can now preprocess, encode, and extract information about.
|
The returned `image` object is a representation of the original image, that you can now preprocess, encode, and extract information about.
|
||||||
|
|
||||||
@@ -39,26 +39,18 @@ The returned `image` object is a representation of the original image, that you
|
|||||||
When an image has been ingested, you can start preprocessing it and encoding it to other formats. This example will resize the image and then encode it to a `.jpg` and `.jxl` image:
|
When an image has been ingested, you can start preprocessing it and encoding it to other formats. This example will resize the image and then encode it to a `.jpg` and `.jxl` image:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
await image.decoded; //Wait until the image is decoded before running preprocessors.
|
await image.decoded; //Wait until the image is decoded before running preprocessors
|
||||||
|
|
||||||
const preprocessOptions = {
|
const preprocessOptions: {
|
||||||
//When both width and height are specified, the image resized to specified size.
|
|
||||||
resize: {
|
resize: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
width: 100,
|
width: 100,
|
||||||
height: 50,
|
height: 50,
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
//When either width or height is specified, the image resized to specified size keeping aspect ratio.
|
|
||||||
resize: {
|
|
||||||
enabled: true,
|
|
||||||
width: 100,
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
await image.preprocess(preprocessOptions);
|
await image.preprocess(preprocessOptions);
|
||||||
|
|
||||||
const encodeOptions = {
|
const encodeOptions: {
|
||||||
mozjpeg: {}, //an empty object means 'use default settings'
|
mozjpeg: {}, //an empty object means 'use default settings'
|
||||||
jxl: {
|
jxl: {
|
||||||
quality: 90,
|
quality: 90,
|
||||||
@@ -68,7 +60,7 @@ await image.encode(encodeOptions);
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The default values for each option can be found in the [`codecs.ts`][codecs.ts] file under `defaultEncoderOptions`. Every unspecified value will use the default value specified there. _Better documentation is needed here._
|
The default values for each option can be found in the [`codecs.js`][codecs.js] file under `defaultEncoderOptions`. Every unspecified value will use the default value specified there. _Better documentation is needed here._
|
||||||
|
|
||||||
You can run your own code inbetween the different steps, if, for example, you want to change how much the image should be resized based on its original height. (See [Extracting image information](#extracting-image-information) to learn how to get the image dimensions).
|
You can run your own code inbetween the different steps, if, for example, you want to change how much the image should be resized based on its original height. (See [Extracting image information](#extracting-image-information) to learn how to get the image dimensions).
|
||||||
|
|
||||||
@@ -166,6 +158,6 @@ const encodeOptions: {
|
|||||||
```
|
```
|
||||||
|
|
||||||
[squoosh]: https://squoosh.app
|
[squoosh]: https://squoosh.app
|
||||||
[codecs.ts]: https://github.com/GoogleChromeLabs/squoosh/blob/dev/libsquoosh/src/codecs.ts
|
[codecs.js]: https://github.com/GoogleChromeLabs/squoosh/blob/dev/libsquoosh/src/codecs.js
|
||||||
[butteraugli]: https://github.com/google/butteraugli
|
[butteraugli]: https://github.com/google/butteraugli
|
||||||
[readfile]: https://nodejs.org/api/fs.html#fs_fspromises_readfile_path_options
|
[readfile]: https://nodejs.org/api/fs.html#fs_fspromises_readfile_path_options
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright 2020 Google Inc. All Rights Reserved.
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
import { promises as fs } from 'fs';
|
|
||||||
import { basename } from 'path';
|
|
||||||
|
|
||||||
const defaultOpts = {
|
|
||||||
prefix: 'chunk-url',
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function chunkPlugin(opts) {
|
|
||||||
opts = { ...defaultOpts, ...opts };
|
|
||||||
|
|
||||||
const prefix = opts.prefix + ':';
|
|
||||||
return {
|
|
||||||
name: 'chunk-plugin',
|
|
||||||
async resolveId(id, importer) {
|
|
||||||
if (!id.startsWith(prefix)) return;
|
|
||||||
const realId = id.slice(prefix.length);
|
|
||||||
const resolveResult = await this.resolve(realId, importer);
|
|
||||||
|
|
||||||
if (!resolveResult) {
|
|
||||||
throw Error(`Cannot find ${realId}`);
|
|
||||||
}
|
|
||||||
return prefix + resolveResult.id;
|
|
||||||
},
|
|
||||||
async load(id) {
|
|
||||||
if (!id.startsWith(prefix)) return;
|
|
||||||
const realId = id.slice(prefix.length);
|
|
||||||
const source = await fs.readFile(realId);
|
|
||||||
this.addWatchFile(realId);
|
|
||||||
|
|
||||||
return `export default import.meta.ROLLUP_FILE_URL_${this.emitFile({
|
|
||||||
type: 'chunk',
|
|
||||||
source,
|
|
||||||
id: realId,
|
|
||||||
})}`;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
162
libsquoosh/package-lock.json
generated
162
libsquoosh/package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@squoosh/lib",
|
"name": "@squoosh/lib",
|
||||||
"version": "0.4.0",
|
"version": "0.2.3",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1060,21 +1060,6 @@
|
|||||||
"to-fast-properties": "^2.0.0"
|
"to-fast-properties": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@cspotcode/source-map-consumer": {
|
|
||||||
"version": "0.8.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz",
|
|
||||||
"integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"@cspotcode/source-map-support": {
|
|
||||||
"version": "0.6.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz",
|
|
||||||
"integrity": "sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"@cspotcode/source-map-consumer": "0.8.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@rollup/plugin-babel": {
|
"@rollup/plugin-babel": {
|
||||||
"version": "5.3.0",
|
"version": "5.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.0.tgz",
|
||||||
@@ -1133,30 +1118,6 @@
|
|||||||
"picomatch": "^2.2.2"
|
"picomatch": "^2.2.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@tsconfig/node10": {
|
|
||||||
"version": "1.0.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz",
|
|
||||||
"integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"@tsconfig/node12": {
|
|
||||||
"version": "1.0.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz",
|
|
||||||
"integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"@tsconfig/node14": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"@tsconfig/node16": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"@types/estree": {
|
"@types/estree": {
|
||||||
"version": "0.0.39",
|
"version": "0.0.39",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
|
||||||
@@ -1178,18 +1139,6 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"acorn": {
|
|
||||||
"version": "8.5.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz",
|
|
||||||
"integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"acorn-walk": {
|
|
||||||
"version": "8.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
|
|
||||||
"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"ansi-styles": {
|
"ansi-styles": {
|
||||||
"version": "3.2.1",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||||
@@ -1199,12 +1148,6 @@
|
|||||||
"color-convert": "^1.9.0"
|
"color-convert": "^1.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"arg": {
|
|
||||||
"version": "4.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
|
|
||||||
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"babel-plugin-dynamic-import-node": {
|
"babel-plugin-dynamic-import-node": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz",
|
||||||
@@ -1378,12 +1321,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"create-require": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"debug": {
|
"debug": {
|
||||||
"version": "4.3.1",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
|
||||||
@@ -1408,18 +1345,6 @@
|
|||||||
"object-keys": "^1.0.12"
|
"object-keys": "^1.0.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dequal": {
|
|
||||||
"version": "2.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz",
|
|
||||||
"integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"diff": {
|
|
||||||
"version": "5.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
|
|
||||||
"integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"electron-to-chromium": {
|
"electron-to-chromium": {
|
||||||
"version": "1.3.725",
|
"version": "1.3.725",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.725.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.725.tgz",
|
||||||
@@ -1622,12 +1547,6 @@
|
|||||||
"minimist": "^1.2.5"
|
"minimist": "^1.2.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"kleur": {
|
|
||||||
"version": "4.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz",
|
|
||||||
"integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"lodash.debounce": {
|
"lodash.debounce": {
|
||||||
"version": "4.0.8",
|
"version": "4.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
||||||
@@ -1643,12 +1562,6 @@
|
|||||||
"sourcemap-codec": "^1.4.4"
|
"sourcemap-codec": "^1.4.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"make-error": {
|
|
||||||
"version": "1.3.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
|
||||||
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"merge-stream": {
|
"merge-stream": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||||
@@ -1670,12 +1583,6 @@
|
|||||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"mri": {
|
|
||||||
"version": "1.1.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz",
|
|
||||||
"integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"ms": {
|
"ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
@@ -1840,15 +1747,6 @@
|
|||||||
"terser": "^5.0.0"
|
"terser": "^5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sade": {
|
|
||||||
"version": "1.7.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/sade/-/sade-1.7.4.tgz",
|
|
||||||
"integrity": "sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"mri": "^1.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
"version": "5.1.2",
|
"version": "5.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
@@ -1934,40 +1832,6 @@
|
|||||||
"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
|
"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"totalist": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/totalist/-/totalist-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-+Y17F0YzxfACxTyjfhnJQEe7afPA0GSpYlFkl2VFMxYP7jshQf9gXV7cH47EfToBumFThfKBvfAcoUn6fdNeRQ==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"ts-node": {
|
|
||||||
"version": "10.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.1.tgz",
|
|
||||||
"integrity": "sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"@cspotcode/source-map-support": "0.6.1",
|
|
||||||
"@tsconfig/node10": "^1.0.7",
|
|
||||||
"@tsconfig/node12": "^1.0.7",
|
|
||||||
"@tsconfig/node14": "^1.0.0",
|
|
||||||
"@tsconfig/node16": "^1.0.2",
|
|
||||||
"acorn": "^8.4.1",
|
|
||||||
"acorn-walk": "^8.1.1",
|
|
||||||
"arg": "^4.1.0",
|
|
||||||
"create-require": "^1.1.0",
|
|
||||||
"diff": "^4.0.1",
|
|
||||||
"make-error": "^1.1.1",
|
|
||||||
"yn": "3.1.1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"diff": {
|
|
||||||
"version": "4.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
|
|
||||||
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
|
|
||||||
"dev": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "4.3.2",
|
"version": "4.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz",
|
||||||
@@ -2002,24 +1866,6 @@
|
|||||||
"integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==",
|
"integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"uvu": {
|
|
||||||
"version": "0.5.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.1.tgz",
|
|
||||||
"integrity": "sha512-JGxttnOGDFs77FaZ0yMUHIzczzQ5R1IlDeNW6Wymw6gAscwMdAffVOP6TlxLIfReZyK8tahoGwWZaTCJzNFDkg==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"dequal": "^2.0.0",
|
|
||||||
"diff": "^5.0.0",
|
|
||||||
"kleur": "^4.0.3",
|
|
||||||
"sade": "^1.7.3",
|
|
||||||
"totalist": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"wasm-feature-detect": {
|
|
||||||
"version": "1.2.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.2.11.tgz",
|
|
||||||
"integrity": "sha512-HUqwaodrQGaZgz1lZaNioIkog9tkeEJjrM3eq4aUL04whXOVDRc/o2EGb/8kV0QX411iAYWEqq7fMBmJ6dKS6w=="
|
|
||||||
},
|
|
||||||
"web-streams-polyfill": {
|
"web-streams-polyfill": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.0.3.tgz",
|
||||||
@@ -2039,12 +1885,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
|
||||||
"yn": {
|
|
||||||
"version": "3.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
|
|
||||||
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
|
||||||
"dev": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@squoosh/lib",
|
"name": "@squoosh/lib",
|
||||||
"version": "0.4.0",
|
"version": "0.2.3",
|
||||||
"description": "A Node library for Squoosh",
|
"description": "A Node library for Squoosh",
|
||||||
"public": true,
|
"public": true,
|
||||||
"main": "./build/index.js",
|
"main": "./build/index.js",
|
||||||
@@ -8,22 +8,12 @@
|
|||||||
"/build/*"
|
"/build/*"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "rollup -c",
|
"build": "rollup -c"
|
||||||
"test": "uvu -r ts-node/register test"
|
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "Google Chrome Developers <chromium-dev@google.com>",
|
"author": "Google Chrome Developers <chromium-dev@google.com>",
|
||||||
"homepage": "https://github.com/GoogleChromeLabs/squoosh",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/GoogleChromeLabs/squoosh.git"
|
|
||||||
},
|
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
|
||||||
"node": " ^12.5.0 || ^14.0.0 || ^16.0.0 "
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"wasm-feature-detect": "^1.2.11",
|
|
||||||
"web-streams-polyfill": "^3.0.3"
|
"web-streams-polyfill": "^3.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -35,9 +25,7 @@
|
|||||||
"@types/node": "^15.6.1",
|
"@types/node": "^15.6.1",
|
||||||
"rollup": "^2.46.0",
|
"rollup": "^2.46.0",
|
||||||
"rollup-plugin-terser": "^7.0.2",
|
"rollup-plugin-terser": "^7.0.2",
|
||||||
"ts-node": "^10.2.1",
|
|
||||||
"typescript": "^4.1.3",
|
"typescript": "^4.1.3",
|
||||||
"uvu": "^0.5.1",
|
|
||||||
"which": "^2.0.2"
|
"which": "^2.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import resolve from '@rollup/plugin-node-resolve';
|
|||||||
import cjs from '@rollup/plugin-commonjs';
|
import cjs from '@rollup/plugin-commonjs';
|
||||||
import simpleTS from './lib/simple-ts';
|
import simpleTS from './lib/simple-ts';
|
||||||
import asset from './lib/asset-plugin.js';
|
import asset from './lib/asset-plugin.js';
|
||||||
import chunk from './lib/chunk-plugin.js';
|
|
||||||
import json from './lib/json-plugin.js';
|
import json from './lib/json-plugin.js';
|
||||||
import autojson from './lib/autojson-plugin.js';
|
import autojson from './lib/autojson-plugin.js';
|
||||||
import { getBabelOutputPlugin } from '@rollup/plugin-babel';
|
import { getBabelOutputPlugin } from '@rollup/plugin-babel';
|
||||||
@@ -10,7 +9,7 @@ import { builtinModules } from 'module';
|
|||||||
|
|
||||||
/** @type {import('rollup').RollupOptions} */
|
/** @type {import('rollup').RollupOptions} */
|
||||||
export default {
|
export default {
|
||||||
input: 'src/index.ts',
|
input: 'src/index.js',
|
||||||
output: {
|
output: {
|
||||||
dir: 'build',
|
dir: 'build',
|
||||||
format: 'cjs',
|
format: 'cjs',
|
||||||
@@ -19,7 +18,6 @@ export default {
|
|||||||
plugins: [
|
plugins: [
|
||||||
resolve(),
|
resolve(),
|
||||||
cjs(),
|
cjs(),
|
||||||
chunk(),
|
|
||||||
asset(),
|
asset(),
|
||||||
autojson(),
|
autojson(),
|
||||||
json(),
|
json(),
|
||||||
|
|||||||
132
libsquoosh/src/WebAssembly.d.ts
vendored
132
libsquoosh/src/WebAssembly.d.ts
vendored
@@ -1,132 +0,0 @@
|
|||||||
/**
|
|
||||||
* WebAssembly definitions are not available in `@types/node` yet,
|
|
||||||
* so these are copied from `lib.dom.d.ts`
|
|
||||||
*/
|
|
||||||
declare namespace WebAssembly {
|
|
||||||
interface CompileError {}
|
|
||||||
|
|
||||||
var CompileError: {
|
|
||||||
prototype: CompileError;
|
|
||||||
new (): CompileError;
|
|
||||||
};
|
|
||||||
|
|
||||||
interface Global {
|
|
||||||
value: any;
|
|
||||||
valueOf(): any;
|
|
||||||
}
|
|
||||||
|
|
||||||
var Global: {
|
|
||||||
prototype: Global;
|
|
||||||
new (descriptor: GlobalDescriptor, v?: any): Global;
|
|
||||||
};
|
|
||||||
|
|
||||||
interface Instance {
|
|
||||||
readonly exports: Exports;
|
|
||||||
}
|
|
||||||
|
|
||||||
var Instance: {
|
|
||||||
prototype: Instance;
|
|
||||||
new (module: Module, importObject?: Imports): Instance;
|
|
||||||
};
|
|
||||||
|
|
||||||
interface LinkError {}
|
|
||||||
|
|
||||||
var LinkError: {
|
|
||||||
prototype: LinkError;
|
|
||||||
new (): LinkError;
|
|
||||||
};
|
|
||||||
|
|
||||||
interface Memory {
|
|
||||||
readonly buffer: ArrayBuffer;
|
|
||||||
grow(delta: number): number;
|
|
||||||
}
|
|
||||||
|
|
||||||
var Memory: {
|
|
||||||
prototype: Memory;
|
|
||||||
new (descriptor: MemoryDescriptor): Memory;
|
|
||||||
};
|
|
||||||
|
|
||||||
interface Module {}
|
|
||||||
|
|
||||||
var Module: {
|
|
||||||
prototype: Module;
|
|
||||||
new (bytes: BufferSource): Module;
|
|
||||||
customSections(moduleObject: Module, sectionName: string): ArrayBuffer[];
|
|
||||||
exports(moduleObject: Module): ModuleExportDescriptor[];
|
|
||||||
imports(moduleObject: Module): ModuleImportDescriptor[];
|
|
||||||
};
|
|
||||||
|
|
||||||
interface RuntimeError {}
|
|
||||||
|
|
||||||
var RuntimeError: {
|
|
||||||
prototype: RuntimeError;
|
|
||||||
new (): RuntimeError;
|
|
||||||
};
|
|
||||||
|
|
||||||
interface Table {
|
|
||||||
readonly length: number;
|
|
||||||
get(index: number): Function | null;
|
|
||||||
grow(delta: number): number;
|
|
||||||
set(index: number, value: Function | null): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
var Table: {
|
|
||||||
prototype: Table;
|
|
||||||
new (descriptor: TableDescriptor): Table;
|
|
||||||
};
|
|
||||||
|
|
||||||
interface GlobalDescriptor {
|
|
||||||
mutable?: boolean;
|
|
||||||
value: ValueType;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MemoryDescriptor {
|
|
||||||
initial: number;
|
|
||||||
maximum?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ModuleExportDescriptor {
|
|
||||||
kind: ImportExportKind;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ModuleImportDescriptor {
|
|
||||||
kind: ImportExportKind;
|
|
||||||
module: string;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TableDescriptor {
|
|
||||||
element: TableKind;
|
|
||||||
initial: number;
|
|
||||||
maximum?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface WebAssemblyInstantiatedSource {
|
|
||||||
instance: Instance;
|
|
||||||
module: Module;
|
|
||||||
}
|
|
||||||
|
|
||||||
type ImportExportKind = 'function' | 'global' | 'memory' | 'table';
|
|
||||||
type TableKind = 'anyfunc';
|
|
||||||
type ValueType = 'f32' | 'f64' | 'i32' | 'i64';
|
|
||||||
type ExportValue = Function | Global | Memory | Table;
|
|
||||||
type Exports = Record<string, ExportValue>;
|
|
||||||
type ImportValue = ExportValue | number;
|
|
||||||
type ModuleImports = Record<string, ImportValue>;
|
|
||||||
type Imports = Record<string, ModuleImports>;
|
|
||||||
function compile(bytes: BufferSource): Promise<Module>;
|
|
||||||
// `compileStreaming` does not exist in NodeJS
|
|
||||||
// function compileStreaming(source: Response | Promise<Response>): Promise<Module>;
|
|
||||||
function instantiate(
|
|
||||||
bytes: BufferSource,
|
|
||||||
importObject?: Imports,
|
|
||||||
): Promise<WebAssemblyInstantiatedSource>;
|
|
||||||
function instantiate(
|
|
||||||
moduleObject: Module,
|
|
||||||
importObject?: Imports,
|
|
||||||
): Promise<Instance>;
|
|
||||||
// `instantiateStreaming` does not exist in NodeJS
|
|
||||||
// function instantiateStreaming(response: Response | PromiseLike<Response>, importObject?: Imports): Promise<WebAssemblyInstantiatedSource>;
|
|
||||||
function validate(bytes: BufferSource): boolean;
|
|
||||||
}
|
|
||||||
@@ -2,39 +2,6 @@ import { instantiateEmscriptenWasm } from './emscripten-utils.js';
|
|||||||
|
|
||||||
import visdif from '../../codecs/visdif/visdif.js';
|
import visdif from '../../codecs/visdif/visdif.js';
|
||||||
import visdifWasm from 'asset-url:../../codecs/visdif/visdif.wasm';
|
import visdifWasm from 'asset-url:../../codecs/visdif/visdif.wasm';
|
||||||
import type ImageData from './image_data';
|
|
||||||
|
|
||||||
interface VisDiff {
|
|
||||||
distance: (data: Uint8ClampedArray) => number;
|
|
||||||
delete: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface VisdiffConstructor {
|
|
||||||
new (data: Uint8ClampedArray, width: number, height: number): VisDiff;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface VisDiffModule extends EmscriptenWasm.Module {
|
|
||||||
VisDiff: VisdiffConstructor;
|
|
||||||
}
|
|
||||||
|
|
||||||
type VisDiffModuleFactory = EmscriptenWasm.ModuleFactory<VisDiffModule>;
|
|
||||||
|
|
||||||
interface BinarySearchParams {
|
|
||||||
min?: number;
|
|
||||||
max?: number;
|
|
||||||
epsilon?: number;
|
|
||||||
maxRounds?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AutoOptimizeParams extends BinarySearchParams {
|
|
||||||
butteraugliDistanceGoal?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AutoOptimizeResult {
|
|
||||||
bitmap: ImageData;
|
|
||||||
binary: Uint8Array;
|
|
||||||
quality: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
// `measure` is a (async) function that takes exactly one numeric parameter and
|
// `measure` is a (async) function that takes exactly one numeric parameter and
|
||||||
// returns a value. The function is assumed to be monotonic (an increase in `parameter`
|
// returns a value. The function is assumed to be monotonic (an increase in `parameter`
|
||||||
@@ -42,9 +9,9 @@ interface AutoOptimizeResult {
|
|||||||
// to find `parameter` such that `measure` returns `measureGoal`, within an error
|
// to find `parameter` such that `measure` returns `measureGoal`, within an error
|
||||||
// of `epsilon`. It will use at most `maxRounds` attempts.
|
// of `epsilon`. It will use at most `maxRounds` attempts.
|
||||||
export async function binarySearch(
|
export async function binarySearch(
|
||||||
measureGoal: number,
|
measureGoal,
|
||||||
measure: (val: number) => Promise<number>,
|
measure,
|
||||||
{ min = 0, max = 100, epsilon = 0.1, maxRounds = 6 }: BinarySearchParams = {},
|
{ min = 0, max = 100, epsilon = 0.1, maxRounds = 8 } = {},
|
||||||
) {
|
) {
|
||||||
let parameter = (max - min) / 2 + min;
|
let parameter = (max - min) / 2 + min;
|
||||||
let delta = (max - min) / 4;
|
let delta = (max - min) / 4;
|
||||||
@@ -66,21 +33,12 @@ export async function binarySearch(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function autoOptimize(
|
export async function autoOptimize(
|
||||||
bitmapIn: ImageData,
|
bitmapIn,
|
||||||
encode: (
|
encode,
|
||||||
bitmap: ImageData,
|
decode,
|
||||||
quality: number,
|
{ butteraugliDistanceGoal = 1.4, ...otherOpts } = {},
|
||||||
) => Promise<Uint8Array> | Uint8Array,
|
) {
|
||||||
decode: (binary: Uint8Array) => Promise<ImageData> | ImageData,
|
const { VisDiff } = await instantiateEmscriptenWasm(visdif, visdifWasm);
|
||||||
{
|
|
||||||
butteraugliDistanceGoal = 1.4,
|
|
||||||
...binarySearchParams
|
|
||||||
}: AutoOptimizeParams = {},
|
|
||||||
): Promise<AutoOptimizeResult> {
|
|
||||||
const { VisDiff } = await instantiateEmscriptenWasm(
|
|
||||||
visdif as VisDiffModuleFactory,
|
|
||||||
visdifWasm,
|
|
||||||
);
|
|
||||||
|
|
||||||
const comparator = new VisDiff(
|
const comparator = new VisDiff(
|
||||||
bitmapIn.data,
|
bitmapIn.data,
|
||||||
@@ -88,11 +46,8 @@ export async function autoOptimize(
|
|||||||
bitmapIn.height,
|
bitmapIn.height,
|
||||||
);
|
);
|
||||||
|
|
||||||
// We're able to do non null assertion because
|
let bitmapOut;
|
||||||
// we know that binarySearch will set these values
|
let binaryOut;
|
||||||
let bitmapOut!: ImageData;
|
|
||||||
let binaryOut!: Uint8Array;
|
|
||||||
|
|
||||||
// Increasing quality means _decrease_ in Butteraugli distance.
|
// Increasing quality means _decrease_ in Butteraugli distance.
|
||||||
// `binarySearch` assumes that increasing `parameter` will
|
// `binarySearch` assumes that increasing `parameter` will
|
||||||
// increase the metric value. So multipliy Butteraugli values by -1.
|
// increase the metric value. So multipliy Butteraugli values by -1.
|
||||||
@@ -103,7 +58,7 @@ export async function autoOptimize(
|
|||||||
bitmapOut = await decode(binaryOut);
|
bitmapOut = await decode(binaryOut);
|
||||||
return -1 * comparator.distance(bitmapOut.data);
|
return -1 * comparator.distance(bitmapOut.data);
|
||||||
},
|
},
|
||||||
binarySearchParams,
|
otherOpts,
|
||||||
);
|
);
|
||||||
comparator.delete();
|
comparator.delete();
|
||||||
|
|
||||||
@@ -1,84 +1,31 @@
|
|||||||
import { promises as fsp } from 'fs';
|
import { promises as fsp } from 'fs';
|
||||||
import { instantiateEmscriptenWasm, pathify } from './emscripten-utils.js';
|
import { instantiateEmscriptenWasm, pathify } from './emscripten-utils.js';
|
||||||
import { threads } from 'wasm-feature-detect';
|
|
||||||
import { cpus } from 'os';
|
|
||||||
|
|
||||||
// We use `navigator.hardwareConcurrency` for Emscripten’s pthread pool size.
|
|
||||||
// This is the only workaround I can get working without crying.
|
|
||||||
(globalThis as any).navigator = {
|
|
||||||
hardwareConcurrency: cpus().length,
|
|
||||||
};
|
|
||||||
|
|
||||||
interface DecodeModule extends EmscriptenWasm.Module {
|
|
||||||
decode: (data: Uint8Array) => ImageData;
|
|
||||||
}
|
|
||||||
|
|
||||||
type DecodeModuleFactory = EmscriptenWasm.ModuleFactory<DecodeModule>;
|
|
||||||
|
|
||||||
interface RotateModuleInstance {
|
|
||||||
exports: {
|
|
||||||
memory: WebAssembly.Memory;
|
|
||||||
rotate(width: number, height: number, rotate: number): void;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ResizeWithAspectParams {
|
|
||||||
input_width: number;
|
|
||||||
input_height: number;
|
|
||||||
target_width: number;
|
|
||||||
target_height: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ResizeInstantiateOptions {
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
method: string;
|
|
||||||
premultiply: boolean;
|
|
||||||
linearRGB: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
// Needed for being able to use ImageData as type in codec types
|
|
||||||
type ImageData = import('./image_data.js').default;
|
|
||||||
// Needed for being able to assign to `globalThis.ImageData`
|
|
||||||
var ImageData: ImageData['constructor'];
|
|
||||||
}
|
|
||||||
|
|
||||||
import type { QuantizerModule } from '../../codecs/imagequant/imagequant.js';
|
|
||||||
|
|
||||||
// MozJPEG
|
// MozJPEG
|
||||||
import type { MozJPEGModule as MozJPEGEncodeModule } from '../../codecs/mozjpeg/enc/mozjpeg_enc';
|
|
||||||
import mozEnc from '../../codecs/mozjpeg/enc/mozjpeg_node_enc.js';
|
import mozEnc from '../../codecs/mozjpeg/enc/mozjpeg_node_enc.js';
|
||||||
import mozEncWasm from 'asset-url:../../codecs/mozjpeg/enc/mozjpeg_node_enc.wasm';
|
import mozEncWasm from 'asset-url:../../codecs/mozjpeg/enc/mozjpeg_node_enc.wasm';
|
||||||
import mozDec from '../../codecs/mozjpeg/dec/mozjpeg_node_dec.js';
|
import mozDec from '../../codecs/mozjpeg/dec/mozjpeg_node_dec.js';
|
||||||
import mozDecWasm from 'asset-url:../../codecs/mozjpeg/dec/mozjpeg_node_dec.wasm';
|
import mozDecWasm from 'asset-url:../../codecs/mozjpeg/dec/mozjpeg_node_dec.wasm';
|
||||||
|
|
||||||
// WebP
|
// WebP
|
||||||
import type { WebPModule as WebPEncodeModule } from '../../codecs/webp/enc/webp_enc';
|
|
||||||
import webpEnc from '../../codecs/webp/enc/webp_node_enc.js';
|
import webpEnc from '../../codecs/webp/enc/webp_node_enc.js';
|
||||||
import webpEncWasm from 'asset-url:../../codecs/webp/enc/webp_node_enc.wasm';
|
import webpEncWasm from 'asset-url:../../codecs/webp/enc/webp_node_enc.wasm';
|
||||||
import webpDec from '../../codecs/webp/dec/webp_node_dec.js';
|
import webpDec from '../../codecs/webp/dec/webp_node_dec.js';
|
||||||
import webpDecWasm from 'asset-url:../../codecs/webp/dec/webp_node_dec.wasm';
|
import webpDecWasm from 'asset-url:../../codecs/webp/dec/webp_node_dec.wasm';
|
||||||
|
|
||||||
// AVIF
|
// AVIF
|
||||||
import type { AVIFModule as AVIFEncodeModule } from '../../codecs/avif/enc/avif_enc';
|
|
||||||
import avifEnc from '../../codecs/avif/enc/avif_node_enc.js';
|
import avifEnc from '../../codecs/avif/enc/avif_node_enc.js';
|
||||||
import avifEncWasm from 'asset-url:../../codecs/avif/enc/avif_node_enc.wasm';
|
import avifEncWasm from 'asset-url:../../codecs/avif/enc/avif_node_enc.wasm';
|
||||||
import avifEncMt from '../../codecs/avif/enc/avif_node_enc_mt.js';
|
|
||||||
import avifEncMtWorker from 'chunk-url:../../codecs/avif/enc/avif_node_enc_mt.worker.js';
|
|
||||||
import avifEncMtWasm from 'asset-url:../../codecs/avif/enc/avif_node_enc_mt.wasm';
|
|
||||||
import avifDec from '../../codecs/avif/dec/avif_node_dec.js';
|
import avifDec from '../../codecs/avif/dec/avif_node_dec.js';
|
||||||
import avifDecWasm from 'asset-url:../../codecs/avif/dec/avif_node_dec.wasm';
|
import avifDecWasm from 'asset-url:../../codecs/avif/dec/avif_node_dec.wasm';
|
||||||
|
|
||||||
// JXL
|
// JXL
|
||||||
import type { JXLModule as JXLEncodeModule } from '../../codecs/jxl/enc/jxl_enc';
|
|
||||||
import jxlEnc from '../../codecs/jxl/enc/jxl_node_enc.js';
|
import jxlEnc from '../../codecs/jxl/enc/jxl_node_enc.js';
|
||||||
import jxlEncWasm from 'asset-url:../../codecs/jxl/enc/jxl_node_enc.wasm';
|
import jxlEncWasm from 'asset-url:../../codecs/jxl/enc/jxl_node_enc.wasm';
|
||||||
import jxlDec from '../../codecs/jxl/dec/jxl_node_dec.js';
|
import jxlDec from '../../codecs/jxl/dec/jxl_node_dec.js';
|
||||||
import jxlDecWasm from 'asset-url:../../codecs/jxl/dec/jxl_node_dec.wasm';
|
import jxlDecWasm from 'asset-url:../../codecs/jxl/dec/jxl_node_dec.wasm';
|
||||||
|
|
||||||
// WP2
|
// WP2
|
||||||
import type { WP2Module as WP2EncodeModule } from '../../codecs/wp2/enc/wp2_enc';
|
|
||||||
import wp2Enc from '../../codecs/wp2/enc/wp2_node_enc.js';
|
import wp2Enc from '../../codecs/wp2/enc/wp2_node_enc.js';
|
||||||
import wp2EncWasm from 'asset-url:../../codecs/wp2/enc/wp2_node_enc.wasm';
|
import wp2EncWasm from 'asset-url:../../codecs/wp2/enc/wp2_node_enc.wasm';
|
||||||
import wp2Dec from '../../codecs/wp2/dec/wp2_node_dec.js';
|
import wp2Dec from '../../codecs/wp2/dec/wp2_node_dec.js';
|
||||||
@@ -104,22 +51,16 @@ const resizePromise = resize.default(fsp.readFile(pathify(resizeWasm)));
|
|||||||
// rotate
|
// rotate
|
||||||
import rotateWasm from 'asset-url:../../codecs/rotate/rotate.wasm';
|
import rotateWasm from 'asset-url:../../codecs/rotate/rotate.wasm';
|
||||||
|
|
||||||
// TODO(ergunsh): Type definitions of some modules do not exist
|
|
||||||
// Figure out creating type definitions for them and remove `allowJs` rule
|
|
||||||
// We shouldn't need to use Promise<QuantizerModule> below after getting type definitions for imageQuant
|
|
||||||
// ImageQuant
|
// ImageQuant
|
||||||
import imageQuant from '../../codecs/imagequant/imagequant_node.js';
|
import imageQuant from '../../codecs/imagequant/imagequant_node.js';
|
||||||
import imageQuantWasm from 'asset-url:../../codecs/imagequant/imagequant_node.wasm';
|
import imageQuantWasm from 'asset-url:../../codecs/imagequant/imagequant_node.wasm';
|
||||||
const imageQuantPromise: Promise<QuantizerModule> = instantiateEmscriptenWasm(
|
const imageQuantPromise = instantiateEmscriptenWasm(imageQuant, imageQuantWasm);
|
||||||
imageQuant,
|
|
||||||
imageQuantWasm,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Our decoders currently rely on a `ImageData` global.
|
// Our decoders currently rely on a `ImageData` global.
|
||||||
import ImageData from './image_data.js';
|
import ImageData from './image_data.js';
|
||||||
globalThis.ImageData = ImageData;
|
globalThis.ImageData = ImageData;
|
||||||
|
|
||||||
function resizeNameToIndex(name: string) {
|
function resizeNameToIndex(name) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case 'triangle':
|
case 'triangle':
|
||||||
return 0;
|
return 0;
|
||||||
@@ -139,26 +80,25 @@ function resizeWithAspect({
|
|||||||
input_height,
|
input_height,
|
||||||
target_width,
|
target_width,
|
||||||
target_height,
|
target_height,
|
||||||
}: ResizeWithAspectParams): { width: number; height: number } {
|
}) {
|
||||||
if (!target_width && !target_height) {
|
if (!target_width && !target_height) {
|
||||||
throw Error('Need to specify at least width or height when resizing');
|
throw Error('Need to specify at least width or height when resizing');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target_width && target_height) {
|
if (target_width && target_height) {
|
||||||
return { width: target_width, height: target_height };
|
return { width: target_width, height: target_height };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!target_width) {
|
if (!target_width) {
|
||||||
return {
|
return {
|
||||||
width: Math.round((input_width / input_height) * target_height),
|
width: Math.round((input_width / input_height) * target_height),
|
||||||
height: target_height,
|
height: target_height,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (!target_height) {
|
||||||
return {
|
return {
|
||||||
width: target_width,
|
width: target_width,
|
||||||
height: Math.round((input_height / input_width) * target_width),
|
height: Math.round((input_height / input_width) * target_width),
|
||||||
};
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const preprocessors = {
|
export const preprocessors = {
|
||||||
@@ -168,16 +108,10 @@ export const preprocessors = {
|
|||||||
instantiate: async () => {
|
instantiate: async () => {
|
||||||
await resizePromise;
|
await resizePromise;
|
||||||
return (
|
return (
|
||||||
buffer: Uint8Array,
|
buffer,
|
||||||
input_width: number,
|
input_width,
|
||||||
input_height: number,
|
input_height,
|
||||||
{
|
{ width, height, method, premultiply, linearRGB },
|
||||||
width,
|
|
||||||
height,
|
|
||||||
method,
|
|
||||||
premultiply,
|
|
||||||
linearRGB,
|
|
||||||
}: ResizeInstantiateOptions,
|
|
||||||
) => {
|
) => {
|
||||||
({ width, height } = resizeWithAspect({
|
({ width, height } = resizeWithAspect({
|
||||||
input_width,
|
input_width,
|
||||||
@@ -214,12 +148,7 @@ export const preprocessors = {
|
|||||||
description: 'Reduce the number of colors used (aka. paletting)',
|
description: 'Reduce the number of colors used (aka. paletting)',
|
||||||
instantiate: async () => {
|
instantiate: async () => {
|
||||||
const imageQuant = await imageQuantPromise;
|
const imageQuant = await imageQuantPromise;
|
||||||
return (
|
return (buffer, width, height, { numColors, dither }) =>
|
||||||
buffer: Uint8Array,
|
|
||||||
width: number,
|
|
||||||
height: number,
|
|
||||||
{ numColors, dither }: { numColors: number; dither: number },
|
|
||||||
) =>
|
|
||||||
new ImageData(
|
new ImageData(
|
||||||
imageQuant.quantize(buffer, width, height, numColors, dither),
|
imageQuant.quantize(buffer, width, height, numColors, dither),
|
||||||
width,
|
width,
|
||||||
@@ -235,18 +164,13 @@ export const preprocessors = {
|
|||||||
name: 'Rotate',
|
name: 'Rotate',
|
||||||
description: 'Rotate image',
|
description: 'Rotate image',
|
||||||
instantiate: async () => {
|
instantiate: async () => {
|
||||||
return async (
|
return async (buffer, width, height, { numRotations }) => {
|
||||||
buffer: Uint8Array,
|
|
||||||
width: number,
|
|
||||||
height: number,
|
|
||||||
{ numRotations }: { numRotations: number },
|
|
||||||
) => {
|
|
||||||
const degrees = (numRotations * 90) % 360;
|
const degrees = (numRotations * 90) % 360;
|
||||||
const sameDimensions = degrees == 0 || degrees == 180;
|
const sameDimensions = degrees == 0 || degrees == 180;
|
||||||
const size = width * height * 4;
|
const size = width * height * 4;
|
||||||
const instance = (
|
const { instance } = await WebAssembly.instantiate(
|
||||||
await WebAssembly.instantiate(await fsp.readFile(pathify(rotateWasm)))
|
await fsp.readFile(pathify(rotateWasm)),
|
||||||
).instance as RotateModuleInstance;
|
);
|
||||||
const { memory } = instance.exports;
|
const { memory } = instance.exports;
|
||||||
const additionalPagesNeeded = Math.ceil(
|
const additionalPagesNeeded = Math.ceil(
|
||||||
(size * 2 - memory.buffer.byteLength + 8) / (64 * 1024),
|
(size * 2 - memory.buffer.byteLength + 8) / (64 * 1024),
|
||||||
@@ -268,20 +192,15 @@ export const preprocessors = {
|
|||||||
numRotations: 0,
|
numRotations: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as const;
|
};
|
||||||
|
|
||||||
export const codecs = {
|
export const codecs = {
|
||||||
mozjpeg: {
|
mozjpeg: {
|
||||||
name: 'MozJPEG',
|
name: 'MozJPEG',
|
||||||
extension: 'jpg',
|
extension: 'jpg',
|
||||||
detectors: [/^\xFF\xD8\xFF/],
|
detectors: [/^\xFF\xD8\xFF/],
|
||||||
dec: () =>
|
dec: () => instantiateEmscriptenWasm(mozDec, mozDecWasm),
|
||||||
instantiateEmscriptenWasm(mozDec as DecodeModuleFactory, mozDecWasm),
|
enc: () => instantiateEmscriptenWasm(mozEnc, mozEncWasm),
|
||||||
enc: () =>
|
|
||||||
instantiateEmscriptenWasm(
|
|
||||||
mozEnc as EmscriptenWasm.ModuleFactory<MozJPEGEncodeModule>,
|
|
||||||
mozEncWasm,
|
|
||||||
),
|
|
||||||
defaultEncoderOptions: {
|
defaultEncoderOptions: {
|
||||||
quality: 75,
|
quality: 75,
|
||||||
baseline: false,
|
baseline: false,
|
||||||
@@ -309,14 +228,9 @@ export const codecs = {
|
|||||||
webp: {
|
webp: {
|
||||||
name: 'WebP',
|
name: 'WebP',
|
||||||
extension: 'webp',
|
extension: 'webp',
|
||||||
detectors: [/^RIFF....WEBPVP8[LX ]/s],
|
detectors: [/^RIFF....WEBPVP8[LX ]/],
|
||||||
dec: () =>
|
dec: () => instantiateEmscriptenWasm(webpDec, webpDecWasm),
|
||||||
instantiateEmscriptenWasm(webpDec as DecodeModuleFactory, webpDecWasm),
|
enc: () => instantiateEmscriptenWasm(webpEnc, webpEncWasm),
|
||||||
enc: () =>
|
|
||||||
instantiateEmscriptenWasm(
|
|
||||||
webpEnc as EmscriptenWasm.ModuleFactory<WebPEncodeModule>,
|
|
||||||
webpEncWasm,
|
|
||||||
),
|
|
||||||
defaultEncoderOptions: {
|
defaultEncoderOptions: {
|
||||||
quality: 75,
|
quality: 75,
|
||||||
target_size: 0,
|
target_size: 0,
|
||||||
@@ -356,21 +270,8 @@ export const codecs = {
|
|||||||
name: 'AVIF',
|
name: 'AVIF',
|
||||||
extension: 'avif',
|
extension: 'avif',
|
||||||
detectors: [/^\x00\x00\x00 ftypavif\x00\x00\x00\x00/],
|
detectors: [/^\x00\x00\x00 ftypavif\x00\x00\x00\x00/],
|
||||||
dec: () =>
|
dec: () => instantiateEmscriptenWasm(avifDec, avifDecWasm),
|
||||||
instantiateEmscriptenWasm(avifDec as DecodeModuleFactory, avifDecWasm),
|
enc: () => instantiateEmscriptenWasm(avifEnc, avifEncWasm),
|
||||||
enc: async () => {
|
|
||||||
if (await threads()) {
|
|
||||||
return instantiateEmscriptenWasm(
|
|
||||||
avifEncMt as EmscriptenWasm.ModuleFactory<AVIFEncodeModule>,
|
|
||||||
avifEncMtWasm,
|
|
||||||
avifEncMtWorker,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return instantiateEmscriptenWasm(
|
|
||||||
avifEnc as EmscriptenWasm.ModuleFactory<AVIFEncodeModule>,
|
|
||||||
avifEncWasm,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
defaultEncoderOptions: {
|
defaultEncoderOptions: {
|
||||||
cqLevel: 33,
|
cqLevel: 33,
|
||||||
cqAlphaLevel: -1,
|
cqAlphaLevel: -1,
|
||||||
@@ -385,21 +286,16 @@ export const codecs = {
|
|||||||
},
|
},
|
||||||
autoOptimize: {
|
autoOptimize: {
|
||||||
option: 'cqLevel',
|
option: 'cqLevel',
|
||||||
min: 62,
|
min: 0,
|
||||||
max: 0,
|
max: 62,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
jxl: {
|
jxl: {
|
||||||
name: 'JPEG-XL',
|
name: 'JPEG-XL',
|
||||||
extension: 'jxl',
|
extension: 'jxl',
|
||||||
detectors: [/^\xff\x0a/],
|
detectors: [/^\xff\x0a/],
|
||||||
dec: () =>
|
dec: () => instantiateEmscriptenWasm(jxlDec, jxlDecWasm),
|
||||||
instantiateEmscriptenWasm(jxlDec as DecodeModuleFactory, jxlDecWasm),
|
enc: () => instantiateEmscriptenWasm(jxlEnc, jxlEncWasm),
|
||||||
enc: () =>
|
|
||||||
instantiateEmscriptenWasm(
|
|
||||||
jxlEnc as EmscriptenWasm.ModuleFactory<JXLEncodeModule>,
|
|
||||||
jxlEncWasm,
|
|
||||||
),
|
|
||||||
defaultEncoderOptions: {
|
defaultEncoderOptions: {
|
||||||
speed: 4,
|
speed: 4,
|
||||||
quality: 75,
|
quality: 75,
|
||||||
@@ -419,13 +315,8 @@ export const codecs = {
|
|||||||
name: 'WebP2',
|
name: 'WebP2',
|
||||||
extension: 'wp2',
|
extension: 'wp2',
|
||||||
detectors: [/^\xF4\xFF\x6F/],
|
detectors: [/^\xF4\xFF\x6F/],
|
||||||
dec: () =>
|
dec: () => instantiateEmscriptenWasm(wp2Dec, wp2DecWasm),
|
||||||
instantiateEmscriptenWasm(wp2Dec as DecodeModuleFactory, wp2DecWasm),
|
enc: () => instantiateEmscriptenWasm(wp2Enc, wp2EncWasm),
|
||||||
enc: () =>
|
|
||||||
instantiateEmscriptenWasm(
|
|
||||||
wp2Enc as EmscriptenWasm.ModuleFactory<WP2EncodeModule>,
|
|
||||||
wp2EncWasm,
|
|
||||||
),
|
|
||||||
defaultEncoderOptions: {
|
defaultEncoderOptions: {
|
||||||
quality: 75,
|
quality: 75,
|
||||||
alpha_quality: 75,
|
alpha_quality: 75,
|
||||||
@@ -455,18 +346,13 @@ export const codecs = {
|
|||||||
await pngEncDecPromise;
|
await pngEncDecPromise;
|
||||||
await oxipngPromise;
|
await oxipngPromise;
|
||||||
return {
|
return {
|
||||||
encode: (
|
encode: (buffer, width, height, opts) => {
|
||||||
buffer: Uint8ClampedArray | ArrayBuffer,
|
|
||||||
width: number,
|
|
||||||
height: number,
|
|
||||||
opts: { level: number },
|
|
||||||
) => {
|
|
||||||
const simplePng = pngEncDec.encode(
|
const simplePng = pngEncDec.encode(
|
||||||
new Uint8Array(buffer),
|
new Uint8Array(buffer),
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
);
|
);
|
||||||
return oxipng.optimise(simplePng, opts.level, false);
|
return oxipng.optimise(simplePng, opts.level);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -479,4 +365,4 @@ export const codecs = {
|
|||||||
max: 1,
|
max: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as const;
|
};
|
||||||
16
libsquoosh/src/emscripten-utils.js
Normal file
16
libsquoosh/src/emscripten-utils.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
export function pathify(path) {
|
||||||
|
if (path.startsWith('file://')) {
|
||||||
|
path = fileURLToPath(path);
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function instantiateEmscriptenWasm(factory, path) {
|
||||||
|
return factory({
|
||||||
|
locateFile() {
|
||||||
|
return pathify(path);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
import { fileURLToPath, URL } from 'url';
|
|
||||||
|
|
||||||
export function pathify(path: string): string {
|
|
||||||
if (path.startsWith('file://')) {
|
|
||||||
path = fileURLToPath(path);
|
|
||||||
}
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function instantiateEmscriptenWasm<T extends EmscriptenWasm.Module>(
|
|
||||||
factory: EmscriptenWasm.ModuleFactory<T>,
|
|
||||||
path: string,
|
|
||||||
workerJS: string = '',
|
|
||||||
): Promise<T> {
|
|
||||||
return factory({
|
|
||||||
locateFile(requestPath) {
|
|
||||||
// The glue code generated by emscripten uses the original
|
|
||||||
// file names of the worker file and the wasm binary.
|
|
||||||
// These will have changed in the bundling process and
|
|
||||||
// we need to inject them here.
|
|
||||||
if (requestPath.endsWith('.wasm')) return pathify(path);
|
|
||||||
if (requestPath.endsWith('.worker.js')) return pathify(workerJS);
|
|
||||||
return requestPath;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -5,18 +5,10 @@ import { promises as fsp } from 'fs';
|
|||||||
import { codecs as encoders, preprocessors } from './codecs.js';
|
import { codecs as encoders, preprocessors } from './codecs.js';
|
||||||
import WorkerPool from './worker_pool.js';
|
import WorkerPool from './worker_pool.js';
|
||||||
import { autoOptimize } from './auto-optimizer.js';
|
import { autoOptimize } from './auto-optimizer.js';
|
||||||
import type ImageData from './image_data';
|
|
||||||
|
|
||||||
export { ImagePool, encoders, preprocessors };
|
export { ImagePool, encoders, preprocessors };
|
||||||
type EncoderKey = keyof typeof encoders;
|
|
||||||
type PreprocessorKey = keyof typeof preprocessors;
|
|
||||||
type FileLike = Buffer | ArrayBuffer | string | ArrayBufferView;
|
|
||||||
|
|
||||||
async function decodeFile({
|
async function decodeFile({ file }) {
|
||||||
file,
|
|
||||||
}: {
|
|
||||||
file: FileLike;
|
|
||||||
}): Promise<{ bitmap: ImageData; size: number }> {
|
|
||||||
let buffer;
|
let buffer;
|
||||||
if (ArrayBuffer.isView(file)) {
|
if (ArrayBuffer.isView(file)) {
|
||||||
buffer = Buffer.from(file.buffer);
|
buffer = Buffer.from(file.buffer);
|
||||||
@@ -24,9 +16,8 @@ async function decodeFile({
|
|||||||
} else if (file instanceof ArrayBuffer) {
|
} else if (file instanceof ArrayBuffer) {
|
||||||
buffer = Buffer.from(file);
|
buffer = Buffer.from(file);
|
||||||
file = 'Binary blob';
|
file = 'Binary blob';
|
||||||
} else if ((file as unknown) instanceof Buffer) {
|
} else if (file instanceof Buffer) {
|
||||||
// TODO: Check why we need type assertions here.
|
buffer = file;
|
||||||
buffer = (file as unknown) as Buffer;
|
|
||||||
file = 'Binary blob';
|
file = 'Binary blob';
|
||||||
} else if (typeof file === 'string') {
|
} else if (typeof file === 'string') {
|
||||||
buffer = await fsp.readFile(file);
|
buffer = await fsp.readFile(file);
|
||||||
@@ -37,33 +28,23 @@ async function decodeFile({
|
|||||||
const firstChunkString = Array.from(firstChunk)
|
const firstChunkString = Array.from(firstChunk)
|
||||||
.map((v) => String.fromCodePoint(v))
|
.map((v) => String.fromCodePoint(v))
|
||||||
.join('');
|
.join('');
|
||||||
const key = Object.entries(encoders).find(([_name, { detectors }]) =>
|
const key = Object.entries(encoders).find(([name, { detectors }]) =>
|
||||||
detectors.some((detector) => detector.exec(firstChunkString)),
|
detectors.some((detector) => detector.exec(firstChunkString)),
|
||||||
)?.[0] as EncoderKey | undefined;
|
)?.[0];
|
||||||
if (!key) {
|
if (!key) {
|
||||||
throw Error(`${file} has an unsupported format`);
|
throw Error(`${file} has an unsupported format`);
|
||||||
}
|
}
|
||||||
const encoder = encoders[key];
|
const rgba = (await encoders[key].dec()).decode(new Uint8Array(buffer));
|
||||||
const mod = await encoder.dec();
|
|
||||||
const rgba = mod.decode(new Uint8Array(buffer));
|
|
||||||
return {
|
return {
|
||||||
bitmap: rgba,
|
bitmap: rgba,
|
||||||
size: buffer.length,
|
size: buffer.length,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function preprocessImage({
|
async function preprocessImage({ preprocessorName, options, image }) {
|
||||||
preprocessorName,
|
|
||||||
options,
|
|
||||||
image,
|
|
||||||
}: {
|
|
||||||
preprocessorName: PreprocessorKey;
|
|
||||||
options: any;
|
|
||||||
image: { bitmap: ImageData };
|
|
||||||
}) {
|
|
||||||
const preprocessor = await preprocessors[preprocessorName].instantiate();
|
const preprocessor = await preprocessors[preprocessorName].instantiate();
|
||||||
image.bitmap = await preprocessor(
|
image.bitmap = await preprocessor(
|
||||||
Uint8Array.from(image.bitmap.data),
|
image.bitmap.data,
|
||||||
image.bitmap.width,
|
image.bitmap.width,
|
||||||
image.bitmap.height,
|
image.bitmap.height,
|
||||||
options,
|
options,
|
||||||
@@ -77,39 +58,26 @@ async function encodeImage({
|
|||||||
encConfig,
|
encConfig,
|
||||||
optimizerButteraugliTarget,
|
optimizerButteraugliTarget,
|
||||||
maxOptimizerRounds,
|
maxOptimizerRounds,
|
||||||
}: {
|
|
||||||
bitmap: ImageData;
|
|
||||||
encName: EncoderKey;
|
|
||||||
encConfig: any;
|
|
||||||
optimizerButteraugliTarget: number;
|
|
||||||
maxOptimizerRounds: number;
|
|
||||||
}) {
|
}) {
|
||||||
let binary: Uint8Array;
|
let binary;
|
||||||
let optionsUsed = encConfig;
|
let optionsUsed = encConfig;
|
||||||
const encoder = await encoders[encName].enc();
|
const encoder = await encoders[encName].enc();
|
||||||
if (encConfig === 'auto') {
|
if (encConfig === 'auto') {
|
||||||
const optionToOptimize = encoders[encName].autoOptimize.option;
|
const optionToOptimize = encoders[encName].autoOptimize.option;
|
||||||
const decoder = await encoders[encName].dec();
|
const decoder = await encoders[encName].dec();
|
||||||
const encode = (bitmapIn: ImageData, quality: number) =>
|
const encode = (bitmapIn, quality) =>
|
||||||
encoder.encode(
|
encoder.encode(
|
||||||
bitmapIn.data,
|
bitmapIn.data,
|
||||||
bitmapIn.width,
|
bitmapIn.width,
|
||||||
bitmapIn.height,
|
bitmapIn.height,
|
||||||
Object.assign({}, encoders[encName].defaultEncoderOptions as any, {
|
Object.assign({}, encoders[encName].defaultEncoderOptions, {
|
||||||
[optionToOptimize]: quality,
|
[optionToOptimize]: quality,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const decode = (binary: Uint8Array) => decoder.decode(binary);
|
const decode = (binary) => decoder.decode(binary);
|
||||||
const nonNullEncode = (bitmap: ImageData, quality: number): Uint8Array => {
|
|
||||||
const result = encode(bitmap, quality);
|
|
||||||
if (!result) {
|
|
||||||
throw new Error('There was an error while encoding');
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
const { binary: optimizedBinary, quality } = await autoOptimize(
|
const { binary: optimizedBinary, quality } = await autoOptimize(
|
||||||
bitmapIn,
|
bitmapIn,
|
||||||
nonNullEncode,
|
encode,
|
||||||
decode,
|
decode,
|
||||||
{
|
{
|
||||||
min: encoders[encName].autoOptimize.min,
|
min: encoders[encName].autoOptimize.min,
|
||||||
@@ -124,18 +92,12 @@ async function encodeImage({
|
|||||||
[optionToOptimize]: Math.round(quality * 10000) / 10000,
|
[optionToOptimize]: Math.round(quality * 10000) / 10000,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const result = encoder.encode(
|
binary = encoder.encode(
|
||||||
bitmapIn.data.buffer,
|
bitmapIn.data.buffer,
|
||||||
bitmapIn.width,
|
bitmapIn.width,
|
||||||
bitmapIn.height,
|
bitmapIn.height,
|
||||||
encConfig,
|
encConfig,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
throw new Error('There was an error while encoding');
|
|
||||||
}
|
|
||||||
|
|
||||||
binary = result;
|
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
optionsUsed,
|
optionsUsed,
|
||||||
@@ -145,15 +107,10 @@ async function encodeImage({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
type EncodeParams = { operation: 'encode' } & Parameters<typeof encodeImage>[0];
|
// both decoding and encoding go through the worker pool
|
||||||
type DecodeParams = { operation: 'decode' } & Parameters<typeof decodeFile>[0];
|
function handleJob(params) {
|
||||||
type PreprocessParams = { operation: 'preprocess' } & Parameters<
|
const { operation } = params;
|
||||||
typeof preprocessImage
|
switch (operation) {
|
||||||
>[0];
|
|
||||||
type JobMessage = EncodeParams | DecodeParams | PreprocessParams;
|
|
||||||
|
|
||||||
function handleJob(params: JobMessage) {
|
|
||||||
switch (params.operation) {
|
|
||||||
case 'encode':
|
case 'encode':
|
||||||
return encodeImage(params);
|
return encodeImage(params);
|
||||||
case 'decode':
|
case 'decode':
|
||||||
@@ -161,7 +118,7 @@ function handleJob(params: JobMessage) {
|
|||||||
case 'preprocess':
|
case 'preprocess':
|
||||||
return preprocessImage(params);
|
return preprocessImage(params);
|
||||||
default:
|
default:
|
||||||
throw Error(`Invalid job "${(params as any).operation}"`);
|
throw Error(`Invalid job "${operation}"`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,12 +126,7 @@ function handleJob(params: JobMessage) {
|
|||||||
* Represents an ingested image.
|
* Represents an ingested image.
|
||||||
*/
|
*/
|
||||||
class Image {
|
class Image {
|
||||||
public file: FileLike;
|
constructor(workerPool, file) {
|
||||||
public workerPool: WorkerPool<JobMessage, any>;
|
|
||||||
public decoded: Promise<{ bitmap: ImageData }>;
|
|
||||||
public encodedWith: { [key: string]: any };
|
|
||||||
|
|
||||||
constructor(workerPool: WorkerPool<JobMessage, any>, file: FileLike) {
|
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.workerPool = workerPool;
|
this.workerPool = workerPool;
|
||||||
this.decoded = workerPool.dispatchJob({ operation: 'decode', file });
|
this.decoded = workerPool.dispatchJob({ operation: 'decode', file });
|
||||||
@@ -191,15 +143,14 @@ class Image {
|
|||||||
if (!Object.keys(preprocessors).includes(name)) {
|
if (!Object.keys(preprocessors).includes(name)) {
|
||||||
throw Error(`Invalid preprocessor "${name}"`);
|
throw Error(`Invalid preprocessor "${name}"`);
|
||||||
}
|
}
|
||||||
const preprocessorName = name as PreprocessorKey;
|
|
||||||
const preprocessorOptions = Object.assign(
|
const preprocessorOptions = Object.assign(
|
||||||
{},
|
{},
|
||||||
preprocessors[preprocessorName].defaultOptions,
|
preprocessors[name].defaultOptions,
|
||||||
options,
|
options,
|
||||||
);
|
);
|
||||||
this.decoded = this.workerPool.dispatchJob({
|
this.decoded = this.workerPool.dispatchJob({
|
||||||
operation: 'preprocess',
|
operation: 'preprocess',
|
||||||
preprocessorName,
|
preprocessorName: name,
|
||||||
image: await this.decoded,
|
image: await this.decoded,
|
||||||
options: preprocessorOptions,
|
options: preprocessorOptions,
|
||||||
});
|
});
|
||||||
@@ -210,22 +161,14 @@ class Image {
|
|||||||
/**
|
/**
|
||||||
* Define one or several encoders to use on the image.
|
* Define one or several encoders to use on the image.
|
||||||
* @param {object} encodeOptions - An object with encoders to use, and their settings.
|
* @param {object} encodeOptions - An object with encoders to use, and their settings.
|
||||||
* @returns {Promise<void>} - A promise that resolves when the image has been encoded with all the specified encoders.
|
* @returns {Promise<undefined>} - A promise that resolves when the image has been encoded with all the specified encoders.
|
||||||
*/
|
*/
|
||||||
async encode(
|
async encode(encodeOptions = {}) {
|
||||||
encodeOptions: {
|
|
||||||
optimizerButteraugliTarget?: number;
|
|
||||||
maxOptimizerRounds?: number;
|
|
||||||
} & {
|
|
||||||
[key in EncoderKey]?: any; // any is okay for now
|
|
||||||
} = {},
|
|
||||||
): Promise<void> {
|
|
||||||
const { bitmap } = await this.decoded;
|
const { bitmap } = await this.decoded;
|
||||||
for (const [name, options] of Object.entries(encodeOptions)) {
|
for (const [encName, options] of Object.entries(encodeOptions)) {
|
||||||
if (!Object.keys(encoders).includes(name)) {
|
if (!Object.keys(encoders).includes(encName)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const encName = name as EncoderKey;
|
|
||||||
const encRef = encoders[encName];
|
const encRef = encoders[encName];
|
||||||
const encConfig =
|
const encConfig =
|
||||||
typeof options === 'string'
|
typeof options === 'string'
|
||||||
@@ -237,9 +180,9 @@ class Image {
|
|||||||
encName,
|
encName,
|
||||||
encConfig,
|
encConfig,
|
||||||
optimizerButteraugliTarget: Number(
|
optimizerButteraugliTarget: Number(
|
||||||
encodeOptions.optimizerButteraugliTarget ?? 1.4,
|
encodeOptions.optimizerButteraugliTarget,
|
||||||
),
|
),
|
||||||
maxOptimizerRounds: Number(encodeOptions.maxOptimizerRounds ?? 6),
|
maxOptimizerRounds: Number(encodeOptions.maxOptimizerRounds),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
await Promise.all(Object.values(this.encodedWith));
|
await Promise.all(Object.values(this.encodedWith));
|
||||||
@@ -250,30 +193,28 @@ class Image {
|
|||||||
* A pool where images can be ingested and squooshed.
|
* A pool where images can be ingested and squooshed.
|
||||||
*/
|
*/
|
||||||
class ImagePool {
|
class ImagePool {
|
||||||
public workerPool: WorkerPool<JobMessage, any>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new pool.
|
* Create a new pool.
|
||||||
* @param {number} [threads] - Number of concurrent image processes to run in the pool. Defaults to the number of CPU cores in the system.
|
* @param {number} [threads] - Number of concurrent image processes to run in the pool. Defaults to the number of CPU cores in the system.
|
||||||
*/
|
*/
|
||||||
constructor(threads: number) {
|
constructor(threads) {
|
||||||
this.workerPool = new WorkerPool(threads || cpus().length, __filename);
|
this.workerPool = new WorkerPool(threads || cpus().length, __filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ingest an image into the image pool.
|
* Ingest an image into the image pool.
|
||||||
* @param {FileLike} image - The image or path to the image that should be ingested and decoded.
|
* @param {string | Buffer | URL | object} image - The image or path to the image that should be ingested and decoded.
|
||||||
* @returns {Image} - A custom class reference to the decoded image.
|
* @returns {Image} - A custom class reference to the decoded image.
|
||||||
*/
|
*/
|
||||||
ingestImage(image: FileLike): Image {
|
ingestImage(image) {
|
||||||
return new Image(this.workerPool, image);
|
return new Image(this.workerPool, image);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the underlying image processing pipeline. The already processed images will still be there, but no new processing can start.
|
* Closes the underlying image processing pipeline. The already processed images will still be there, but no new processing can start.
|
||||||
* @returns {Promise<void>} - A promise that resolves when the underlying pipeline has closed.
|
* @returns {Promise<undefined>} - A promise that resolves when the underlying pipeline has closed.
|
||||||
*/
|
*/
|
||||||
async close(): Promise<void> {
|
async close() {
|
||||||
await this.workerPool.join();
|
await this.workerPool.join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
43
libsquoosh/src/missing-types.d.ts
vendored
43
libsquoosh/src/missing-types.d.ts
vendored
@@ -1,43 +0,0 @@
|
|||||||
/// <reference path="../../missing-types.d.ts" />
|
|
||||||
|
|
||||||
declare module 'asset-url:*' {
|
|
||||||
const value: string;
|
|
||||||
export default value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Somehow TS picks up definitions from the module itself
|
|
||||||
// instead of using `asset-url:*`. It is probably related to
|
|
||||||
// specifity of the module declaration and these declarations below fix it
|
|
||||||
declare module 'asset-url:../../codecs/png/pkg/squoosh_png_bg.wasm' {
|
|
||||||
const value: string;
|
|
||||||
export default value;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'asset-url:../../codecs/oxipng/pkg/squoosh_oxipng_bg.wasm' {
|
|
||||||
const value: string;
|
|
||||||
export default value;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'asset-url:../../codecs/resize/pkg/squoosh_resize_bg.wasm' {
|
|
||||||
const value: string;
|
|
||||||
export default value;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'chunk-url:../../codecs/avif/enc/avif_node_enc_mt.worker.js' {
|
|
||||||
const value: string;
|
|
||||||
export default value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// These don't exist in NodeJS types so we're not able to use them but they are referenced in some emscripten and codec types
|
|
||||||
// Thus, we need to explicitly assign them to be `never`
|
|
||||||
// We're also not able to use the APIs that use these types
|
|
||||||
// So, if we want to use those APIs we need to supply its dependencies ourselves
|
|
||||||
// However, probably those APIs are more suited to be used in web (i.e. there can be other
|
|
||||||
// dependencies to web APIs that might not work in Node)
|
|
||||||
type RequestInfo = never;
|
|
||||||
type Response = never;
|
|
||||||
type WebGLRenderingContext = never;
|
|
||||||
type MessageEvent = never;
|
|
||||||
|
|
||||||
type BufferSource = ArrayBufferView | ArrayBuffer;
|
|
||||||
type URL = import('url').URL;
|
|
||||||
@@ -7,19 +7,26 @@ function uuid() {
|
|||||||
).join('');
|
).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Job<I> {
|
function jobPromise(worker, msg) {
|
||||||
msg: I;
|
return new Promise((resolve, reject) => {
|
||||||
resolve: Function;
|
const id = uuid();
|
||||||
reject: Function;
|
worker.postMessage({ msg, id });
|
||||||
|
worker.on('message', function f({ error, result, id: rid }) {
|
||||||
|
if (rid !== id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
reject(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
worker.off('message', f);
|
||||||
|
resolve(result);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class WorkerPool<I, O> {
|
export default class WorkerPool {
|
||||||
public numWorkers: number;
|
constructor(numWorkers, workerFile) {
|
||||||
public jobQueue: TransformStream<Job<I>, Job<I>>;
|
|
||||||
public workerQueue: TransformStream<Worker, Worker>;
|
|
||||||
public done: Promise<void>;
|
|
||||||
|
|
||||||
constructor(numWorkers: number, workerFile: string) {
|
|
||||||
this.numWorkers = numWorkers;
|
this.numWorkers = numWorkers;
|
||||||
this.jobQueue = new TransformStream();
|
this.jobQueue = new TransformStream();
|
||||||
this.workerQueue = new TransformStream();
|
this.workerQueue = new TransformStream();
|
||||||
@@ -41,14 +48,9 @@ export default class WorkerPool<I, O> {
|
|||||||
await this._terminateAll();
|
await this._terminateAll();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!value) {
|
|
||||||
throw new Error('Reader did not return any value');
|
|
||||||
}
|
|
||||||
|
|
||||||
const { msg, resolve, reject } = value;
|
const { msg, resolve, reject } = value;
|
||||||
const worker = await this._nextWorker();
|
const worker = await this._nextWorker();
|
||||||
this.jobPromise(worker, msg)
|
jobPromise(worker, msg)
|
||||||
.then((result) => resolve(result))
|
.then((result) => resolve(result))
|
||||||
.catch((reason) => reject(reason))
|
.catch((reason) => reject(reason))
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
@@ -62,12 +64,8 @@ export default class WorkerPool<I, O> {
|
|||||||
|
|
||||||
async _nextWorker() {
|
async _nextWorker() {
|
||||||
const reader = this.workerQueue.readable.getReader();
|
const reader = this.workerQueue.readable.getReader();
|
||||||
const { value } = await reader.read();
|
const { value, done } = await reader.read();
|
||||||
reader.releaseLock();
|
reader.releaseLock();
|
||||||
if (!value) {
|
|
||||||
throw new Error('No worker left');
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +82,7 @@ export default class WorkerPool<I, O> {
|
|||||||
await this.done;
|
await this.done;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchJob(msg: I): Promise<O> {
|
dispatchJob(msg) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const writer = this.jobQueue.writable.getWriter();
|
const writer = this.jobQueue.writable.getWriter();
|
||||||
writer.write({ msg, resolve, reject });
|
writer.write({ msg, resolve, reject });
|
||||||
@@ -92,32 +90,14 @@ export default class WorkerPool<I, O> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private jobPromise(worker: Worker, msg: I) {
|
static useThisThreadAsWorker(cb) {
|
||||||
return new Promise((resolve, reject) => {
|
parentPort.on('message', async (data) => {
|
||||||
const id = uuid();
|
|
||||||
worker.postMessage({ msg, id });
|
|
||||||
worker.on('message', function f({ error, result, id: rid }) {
|
|
||||||
if (rid !== id) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (error) {
|
|
||||||
reject(error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
worker.off('message', f);
|
|
||||||
resolve(result);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static useThisThreadAsWorker<I, O>(cb: (msg: I) => O) {
|
|
||||||
parentPort!.on('message', async (data) => {
|
|
||||||
const { msg, id } = data;
|
const { msg, id } = data;
|
||||||
try {
|
try {
|
||||||
const result = await cb(msg);
|
const result = await cb(msg);
|
||||||
parentPort!.postMessage({ result, id });
|
parentPort.postMessage({ result, id });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
parentPort!.postMessage({ error: e.message, id });
|
parentPort.postMessage({ error: e.message, id });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
import * as path from 'path';
|
|
||||||
import { test } from 'uvu';
|
|
||||||
import * as assert from 'uvu/assert';
|
|
||||||
import { ImagePool } from '..';
|
|
||||||
|
|
||||||
let imagePool: ImagePool;
|
|
||||||
|
|
||||||
test.after.each(async () => {
|
|
||||||
if (imagePool) {
|
|
||||||
try {
|
|
||||||
await imagePool.close();
|
|
||||||
} catch (e) {}
|
|
||||||
}
|
|
||||||
imagePool = undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
test('smoke test', async () => {
|
|
||||||
imagePool = new ImagePool(1);
|
|
||||||
|
|
||||||
const imagePath = path.resolve(__dirname, '../../icon-large-maskable.png');
|
|
||||||
const image = imagePool.ingestImage(imagePath);
|
|
||||||
|
|
||||||
const { bitmap } = await image.decoded;
|
|
||||||
assert.equal(bitmap.width, 1024);
|
|
||||||
|
|
||||||
await image.preprocess({
|
|
||||||
resize: {
|
|
||||||
enabled: true,
|
|
||||||
width: 100,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
await image.encode({
|
|
||||||
mozjpeg: {},
|
|
||||||
});
|
|
||||||
|
|
||||||
const { size } = await image.encodedWith.mozjpeg;
|
|
||||||
// resulting image is 1554b
|
|
||||||
assert.ok(size > 500);
|
|
||||||
assert.ok(size < 5000);
|
|
||||||
});
|
|
||||||
|
|
||||||
test.run();
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user