mirror of
https://github.com/GoogleChromeLabs/squoosh.git
synced 2025-11-12 16:57:26 +00:00
Compare commits
9 Commits
minimal-ru
...
urls-bug
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
886d8d632b | ||
|
|
e2d1adf5e9 | ||
|
|
223da087b2 | ||
|
|
765402404a | ||
|
|
c260f3e280 | ||
|
|
45187c4932 | ||
|
|
9b8d3b1bd8 | ||
|
|
a811b6cf41 | ||
|
|
ba0df8e2ff |
44
README.md
44
README.md
@@ -1,42 +1,36 @@
|
||||
# [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
|
||||
|
||||
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
|
||||
|
||||
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).
|
||||
- The before and after image size value.
|
||||
- If Squoosh PWA, the type of Squoosh installation.
|
||||
- If Squoosh PWA, the installation time and date.
|
||||
Image compression is handled locally; no additional data is sent to the server.
|
||||
|
||||
# Developing
|
||||
# Building locally
|
||||
|
||||
To develop for Squoosh:
|
||||
Clone the repo, and:
|
||||
|
||||
1. Clone the repository
|
||||
1. To install node packages, run:
|
||||
```sh
|
||||
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
|
||||
```
|
||||
```sh
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
# 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
|
||||
|
||||
@@ -42,7 +42,7 @@ Options:
|
||||
-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
|
||||
|
||||
@@ -55,5 +55,5 @@ $ npx @squoosh/cli --wp2 auto test.png
|
||||
```
|
||||
|
||||
[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
|
||||
|
||||
36
cli/package-lock.json
generated
36
cli/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@squoosh/cli",
|
||||
"version": "0.7.2",
|
||||
"version": "0.7.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@squoosh/cli",
|
||||
"version": "0.7.2",
|
||||
"version": "0.7.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@squoosh/lib": "^0.4.0",
|
||||
"@squoosh/lib": "^0.2.0",
|
||||
"commander": "^7.2.0",
|
||||
"json5": "^2.2.0",
|
||||
"kleur": "^4.1.4",
|
||||
@@ -18,21 +18,14 @@
|
||||
"bin": {
|
||||
"cli": "src/index.js",
|
||||
"squoosh-cli": "src/index.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": " ^12.20.2 || ^14.13.1 || ^16.0.0 "
|
||||
}
|
||||
},
|
||||
"node_modules/@squoosh/lib": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@squoosh/lib/-/lib-0.4.0.tgz",
|
||||
"integrity": "sha512-O1LyugWLZjMI4JZeZMA5vzfhfPjfMZXH5/HmVkRagP8B70wH3uoR7tjxfGNdSavey357MwL8YJDxbGwBBdHp7Q==",
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@squoosh/lib/-/lib-0.2.0.tgz",
|
||||
"integrity": "sha512-zKId9h/LzEnCdoOGnIgjzvqbk5g2aHgfEqgKQ+S+r5K3TasgD/DAsT6r7v6gXft1ao0f/00CTcwIp1KviWTQbw==",
|
||||
"dependencies": {
|
||||
"wasm-feature-detect": "^1.2.11",
|
||||
"web-streams-polyfill": "^3.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": " ^12.5.0 || ^14.0.0 || ^16.0.0 "
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
@@ -330,11 +323,6 @@
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"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": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
|
||||
@@ -354,11 +342,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@squoosh/lib": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@squoosh/lib/-/lib-0.4.0.tgz",
|
||||
"integrity": "sha512-O1LyugWLZjMI4JZeZMA5vzfhfPjfMZXH5/HmVkRagP8B70wH3uoR7tjxfGNdSavey357MwL8YJDxbGwBBdHp7Q==",
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@squoosh/lib/-/lib-0.2.0.tgz",
|
||||
"integrity": "sha512-zKId9h/LzEnCdoOGnIgjzvqbk5g2aHgfEqgKQ+S+r5K3TasgD/DAsT6r7v6gXft1ao0f/00CTcwIp1KviWTQbw==",
|
||||
"requires": {
|
||||
"wasm-feature-detect": "^1.2.11",
|
||||
"web-streams-polyfill": "^3.0.3"
|
||||
}
|
||||
},
|
||||
@@ -591,11 +578,6 @@
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"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": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
{
|
||||
"name": "@squoosh/cli",
|
||||
"version": "0.7.2",
|
||||
"version": "0.7.0",
|
||||
"description": "A CLI for Squoosh",
|
||||
"public": true,
|
||||
"type": "module",
|
||||
"homepage": "https://github.com/GoogleChromeLabs/squoosh",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/GoogleChromeLabs/squoosh.git"
|
||||
},
|
||||
"bin": {
|
||||
"squoosh-cli": "src/index.js",
|
||||
"@squoosh/cli": "src/index.js"
|
||||
@@ -19,11 +14,8 @@
|
||||
"keywords": [],
|
||||
"author": "Google Chrome Developers <chromium-dev@google.com>",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": " ^12.20.2 || ^14.13.1 || ^16.0.0 "
|
||||
},
|
||||
"dependencies": {
|
||||
"@squoosh/lib": "^0.4.0",
|
||||
"@squoosh/lib": "^0.2.0",
|
||||
"commander": "^7.2.0",
|
||||
"json5": "^2.2.0",
|
||||
"kleur": "^4.1.4",
|
||||
|
||||
@@ -177,8 +177,8 @@ async function processFiles(files) {
|
||||
jobsFinished++;
|
||||
const outputPath = path.join(
|
||||
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)) {
|
||||
const outputFile = `${outputPath}.${(await output).extension}`;
|
||||
|
||||
@@ -10,16 +10,13 @@ export CODEC_DIR = node_modules/libavif
|
||||
export BUILD_DIR = node_modules/build
|
||||
export LIBAOM_DIR = node_modules/libaom
|
||||
|
||||
override CFLAGS += "-Wno-unused-macros"
|
||||
export
|
||||
|
||||
OUT_ENC_JS = enc/avif_enc.js
|
||||
OUT_NODE_ENC_JS = enc/avif_node_enc.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_NODE_DEC_JS = dec/avif_node_dec.js
|
||||
|
||||
OUT_ENC_CPP = enc/avif_enc.cpp
|
||||
OUT_ENC_CPP = enc/avif_enc.cpp
|
||||
OUT_DEC_CPP = dec/avif_dec.cpp
|
||||
ENVIRONMENT = worker
|
||||
@@ -28,9 +25,9 @@ HELPER_MAKEFLAGS := -f helper.Makefile
|
||||
|
||||
.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
|
||||
$(MAKE) \
|
||||
$(HELPER_MAKEFLAGS) \
|
||||
@@ -44,7 +41,7 @@ $(OUT_NODE_ENC_JS) $(OUT_ENC_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(L
|
||||
ENVIRONMENT=$(ENVIRONMENT) \
|
||||
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) \
|
||||
$(HELPER_MAKEFLAGS) \
|
||||
OUT_JS=$@ \
|
||||
@@ -89,7 +86,4 @@ $(LIBAOM_DIR)/CMakeLists.txt: $(LIBAOM_PACKAGE)
|
||||
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_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_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.
57
codecs/avif/enc/avif_enc.js
generated
57
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;function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){var imports={};imports["wasm"]=e.data.wasmModule;imports["wasmMemory"]=e.data.wasmMemory;imports["buffer"]=imports["wasmMemory"].buffer;imports["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);Module["PThread"].threadExit(result)}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){{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,14 +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
|
||||
ENV CFLAGS "-O3 -flto"
|
||||
ENV CXXFLAGS "${CFLAGS} -std=c++17"
|
||||
ENV LDFLAGS "${CFLAGS} \
|
||||
--closure 1 \
|
||||
-s FILESYSTEM=0 \
|
||||
-s PTHREAD_POOL_SIZE=navigator.hardwareConcurrency \
|
||||
-s ALLOW_MEMORY_GROWTH=1 \
|
||||
-s TEXTDECODER=2 \
|
||||
-s NODEJS_CATCH_EXIT=0 -s NODEJS_CATCH_REJECTION=0 \
|
||||
-s MINIMAL_RUNTIME=1 \
|
||||
"
|
||||
# Build and cache standard libraries with these flags + Embind.
|
||||
RUN emcc ${CXXFLAGS} ${LDFLAGS} --bind -xc++ /dev/null -o /dev/null
|
||||
|
||||
49
codecs/imagequant/imagequant.js
generated
49
codecs/imagequant/imagequant.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
50
codecs/imagequant/imagequant_node.js
generated
50
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_VERSION = 3f76321a7cbcf4f452894dc173eb7be60f508ecb
|
||||
CODEC_URL = https://gitlab.com/wg1/jpeg-xl.git
|
||||
CODEC_VERSION = ab7c5e9b6795134377aa4846ceaae2c5bc504f76
|
||||
CODEC_DIR = node_modules/jxl
|
||||
CODEC_BUILD_ROOT := $(CODEC_DIR)/build
|
||||
CODEC_MT_BUILD_DIR := $(CODEC_BUILD_ROOT)/mt
|
||||
|
||||
50
codecs/jxl/dec/jxl_dec.js
generated
50
codecs/jxl/dec/jxl_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
51
codecs/jxl/dec/jxl_node_dec.js
generated
51
codecs/jxl/dec/jxl_node_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -35,15 +35,13 @@ val encode(std::string image, int width, int height, JXLOptions options) {
|
||||
|
||||
cparams.epf = options.epf;
|
||||
cparams.speed_tier = static_cast<jxl::SpeedTier>(options.speed);
|
||||
cparams.near_lossless = options.nearLossless;
|
||||
cparams.decoding_speed_tier = options.decodingSpeedTier;
|
||||
|
||||
if (options.lossyPalette || options.nearLossless) {
|
||||
if (options.lossyPalette) {
|
||||
cparams.lossy_palette = true;
|
||||
cparams.palette_colors = 0;
|
||||
cparams.options.predictor = jxl::Predictor::Zero;
|
||||
// Near-lossless assumes -R 0
|
||||
cparams.responsive = 0;
|
||||
cparams.modular_mode = true;
|
||||
}
|
||||
|
||||
float quality = options.quality;
|
||||
@@ -79,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);
|
||||
if (!io.metadata.size.Set(width, height)) {
|
||||
return val::null();
|
||||
|
||||
63
codecs/jxl/enc/jxl_enc.js
generated
63
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;function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){var imports={};imports["wasm"]=e.data.wasmModule;imports["wasmMemory"]=e.data.wasmMemory;imports["buffer"]=imports["wasmMemory"].buffer;imports["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);Module["PThread"].threadExit(result)}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){{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;function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){var imports={};imports["wasm"]=e.data.wasmModule;imports["wasmMemory"]=e.data.wasmMemory;imports["buffer"]=imports["wasmMemory"].buffer;imports["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);Module["PThread"].threadExit(result)}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){{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}};
|
||||
|
||||
65
codecs/jxl/enc/jxl_node_enc.js
generated
65
codecs/jxl/enc/jxl_node_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
52
codecs/mozjpeg/dec/mozjpeg_node_dec.js
generated
52
codecs/mozjpeg/dec/mozjpeg_node_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
53
codecs/mozjpeg/enc/mozjpeg_enc.js
generated
53
codecs/mozjpeg/enc/mozjpeg_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
54
codecs/mozjpeg/enc/mozjpeg_node_enc.js
generated
54
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]
|
||||
pub fn decode(mut data: &[u8]) -> ImageData {
|
||||
let mut decoder = png::Decoder::new(&mut data);
|
||||
decoder.set_transformations(
|
||||
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
|
||||
);
|
||||
decoder.set_transformations(png::Transformations::EXPAND);
|
||||
let (info, mut reader) = decoder.read_info().unwrap_throw();
|
||||
let num_pixels = (info.width * info.height) as usize;
|
||||
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 {boolean} premultiply
|
||||
* @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;
|
||||
|
||||
|
||||
16
codecs/resize/pkg/squoosh_resize.js
generated
16
codecs/resize/pkg/squoosh_resize.js
generated
@@ -26,16 +26,8 @@ function getInt32Memory0() {
|
||||
return cachegetInt32Memory0;
|
||||
}
|
||||
|
||||
let cachegetUint8ClampedMemory0 = null;
|
||||
function getUint8ClampedMemory0() {
|
||||
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);
|
||||
function getArrayU8FromWasm0(ptr, len) {
|
||||
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len);
|
||||
}
|
||||
/**
|
||||
* @param {Uint8Array} input_image
|
||||
@@ -46,7 +38,7 @@ function getClampedArrayU8FromWasm0(ptr, len) {
|
||||
* @param {number} typ_idx
|
||||
* @param {boolean} premultiply
|
||||
* @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) {
|
||||
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);
|
||||
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
||||
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
||||
var v1 = getClampedArrayU8FromWasm0(r0, r1).slice();
|
||||
var v1 = getArrayU8FromWasm0(r0, r1).slice();
|
||||
wasm.__wbindgen_free(r0, r1 * 1);
|
||||
return v1;
|
||||
} 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::Type;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen::Clamped;
|
||||
|
||||
mod srgb;
|
||||
use srgb::{linear_to_srgb, Clamp};
|
||||
@@ -67,7 +66,7 @@ pub fn resize(
|
||||
typ_idx: usize,
|
||||
premultiply: bool,
|
||||
color_space_conversion: bool,
|
||||
) -> Clamped<Vec<u8>> {
|
||||
) -> Vec<u8> {
|
||||
let typ = match typ_idx {
|
||||
0 => Type::Triangle,
|
||||
1 => Type::Catrom,
|
||||
@@ -92,7 +91,7 @@ pub fn resize(
|
||||
typ,
|
||||
);
|
||||
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
|
||||
@@ -139,5 +138,5 @@ pub fn resize(
|
||||
.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",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "../build-cpp.sh"
|
||||
}
|
||||
|
||||
@@ -5,19 +5,12 @@
|
||||
using namespace emscripten;
|
||||
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
|
||||
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);
|
||||
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_a = img[3].Row(y);
|
||||
for (int x = 0; x < width; x++) {
|
||||
row_r[x] = SrgbToLinear[rgba[(y * width + x) * 4 + 0]];
|
||||
row_g[x] = SrgbToLinear[rgba[(y * width + x) * 4 + 1]];
|
||||
row_b[x] = SrgbToLinear[rgba[(y * width + x) * 4 + 2]];
|
||||
row_a[x] = SrgbToLinear[rgba[(y * width + x) * 4 + 3]];
|
||||
row_r[x] = 255.0 * pow(rgba[(y * width + x) * 4 + 0] / 255.0, gamma);
|
||||
row_g[x] = 255.0 * pow(rgba[(y * width + x) * 4 + 1] / 255.0, gamma);
|
||||
row_b[x] = 255.0 * pow(rgba[(y * width + x) * 4 + 2] / 255.0, gamma);
|
||||
row_a[x] = 255.0 * pow(rgba[(y * width + x) * 4 + 3] / 255.0, gamma);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,7 +37,6 @@ class VisDiff {
|
||||
|
||||
public:
|
||||
VisDiff(std::string ref_img, int width, int height) {
|
||||
gammaLookupTable();
|
||||
planarize(this->ref_img, (uint8_t*)ref_img.c_str(), width, height);
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
|
||||
64
codecs/visdif/visdif.js
generated
64
codecs/visdif/visdif.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
49
codecs/webp/dec/webp_dec.js
generated
49
codecs/webp/dec/webp_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
50
codecs/webp/dec/webp_node_dec.js
generated
50
codecs/webp/dec/webp_node_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
53
codecs/webp/enc/webp_enc.js
generated
53
codecs/webp/enc/webp_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
53
codecs/webp/enc/webp_enc_simd.js
generated
53
codecs/webp/enc/webp_enc_simd.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
53
codecs/webp/enc/webp_node_enc.js
generated
53
codecs/webp/enc/webp_node_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
50
codecs/wp2/dec/wp2_dec.js
generated
50
codecs/wp2/dec/wp2_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
50
codecs/wp2/dec/wp2_node_dec.js
generated
50
codecs/wp2/dec/wp2_node_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
54
codecs/wp2/enc/wp2_enc.js
generated
54
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;function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){var imports={};imports["wasm"]=e.data.wasmModule;imports["wasmMemory"]=e.data.wasmMemory;imports["buffer"]=imports["wasmMemory"].buffer;imports["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);Module["PThread"].threadExit(result)}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){{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;function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){var imports={};imports["wasm"]=e.data.wasmModule;imports["wasmMemory"]=e.data.wasmMemory;imports["buffer"]=imports["wasmMemory"].buffer;imports["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);Module["PThread"].threadExit(result)}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){{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}};
|
||||
|
||||
55
codecs/wp2/enc/wp2_node_enc.js
generated
55
codecs/wp2/enc/wp2_node_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -20,6 +20,7 @@ const allSrcPlaceholder = 'CLIENT_BUNDLE_PLUGIN_ALL_SRC';
|
||||
|
||||
export function getDependencies(clientOutput, item) {
|
||||
const crawlDependencies = new Set([item.fileName]);
|
||||
const referencedFiles = new Set();
|
||||
|
||||
for (const fileName of crawlDependencies) {
|
||||
const chunk = clientOutput.find((v) => v.fileName === fileName);
|
||||
@@ -27,11 +28,24 @@ export function getDependencies(clientOutput, item) {
|
||||
for (const dep of chunk.imports) {
|
||||
crawlDependencies.add(dep);
|
||||
}
|
||||
|
||||
for (const dep of chunk.referencedFiles) {
|
||||
referencedFiles.add(dep);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't add self as dependency
|
||||
crawlDependencies.delete(item.fileName);
|
||||
|
||||
// Merge referencedFiles as regular deps. They need to be in the same Set as
|
||||
// some JS files might appear in both lists and need to be deduped too.
|
||||
//
|
||||
// Didn't do this as part of the main loop since their `chunk` can't have
|
||||
// nested deps and sometimes might be missing altogether, depending on type.
|
||||
for (const dep of referencedFiles) {
|
||||
crawlDependencies.add(dep);
|
||||
}
|
||||
|
||||
return [...crawlDependencies];
|
||||
}
|
||||
|
||||
@@ -139,9 +153,9 @@ export default function (inputOptions, outputOptions, resolveFileUrl) {
|
||||
if (property.startsWith(allSrcPlaceholder)) {
|
||||
const allModules = [
|
||||
clientEntry,
|
||||
...dependencies.map((name) =>
|
||||
clientOutput.find((item) => item.fileName === name),
|
||||
),
|
||||
...dependencies
|
||||
.map((name) => clientOutput.find((item) => item.fileName === name))
|
||||
.filter((item) => item.code),
|
||||
];
|
||||
|
||||
const inlineDefines = [
|
||||
|
||||
@@ -17,10 +17,14 @@ const prefix = 'entry-data:';
|
||||
const mainNamePlaceholder = 'ENTRY_DATA_PLUGIN_MAIN_NAME';
|
||||
const dependenciesPlaceholder = 'ENTRY_DATA_PLUGIN_DEPS';
|
||||
const placeholderRe = /(ENTRY_DATA_PLUGIN_(?:MAIN_NAME|DEPS))(\d+)/g;
|
||||
const filenamePrefix = 'static/';
|
||||
|
||||
/** @param {string} fileName */
|
||||
export function fileNameToURL(fileName) {
|
||||
return fileName.replace(/^static\//, '/');
|
||||
}
|
||||
|
||||
export default function entryDataPlugin() {
|
||||
/** @type {string} */
|
||||
/** @type {number} */
|
||||
let exportCounter;
|
||||
/** @type {Map<number, string>} */
|
||||
let counterToIdMap;
|
||||
@@ -69,15 +73,11 @@ export default function entryDataPlugin() {
|
||||
if (!chunk) throw Error(`Cannot find ${id}`);
|
||||
|
||||
if (placeholder === mainNamePlaceholder) {
|
||||
return JSON.stringify(
|
||||
chunk.fileName.slice(filenamePrefix.length),
|
||||
);
|
||||
return JSON.stringify(fileNameToURL(chunk.fileName));
|
||||
}
|
||||
|
||||
return JSON.stringify(
|
||||
getDependencies(chunks, chunk).map((item) =>
|
||||
item.slice(filenamePrefix.length),
|
||||
),
|
||||
getDependencies(chunks, chunk).map((filename) => fileNameToURL(filename)),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -30,7 +30,7 @@ const imagePath = 'path/to/image.png';
|
||||
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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
```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 = {
|
||||
//When both width and height are specified, the image resized to specified size.
|
||||
const preprocessOptions: {
|
||||
resize: {
|
||||
enabled: true,
|
||||
width: 100,
|
||||
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);
|
||||
|
||||
const encodeOptions = {
|
||||
const encodeOptions: {
|
||||
mozjpeg: {}, //an empty object means 'use default settings'
|
||||
jxl: {
|
||||
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).
|
||||
|
||||
@@ -89,7 +81,7 @@ When you have encoded an image, you normally want to write it to a file.
|
||||
This example takes an image that has been encoded as a `jpg` and writes it to a file:
|
||||
|
||||
```js
|
||||
const rawEncodedImage = (await image.encodedWith.mozjpeg).binary;
|
||||
const rawEncodedImage = (await image.encodedWidth.mozjpeg).binary;
|
||||
|
||||
fs.writeFile('/path/to/new/image.jpg', rawEncodedImage);
|
||||
```
|
||||
@@ -166,6 +158,6 @@ const encodeOptions: {
|
||||
```
|
||||
|
||||
[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
|
||||
[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,
|
||||
})}`;
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,133 +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 { spawn } from 'child_process';
|
||||
import { relative, join } from 'path';
|
||||
import { promises as fsp } from 'fs';
|
||||
import { promisify } from 'util';
|
||||
|
||||
import * as ts from 'typescript';
|
||||
import glob from 'glob';
|
||||
import { sync as whichSync } from 'which';
|
||||
|
||||
const globP = promisify(glob);
|
||||
|
||||
const tscPath = whichSync('tsc');
|
||||
|
||||
const extRe = /\.tsx?$/;
|
||||
|
||||
function loadConfig(mainPath) {
|
||||
const fileName = ts.findConfigFile(mainPath, ts.sys.fileExists);
|
||||
if (!fileName) throw Error('tsconfig not found');
|
||||
const text = ts.sys.readFile(fileName);
|
||||
const loadedConfig = ts.parseConfigFileTextToJson(fileName, text).config;
|
||||
const parsedTsConfig = ts.parseJsonConfigFileContent(
|
||||
loadedConfig,
|
||||
ts.sys,
|
||||
process.cwd(),
|
||||
undefined,
|
||||
fileName,
|
||||
);
|
||||
return parsedTsConfig;
|
||||
}
|
||||
|
||||
export default function simpleTS(mainPath, { noBuild, watch } = {}) {
|
||||
const config = loadConfig(mainPath);
|
||||
const args = ['-b', mainPath];
|
||||
|
||||
let tsBuildDone;
|
||||
|
||||
async function watchBuiltFiles(rollupContext) {
|
||||
const matches = await globP(config.options.outDir + '/**/*.js');
|
||||
for (const match of matches) rollupContext.addWatchFile(match);
|
||||
}
|
||||
|
||||
async function tsBuild(rollupContext) {
|
||||
if (tsBuildDone) {
|
||||
// Watch lists are cleared on each build, so we need to rewatch all the JS files.
|
||||
await watchBuiltFiles(rollupContext);
|
||||
return tsBuildDone;
|
||||
}
|
||||
if (noBuild) {
|
||||
return (tsBuildDone = Promise.resolve());
|
||||
}
|
||||
tsBuildDone = Promise.resolve().then(async () => {
|
||||
await new Promise((resolve) => {
|
||||
const proc = spawn(tscPath, args, {
|
||||
stdio: 'inherit',
|
||||
});
|
||||
|
||||
proc.on('exit', (code) => {
|
||||
if (code !== 0) {
|
||||
throw Error('TypeScript build failed');
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
await watchBuiltFiles(rollupContext);
|
||||
|
||||
if (watch) {
|
||||
tsBuildDone.then(() => {
|
||||
spawn(tscPath, [...args, '--watch', '--preserveWatchOutput'], {
|
||||
stdio: 'inherit',
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return tsBuildDone;
|
||||
}
|
||||
|
||||
return {
|
||||
name: 'simple-ts',
|
||||
resolveId(id, importer) {
|
||||
// If there isn't an importer, it's an entry point, so we don't need to resolve it relative
|
||||
// to something.
|
||||
if (!importer) return null;
|
||||
|
||||
const tsResolve = ts.resolveModuleName(
|
||||
id,
|
||||
importer,
|
||||
config.options,
|
||||
ts.sys,
|
||||
);
|
||||
|
||||
if (
|
||||
// It didn't find anything
|
||||
!tsResolve.resolvedModule ||
|
||||
// Or if it's linking to a definition file, it's something in node_modules,
|
||||
// or something local like css.d.ts
|
||||
tsResolve.resolvedModule.extension === '.d.ts'
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
return tsResolve.resolvedModule.resolvedFileName;
|
||||
},
|
||||
async load(id) {
|
||||
if (!extRe.test(id)) return null;
|
||||
|
||||
// TypeScript building is deferred until the first TS file load.
|
||||
// This allows prerequisites to happen first,
|
||||
// such as css.d.ts generation in css-plugin.
|
||||
await tsBuild(this);
|
||||
|
||||
// Look for the JS equivalent in the tmp folder
|
||||
const newId = join(
|
||||
config.options.outDir,
|
||||
relative(config.options.rootDir, id),
|
||||
).replace(extRe, '.js');
|
||||
|
||||
return fsp.readFile(newId, { encoding: 'utf8' });
|
||||
},
|
||||
};
|
||||
}
|
||||
2127
libsquoosh/package-lock.json
generated
2127
libsquoosh/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "@squoosh/lib",
|
||||
"version": "0.4.0",
|
||||
"version": "0.2.3",
|
||||
"description": "A Node library for Squoosh",
|
||||
"public": true,
|
||||
"main": "./build/index.js",
|
||||
"main": "/build/index.js",
|
||||
"files": [
|
||||
"/build/*"
|
||||
],
|
||||
@@ -12,17 +12,8 @@
|
||||
},
|
||||
"keywords": [],
|
||||
"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",
|
||||
"engines": {
|
||||
"node": " ^12.5.0 || ^14.0.0 || ^16.0.0 "
|
||||
},
|
||||
"dependencies": {
|
||||
"wasm-feature-detect": "^1.2.11",
|
||||
"web-streams-polyfill": "^3.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -31,10 +22,7 @@
|
||||
"@rollup/plugin-babel": "^5.3.0",
|
||||
"@rollup/plugin-commonjs": "^18.0.0",
|
||||
"@rollup/plugin-node-resolve": "^11.2.1",
|
||||
"@types/node": "^15.6.1",
|
||||
"rollup": "^2.46.0",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"typescript": "^4.1.3",
|
||||
"which": "^2.0.2"
|
||||
"rollup-plugin-terser": "^7.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import cjs from '@rollup/plugin-commonjs';
|
||||
import simpleTS from './lib/simple-ts';
|
||||
import asset from './lib/asset-plugin.js';
|
||||
import chunk from './lib/chunk-plugin.js';
|
||||
import json from './lib/json-plugin.js';
|
||||
import autojson from './lib/autojson-plugin.js';
|
||||
import { getBabelOutputPlugin } from '@rollup/plugin-babel';
|
||||
@@ -19,11 +17,9 @@ export default {
|
||||
plugins: [
|
||||
resolve(),
|
||||
cjs(),
|
||||
chunk(),
|
||||
asset(),
|
||||
autojson(),
|
||||
json(),
|
||||
simpleTS('.'),
|
||||
getBabelOutputPlugin({
|
||||
babelrc: false,
|
||||
configFile: false,
|
||||
|
||||
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 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
|
||||
// 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
|
||||
// of `epsilon`. It will use at most `maxRounds` attempts.
|
||||
export async function binarySearch(
|
||||
measureGoal: number,
|
||||
measure: (val: number) => Promise<number>,
|
||||
{ min = 0, max = 100, epsilon = 0.1, maxRounds = 6 }: BinarySearchParams = {},
|
||||
measureGoal,
|
||||
measure,
|
||||
{ min = 0, max = 100, epsilon = 0.1, maxRounds = 8 } = {},
|
||||
) {
|
||||
let parameter = (max - min) / 2 + min;
|
||||
let delta = (max - min) / 4;
|
||||
@@ -66,21 +33,12 @@ export async function binarySearch(
|
||||
}
|
||||
|
||||
export async function autoOptimize(
|
||||
bitmapIn: ImageData,
|
||||
encode: (
|
||||
bitmap: ImageData,
|
||||
quality: number,
|
||||
) => Promise<Uint8Array> | Uint8Array,
|
||||
decode: (binary: Uint8Array) => Promise<ImageData> | ImageData,
|
||||
{
|
||||
butteraugliDistanceGoal = 1.4,
|
||||
...binarySearchParams
|
||||
}: AutoOptimizeParams = {},
|
||||
): Promise<AutoOptimizeResult> {
|
||||
const { VisDiff } = await instantiateEmscriptenWasm(
|
||||
visdif as VisDiffModuleFactory,
|
||||
visdifWasm,
|
||||
);
|
||||
bitmapIn,
|
||||
encode,
|
||||
decode,
|
||||
{ butteraugliDistanceGoal = 1.4, ...otherOpts } = {},
|
||||
) {
|
||||
const { VisDiff } = await instantiateEmscriptenWasm(visdif, visdifWasm);
|
||||
|
||||
const comparator = new VisDiff(
|
||||
bitmapIn.data,
|
||||
@@ -88,11 +46,8 @@ export async function autoOptimize(
|
||||
bitmapIn.height,
|
||||
);
|
||||
|
||||
// We're able to do non null assertion because
|
||||
// we know that binarySearch will set these values
|
||||
let bitmapOut!: ImageData;
|
||||
let binaryOut!: Uint8Array;
|
||||
|
||||
let bitmapOut;
|
||||
let binaryOut;
|
||||
// Increasing quality means _decrease_ in Butteraugli distance.
|
||||
// `binarySearch` assumes that increasing `parameter` will
|
||||
// increase the metric value. So multipliy Butteraugli values by -1.
|
||||
@@ -103,7 +58,7 @@ export async function autoOptimize(
|
||||
bitmapOut = await decode(binaryOut);
|
||||
return -1 * comparator.distance(bitmapOut.data);
|
||||
},
|
||||
binarySearchParams,
|
||||
otherOpts,
|
||||
);
|
||||
comparator.delete();
|
||||
|
||||
@@ -1,44 +1,5 @@
|
||||
import { promises as fsp } from 'fs';
|
||||
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 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 = typeof import('./image_data.js');
|
||||
// Needed for being able to assign to `globalThis.ImageData`
|
||||
var ImageData: ImageData['constructor'];
|
||||
}
|
||||
|
||||
import type { QuantizerModule } from '../../codecs/imagequant/imagequant.js';
|
||||
|
||||
// MozJPEG
|
||||
import mozEnc from '../../codecs/mozjpeg/enc/mozjpeg_node_enc.js';
|
||||
@@ -55,9 +16,6 @@ import webpDecWasm from 'asset-url:../../codecs/webp/dec/webp_node_dec.wasm';
|
||||
// AVIF
|
||||
import avifEnc from '../../codecs/avif/enc/avif_node_enc.js';
|
||||
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 avifDecWasm from 'asset-url:../../codecs/avif/dec/avif_node_dec.wasm';
|
||||
|
||||
@@ -93,22 +51,16 @@ const resizePromise = resize.default(fsp.readFile(pathify(resizeWasm)));
|
||||
// rotate
|
||||
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
|
||||
import imageQuant from '../../codecs/imagequant/imagequant_node.js';
|
||||
import imageQuantWasm from 'asset-url:../../codecs/imagequant/imagequant_node.wasm';
|
||||
const imageQuantPromise: Promise<QuantizerModule> = instantiateEmscriptenWasm(
|
||||
imageQuant,
|
||||
imageQuantWasm,
|
||||
);
|
||||
const imageQuantPromise = instantiateEmscriptenWasm(imageQuant, imageQuantWasm);
|
||||
|
||||
// Our decoders currently rely on a `ImageData` global.
|
||||
import ImageData from './image_data.js';
|
||||
globalThis.ImageData = ImageData;
|
||||
|
||||
function resizeNameToIndex(name: string) {
|
||||
function resizeNameToIndex(name) {
|
||||
switch (name) {
|
||||
case 'triangle':
|
||||
return 0;
|
||||
@@ -128,26 +80,25 @@ function resizeWithAspect({
|
||||
input_height,
|
||||
target_width,
|
||||
target_height,
|
||||
}: ResizeWithAspectParams): { width: number; height: number } {
|
||||
}) {
|
||||
if (!target_width && !target_height) {
|
||||
throw Error('Need to specify at least width or height when resizing');
|
||||
}
|
||||
|
||||
if (target_width && target_height) {
|
||||
return { width: target_width, height: target_height };
|
||||
}
|
||||
|
||||
if (!target_width) {
|
||||
return {
|
||||
width: Math.round((input_width / input_height) * target_height),
|
||||
height: target_height,
|
||||
};
|
||||
}
|
||||
|
||||
if (!target_height) {
|
||||
return {
|
||||
width: target_width,
|
||||
height: Math.round((input_height / input_width) * target_width),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const preprocessors = {
|
||||
@@ -157,16 +108,10 @@ export const preprocessors = {
|
||||
instantiate: async () => {
|
||||
await resizePromise;
|
||||
return (
|
||||
buffer: Uint8Array,
|
||||
input_width: number,
|
||||
input_height: number,
|
||||
{
|
||||
width,
|
||||
height,
|
||||
method,
|
||||
premultiply,
|
||||
linearRGB,
|
||||
}: ResizeInstantiateOptions,
|
||||
buffer,
|
||||
input_width,
|
||||
input_height,
|
||||
{ width, height, method, premultiply, linearRGB },
|
||||
) => {
|
||||
({ width, height } = resizeWithAspect({
|
||||
input_width,
|
||||
@@ -203,12 +148,7 @@ export const preprocessors = {
|
||||
description: 'Reduce the number of colors used (aka. paletting)',
|
||||
instantiate: async () => {
|
||||
const imageQuant = await imageQuantPromise;
|
||||
return (
|
||||
buffer: Uint8Array,
|
||||
width: number,
|
||||
height: number,
|
||||
{ numColors, dither }: { numColors: number; dither: number },
|
||||
) =>
|
||||
return (buffer, width, height, { numColors, dither }) =>
|
||||
new ImageData(
|
||||
imageQuant.quantize(buffer, width, height, numColors, dither),
|
||||
width,
|
||||
@@ -224,18 +164,13 @@ export const preprocessors = {
|
||||
name: 'Rotate',
|
||||
description: 'Rotate image',
|
||||
instantiate: async () => {
|
||||
return async (
|
||||
buffer: Uint8Array,
|
||||
width: number,
|
||||
height: number,
|
||||
{ numRotations }: { numRotations: number },
|
||||
) => {
|
||||
return async (buffer, width, height, { numRotations }) => {
|
||||
const degrees = (numRotations * 90) % 360;
|
||||
const sameDimensions = degrees == 0 || degrees == 180;
|
||||
const size = width * height * 4;
|
||||
const instance = (
|
||||
await WebAssembly.instantiate(await fsp.readFile(pathify(rotateWasm)))
|
||||
).instance as RotateModuleInstance;
|
||||
const { instance } = await WebAssembly.instantiate(
|
||||
await fsp.readFile(pathify(rotateWasm)),
|
||||
);
|
||||
const { memory } = instance.exports;
|
||||
const additionalPagesNeeded = Math.ceil(
|
||||
(size * 2 - memory.buffer.byteLength + 8) / (64 * 1024),
|
||||
@@ -293,7 +228,7 @@ export const codecs = {
|
||||
webp: {
|
||||
name: 'WebP',
|
||||
extension: 'webp',
|
||||
detectors: [/^RIFF....WEBPVP8[LX ]/s],
|
||||
detectors: [/^RIFF....WEBPVP8[LX ]/],
|
||||
dec: () => instantiateEmscriptenWasm(webpDec, webpDecWasm),
|
||||
enc: () => instantiateEmscriptenWasm(webpEnc, webpEncWasm),
|
||||
defaultEncoderOptions: {
|
||||
@@ -336,16 +271,7 @@ export const codecs = {
|
||||
extension: 'avif',
|
||||
detectors: [/^\x00\x00\x00 ftypavif\x00\x00\x00\x00/],
|
||||
dec: () => instantiateEmscriptenWasm(avifDec, avifDecWasm),
|
||||
enc: async () => {
|
||||
if (await threads()) {
|
||||
return instantiateEmscriptenWasm(
|
||||
avifEncMt,
|
||||
avifEncMtWasm,
|
||||
avifEncMtWorker,
|
||||
);
|
||||
}
|
||||
return instantiateEmscriptenWasm(avifEnc, avifEncWasm);
|
||||
},
|
||||
enc: () => instantiateEmscriptenWasm(avifEnc, avifEncWasm),
|
||||
defaultEncoderOptions: {
|
||||
cqLevel: 33,
|
||||
cqAlphaLevel: -1,
|
||||
@@ -360,8 +286,8 @@ export const codecs = {
|
||||
},
|
||||
autoOptimize: {
|
||||
option: 'cqLevel',
|
||||
min: 62,
|
||||
max: 0,
|
||||
min: 0,
|
||||
max: 62,
|
||||
},
|
||||
},
|
||||
jxl: {
|
||||
@@ -420,18 +346,13 @@ export const codecs = {
|
||||
await pngEncDecPromise;
|
||||
await oxipngPromise;
|
||||
return {
|
||||
encode: (
|
||||
buffer: Uint8Array,
|
||||
width: number,
|
||||
height: number,
|
||||
opts: { level: number },
|
||||
) => {
|
||||
encode: (buffer, width, height, opts) => {
|
||||
const simplePng = pngEncDec.encode(
|
||||
new Uint8Array(buffer),
|
||||
width,
|
||||
height,
|
||||
);
|
||||
return oxipng.optimise(simplePng, opts.level, false);
|
||||
return oxipng.optimise(simplePng, opts.level);
|
||||
},
|
||||
};
|
||||
},
|
||||
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 new URL(workerJS).pathname;
|
||||
return requestPath;
|
||||
},
|
||||
});
|
||||
}
|
||||
7
libsquoosh/src/image_data.js
Normal file
7
libsquoosh/src/image_data.js
Normal file
@@ -0,0 +1,7 @@
|
||||
export default class ImageData {
|
||||
constructor(data, width, height) {
|
||||
this.data = data;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
export default class ImageData {
|
||||
readonly data: Uint8ClampedArray;
|
||||
readonly width: number;
|
||||
readonly height: number;
|
||||
|
||||
constructor(data: Uint8ClampedArray, width: number, height: number) {
|
||||
this.data = data;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
}
|
||||
@@ -180,9 +180,9 @@ class Image {
|
||||
encName,
|
||||
encConfig,
|
||||
optimizerButteraugliTarget: Number(
|
||||
encodeOptions.optimizerButteraugliTarget ?? 1.4,
|
||||
encodeOptions.optimizerButteraugliTarget,
|
||||
),
|
||||
maxOptimizerRounds: Number(encodeOptions.maxOptimizerRounds ?? 6),
|
||||
maxOptimizerRounds: Number(encodeOptions.maxOptimizerRounds),
|
||||
});
|
||||
}
|
||||
await Promise.all(Object.values(this.encodedWith));
|
||||
|
||||
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;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user