Compare commits

..

44 Commits

Author SHA1 Message Date
Jason Miller
6ed26ec70c a couple more fixes from CR 2021-06-07 15:04:51 -04:00
Jason Miller
73b3fd0ef3 Merge branch 'dev' into preprocessor-transformations-rebased 2021-06-07 15:02:13 -04:00
Jason Miller
ad6f91692f Reuse glyphs for multiple icons, fix up typings 2021-06-07 15:01:24 -04:00
Jason Miller
7918938d8a Suggestions from code review 2021-06-07 14:59:26 -04:00
Jason Miller
543c2e73fb Avoid mutating input buffer in crop preprocessor 2021-06-03 11:16:26 -04:00
Jason Miller
8c5b4f33bf remove missing-types.d.ts 2021-06-03 11:13:53 -04:00
Jason Miller
066e9acf93 Merge branch 'dev' into preprocessor-transformations-rebased 2021-06-03 11:10:43 -04:00
Jake Archibald
44de57a92a Merge branch 'dev' into preprocessor-transformations-rebased 2021-02-09 13:40:02 +00:00
Jason Miller
33347951d7 Merge branch 'dev' into preprocessor-transformations-rebased 2020-12-15 22:50:01 -05:00
Jason Miller
c459319b21 Fix rotation transforms 2020-12-14 17:32:29 -05:00
Jason Miller
588ec61543 fix rotate crop adjustment 2020-12-14 16:45:15 -05:00
Jason Miller
82914f9cde Fix Firefox, remove dead code. 2020-12-11 12:55:14 -05:00
Jason Miller
37f4d753f9 Merge pull request #897 from GoogleChromeLabs/cli-invoc-2
Flyouts
2020-12-10 23:46:54 -05:00
Jason Miller
ce3d94297d Close Options flyout when clicking an item 2020-12-10 23:44:48 -05:00
Jason Miller
76ef6294f3 Fix merge issue 2020-12-10 23:37:55 -05:00
Jason Miller
50bc8e4106 Merge branch 'preprocessor-transformations-rebased' into cli-invoc-2 2020-12-10 23:34:10 -05:00
Jason Miller
1b8f051438 Merge branch 'dev' of github.com:GoogleChromeLabs/squoosh into preprocessor-transformations-rebased 2020-12-10 23:32:15 -05:00
Jason Miller
cf894b7d19 fix 2020-12-10 12:34:50 -05:00
Jason Miller
d1d181fccd Merge upstream 2020-12-10 10:24:56 -05:00
Jason Miller
a65bbdf811 Hoist flyouts to <body> 2020-12-09 23:47:43 -05:00
Jason Miller
7de8fa9da3 Initial Options Flyout 2020-12-09 18:11:44 -05:00
Jason Miller
646747b039 Merge branch 'preprocessor-transformations-rebased' into cli-invoc-2 2020-12-09 12:21:24 -05:00
Jason Miller
a2fb7a38cd Fix mobile fly-out 2020-12-09 12:20:55 -05:00
Jason Miller
81890e972b Remove development image load 2020-12-09 12:14:11 -05:00
Jason Miller
c2aa35aa02 Hide options on mobile 2020-12-09 12:12:32 -05:00
Jason Miller
c6d936cd49 Fix cropbox UI in Firefox 2020-12-09 11:58:27 -05:00
Jason Miller
60b79da936 Keep resize enabled when cropping 2020-12-09 11:58:10 -05:00
Jason Miller
dbd80f15eb Fix cropbox background when zoomed 2020-12-09 11:49:03 -05:00
Jason Miller
ed3c79894d Remove "Retina" zoom preset 2020-12-09 11:48:28 -05:00
Jason Miller
213028cfdd Changing crop updates and disables resize processor 2020-12-09 11:48:10 -05:00
Jason Miller
952aea049d Merge branch 'cli-invoc' of github.com:GoogleChromeLabs/squoosh into cli-invoc-2 2020-12-09 11:28:24 -05:00
Jason Miller
e3b053db12 Fix crop preprocessor 2020-12-09 11:22:43 -05:00
Jason Miller
b8574b228a fix ordering of preprocessors 2020-12-09 11:22:33 -05:00
Jason Miller
ee8ea539e7 fix crop aspect and presets 2020-12-09 11:22:22 -05:00
Jake Archibald
a7a991ae45 Removing redundant imports, restoring auto-load 2020-12-09 12:38:32 +00:00
Jason Miller
32232c7f0b Add yet another gray 2020-12-09 12:33:59 +00:00
Jason Miller
bb78632cf5 Preact TS tweak 2020-12-09 12:33:59 +00:00
Jason Miller
68cd15bd14 crop and flip preprocessor 2020-12-09 12:33:59 +00:00
Jason Miller
bde3a93b6e Add Transform modal 2020-12-09 12:33:57 +00:00
Jason Miller
7aeef5ff37 Add Flyout, hoist altBackground to Compress 2020-12-09 12:29:59 +00:00
Jason Miller
0ee234f03b Preact 10.5.7 2020-12-09 12:29:06 +00:00
Surma
8105633ca6 Update src/client/lazy-app/util/cli-invocation-generator.ts 2020-12-07 11:17:38 +00:00
Surma
46764f3375 Show snack on error 2020-12-01 13:14:35 +00:00
Surma
0371cfd292 Add CLI button 2020-12-01 13:12:28 +00:00
164 changed files with 4612 additions and 12714 deletions

4
.gitattributes vendored
View File

@@ -1,2 +1,2 @@
/codecs/**/*.js linguist-generated -diff
/codecs/*/pkg*/*.d.ts linguist-generated
/codecs/**/*.js linguist-generated=true
/codecs/*/pkg*/*.d.ts linguist-generated=true

View File

@@ -1 +0,0 @@
npx lint-staged

View File

@@ -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

View File

@@ -1,7 +1,3 @@
# Project no longer maintained
Unfortunately, due to a few people leaving the team, and staffing issues resulting from the current economic climate (ugh), this package is no longer actively maintained. I know that sucks, but there simply isn't the time & people to work on this. If anyone from the community wants to fork it, you have my blessing. The [squoosh.app](https://squoosh.app) will continue to be supported and improved.
# Squoosh CLI
Squoosh CLI is an _experimental_ way to run all the codecs you know from the [Squoosh] web app on your command line using WebAssembly. The Squoosh CLI uses a worker pool to parallelize processing images. This way you can apply the same codec to many images at once.
@@ -46,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
@@ -59,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
View File

@@ -1,15 +1,15 @@
{
"name": "@squoosh/cli",
"version": "0.7.3",
"version": "0.7.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@squoosh/cli",
"version": "0.7.3",
"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",

View File

@@ -1,14 +1,9 @@
{
"name": "@squoosh/cli",
"version": "0.7.3",
"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",

View File

@@ -4,7 +4,6 @@ import { program } from 'commander/esm.mjs';
import JSON5 from 'json5';
import path from 'path';
import { promises as fsp } from 'fs';
import { cpus } from 'os';
import ora from 'ora';
import kleur from 'kleur';
@@ -104,7 +103,7 @@ async function getInputFiles(paths) {
async function processFiles(files) {
files = await getInputFiles(files);
const imagePool = new ImagePool(cpus().length);
const imagePool = new ImagePool();
const results = new Map();
const progress = progressTracker(results);
@@ -119,8 +118,7 @@ async function processFiles(files) {
let decoded = 0;
let decodedFiles = await Promise.all(
files.map(async (file) => {
const buffer = await fsp.readFile(file);
const image = imagePool.ingestImage(buffer);
const image = imagePool.ingestImage(file);
await image.decoded;
results.set(image, {
file,
@@ -181,8 +179,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}`;

View File

@@ -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

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -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}};

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -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}};

View File

@@ -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
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 \
"
# Build and cache standard libraries with these flags + Embind.
RUN emcc ${CXXFLAGS} ${LDFLAGS} --bind -xc++ /dev/null -o /dev/null

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,5 @@
CODEC_URL = https://github.com/libjxl/libjxl.git
CODEC_VERSION = 9f544641ec83f6abd9da598bdd08178ee8a003e0
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
@@ -75,9 +75,6 @@ $(CODEC_MT_SIMD_BUILD_DIR)/Makefile: CXXFLAGS+=-msimd128
-DCMAKE_CROSSCOMPILING_EMULATOR=node \
-B $(@D) \
$(<D)
emcc -Wall -O3 -o $(CODEC_DIR)/third_party/skcms/skcms.cc.o -I$(CODEC_DIR)/third_party/skcms -c $(CODEC_DIR)/third_party/skcms/skcms.cc
llvm-ar rc $(CODEC_BUILD_DIR)/third_party/libskcms.a $(CODEC_DIR)/third_party/skcms/skcms.cc.o
rm $(CODEC_DIR)/third_party/skcms/skcms.cc.o
$(CODEC_DIR)/CMakeLists.txt:
$(RM) -r $(@D)

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -4,21 +4,21 @@
#include "lib/jxl/base/thread_pool_internal.h"
#include "lib/jxl/enc_external_image.h"
#include "lib/jxl/enc_file.h"
#include "lib/jxl/enc_color_management.h"
using namespace emscripten;
thread_local const val Uint8Array = val::global("Uint8Array");
struct JXLOptions {
int effort;
// 1 = slowest
// 7 = fastest
int speed;
float quality;
bool progressive;
int epf;
int nearLossless;
bool lossyPalette;
size_t decodingSpeedTier;
float photonNoiseIso;
bool lossyModular;
};
val encode(std::string image, int width, int height, JXLOptions options) {
@@ -33,35 +33,25 @@ val encode(std::string image, int width, int height, JXLOptions options) {
pool_ptr = &pool;
#endif
size_t st = 10 - options.effort;
cparams.speed_tier = jxl::SpeedTier(st);
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.photon_noise_iso = options.photonNoiseIso;
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;
// Quality settings roughly match libjpeg qualities.
if (options.lossyModular || quality == 100) {
if (quality < 7 || quality == 100) {
cparams.modular_mode = true;
// Internal modular quality to roughly match VarDCT size.
if (quality < 7) {
cparams.quality_pair.first = cparams.quality_pair.second =
std::min(35 + (quality - 7) * 3.0f, 100.0f);
} else {
cparams.quality_pair.first = cparams.quality_pair.second =
std::min(35 + (quality - 7) * 65.f / 93.f, 100.0f);
}
cparams.quality_pair.first = cparams.quality_pair.second =
std::min(35 + (quality - 7) * 3.0f, 100.0f);
} else {
cparams.modular_mode = false;
if (quality >= 30) {
@@ -87,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();
@@ -98,14 +94,14 @@ val encode(std::string image, int width, int height, JXLOptions options) {
jxl::Span<const uint8_t>(reinterpret_cast<const uint8_t*>(image.data()), image.size()), width,
height, jxl::ColorEncoding::SRGB(/*is_gray=*/false), /*has_alpha=*/true,
/*alpha_is_premultiplied=*/false, /*bits_per_sample=*/8, /*endiannes=*/JXL_LITTLE_ENDIAN,
/*flipped_y=*/false, pool_ptr, main, /*(only true if bits_per_sample==32) float_in=*/false);
/*flipped_y=*/false, pool_ptr, main);
if (!result) {
return val::null();
}
auto js_result = val::null();
if (EncodeFile(cparams, &io, &passes_enc_state, &bytes, jxl::GetJxlCms(), /*aux=*/nullptr, pool_ptr)) {
if (EncodeFile(cparams, &io, &passes_enc_state, &bytes, /*aux=*/nullptr, pool_ptr)) {
js_result = Uint8Array.new_(typed_memory_view(bytes.size(), bytes.data()));
}
@@ -114,13 +110,12 @@ val encode(std::string image, int width, int height, JXLOptions options) {
EMSCRIPTEN_BINDINGS(my_module) {
value_object<JXLOptions>("JXLOptions")
.field("effort", &JXLOptions::effort)
.field("speed", &JXLOptions::speed)
.field("quality", &JXLOptions::quality)
.field("progressive", &JXLOptions::progressive)
.field("nearLossless", &JXLOptions::nearLossless)
.field("lossyPalette", &JXLOptions::lossyPalette)
.field("decodingSpeedTier", &JXLOptions::decodingSpeedTier)
.field("photonNoiseIso", &JXLOptions::photonNoiseIso)
.field("lossyModular", &JXLOptions::lossyModular)
.field("epf", &JXLOptions::epf);
function("encode", &encode);

View File

@@ -1,12 +1,11 @@
export interface EncodeOptions {
effort: number;
speed: number;
quality: number;
progressive: boolean;
epf: number;
nearLossless: number;
lossyPalette: boolean;
decodingSpeedTier: number;
photonNoiseIso: number;
lossyModular: boolean;
}
export interface JXLModule extends EmscriptenWasm.Module {

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -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}};

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -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}};

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -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) {
cinfo.comp_info[0].h_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) {

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -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];

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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
```

View File

@@ -1,6 +1,5 @@
{
"name": "avif",
"type": "module",
"scripts": {
"build": "../build-cpp.sh"
}

View File

@@ -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;

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -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}};

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -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}};

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -14,40 +14,28 @@ import { promises as fs } from 'fs';
import { lookup as lookupMime } from 'mime-types';
const prefix = /^data-url(-text)?:/;
const prefix = 'data-url:';
export default function dataURLPlugin() {
return {
name: 'data-url-plugin',
async resolveId(id, importer) {
const match = prefix.exec(id);
if (!match) return;
if (!id.startsWith(prefix)) return;
return (
match[0] + (await this.resolve(id.slice(match[0].length), importer)).id
prefix + (await this.resolve(id.slice(prefix.length), importer)).id
);
},
async load(id) {
const match = prefix.exec(id);
if (!match) return;
const isText = !!match[1];
const realId = id.slice(match[0].length);
if (!id.startsWith(prefix)) return;
const realId = id.slice(prefix.length);
this.addWatchFile(realId);
const source = await fs.readFile(realId);
const type = lookupMime(realId) || 'text/plain';
if (isText) {
const encodedBody = encodeURIComponent(source.toString('utf8'));
return `export default ${JSON.stringify(
`data:${type};charset=utf-8,${encodedBody}`,
)};`;
}
return `export default ${JSON.stringify(
`data:${type};base64,${source.toString('base64')}`,
)};`;
return `export default 'data:${type};base64,${source.toString(
'base64',
)}';`;
},
};
}

View File

@@ -28,17 +28,10 @@ if (!self.<%- amdFunctionName %>) {
<% } else { %>
new Promise(resolve => {
if ("document" in self) {
const link = document.createElement("link");
link.rel = "preload";
link.as = "script";
link.href = uri;
link.onload = () => {
const script = document.createElement("script");
script.src = uri;
script.onload = resolve;
document.head.appendChild(script);
};
document.head.appendChild(link);
const script = document.createElement("script");
script.src = uri;
script.onload = resolve;
document.head.appendChild(script);
} else {
self.nextDefineUri = uri;
importScripts(uri);

View File

@@ -1,7 +1,3 @@
# Project no longer maintained
Unfortunately, due to a few people leaving the team, and staffing issues resulting from the current economic climate (ugh), this package is no longer actively maintained. I know that sucks, but there simply isn't the time & people to work on this. If anyone from the community wants to fork it, you have my blessing. The [squoosh.app](https://squoosh.app) will continue to be supported and improved.
# libSquoosh
libSquoosh is an _experimental_ way to run all the codecs you know from the [Squoosh] web app directly inside your own JavaScript program. libSquoosh uses a worker pool to parallelize processing images. This way you can apply the same codec to many images at once.
@@ -20,25 +16,21 @@ You can start using the libSquoosh by adding these lines to the top of your JS p
```js
import { ImagePool } from '@squoosh/lib';
import { cpus } from 'os';
const imagePool = new ImagePool(cpus().length);
const imagePool = new ImagePool();
```
This will create an image pool with an underlying processing pipeline that you can use to ingest and encode images. The ImagePool constructor takes one argument that defines how many parallel operations it is allowed to run at any given time.
:warning: Important! Make sure to only create 1 `ImagePool` when performing parallel image processing. If you create multiple pools, the `ImagePool` can run out of memory and crash. By reusing a single `ImagePool`, you can ensure that the backing worker queue and processing pipeline releases memory prior to processing the next image.
This will create an image pool with an underlying processing pipeline that you can use to ingest and encode images. The ImagePool constructor takes one argument that defines how many parallel operations it is allowed to run at any given time. By default, this number is set to the amount of CPU cores available in the system it is running on.
## Ingesting images
You can ingest a new image like so:
```js
import fs from 'fs/promises';
const file = await fs.readFile('./path/to/image.png');
const image = imagePool.ingestImage(file);
const imagePath = 'path/to/image.png';
const image = imagePool.ingestImage(imagePath);
```
The `ingestImage` function can accept any [`ArrayBuffer`][arraybuffer] whether that is from `readFile()` or `fetch()`.
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.
@@ -47,31 +39,28 @@ 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
const preprocessOptions = {
//When both width and height are specified, the image resized to specified size.
await image.decoded; //Wait until the image is decoded before running preprocessors
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: {
width: 100,
}
*/
};
}
await image.preprocess(preprocessOptions);
const encodeOptions = {
const encodeOptions: {
mozjpeg: {}, //an empty object means 'use default settings'
jxl: {
quality: 90,
},
};
const result = await image.encode(encodeOptions);
}
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).
@@ -92,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 = image.encodedWith.mozjpeg.binary;
const rawEncodedImage = (await image.encodedWith.mozjpeg).binary;
fs.writeFile('/path/to/new/image.jpg', rawEncodedImage);
```
@@ -103,7 +92,10 @@ This example iterates through all encoded versions of the image and writes them
const newImagePath = '/path/to/image.'; //extension is added automatically
for (const encodedImage of Object.values(image.encodedWith)) {
fs.writeFile(newImagePath + encodedImage.extension, encodedImage.binary);
fs.writeFile(
newImagePath + (await encodedImage).extension,
(await encodedImage).binary,
);
}
```
@@ -132,7 +124,7 @@ console.log(await image.decoded);
Information about an encoded image can be found at `Image.encodedWith[encoderName]`. It looks something like this:
```js
console.log(image.encodedWith.jxl);
console.log(await image.encodedWith.jxl);
// Returns:
{
optionsUsed: {
@@ -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
[arraybuffer]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer
[readfile]: https://nodejs.org/api/fs.html#fs_fspromises_readfile_path_options

View File

@@ -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,
})}`;
},
};
}

View File

@@ -1,26 +0,0 @@
const fs = require('fs');
const del = require('del');
const path = require('path');
const tsOutputDir = path.resolve('..', '.tmp', 'ts', 'libsquoosh');
const tsOutputSourceDir = path.join(tsOutputDir, 'src');
const buildDir = path.resolve('build');
(async () => {
await del(path.join(buildDir, '*.d.ts'));
const files = await fs.promises.readdir(tsOutputSourceDir);
const movePromises = [];
for (const file of files) {
if (file.endsWith('d.ts') || file.endsWith('d.ts.map')) {
movePromises.push(
fs.promises.rename(
path.join(tsOutputSourceDir, file),
path.join(buildDir, file),
),
);
}
}
// We need to remove `tsconfig.tsbuildinfo` otherwise TS does not emit unchanged `.d.ts` files
await del([path.join(tsOutputDir, 'tsconfig.tsbuildinfo')], { force: true });
})();

File diff suppressed because it is too large Load Diff

View File

@@ -1,29 +1,19 @@
{
"name": "@squoosh/lib",
"version": "0.5.2",
"version": "0.2.3",
"description": "A Node library for Squoosh",
"public": true,
"main": "./build/index.js",
"types": "./build/index.d.ts",
"files": [
"/build/*"
],
"scripts": {
"build": "rollup -c && node lib/move-d-ts.js"
"build": "rollup -c"
},
"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": {

View File

@@ -2,7 +2,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';
@@ -10,7 +9,7 @@ import { builtinModules } from 'module';
/** @type {import('rollup').RollupOptions} */
export default {
input: 'src/index.ts',
input: 'src/index.js',
output: {
dir: 'build',
format: 'cjs',
@@ -19,7 +18,6 @@ export default {
plugins: [
resolve(),
cjs(),
chunk(),
asset(),
autojson(),
json(),

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -1,102 +1,35 @@
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 Emscriptens 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;
}
export interface ResizeOptions {
width: number;
height: number;
method: 'triangle' | 'catrom' | 'mitchell' | 'lanczos3';
premultiply: boolean;
linearRGB: boolean;
}
export interface QuantOptions {
numColors: number;
dither: number;
}
export interface RotateOptions {
numRotations: number;
}
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
import type { MozJPEGModule as MozJPEGEncodeModule } from '../../codecs/mozjpeg/enc/mozjpeg_enc';
import mozEnc from '../../codecs/mozjpeg/enc/mozjpeg_node_enc.js';
import mozEncWasm from 'asset-url:../../codecs/mozjpeg/enc/mozjpeg_node_enc.wasm';
import mozDec from '../../codecs/mozjpeg/dec/mozjpeg_node_dec.js';
import mozDecWasm from 'asset-url:../../codecs/mozjpeg/dec/mozjpeg_node_dec.wasm';
import type { EncodeOptions as MozJPEGEncodeOptions } from '../../codecs/mozjpeg/enc/mozjpeg_enc';
// WebP
import type { WebPModule as WebPEncodeModule } from '../../codecs/webp/enc/webp_enc';
import webpEnc from '../../codecs/webp/enc/webp_node_enc.js';
import webpEncWasm from 'asset-url:../../codecs/webp/enc/webp_node_enc.wasm';
import webpDec from '../../codecs/webp/dec/webp_node_dec.js';
import webpDecWasm from 'asset-url:../../codecs/webp/dec/webp_node_dec.wasm';
import type { EncodeOptions as WebPEncodeOptions } from '../../codecs/webp/enc/webp_enc.js';
// AVIF
import type { AVIFModule as AVIFEncodeModule } from '../../codecs/avif/enc/avif_enc';
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';
import type { EncodeOptions as AvifEncodeOptions } from '../../codecs/avif/enc/avif_enc.js';
// JXL
import type { JXLModule as JXLEncodeModule } from '../../codecs/jxl/enc/jxl_enc';
import jxlEnc from '../../codecs/jxl/enc/jxl_node_enc.js';
import jxlEncWasm from 'asset-url:../../codecs/jxl/enc/jxl_node_enc.wasm';
import jxlDec from '../../codecs/jxl/dec/jxl_node_dec.js';
import jxlDecWasm from 'asset-url:../../codecs/jxl/dec/jxl_node_dec.wasm';
import type { EncodeOptions as JxlEncodeOptions } from '../../codecs/jxl/enc/jxl_enc.js';
// WP2
import type { WP2Module as WP2EncodeModule } from '../../codecs/wp2/enc/wp2_enc';
import wp2Enc from '../../codecs/wp2/enc/wp2_node_enc.js';
import wp2EncWasm from 'asset-url:../../codecs/wp2/enc/wp2_node_enc.wasm';
import wp2Dec from '../../codecs/wp2/dec/wp2_node_dec.js';
import wp2DecWasm from 'asset-url:../../codecs/wp2/dec/wp2_node_dec.wasm';
import type { EncodeOptions as WP2EncodeOptions } from '../../codecs/wp2/enc/wp2_enc.js';
// PNG
import * as pngEncDec from '../../codecs/png/pkg/squoosh_png.js';
@@ -109,9 +42,6 @@ const pngEncDecPromise = pngEncDec.default(
import * as oxipng from '../../codecs/oxipng/pkg/squoosh_oxipng.js';
import oxipngWasm from 'asset-url:../../codecs/oxipng/pkg/squoosh_oxipng_bg.wasm';
const oxipngPromise = oxipng.default(fsp.readFile(pathify(oxipngWasm)));
interface OxiPngEncodeOptions {
level: number;
}
// Resize
import * as resize from '../../codecs/resize/pkg/squoosh_resize.js';
@@ -121,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;
@@ -156,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,
};
}
return {
width: target_width,
height: Math.round((input_height / input_width) * target_width),
};
if (!target_height) {
return {
width: target_width,
height: Math.round((input_height / input_width) * target_width),
};
}
}
export const preprocessors = {
@@ -185,10 +108,10 @@ export const preprocessors = {
instantiate: async () => {
await resizePromise;
return (
buffer: Uint8Array,
input_width: number,
input_height: number,
{ width, height, method, premultiply, linearRGB }: ResizeOptions,
buffer,
input_width,
input_height,
{ width, height, method, premultiply, linearRGB },
) => {
({ width, height } = resizeWithAspect({
input_width,
@@ -225,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 }: QuantOptions,
) =>
return (buffer, width, height, { numColors, dither }) =>
new ImageData(
imageQuant.quantize(buffer, width, height, numColors, dither),
width,
@@ -246,18 +164,13 @@ export const preprocessors = {
name: 'Rotate',
description: 'Rotate image',
instantiate: async () => {
return async (
buffer: Uint8Array,
width: number,
height: number,
{ numRotations }: RotateOptions,
) => {
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),
@@ -279,20 +192,15 @@ export const preprocessors = {
numRotations: 0,
},
},
} as const;
};
export const codecs = {
mozjpeg: {
name: 'MozJPEG',
extension: 'jpg',
detectors: [/^\xFF\xD8\xFF/],
dec: () =>
instantiateEmscriptenWasm(mozDec as DecodeModuleFactory, mozDecWasm),
enc: () =>
instantiateEmscriptenWasm(
mozEnc as EmscriptenWasm.ModuleFactory<MozJPEGEncodeModule>,
mozEncWasm,
),
dec: () => instantiateEmscriptenWasm(mozDec, mozDecWasm),
enc: () => instantiateEmscriptenWasm(mozEnc, mozEncWasm),
defaultEncoderOptions: {
quality: 75,
baseline: false,
@@ -320,14 +228,9 @@ export const codecs = {
webp: {
name: 'WebP',
extension: 'webp',
detectors: [/^RIFF....WEBPVP8[LX ]/s],
dec: () =>
instantiateEmscriptenWasm(webpDec as DecodeModuleFactory, webpDecWasm),
enc: () =>
instantiateEmscriptenWasm(
webpEnc as EmscriptenWasm.ModuleFactory<WebPEncodeModule>,
webpEncWasm,
),
detectors: [/^RIFF....WEBPVP8[LX ]/],
dec: () => instantiateEmscriptenWasm(webpDec, webpDecWasm),
enc: () => instantiateEmscriptenWasm(webpEnc, webpEncWasm),
defaultEncoderOptions: {
quality: 75,
target_size: 0,
@@ -367,21 +270,8 @@ export const codecs = {
name: 'AVIF',
extension: 'avif',
detectors: [/^\x00\x00\x00 ftypavif\x00\x00\x00\x00/],
dec: () =>
instantiateEmscriptenWasm(avifDec as DecodeModuleFactory, avifDecWasm),
enc: async () => {
if (await threads()) {
return instantiateEmscriptenWasm(
avifEncMt as EmscriptenWasm.ModuleFactory<AVIFEncodeModule>,
avifEncMtWasm,
avifEncMtWorker,
);
}
return instantiateEmscriptenWasm(
avifEnc as EmscriptenWasm.ModuleFactory<AVIFEncodeModule>,
avifEncWasm,
);
},
dec: () => instantiateEmscriptenWasm(avifDec, avifDecWasm),
enc: () => instantiateEmscriptenWasm(avifEnc, avifEncWasm),
defaultEncoderOptions: {
cqLevel: 33,
cqAlphaLevel: -1,
@@ -396,30 +286,24 @@ export const codecs = {
},
autoOptimize: {
option: 'cqLevel',
min: 62,
max: 0,
min: 0,
max: 62,
},
},
jxl: {
name: 'JPEG-XL',
extension: 'jxl',
detectors: [/^\xff\x0a/],
dec: () =>
instantiateEmscriptenWasm(jxlDec as DecodeModuleFactory, jxlDecWasm),
enc: () =>
instantiateEmscriptenWasm(
jxlEnc as EmscriptenWasm.ModuleFactory<JXLEncodeModule>,
jxlEncWasm,
),
dec: () => instantiateEmscriptenWasm(jxlDec, jxlDecWasm),
enc: () => instantiateEmscriptenWasm(jxlEnc, jxlEncWasm),
defaultEncoderOptions: {
effort: 1,
speed: 4,
quality: 75,
progressive: false,
epf: -1,
nearLossless: 0,
lossyPalette: false,
decodingSpeedTier: 0,
photonNoiseIso: 0,
lossyModular: false,
},
autoOptimize: {
option: 'quality',
@@ -431,13 +315,8 @@ export const codecs = {
name: 'WebP2',
extension: 'wp2',
detectors: [/^\xF4\xFF\x6F/],
dec: () =>
instantiateEmscriptenWasm(wp2Dec as DecodeModuleFactory, wp2DecWasm),
enc: () =>
instantiateEmscriptenWasm(
wp2Enc as EmscriptenWasm.ModuleFactory<WP2EncodeModule>,
wp2EncWasm,
),
dec: () => instantiateEmscriptenWasm(wp2Dec, wp2DecWasm),
enc: () => instantiateEmscriptenWasm(wp2Enc, wp2EncWasm),
defaultEncoderOptions: {
quality: 75,
alpha_quality: 75,
@@ -467,18 +346,13 @@ export const codecs = {
await pngEncDecPromise;
await oxipngPromise;
return {
encode: (
buffer: Uint8ClampedArray | ArrayBuffer,
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);
},
};
},
@@ -491,13 +365,4 @@ export const codecs = {
max: 1,
},
},
} as const;
export {
MozJPEGEncodeOptions,
WebPEncodeOptions,
AvifEncodeOptions,
JxlEncodeOptions,
WP2EncodeOptions,
OxiPngEncodeOptions,
};

View 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);
},
});
}

View File

@@ -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;
},
});
}

Some files were not shown because too many files have changed in this diff Show More