Compare commits

...

97 Commits

Author SHA1 Message Date
Surma
5bc80e66ec Merge remote-tracking branch 'origin/dev' into visdif-error 2021-06-16 13:54:49 +01:00
Surma
b1f50cd27c Fix AVIF auto optimizer options 2021-06-16 13:54:17 +01:00
Surma
3d136016e2 Provide optimizer default value 2021-06-16 13:44:24 +01:00
Surma
14a715e952 Add test files for now 2021-06-16 12:56:37 +01:00
Surma
324b04d398 Merge pull request #1044 from ergunsh/libsquoosh-codecs-to-ts
Typescriptify libsquoosh's codecs.js and emscripten-utils.js
2021-06-16 11:47:21 +01:00
Surma
eb76fbc4bc Merge branch 'dev' into libsquoosh-codecs-to-ts 2021-06-16 11:43:35 +01:00
Jake Archibald
1d292468b0 Everything supports ResizeObserver now 2021-06-16 10:13:46 +01:00
Jake Archibald
828f9a5eeb Fix memory leaks (#1054) 2021-06-15 10:45:53 +01:00
Surma
5595525c8a Merge pull request #1053 from alex-drocks/patch-1
Update README.md @libSquoosh code example
2021-06-11 16:25:23 +01:00
Alexandre Desroches
5e14444b13 Update README.md
To close typo in example code as reported in issue #1051
2021-06-11 09:36:30 -04:00
Ergün Erdoğmuş
3d58c616af Merge branch 'dev' into libsquoosh-codecs-to-ts 2021-06-10 18:31:02 +02:00
Surma
d7090042a6 Fix alignment issue 2021-06-10 12:25:58 -04:00
Surma
be3249bf2f Add test case 2021-06-10 11:31:59 -04:00
ergunsh
1b59c3f47a Keep js extension while importing module & types 2021-06-09 18:11:30 +02:00
Surma
9a37cc7959 Merge pull request #1042 from GoogleChromeLabs/issue-1022 2021-06-09 12:17:00 +01:00
Surma
ffb9135a7a Merge remote-tracking branch 'origin/dev' into issue-1022 2021-06-09 06:35:00 -04:00
ergunsh
5707eeff41 Return Uint8ClampedArray in resize operation 2021-06-08 20:28:22 +02:00
ergunsh
a18ed360eb Address review comments
* Updated import to contain file extension `js`
* Separated WebAssembly definitions from missing-types
* Converted resizer.resize result to Uint8ClampedArray
* Moved ResizeInstantiateOptions to an interface
2021-06-08 20:09:37 +02:00
Surma
011d0c2099 Update AVIF 2021-06-08 16:51:08 +01:00
Surma
89105bbb22 Update wp2 2021-06-08 11:07:32 -04:00
Surma
5f7c619413 Update webp 2021-06-08 11:02:43 -04:00
Surma
3ec7d4db16 Update visdif 2021-06-08 10:59:47 -04:00
Surma
8ef8cef522 Update MozJPEG 2021-06-08 10:58:10 -04:00
Surma
f6431d8147 Update JXL 2021-06-08 10:54:16 -04:00
Surma
be037754ce Update imagequant 2021-06-08 10:43:33 -04:00
Surma
32107124e6 Update Emscripten version 2021-06-08 10:43:11 -04:00
ergunsh
1af5d1fa7b Typescriptify libsquoosh's codecs and emscripten-utils 2021-06-04 19:12:31 +02:00
Surma
08adfba8be Merge pull request #1037 from ergunsh/libsquoosh-ts-setup
Add initial ts setup for libsquoosh
2021-06-04 15:46:23 +01:00
Surma
5df04f6419 Update wp2 2021-06-04 09:51:10 -04:00
Surma
cf570a4d3f Update webp 2021-06-04 09:29:16 -04:00
Surma
2aa691339c Update visdif 2021-06-04 09:25:57 -04:00
Surma
9fcb4a4c55 Update mozjpeg 2021-06-04 09:23:23 -04:00
Surma
18e3d77aef Update jxl 2021-06-04 09:18:27 -04:00
Surma
6a4982bf4c Update imagequant 2021-06-04 08:52:46 -04:00
Surma
c7b998a877 Add flags 2021-06-04 08:33:57 -04:00
ergunsh
e5b2030666 Merge branch 'dev' into libsquoosh-ts-setup 2021-06-03 18:54:36 +02:00
ergunsh
0e09d0b33f Remove unnecessary missing-typed.d.ts for now
We don't need it for ImageData module
2021-06-03 18:50:44 +02:00
Surma
ed03a37fb8 Merge pull request #1041 from alexander-akait/issue-1034
fix: `main` filed
2021-06-03 11:18:41 +01:00
evilebottnawi
2bc4ab8fd6 fix: main filed 2021-06-03 12:36:49 +03:00
Ingvar Stepanyan
2037fe8964 Add an error for unsupported usage of new URL 2021-06-02 17:03:14 +01:00
Ingvar Stepanyan
d07c57ecaa Update lib/client-bundle-plugin.js 2021-06-02 17:03:14 +01:00
Ingvar Stepanyan
e7d55bf903 Update lib/entry-data-plugin.js
Co-authored-by: Jake Archibald <jaffathecake@gmail.com>
2021-06-02 17:03:14 +01:00
Ingvar Stepanyan
687cf5aae2 Bundle URL assets as dependencies
I've added support for `new URL(..., import.meta.url)` pattern accepted by many bundlers to wasm-bindgen and Emscripten, both for Wasm files as well as for side Workers autogenerated to support multithreading.

On the apps side like Squoosh this means we no longer have to manually specify URLs to be passed to wasm-bindgen or Emscripten init functions. In this PR I'm primarily doing just that - removing all the manual Wasm URL locators, as well as the associated logic.

One notable change on the build system side is that, in order for Wasm and multithreading-related Workers to be detected as dependencies, I'm now walking over `referencedFiles` in addition to `imports` when collecting list of dependencies in `getDependencies` function (client-bundle-plugin.js).

As a side effect, it also included other linked assets - images and CSS - which simplified quite a few caching lists in to-cache.ts as well. Instead of having to manually specify each asset that needs to be included, the logic is inverted and only few extra assets had to be excluded to keep the list of in items cached on the first load as low as it was before the change.

All in all, I think this simplification is worth it and even helped to accidentally uncover & fix one caching bug where WP2 regular JS was cached in addition to WP2 multithreaded JS simultaneously.
2021-06-02 17:03:14 +01:00
Ingvar Stepanyan
d63823d196 Add @web/rollup-plugin-import-meta-assets 2021-06-02 17:03:14 +01:00
Ingvar Stepanyan
7d111b6a43 Update wasm-bindgen 2021-06-02 17:03:14 +01:00
Ingvar Stepanyan
426f31e548 Upgrade Emscripten to 2.0.21
Few notes:
 - Lots of deprecated SIMD intrinsic warnings & errors in JPEG-XL -> Highway; had to suppress erorrs to make project build.
 - Moved couple of common link flags to cpp.Dockerfile (note: can't move `EXPORT_ES6` otherwise `configure` will fail).
 - MODULARIZE=1 is no longer necessary and implied by EXPORT_ES6.
 - EXPORT_NAME=... is no longer necessary in EXPORT_ES6.
 - Changed visdif to also use EXPORT_ES6 and ENVIRONMENT=node instead of generic JS.
2021-06-02 17:03:14 +01:00
Ingvar Stepanyan
dd0adba6b1 Revert "Remove SIMD for now (#1025)"
This reverts commit f779e13bc8.
2021-06-02 17:03:14 +01:00
ergunsh
30445927ea Add initial ts setup for libsquoosh
Convert `image_data` to typescript as an example
2021-05-31 21:45:28 +02:00
Surma
31b263fc27 Merge pull request #1035 from JustTestCode/patch-1
Update README.md
2021-05-30 10:06:01 +01:00
JustTestCode
fc590918ed Update README.md
I check 2 hours, why can't run...
2021-05-30 12:16:58 +08:00
Surma
c4783b03df Merge pull request #1031 from GoogleChromeLabs/defensive-web-codec 2021-05-27 10:30:38 +01:00
Jake Archibald
8f9c0ff0e7 More defensive use of isTypeSupported 2021-05-27 09:14:13 +01:00
Jake Archibald
40c81ef782 Remove circular dependency 2021-05-27 09:13:17 +01:00
Howard Chiam
397193a5f5 <title> to indicate progress/error (#1023)
Fixes #644
2021-05-25 14:29:42 +01:00
Surma
f91c7a267d libsquoosh v0.2.3 2021-05-25 11:49:54 +01:00
Surma
99f2286a73 Better error handling for libSquoosh 2021-05-25 11:46:30 +01:00
Surma
f414092ea9 libsquoosh v0.2.2 2021-05-24 23:58:15 +01:00
Surma
c683dfaaed Merge branch 'libsquoosh-kinks' into dev 2021-05-24 23:57:33 +01:00
Surma
12fb647fde Fix JXL in libsquoosh 2021-05-24 23:57:24 +01:00
Surma
2ee1dfa867 Fix AVIF in libsquoosh 2021-05-24 23:54:26 +01:00
Surma
fa331586d7 Handle more input types gracefully 2021-05-24 17:56:53 +01:00
Surma
4192c607f1 Merge pull request #1018 from GoogleChromeLabs/web-codecs
Add a call-out to Web Codecs API during decoding
2021-05-24 17:08:54 +01:00
Surma
128096afd9 Make TS happy 2021-05-24 16:29:12 +01:00
Surma
58661078e2 Update src/client/lazy-app/util/index.ts
Co-authored-by: Jake Archibald <jaffathecake@gmail.com>
2021-05-24 16:26:20 +01:00
Surma
cbfa503fcb Update src/client/lazy-app/util/index.ts
Co-authored-by: Jake Archibald <jaffathecake@gmail.com>
2021-05-24 16:26:05 +01:00
Jake Archibald
96b6dc8e6e Merge branch 'dev' into web-codecs 2021-05-24 16:06:09 +01:00
Surma
4033d1c965 Move logic to builtinDecode 2021-05-24 15:39:38 +01:00
Ingvar Stepanyan
f779e13bc8 Remove SIMD for now (#1025)
This is by no means a proper fix, but Chrome 91 (stable tomorrow) brings some breaking changes to SIMD, and I'd rather disable SIMD for now to avoid breaking Squoosh altogether once it hits stable, and work on a proper fix in a separate branch.
2021-05-24 12:50:48 +01:00
Surma
2f00fe2b1b I’m an idiot 2021-05-21 15:14:22 +01:00
Surma
118885cd26 Fall through to built-in decoding 2021-05-21 15:13:00 +01:00
Jake Archibald
af80643809 Remove redundant code (#1024) 2021-05-21 11:16:47 +01:00
Surma
1aba7b51ee Merge pull request #1021 from atjn/documentation-fixes 2021-05-20 10:08:27 +01:00
Surma
b0a7b21b0b Merge branch 'dev' into documentation-fixes 2021-05-20 10:00:36 +01:00
Surma
8dfe35aa77 Merge pull request #1019 from atjn/readdir-fix-rebase 2021-05-20 09:59:08 +01:00
atjn
1a891072c0 Fix broken links after libsquoosh release 2021-05-20 09:36:37 +02:00
atjn
720cb98872 [CLI] Handle subdirectories without failing 2021-05-20 09:12:29 +02:00
Surma
4e1dcb819c Release v0.2.1 of libSquoosh 2021-05-19 12:30:05 +01:00
Surma
c36f4bebb8 Update libSquoosh README after rename 2021-05-19 12:28:35 +01:00
Surma
c04bb54f0d Merge branch 'API' into dev 2021-05-19 12:23:07 +01:00
Surma
4890c56abb Publish v0.2.0 of @squoosh/lib 2021-05-19 12:22:50 +01:00
Surma
392aced394 Introduce libSquoosh 2021-05-19 12:15:00 +01:00
Surma
8bcaeb2f78 Simplify types a bit 2021-05-18 20:04:35 +01:00
Surma
c417bd0a7a Its working now 2021-05-18 20:02:43 +01:00
Surma
eb8204d69b Add a call-out to Web Codecs API 2021-05-18 19:53:39 +01:00
atjn
25754b91b7 Change 'encodedAs' to 'encodedWith' 2021-05-13 19:34:50 +02:00
atjn
875c24525b Upgrade commander to v7 2021-05-13 19:07:42 +02:00
atjn
50ed5febd3 Stick to the term 'preprocessor' 2021-05-13 16:53:15 +02:00
Ingvar Stepanyan
10c5082499 Add back a loader customization for full URL (#1016)
Emscripten uses dynamic `import(fullUrlOfTheMainJS)` in generated Workers.

It appears that upstream rollup-plugin-off-main-thread never handled this correctly, but we had a customization in Squoosh loader template that allowed those anyway, which I removed together with most other customizations in #1007, thus breaking Emscripten codecs.

This adds a hotfix back, but we need to fix this properly upstream too (TBD separately).
2021-05-13 15:48:23 +01:00
Jake Archibald
f0fb891498 Updating oxi, adding interlace option (#1014) 2021-05-13 14:22:19 +01:00
Ingvar Stepanyan
b9b6e57581 wasm-bindgen-rayon and new OMT plugin (#1007)
* WIP: wasm-bindgen-rayon and new OMT plugin

* Bump package-lock

* Make OMT work again

* Update year

* Restore accidental change

* Prevent minification of `nextDefineUri`

* Delay loading external deps

This gives inline `define` calls a chance to define dependencies for earlier `define` calls on the same page.

* Add comment
2021-05-13 13:50:31 +01:00
Jake Archibald
ff9dea465f Updating AVIF, and 'auto' SSIM option (#1008) 2021-05-10 18:56:33 +01:00
Jake Archibald
912c1fac08 Better DC pass (#1006) 2021-05-06 15:02:04 +01:00
atjn
ad0d46de3e Fix typo in README 2021-05-04 15:40:44 +02:00
Jake Archibald
efc89efba5 JXL decoding speed tier (#1001) 2021-05-04 13:16:54 +01:00
atjn
8ed50d8f0c Fix install command in README 2021-05-04 14:13:34 +02:00
atjn
b50402e3b3 Separate CLI and API 2021-05-04 12:57:48 +02:00
Luca Versari
df65f1a112 Update JPEG XL to latest. (#1000) 2021-05-04 11:47:19 +01:00
179 changed files with 13533 additions and 4838 deletions

View File

@@ -3,9 +3,9 @@
[Squoosh] is an image compression web app that allows you to dive into the advanced options provided
by various image compressors.
# CLI
# API & CLI
[Squoosh now has a CLI](https://github.com/GoogleChromeLabs/squoosh/tree/dev/cli) that allows you 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

View File

@@ -55,5 +55,5 @@ $ npx @squoosh/cli --wp2 auto test.png
```
[squoosh]: https://squoosh.app
[codecs.js]: https://github.com/GoogleChromeLabs/squoosh/blob/dev/cli/src/codecs.js
[codecs.js]: https://github.com/GoogleChromeLabs/squoosh/blob/dev/libsquoosh/src/codecs.js
[butteraugli]: https://github.com/google/butteraugli

2445
cli/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,32 +1,24 @@
{
"name": "@squoosh/cli",
"version": "0.6.0",
"version": "0.7.0",
"description": "A CLI for Squoosh",
"public": true,
"type": "module",
"bin": {
"squoosh-cli": "build/index.js",
"@squoosh/cli": "build/index.js"
},
"scripts": {
"build": "rollup -c"
"squoosh-cli": "src/index.js",
"@squoosh/cli": "src/index.js"
},
"files": [
"/src/index.js"
],
"keywords": [],
"author": "Google Chrome Developers <chromium-dev@google.com>",
"license": "Apache-2.0",
"dependencies": {
"web-streams-polyfill": "^3.0.0"
},
"devDependencies": {
"@babel/core": "^7.11.6",
"@babel/preset-env": "^7.11.5",
"@rollup/plugin-babel": "^5.2.1",
"@rollup/plugin-commonjs": "^15.0.0",
"@rollup/plugin-node-resolve": "^9.0.0",
"commander": "^6.0.0",
"json5": "^2.1.3",
"kleur": "^4.1.3",
"ora": "^5.1.0",
"rollup": "^2.26.11",
"rollup-plugin-terser": "^7.0.2"
"@squoosh/lib": "^0.2.0",
"commander": "^7.2.0",
"json5": "^2.2.0",
"kleur": "^4.1.4",
"ora": "^5.4.0"
}
}

View File

@@ -1,7 +0,0 @@
export default class ImageData {
constructor(data, width, height) {
this.data = data;
this.width = width;
this.height = height;
}
}

326
cli/src/index.js Normal file → Executable file
View File

@@ -1,17 +1,13 @@
import { program } from 'commander';
#!/usr/bin/env node
import { program } from 'commander/esm.mjs';
import JSON5 from 'json5';
import { isMainThread } from 'worker_threads';
import { cpus } from 'os';
import { extname, join, basename } from 'path';
import path from 'path';
import { promises as fsp } from 'fs';
import { resolve as resolvePath } from 'path';
import { version } from 'json:../package.json';
import ora from 'ora';
import kleur from 'kleur';
import { codecs as supportedFormats, preprocessors } from './codecs.js';
import WorkerPool from './worker_pool.js';
import { autoOptimize } from './auto-optimizer.js';
import { ImagePool, preprocessors, encoders } from '@squoosh/lib';
function clamp(v, min, max) {
if (v < min) return min;
@@ -26,114 +22,6 @@ function prettyPrintSize(size) {
return (size / 2 ** (10 * index)).toFixed(2) + suffix[index];
}
async function decodeFile(file) {
const buffer = await fsp.readFile(file);
const firstChunk = buffer.slice(0, 16);
const firstChunkString = Array.from(firstChunk)
.map((v) => String.fromCodePoint(v))
.join('');
const key = Object.entries(supportedFormats).find(([name, { detectors }]) =>
detectors.some((detector) => detector.exec(firstChunkString)),
)?.[0];
if (!key) {
throw Error(`${file} has an unsupported format`);
}
const rgba = (await supportedFormats[key].dec()).decode(
new Uint8Array(buffer),
);
return {
file,
bitmap: rgba,
size: buffer.length,
};
}
async function preprocessImage({ preprocessorName, options, file }) {
const preprocessor = await preprocessors[preprocessorName].instantiate();
file.bitmap = await preprocessor(
file.bitmap.data,
file.bitmap.width,
file.bitmap.height,
options,
);
return file;
}
async function encodeFile({
file,
size,
bitmap: bitmapIn,
outputFile,
encName,
encConfig,
optimizerButteraugliTarget,
maxOptimizerRounds,
}) {
let out, infoText;
const encoder = await supportedFormats[encName].enc();
if (encConfig === 'auto') {
const optionToOptimize = supportedFormats[encName].autoOptimize.option;
const decoder = await supportedFormats[encName].dec();
const encode = (bitmapIn, quality) =>
encoder.encode(
bitmapIn.data,
bitmapIn.width,
bitmapIn.height,
Object.assign({}, supportedFormats[encName].defaultEncoderOptions, {
[optionToOptimize]: quality,
}),
);
const decode = (binary) => decoder.decode(binary);
const { bitmap, binary, quality } = await autoOptimize(
bitmapIn,
encode,
decode,
{
min: supportedFormats[encName].autoOptimize.min,
max: supportedFormats[encName].autoOptimize.max,
butteraugliDistanceGoal: optimizerButteraugliTarget,
maxRounds: maxOptimizerRounds,
},
);
out = binary;
const opts = {
// 5 significant digits is enough
[optionToOptimize]: Math.round(quality * 10000) / 10000,
};
infoText = ` using --${encName} '${JSON5.stringify(opts)}'`;
} else {
out = encoder.encode(
bitmapIn.data.buffer,
bitmapIn.width,
bitmapIn.height,
encConfig,
);
}
await fsp.writeFile(outputFile, out);
return {
infoText,
inputSize: size,
inputFile: file,
outputFile,
outputSize: out.length,
};
}
// both decoding and encoding go through the worker pool
function handleJob(params) {
const { operation } = params;
switch (operation) {
case 'encode':
return encodeFile(params);
case 'decode':
return decodeFile(params.file);
case 'preprocess':
return preprocessImage(params);
default:
throw Error(`Invalid job "${operation}"`);
}
}
function progressTracker(results) {
const spinner = ora();
const tracker = {};
@@ -163,13 +51,12 @@ function progressTracker(results) {
};
function getResultsText() {
let out = '';
for (const [filename, result] of results.entries()) {
out += `\n ${kleur.cyan(filename)}: ${prettyPrintSize(result.size)}`;
for (const { outputFile, outputSize, infoText } of result.outputs) {
const name = (program.suffix + extname(outputFile)).padEnd(5);
out += `\n ${kleur.dim('└')} ${kleur.cyan(name)}${prettyPrintSize(
outputSize,
)}`;
for (const result of results.values()) {
out += `\n ${kleur.cyan(result.file)}: ${prettyPrintSize(result.size)}`;
for (const { outputFile, size: outputSize, infoText } of result.outputs) {
out += `\n ${kleur.dim('└')} ${kleur.cyan(
outputFile.padEnd(5),
)}${prettyPrintSize(outputSize)}`;
const percent = ((outputSize / result.size) * 100).toPrecision(3);
out += ` (${kleur[outputSize > result.size ? 'red' : 'green'](
percent + '%',
@@ -186,17 +73,17 @@ function progressTracker(results) {
async function getInputFiles(paths) {
const validFiles = [];
for (const path of paths) {
const files = (await fsp.lstat(path)).isDirectory()
? (await fsp.readdir(path)).map(file => join(path, file))
: [path];
for (const inputPath of paths) {
const files = (await fsp.lstat(inputPath)).isDirectory()
? (await fsp.readdir(inputPath, {withFileTypes: true})).filter(dirent => dirent.isFile()).map(dirent => path.join(inputPath, dirent.name))
: [inputPath];
for (const file of files) {
try {
await fsp.stat(file);
} catch (err) {
if (err.code === 'ENOENT') {
console.warn(
`Warning: Input file does not exist: ${resolvePath(file)}`,
`Warning: Input file does not exist: ${path.resolve(file)}`,
);
continue;
} else {
@@ -214,7 +101,7 @@ async function getInputFiles(paths) {
async function processFiles(files) {
files = await getInputFiles(files);
const parallelism = cpus().length;
const imagePool = new ImagePool();
const results = new Map();
const progress = progressTracker(results);
@@ -223,140 +110,123 @@ async function processFiles(files) {
progress.totalOffset = files.length;
progress.setProgress(0, files.length);
const workerPool = new WorkerPool(parallelism, __filename);
// Create output directory
await fsp.mkdir(program.outputDir, { recursive: true });
await fsp.mkdir(program.opts().outputDir, { recursive: true });
let decoded = 0;
let decodedFiles = await Promise.all(
files.map(async (file) => {
const result = await workerPool.dispatchJob({
operation: 'decode',
const image = imagePool.ingestImage(file);
await image.decoded;
results.set(image, {
file,
});
results.set(file, {
file: result.file,
size: result.size,
size: (await image.decoded).size,
outputs: [],
});
progress.setProgress(++decoded, files.length);
return result;
return image;
}),
);
for (const [preprocessorName, value] of Object.entries(preprocessors)) {
if (!program[preprocessorName]) {
const preprocessOptions = {};
for (const preprocessorName of Object.keys(preprocessors)) {
if (!program.opts()[preprocessorName]) {
continue;
}
const preprocessorParam = program[preprocessorName];
const preprocessorOptions = Object.assign(
{},
value.defaultOptions,
JSON5.parse(preprocessorParam),
);
decodedFiles = await Promise.all(
decodedFiles.map(async (file) => {
return workerPool.dispatchJob({
file,
operation: 'preprocess',
preprocessorName,
options: preprocessorOptions,
});
}),
preprocessOptions[preprocessorName] = JSON5.parse(
program.opts()[preprocessorName],
);
}
for (const image of decodedFiles) {
image.preprocess(preprocessOptions);
}
await Promise.all(decodedFiles.map((image) => image.decoded));
progress.progressOffset = decoded;
progress.setStatus('Encoding ' + kleur.dim(`(${parallelism} threads)`));
progress.setStatus(
'Encoding ' + kleur.dim(`(${imagePool.workerPool.numWorkers} threads)`),
);
progress.setProgress(0, files.length);
const jobs = [];
let jobsStarted = 0;
let jobsFinished = 0;
for (const { file, bitmap, size } of decodedFiles) {
const ext = extname(file);
const base = basename(file, ext) + program.suffix;
for (const image of decodedFiles) {
const originalFile = results.get(image).file;
for (const [encName, value] of Object.entries(supportedFormats)) {
if (!program[encName]) {
const encodeOptions = {
optimizerButteraugliTarget: Number(
program.opts().optimizerButteraugliTarget,
),
maxOptimizerRounds: Number(program.opts().maxOptimizerRounds),
};
for (const encName of Object.keys(encoders)) {
if (!program.opts()[encName]) {
continue;
}
const encParam =
typeof program[encName] === 'string' ? program[encName] : '{}';
const encParam = program.opts()[encName];
const encConfig =
encParam.toLowerCase() === 'auto'
? 'auto'
: Object.assign(
{},
value.defaultEncoderOptions,
JSON5.parse(encParam),
);
const outputFile = join(program.outputDir, `${base}.${value.extension}`);
jobsStarted++;
const p = workerPool
.dispatchJob({
operation: 'encode',
file,
size,
bitmap,
outputFile,
encName,
encConfig,
optimizerButteraugliTarget: Number(
program.optimizerButteraugliTarget,
),
maxOptimizerRounds: Number(program.maxOptimizerRounds),
})
.then((output) => {
jobsFinished++;
results.get(file).outputs.push(output);
progress.setProgress(jobsFinished, jobsStarted);
});
jobs.push(p);
encParam.toLowerCase() === 'auto' ? 'auto' : JSON5.parse(encParam);
encodeOptions[encName] = encConfig;
}
jobsStarted++;
const job = image.encode(encodeOptions).then(async () => {
jobsFinished++;
const outputPath = path.join(
program.opts().outputDir,
program.opts().suffix +
path.basename(originalFile, path.extname(originalFile)),
);
for (const output of Object.values(image.encodedWith)) {
const outputFile = `${outputPath}.${(await output).extension}`;
await fsp.writeFile(outputFile, (await output).binary);
results
.get(image)
.outputs.push(Object.assign(await output, { outputFile }));
}
progress.setProgress(jobsFinished, jobsStarted);
});
jobs.push(job);
}
// update the progress to account for multi-format
progress.setProgress(jobsFinished, jobsStarted);
// Wait for all jobs to finish
await workerPool.join();
await Promise.all(jobs);
await imagePool.close();
progress.finish('Squoosh results:');
}
if (isMainThread) {
program
.name('squoosh-cli')
.version(version)
.arguments('<files...>')
.option('-d, --output-dir <dir>', 'Output directory', '.')
.option('-s, --suffix <suffix>', 'Append suffix to output files', '')
.option(
'--max-optimizer-rounds <rounds>',
'Maximum number of compressions to use for auto optimizations',
'6',
)
.option(
'--optimizer-butteraugli-target <butteraugli distance>',
'Target Butteraugli distance for auto optimizer',
'1.4',
)
.action(processFiles);
program
.name('squoosh-cli')
.arguments('<files...>')
.option('-d, --output-dir <dir>', 'Output directory', '.')
.option('-s, --suffix <suffix>', 'Append suffix to output files', '')
.option(
'--max-optimizer-rounds <rounds>',
'Maximum number of compressions to use for auto optimizations',
'6',
)
.option(
'--optimizer-butteraugli-target <butteraugli distance>',
'Target Butteraugli distance for auto optimizer',
'1.4',
)
.action(processFiles);
// Create a CLI option for each supported preprocessor
for (const [key, value] of Object.entries(preprocessors)) {
program.option(`--${key} [config]`, value.description);
}
// Create a CLI option for each supported encoder
for (const [key, value] of Object.entries(supportedFormats)) {
program.option(
`--${key} [config]`,
`Use ${value.name} to generate a .${value.extension} file with the given configuration`,
);
}
program.parse(process.argv);
} else {
WorkerPool.useThisThreadAsWorker(handleJob);
// Create a CLI option for each supported preprocessor
for (const [key, value] of Object.entries(preprocessors)) {
program.option(`--${key} [config]`, value.description);
}
// Create a CLI option for each supported encoder
for (const [key, value] of Object.entries(encoders)) {
program.option(
`--${key} [config]`,
`Use ${value.name} to generate a .${value.extension} file with the given configuration`,
);
}
program.parse(process.argv);

View File

@@ -1,15 +1,18 @@
# libavif and libaom versions are from
# https://docs.google.com/document/d/1wEEA5rRU7wT54k41u3qyZIZHDCJArIMzLuzsrLAwaK8/edit
CODEC_URL = https://github.com/AOMediaCodec/libavif/archive/d37ef74127986184500e571bf1f9793cc0bdef50.tar.gz
CODEC_URL = https://github.com/AOMediaCodec/libavif/archive/1c39e772c2c0d687691dd4b589a12c323f5f767d.tar.gz
CODEC_PACKAGE = node_modules/libavif.tar.gz
LIBAOM_URL = https://aomedia.googlesource.com/aom/+archive/0a5da45c7f942908974f5ab8e107c9fa82048ae7.tar.gz
LIBAOM_URL = https://aomedia.googlesource.com/aom/+archive/v3.1.0.tar.gz
LIBAOM_PACKAGE = node_modules/libaom.tar.gz
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

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

@@ -29,8 +29,10 @@ struct AvifOptions {
bool chromaDeltaQ;
// 0-7
int sharpness;
// Target ssim rather than psnr
bool targetSsim;
// 0 = auto
// 1 = PSNR
// 2 = SSIM
int tune;
// 0-50
int denoiseLevel;
};
@@ -98,7 +100,7 @@ val encode(std::string buffer, int width, int height, AvifOptions options) {
std::to_string(options.cqAlphaLevel).c_str());
}
if (options.targetSsim) {
if (options.tune == 2 || (options.tune == 0 && options.cqLevel <= 32)) {
avifEncoderSetCodecSpecificOption(encoder, "tune", "ssim");
}
@@ -136,7 +138,7 @@ EMSCRIPTEN_BINDINGS(my_module) {
.field("speed", &AvifOptions::speed)
.field("chromaDeltaQ", &AvifOptions::chromaDeltaQ)
.field("sharpness", &AvifOptions::sharpness)
.field("targetSsim", &AvifOptions::targetSsim)
.field("tune", &AvifOptions::tune)
.field("denoiseLevel", &AvifOptions::denoiseLevel)
.field("subsample", &AvifOptions::subsample);

View File

@@ -1,3 +1,9 @@
export const enum AVIFTune {
auto,
psnr,
ssim,
}
export interface EncodeOptions {
cqLevel: number;
denoiseLevel: number;
@@ -8,7 +14,7 @@ export interface EncodeOptions {
subsample: number;
chromaDeltaQ: boolean;
sharpness: number;
targetSsim: boolean;
tune: AVIFTune;
}
export interface AVIFModule 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 @@
var threadInfoStruct=0;var selfThreadId=0;var parentThreadId=0;var initializedJS=false;var Module={};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:selfThreadId})}var err=threadPrintErr;this.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);Module["wasmModule"]=null;receiveInstance(instance);return instance.exports};this.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;import(e.data.urlOrBlob).then(function(avif_enc_mt){return avif_enc_mt.default(Module)}).then(function(instance){Module=instance;postMessage({"cmd":"loaded"})})}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;threadInfoStruct=e.data.threadInfoStruct;Module["registerPthreadPtr"](threadInfoStruct,/*isMainBrowserThread=*/0,/*isMainRuntimeThread=*/0);selfThreadId=e.data.selfThreadId;parentThreadId=e.data.parentThreadId;var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["_emscripten_tls_init"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].setThreadStatus(Module["_pthread_self"](),1);if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["dynCall"]("ii",e.data.start_routine,[e.data.arg]);if(!Module["getNoExitRuntime"]())Module["PThread"].threadExit(result)}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){Atomics.store(Module["HEAPU32"],(threadInfoStruct+4)>>/*C_STRUCTS.pthread.threadExitCode*/2,(ex instanceof Module["ExitStatus"])?ex.status:-2);/*A custom entry specific to Emscripten denoting that the thread crashed.*/Atomics.store(Module["HEAPU32"],(threadInfoStruct+0)>>/*C_STRUCTS.pthread.threadStatus*/2,1);Module["_emscripten_futex_wake"](threadInfoStruct+0,/*C_STRUCTS.pthread.threadStatus*/2147483647);if(!(ex instanceof Module["ExitStatus"]))throw ex}}}else if(e.data.cmd==="cancel"){if(threadInfoStruct){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(threadInfoStruct){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,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}};

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -32,13 +32,8 @@ $(OUT_JS): $(OUT_CPP) $(LIBAOM_OUT) $(CODEC_OUT)
$(LDFLAGS) \
$(OUT_FLAGS) \
--bind \
--closure 1 \
-s ALLOW_MEMORY_GROWTH=1 \
-s MODULARIZE=1 \
-s TEXTDECODER=2 \
-s ENVIRONMENT=$(ENVIRONMENT) \
-s EXPORT_ES6=1 \
-s EXPORT_NAME="$(basename $(@F))" \
-o $@ \
$+

View File

@@ -1,9 +1,17 @@
FROM emscripten/emsdk:2.0.8
FROM emscripten/emsdk:2.0.23
RUN apt-get update && apt-get install -qqy autoconf libtool pkg-config
ENV CFLAGS "-O3 -flto -s FILESYSTEM=0"
ENV CFLAGS "-O3 -flto"
ENV CXXFLAGS "${CFLAGS} -std=c++17"
ENV LDFLAGS "${CFLAGS} -s PTHREAD_POOL_SIZE=navigator.hardwareConcurrency"
# Build and cache standard libraries with these flags
RUN emcc ${CXXFLAGS} --bind -xc++ /dev/null -o /dev/null
ENV LDFLAGS "${CFLAGS} \
-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
# And another set for the pthread variant.
RUN emcc ${CXXFLAGS} ${LDFLAGS} --bind -pthread -xc++ /dev/null -o /dev/null
WORKDIR /src
CMD ["sh", "-c", "emmake make -j`nproc`"]

54
codecs/hqx/Cargo.lock generated
View File

@@ -12,13 +12,19 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "console_error_panic_hook"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"wasm-bindgen",
]
@@ -63,7 +69,7 @@ version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
]
[[package]]
@@ -83,9 +89,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.19"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12"
checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
dependencies = [
"unicode-xid 0.2.1",
]
@@ -105,7 +111,7 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
dependencies = [
"proc-macro2 1.0.19",
"proc-macro2 1.0.27",
]
[[package]]
@@ -118,7 +124,7 @@ checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
name = "squooshhqx"
version = "0.1.0"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"console_error_panic_hook",
"hqx",
"wasm-bindgen",
@@ -128,11 +134,11 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.35"
version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb7f4c519df8c117855e19dd8cc851e89eb746fe7a73f0157e0d95fdec5369b0"
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
dependencies = [
"proc-macro2 1.0.19",
"proc-macro2 1.0.27",
"quote 1.0.7",
"unicode-xid 0.2.1",
]
@@ -151,24 +157,24 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "wasm-bindgen"
version = "0.2.65"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3edbcc9536ab7eababcc6d2374a0b7bfe13a2b6d562c5e07f370456b1a8f33d"
checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.65"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89ed2fb8c84bfad20ea66b26a3743f3e7ba8735a69fe7d95118c33ec8fc1244d"
checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2 1.0.19",
"proc-macro2 1.0.27",
"quote 1.0.7",
"syn",
"wasm-bindgen-shared",
@@ -180,7 +186,7 @@ version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83420b37346c311b9ed822af41ec2e82839bfe99867ec6c54e2da43b7538771c"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"futures",
"js-sys",
"wasm-bindgen",
@@ -189,9 +195,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.65"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb071268b031a64d92fc6cf691715ca5a40950694d8f683c5bb43db7c730929e"
checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4"
dependencies = [
"quote 1.0.7",
"wasm-bindgen-macro-support",
@@ -199,11 +205,11 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.65"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf592c807080719d1ff2f245a687cbadb3ed28b2077ed7084b47aba8b691f2c6"
checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
dependencies = [
"proc-macro2 1.0.19",
"proc-macro2 1.0.27",
"quote 1.0.7",
"syn",
"wasm-bindgen-backend",
@@ -212,9 +218,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.65"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b6c0220ded549d63860c78c38f3bcc558d1ca3f4efa74942c536ddbbb55e87"
checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
[[package]]
name = "wasm-bindgen-test"
@@ -257,7 +263,7 @@ version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"libc",
"memory_units",
"winapi",

2
codecs/hqx/pkg/squooshhqx.d.ts generated vendored
View File

@@ -14,6 +14,7 @@ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembl
export interface InitOutput {
readonly memory: WebAssembly.Memory;
readonly resize: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
readonly __wbindgen_malloc: (a: number) => number;
readonly __wbindgen_free: (a: number, b: number) => void;
}
@@ -27,4 +28,3 @@ export interface InitOutput {
* @returns {Promise<InitOutput>}
*/
export default function init (module_or_path?: InitInput | Promise<InitInput>): Promise<InitOutput>;

View File

@@ -37,19 +37,23 @@ function getArrayU32FromWasm0(ptr, len) {
* @returns {Uint32Array}
*/
export function resize(input_image, input_width, input_height, factor) {
var ptr0 = passArray32ToWasm0(input_image, wasm.__wbindgen_malloc);
var len0 = WASM_VECTOR_LEN;
wasm.resize(8, ptr0, len0, input_width, input_height, factor);
var r0 = getInt32Memory0()[8 / 4 + 0];
var r1 = getInt32Memory0()[8 / 4 + 1];
var v1 = getArrayU32FromWasm0(r0, r1).slice();
wasm.__wbindgen_free(r0, r1 * 4);
return v1;
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
var ptr0 = passArray32ToWasm0(input_image, wasm.__wbindgen_malloc);
var len0 = WASM_VECTOR_LEN;
wasm.resize(retptr, ptr0, len0, input_width, input_height, factor);
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
var v1 = getArrayU32FromWasm0(r0, r1).slice();
wasm.__wbindgen_free(r0, r1 * 4);
return v1;
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
}
}
async function load(module, imports) {
if (typeof Response === 'function' && module instanceof Response) {
if (typeof WebAssembly.instantiateStreaming === 'function') {
try {
return await WebAssembly.instantiateStreaming(module, imports);
@@ -68,7 +72,6 @@ async function load(module, imports) {
return await WebAssembly.instantiate(bytes, imports);
} else {
const instance = await WebAssembly.instantiate(module, imports);
if (instance instanceof WebAssembly.Instance) {
@@ -82,7 +85,7 @@ async function load(module, imports) {
async function init(input) {
if (typeof input === 'undefined') {
input = import.meta.url.replace(/\.js$/, '_bg.wasm');
input = new URL('squooshhqx_bg.wasm', import.meta.url);
}
const imports = {};
@@ -91,6 +94,8 @@ async function init(input) {
input = fetch(input);
}
const { instance, module } = await load(await input, imports);
wasm = instance.exports;

6
codecs/hqx/pkg/squooshhqx_bg.d.ts generated vendored
View File

@@ -1,6 +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): void;
export function __wbindgen_malloc(a: number): number;
export function __wbindgen_free(a: number, b: number): void;

Binary file not shown.

View File

@@ -17,10 +17,6 @@ $(OUT_JS): $(CODEC_OUT)
${CXXFLAGS} \
${LDFLAGS} \
--bind \
--closure 1 \
-s ALLOW_MEMORY_GROWTH=1 \
-s MODULARIZE=1 \
-s TEXTDECODER=2 \
-s ENVIRONMENT=$(ENVIRONMENT) \
-s EXPORT_ES6=1 \
-o $@ \

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://gitlab.com/wg1/jpeg-xl.git
CODEC_VERSION = v0.3.3
CODEC_VERSION = ab7c5e9b6795134377aa4846ceaae2c5bc504f76
CODEC_DIR = node_modules/jxl
CODEC_BUILD_ROOT := $(CODEC_DIR)/build
CODEC_MT_BUILD_DIR := $(CODEC_BUILD_ROOT)/mt
@@ -28,6 +28,10 @@ enc/jxl_node_enc.js dec/jxl_node_dec.js enc/jxl_enc.js dec/jxl_dec.js: $(CODEC_M
enc/jxl_enc_mt.js: $(CODEC_MT_BUILD_DIR)/lib/libjxl.a $(CODEC_MT_BUILD_DIR)/lib/libjxl_threads.a
enc/jxl_enc_mt_simd.js: $(CODEC_MT_SIMD_BUILD_DIR)/lib/libjxl.a $(CODEC_MT_SIMD_BUILD_DIR)/lib/libjxl_threads.a
# Disable errors on deprecated SIMD intrinsics.
# JPEG-XL & Highway need to catch up, once they do, we can remove this suppression.
export CXXFLAGS += -Wno-deprecated-declarations
# Compile multithreaded wrappers with -pthread.
enc/jxl_enc_mt.js enc/jxl_enc_mt_simd.js: CXXFLAGS+=-pthread
@@ -42,13 +46,8 @@ $(OUT_JS):
-I $(CODEC_DIR)/third_party/highway \
-I $(CODEC_DIR)/third_party/skcms \
--bind \
--closure 1 \
-s ALLOW_MEMORY_GROWTH=1 \
-s MODULARIZE=1 \
-s TEXTDECODER=2 \
-s ENVIRONMENT=$(ENVIRONMENT) \
-s EXPORT_ES6=1 \
-s EXPORT_NAME="$(basename $(@F))" \
-o $@ \
$+ \
$(CODEC_BUILD_DIR)/third_party/brotli/libbrotlidec-static.a \
@@ -73,10 +72,11 @@ $(CODEC_MT_SIMD_BUILD_DIR)/Makefile: CXXFLAGS+=-msimd128
-DJPEGXL_ENABLE_BENCHMARK=0 \
-DJPEGXL_ENABLE_EXAMPLES=0 \
-DBUILD_TESTING=0 \
-DCMAKE_CROSSCOMPILING_EMULATOR=node \
-B $(@D) \
$(<D)
$(CODEC_DIR)/CMakeLists.txt:
$(CODEC_DIR)/CMakeLists.txt:
$(RM) -r $(@D)
git init $(@D)
git -C $(@D) fetch $(CODEC_URL) $(CODEC_VERSION) --depth 1

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

@@ -18,6 +18,7 @@ struct JXLOptions {
int epf;
int nearLossless;
bool lossyPalette;
size_t decodingSpeedTier;
};
val encode(std::string image, int width, int height, JXLOptions options) {
@@ -35,6 +36,7 @@ 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) {
cparams.lossy_palette = true;
@@ -113,6 +115,7 @@ EMSCRIPTEN_BINDINGS(my_module) {
.field("progressive", &JXLOptions::progressive)
.field("nearLossless", &JXLOptions::nearLossless)
.field("lossyPalette", &JXLOptions::lossyPalette)
.field("decodingSpeedTier", &JXLOptions::decodingSpeedTier)
.field("epf", &JXLOptions::epf);
function("encode", &encode);

View File

@@ -5,6 +5,7 @@ export interface EncodeOptions {
epf: number;
nearLossless: number;
lossyPalette: boolean;
decodingSpeedTier: number;
}
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 @@
var threadInfoStruct=0;var selfThreadId=0;var parentThreadId=0;var initializedJS=false;var Module={};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:selfThreadId})}var err=threadPrintErr;this.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);Module["wasmModule"]=null;receiveInstance(instance);return instance.exports};this.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;import(e.data.urlOrBlob).then(function(jxl_enc_mt){return jxl_enc_mt.default(Module)}).then(function(instance){Module=instance;postMessage({"cmd":"loaded"})})}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;threadInfoStruct=e.data.threadInfoStruct;Module["registerPthreadPtr"](threadInfoStruct,/*isMainBrowserThread=*/0,/*isMainRuntimeThread=*/0);selfThreadId=e.data.selfThreadId;parentThreadId=e.data.parentThreadId;var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["_emscripten_tls_init"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].setThreadStatus(Module["_pthread_self"](),1);if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["dynCall"]("ii",e.data.start_routine,[e.data.arg]);if(!Module["getNoExitRuntime"]())Module["PThread"].threadExit(result)}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){Atomics.store(Module["HEAPU32"],(threadInfoStruct+4)>>/*C_STRUCTS.pthread.threadExitCode*/2,(ex instanceof Module["ExitStatus"])?ex.status:-2);/*A custom entry specific to Emscripten denoting that the thread crashed.*/Atomics.store(Module["HEAPU32"],(threadInfoStruct+0)>>/*C_STRUCTS.pthread.threadStatus*/2,1);Module["_emscripten_futex_wake"](threadInfoStruct+0,/*C_STRUCTS.pthread.threadStatus*/2147483647);if(!(ex instanceof Module["ExitStatus"]))throw ex}}}else if(e.data.cmd==="cancel"){if(threadInfoStruct){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(threadInfoStruct){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,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}};

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -1 +1 @@
var threadInfoStruct=0;var selfThreadId=0;var parentThreadId=0;var initializedJS=false;var Module={};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:selfThreadId})}var err=threadPrintErr;this.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);Module["wasmModule"]=null;receiveInstance(instance);return instance.exports};this.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;import(e.data.urlOrBlob).then(function(jxl_enc_mt_simd){return jxl_enc_mt_simd.default(Module)}).then(function(instance){Module=instance;postMessage({"cmd":"loaded"})})}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;threadInfoStruct=e.data.threadInfoStruct;Module["registerPthreadPtr"](threadInfoStruct,/*isMainBrowserThread=*/0,/*isMainRuntimeThread=*/0);selfThreadId=e.data.selfThreadId;parentThreadId=e.data.parentThreadId;var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["_emscripten_tls_init"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].setThreadStatus(Module["_pthread_self"](),1);if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["dynCall"]("ii",e.data.start_routine,[e.data.arg]);if(!Module["getNoExitRuntime"]())Module["PThread"].threadExit(result)}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){Atomics.store(Module["HEAPU32"],(threadInfoStruct+4)>>/*C_STRUCTS.pthread.threadExitCode*/2,(ex instanceof Module["ExitStatus"])?ex.status:-2);/*A custom entry specific to Emscripten denoting that the thread crashed.*/Atomics.store(Module["HEAPU32"],(threadInfoStruct+0)>>/*C_STRUCTS.pthread.threadStatus*/2,1);Module["_emscripten_futex_wake"](threadInfoStruct+0,/*C_STRUCTS.pthread.threadStatus*/2147483647);if(!(ex instanceof Module["ExitStatus"]))throw ex}}}else if(e.data.cmd==="cancel"){if(threadInfoStruct){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(threadInfoStruct){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,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}};

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -22,11 +22,7 @@ enc/mozjpeg_node_enc.js dec/mozjpeg_node_dec.js: ENVIRONMENT = node
-I $(CODEC_DIR) \
${CXXFLAGS} \
${LDFLAGS} \
--closure 1 \
--bind \
-s ALLOW_MEMORY_GROWTH=1 \
-s MODULARIZE=1 \
-s TEXTDECODER=2 \
-s ENVIRONMENT=$(ENVIRONMENT) \
-s EXPORT_ES6=1 \
-o $@ \

File diff suppressed because one or more lines are too long

View File

@@ -141,6 +141,7 @@ val encode(std::string image_in, int image_width, int image_height, MozJpegOptio
jpeg_c_set_bool_param(&cinfo, JBOOLEAN_TRELLIS_EOB_OPT, opts.trellis_opt_zero);
jpeg_c_set_bool_param(&cinfo, JBOOLEAN_TRELLIS_Q_OPT, opts.trellis_opt_table);
jpeg_c_set_int_param(&cinfo, JINT_TRELLIS_NUM_LOOPS, opts.trellis_loops);
jpeg_c_set_int_param(&cinfo, JINT_DC_SCAN_OPT_MODE, 0);
// A little hacky to build a string for this, but it means we can use
// set_quality_ratings which does some useful heuristic stuff.

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,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "adler"
version = "0.2.3"
@@ -232,6 +234,15 @@ dependencies = [
"either",
]
[[package]]
name = "js-sys"
version = "0.3.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc9f84f9b115ce7843d60706df1422a916680bfdfcbdb0447c5614ff9d7e4d78"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
@@ -350,12 +361,6 @@ dependencies = [
"libc",
]
[[package]]
name = "once_cell"
version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
[[package]]
name = "oxipng"
version = "4.0.3"
@@ -401,9 +406,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.24"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
dependencies = [
"unicode-xid",
]
@@ -484,24 +489,28 @@ dependencies = [
"pest",
]
[[package]]
name = "spmc"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02a8428da277a8e3a15271d79943e80ccc2ef254e78813a166a08d65e4c3ece5"
[[package]]
name = "squoosh-oxipng"
version = "0.1.0"
dependencies = [
"crossbeam-channel",
"libdeflater",
"log",
"once_cell",
"oxipng",
"rayon",
"wasm-bindgen",
"wasm-bindgen-rayon",
]
[[package]]
name = "syn"
version = "1.0.58"
version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5"
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
dependencies = [
"proc-macro2",
"quote",
@@ -522,9 +531,9 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "wasm-bindgen"
version = "0.2.69"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e"
checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
dependencies = [
"cfg-if 1.0.0",
"wasm-bindgen-macro",
@@ -532,9 +541,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.69"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62"
checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900"
dependencies = [
"bumpalo",
"lazy_static",
@@ -547,9 +556,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.69"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084"
checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -557,9 +566,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.69"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549"
checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
dependencies = [
"proc-macro2",
"quote",
@@ -569,7 +578,19 @@ dependencies = [
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.69"
name = "wasm-bindgen-rayon"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158"
checksum = "3069d2a42e7a7e3bfde668f84adb5fbc35701ca2b39b27a064cbd5ede4e78194"
dependencies = [
"js-sys",
"rayon",
"spmc",
"wasm-bindgen",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"

View File

@@ -12,17 +12,15 @@ wasm-opt = ["-O", "--no-validation"]
crate-type = ["cdylib"]
[dependencies]
oxipng = { version = "4.0.1", default-features = false, features = ["libdeflater"] }
oxipng = { version = "4.0.3", default-features = false, features = ["libdeflater"] }
libdeflater = { version = "0.7.1", features = ["freestanding"] }
wasm-bindgen = "0.2.68"
wasm-bindgen = "0.2.73"
log = { version = "0.4.11", features = ["release_max_level_off"] }
rayon = { version = "1.5.0", optional = true }
once_cell = { version = "1.5.2", optional = true }
crossbeam-channel = { version = "0.5.0", optional = true }
wasm-bindgen-rayon = { version = "1.0", optional = true }
[profile.release]
lto = true
opt-level = "s"
[features]
parallel = ["oxipng/parallel", "rayon", "crossbeam-channel", "once_cell"]
parallel = ["oxipng/parallel", "wasm-bindgen-rayon"]

View File

@@ -6,6 +6,4 @@ rm -rf pkg,{-parallel}
export CFLAGS="${CFLAGS} -DUNALIGNED_ACCESS_IS_FAST=1"
wasm-pack build -t web
RUSTFLAGS='-C target-feature=+atomics,+bulk-memory' wasm-pack build -t web -d pkg-parallel -- -Z build-std=panic_abort,std --features=parallel
# Workaround https://github.com/rustwasm/wasm-bindgen/issues/2133:
sed -i "s|maybe_memory:|maybe_memory?:|" pkg-parallel/squoosh_oxipng.d.ts
rm pkg{,-parallel}/.gitignore

View File

@@ -0,0 +1,98 @@
/**
* Copyright 2021 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.
*/
// Note: we use `wasm_bindgen_worker_`-prefixed message types to make sure
// we can handle bundling into other files, which might happen to have their
// own `postMessage`/`onmessage` communication channels.
//
// If we didn't take that into the account, we could send much simpler signals
// like just `0` or whatever, but the code would be less resilient.
function waitForMsgType(target, type) {
return new Promise(resolve => {
target.addEventListener('message', function onMsg({ data }) {
if (data == null || data.type !== type) return;
target.removeEventListener('message', onMsg);
resolve(data);
});
});
}
waitForMsgType(self, 'wasm_bindgen_worker_init').then(async data => {
// # Note 1
// Our JS should have been generated in
// `[out-dir]/snippets/wasm-bindgen-rayon-[hash]/workerHelpers.js`,
// resolve the main module via `../../..`.
//
// This might need updating if the generated structure changes on wasm-bindgen
// side ever in the future, but works well with bundlers today. The whole
// point of this crate, after all, is to abstract away unstable features
// and temporary bugs so that you don't need to deal with them in your code.
//
// # Note 2
// This could be a regular import, but then some bundlers complain about
// circular deps.
//
// Dynamic import could be cheap if this file was inlined into the parent,
// which would require us just using `../../..` in `new Worker` below,
// but that doesn't work because wasm-pack unconditionally adds
// "sideEffects":false (see below).
//
// OTOH, even though it can't be inlined, it should be still reasonably
// cheap since the requested file is already in cache (it was loaded by
// the main thread).
const pkg = await import('../../..');
await pkg.default(data.module, data.memory);
postMessage({ type: 'wasm_bindgen_worker_ready' });
pkg.wbg_rayon_start_worker(data.receiver);
});
export async function startWorkers(module, memory, builder) {
const workerInit = {
type: 'wasm_bindgen_worker_init',
module,
memory,
receiver: builder.receiver()
};
try {
await Promise.all(
Array.from({ length: builder.numThreads() }, () => {
// Self-spawn into a new Worker.
//
// TODO: while `new URL('...', import.meta.url) becomes a semi-standard
// way to get asset URLs relative to the module across various bundlers
// and browser, ideally we should switch to `import.meta.resolve`
// once it becomes a standard.
//
// Note: we could use `../../..` as the URL here to inline workerHelpers.js
// into the parent entry instead of creating another split point -
// this would be preferable from optimization perspective -
// however, Webpack then eliminates all message handler code
// because wasm-pack produces "sideEffects":false in package.json
// unconditionally.
//
// The only way to work around that is to have side effect code
// in an entry point such as Worker file itself.
const worker = new Worker(new URL('./workerHelpers.js', import.meta.url), {
type: 'module'
});
worker.postMessage(workerInit);
return waitForMsgType(worker, 'wasm_bindgen_worker_ready');
})
);
builder.build();
} finally {
builder.free();
}
}

View File

@@ -3,29 +3,49 @@
/**
* @param {Uint8Array} data
* @param {number} level
* @param {boolean} interlace
* @returns {Uint8Array}
*/
export function optimise(data: Uint8Array, level: number): Uint8Array;
export function optimise(data: Uint8Array, level: number, interlace: boolean): Uint8Array;
/**
* @param {number} num
* @returns {any}
* @param {number} num_threads
* @returns {Promise<any>}
*/
export function worker_initializer(num: number): any;
export function initThreadPool(num_threads: number): Promise<any>;
/**
* @param {number} receiver
*/
export function wbg_rayon_start_worker(receiver: number): void;
/**
*/
export function start_main_thread(): void;
export class wbg_rayon_PoolBuilder {
free(): void;
/**
* @returns {number}
*/
numThreads(): number;
/**
* @returns {number}
*/
receiver(): number;
/**
*/
export function start_worker_thread(): void;
build(): void;
}
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
export interface InitOutput {
readonly optimise: (a: number, b: number, c: number, d: number) => void;
readonly worker_initializer: (a: number) => number;
readonly start_main_thread: () => void;
readonly start_worker_thread: () => void;
readonly __wasm_init_memory: () => void;
readonly optimise: (a: number, b: number, c: number, d: number, e: number) => void;
readonly __wbg_wbg_rayon_poolbuilder_free: (a: number) => void;
readonly wbg_rayon_poolbuilder_numThreads: (a: number) => number;
readonly wbg_rayon_poolbuilder_receiver: (a: number) => number;
readonly wbg_rayon_poolbuilder_build: (a: number) => void;
readonly initThreadPool: (a: number) => number;
readonly wbg_rayon_start_worker: (a: number) => void;
readonly __wbindgen_export_0: WebAssembly.Memory;
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
readonly __wbindgen_malloc: (a: number) => number;
readonly __wbindgen_free: (a: number, b: number) => void;
readonly __wbindgen_start: () => void;
@@ -41,4 +61,3 @@ export interface InitOutput {
* @returns {Promise<InitOutput>}
*/
export default function init (module_or_path?: InitInput | Promise<InitInput>, maybe_memory?: WebAssembly.Memory): Promise<InitOutput>;

View File

@@ -1,21 +1,6 @@
import { startWorkers } from './snippets/wasm-bindgen-rayon-3d2df09ebec17a22/src/workerHelpers.js';
let wasm;
let memory;
const heap = new Array(32).fill(undefined);
heap.push(undefined, null, true, false);
let heap_next = heap.length;
function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];
heap[idx] = obj;
return idx;
}
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
@@ -33,6 +18,21 @@ function getStringFromWasm0(ptr, len) {
return cachedTextDecoder.decode(getUint8Memory0().slice(ptr, ptr + len));
}
const heap = new Array(32).fill(undefined);
heap.push(undefined, null, true, false);
let heap_next = heap.length;
function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];
heap[idx] = obj;
return idx;
}
let WASM_VECTOR_LEN = 0;
function passArray8ToWasm0(arg, malloc) {
@@ -56,22 +56,22 @@ function getArrayU8FromWasm0(ptr, len) {
/**
* @param {Uint8Array} data
* @param {number} level
* @param {boolean} interlace
* @returns {Uint8Array}
*/
export function optimise(data, level) {
export function optimise(data, level, interlace) {
try {
const retptr = wasm.__wbindgen_export_1.value - 16;
wasm.__wbindgen_export_1.value = retptr;
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
var ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
var len0 = WASM_VECTOR_LEN;
wasm.optimise(retptr, ptr0, len0, level);
wasm.optimise(retptr, ptr0, len0, level, interlace);
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
var v1 = getArrayU8FromWasm0(r0, r1).slice();
wasm.__wbindgen_free(r0, r1 * 1);
return v1;
} finally {
wasm.__wbindgen_export_1.value += 16;
wasm.__wbindgen_add_to_stack_pointer(16);
}
}
@@ -89,29 +89,66 @@ function takeObject(idx) {
return ret;
}
/**
* @param {number} num
* @returns {any}
* @param {number} num_threads
* @returns {Promise<any>}
*/
export function worker_initializer(num) {
var ret = wasm.worker_initializer(num);
export function initThreadPool(num_threads) {
var ret = wasm.initThreadPool(num_threads);
return takeObject(ret);
}
/**
* @param {number} receiver
*/
export function start_main_thread() {
wasm.start_main_thread();
export function wbg_rayon_start_worker(receiver) {
wasm.wbg_rayon_start_worker(receiver);
}
/**
*/
export function start_worker_thread() {
wasm.start_worker_thread();
export class wbg_rayon_PoolBuilder {
static __wrap(ptr) {
const obj = Object.create(wbg_rayon_PoolBuilder.prototype);
obj.ptr = ptr;
return obj;
}
__destroy_into_raw() {
const ptr = this.ptr;
this.ptr = 0;
return ptr;
}
free() {
const ptr = this.__destroy_into_raw();
wasm.__wbg_wbg_rayon_poolbuilder_free(ptr);
}
/**
* @returns {number}
*/
numThreads() {
var ret = wasm.wbg_rayon_poolbuilder_numThreads(this.ptr);
return ret >>> 0;
}
/**
* @returns {number}
*/
receiver() {
var ret = wasm.wbg_rayon_poolbuilder_receiver(this.ptr);
return ret;
}
/**
*/
build() {
wasm.wbg_rayon_poolbuilder_build(this.ptr);
}
}
async function load(module, imports, maybe_memory) {
async function load(module, imports) {
if (typeof Response === 'function' && module instanceof Response) {
memory = imports.wbg.memory = new WebAssembly.Memory({initial:17,maximum:16384,shared:true});
if (typeof WebAssembly.instantiateStreaming === 'function') {
try {
return await WebAssembly.instantiateStreaming(module, imports);
@@ -130,7 +167,6 @@ async function load(module, imports, maybe_memory) {
return await WebAssembly.instantiate(bytes, imports);
} else {
memory = imports.wbg.memory = maybe_memory;
const instance = await WebAssembly.instantiate(module, imports);
if (instance instanceof WebAssembly.Instance) {
@@ -144,10 +180,13 @@ async function load(module, imports, maybe_memory) {
async function init(input, maybe_memory) {
if (typeof input === 'undefined') {
input = import.meta.url.replace(/\.js$/, '_bg.wasm');
input = new URL('squoosh_oxipng_bg.wasm', import.meta.url);
}
const imports = {};
imports.wbg = {};
imports.wbg.__wbindgen_throw = function(arg0, arg1) {
throw new Error(getStringFromWasm0(arg0, arg1));
};
imports.wbg.__wbindgen_module = function() {
var ret = init.__wbindgen_wasm_module;
return addHeapObject(ret);
@@ -156,19 +195,18 @@ async function init(input, maybe_memory) {
var ret = wasm.__wbindgen_export_0;
return addHeapObject(ret);
};
imports.wbg.__wbg_of_6510501edc06d65e = function(arg0, arg1) {
var ret = Array.of(takeObject(arg0), takeObject(arg1));
imports.wbg.__wbg_startWorkers_914655bb4d5bb5e1 = function(arg0, arg1, arg2) {
var ret = startWorkers(takeObject(arg0), takeObject(arg1), wbg_rayon_PoolBuilder.__wrap(arg2));
return addHeapObject(ret);
};
imports.wbg.__wbindgen_throw = function(arg0, arg1) {
throw new Error(getStringFromWasm0(arg0, arg1));
};
if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
input = fetch(input);
}
const { instance, module } = await load(await input, imports, maybe_memory);
imports.wbg.memory = maybe_memory || new WebAssembly.Memory({initial:17,maximum:16384,shared:true});
const { instance, module } = await load(await input, imports);
wasm = instance.exports;
init.__wbindgen_wasm_module = module;

View File

@@ -1,10 +1,15 @@
/* tslint:disable */
/* eslint-disable */
export function optimise(a: number, b: number, c: number, d: number): void;
export function worker_initializer(a: number): number;
export function start_main_thread(): void;
export function start_worker_thread(): void;
export function __wasm_init_memory(): void;
export function optimise(a: number, b: number, c: number, d: number, e: number): void;
export function __wbg_wbg_rayon_poolbuilder_free(a: number): void;
export function wbg_rayon_poolbuilder_numThreads(a: number): number;
export function wbg_rayon_poolbuilder_receiver(a: number): number;
export function wbg_rayon_poolbuilder_build(a: number): void;
export function initThreadPool(a: number): number;
export function wbg_rayon_start_worker(a: number): void;
export const __wbindgen_export_0: WebAssembly.Memory;
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;
export function __wbindgen_start(): void;

View File

@@ -3,15 +3,17 @@
/**
* @param {Uint8Array} data
* @param {number} level
* @param {boolean} interlace
* @returns {Uint8Array}
*/
export function optimise(data: Uint8Array, level: number): Uint8Array;
export function optimise(data: Uint8Array, level: number, interlace: boolean): Uint8Array;
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
export interface InitOutput {
readonly memory: WebAssembly.Memory;
readonly optimise: (a: number, b: number, c: number, d: number) => void;
readonly optimise: (a: number, b: number, c: number, d: number, e: number) => void;
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
readonly __wbindgen_malloc: (a: number) => number;
readonly __wbindgen_free: (a: number, b: number) => void;
}
@@ -25,4 +27,3 @@ export interface InitOutput {
* @returns {Promise<InitOutput>}
*/
export default function init (module_or_path?: InitInput | Promise<InitInput>): Promise<InitOutput>;

View File

@@ -40,28 +40,27 @@ function getArrayU8FromWasm0(ptr, len) {
/**
* @param {Uint8Array} data
* @param {number} level
* @param {boolean} interlace
* @returns {Uint8Array}
*/
export function optimise(data, level) {
export function optimise(data, level, interlace) {
try {
const retptr = wasm.__wbindgen_export_0.value - 16;
wasm.__wbindgen_export_0.value = retptr;
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
var ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
var len0 = WASM_VECTOR_LEN;
wasm.optimise(retptr, ptr0, len0, level);
wasm.optimise(retptr, ptr0, len0, level, interlace);
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
var v1 = getArrayU8FromWasm0(r0, r1).slice();
wasm.__wbindgen_free(r0, r1 * 1);
return v1;
} finally {
wasm.__wbindgen_export_0.value += 16;
wasm.__wbindgen_add_to_stack_pointer(16);
}
}
async function load(module, imports) {
if (typeof Response === 'function' && module instanceof Response) {
if (typeof WebAssembly.instantiateStreaming === 'function') {
try {
return await WebAssembly.instantiateStreaming(module, imports);
@@ -80,7 +79,6 @@ async function load(module, imports) {
return await WebAssembly.instantiate(bytes, imports);
} else {
const instance = await WebAssembly.instantiate(module, imports);
if (instance instanceof WebAssembly.Instance) {
@@ -94,7 +92,7 @@ async function load(module, imports) {
async function init(input) {
if (typeof input === 'undefined') {
input = import.meta.url.replace(/\.js$/, '_bg.wasm');
input = new URL('squoosh_oxipng_bg.wasm', import.meta.url);
}
const imports = {};
imports.wbg = {};
@@ -106,6 +104,8 @@ async function init(input) {
input = fetch(input);
}
const { instance, module } = await load(await input, imports);
wasm = instance.exports;

View File

@@ -1,6 +1,7 @@
/* tslint:disable */
/* eslint-disable */
export const memory: WebAssembly.Memory;
export function optimise(a: number, b: number, c: number, d: number): void;
export function optimise(a: number, b: number, c: number, d: number, e: 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

@@ -1,11 +1,11 @@
#[cfg(feature = "parallel")]
pub use wasm_bindgen_rayon::init_thread_pool;
use oxipng::AlphaOptim;
use wasm_bindgen::prelude::*;
#[cfg(feature = "parallel")]
pub mod parallel;
#[wasm_bindgen]
pub fn optimise(data: &[u8], level: u8) -> Vec<u8> {
pub fn optimise(data: &[u8], level: u8, interlace: bool) -> Vec<u8> {
let mut options = oxipng::Options::from_preset(level);
options.alphas.insert(AlphaOptim::Black);
options.alphas.insert(AlphaOptim::White);
@@ -13,6 +13,7 @@ pub fn optimise(data: &[u8], level: u8) -> Vec<u8> {
options.alphas.insert(AlphaOptim::Down);
options.alphas.insert(AlphaOptim::Left);
options.alphas.insert(AlphaOptim::Right);
options.interlace = Some(if interlace { 1 } else { 0 });
options.deflate = oxipng::Deflaters::Libdeflater;
oxipng::optimize_from_memory(data, &options).unwrap_throw()

View File

@@ -1,62 +0,0 @@
use crossbeam_channel::{bounded, Receiver, Sender};
use once_cell::sync::OnceCell;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsValue;
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = Array, js_name = of)]
fn array_of_2(a: JsValue, b: JsValue) -> JsValue;
}
// This is one of the parts that work around Chromium incorrectly implementing postMessage:
// https://bugs.chromium.org/p/chromium/issues/detail?id=1075645
//
// rayon::ThreadPoolBuilder (used below) executes spawn handler to populate the worker pool,
// and then blocks the current thread until each worker unblocks its (opaque) lock.
//
// Normally, we could use postMessage directly inside the spawn handler to
// post module + memory + threadPtr to each worker, and the block the current thread.
//
// However, that bug means that postMessage is currently delayed until the next event loop,
// which will never spin since we block the current thread, and so the other workers will
// never be able to unblock us.
//
// To work around this problem, we:
// 1) Expose `worker_initializer` that returns module + memory pair (without threadPtr)
// that workers can be initialised with to become native threads.
// JavaScript can postMessage this pair in advance, and asynchronously wait for workers
// to acknowledge the receipt.
// 2) Create a global communication channel on the Rust side using crossbeam.
// It will be used to send threadPtr to the pre-initialised workers
// instead of postMessage.
// 3) Provide a separate `start_main_thread` that expects all workers to be ready,
// and just uses the provided channel to send `threadPtr`s using the
// shared memory and blocks the current thread until they're all grabbed.
// 4) Provide a `worker_initializer` that is expected to be invoked from various workers,
// reads one `threadPtr` from the shared channel and starts running it.
static CHANNEL: OnceCell<(Sender<rayon::ThreadBuilder>, Receiver<rayon::ThreadBuilder>)> =
OnceCell::new();
#[wasm_bindgen]
pub fn worker_initializer(num: usize) -> JsValue {
CHANNEL.get_or_init(|| bounded(num));
array_of_2(wasm_bindgen::module(), wasm_bindgen::memory())
}
#[wasm_bindgen]
pub fn start_main_thread() {
let (sender, _) = CHANNEL.get().unwrap();
rayon::ThreadPoolBuilder::new()
.num_threads(sender.capacity().unwrap())
.spawn_handler(|thread| Ok(sender.send(thread).unwrap_throw()))
.build_global()
.unwrap_throw()
}
#[wasm_bindgen]
pub fn start_worker_thread() {
let (_, receiver) = CHANNEL.get().unwrap();
receiver.recv().unwrap_throw().run()
}

40
codecs/png/Cargo.lock generated
View File

@@ -36,13 +36,19 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crc32fast"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
]
[[package]]
@@ -76,7 +82,7 @@ version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
]
[[package]]
@@ -102,9 +108,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.18"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa"
checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
dependencies = [
"unicode-xid",
]
@@ -139,9 +145,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.34"
version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936cae2873c940d92e697597c5eee105fb570cd5689c695806f672883653349b"
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
dependencies = [
"proc-macro2",
"quote",
@@ -156,19 +162,19 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "wasm-bindgen"
version = "0.2.68"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ac64ead5ea5f05873d7c12b545865ca2b8d28adfc50a49b84770a3a97265d42"
checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.68"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f22b422e2a757c35a73774860af8e112bff612ce6cb604224e8e47641a9e4f68"
checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900"
dependencies = [
"bumpalo",
"lazy_static",
@@ -181,9 +187,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.68"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b13312a745c08c469f0b292dd2fcd6411dba5f7160f593da6ef69b64e407038"
checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -191,9 +197,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.68"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe"
checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
dependencies = [
"proc-macro2",
"quote",
@@ -204,9 +210,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.68"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307"
checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
[[package]]
name = "web-sys"

2
codecs/png/pkg/squoosh_png.d.ts generated vendored
View File

@@ -20,6 +20,7 @@ export interface InitOutput {
readonly encode: (a: number, b: number, c: number, d: number, e: number) => void;
readonly decode: (a: number, b: number) => number;
readonly __wbindgen_free: (a: number, b: number) => void;
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
readonly __wbindgen_malloc: (a: number) => number;
}
@@ -32,4 +33,3 @@ export interface InitOutput {
* @returns {Promise<InitOutput>}
*/
export default function init (module_or_path?: InitInput | Promise<InitInput>): Promise<InitOutput>;

View File

@@ -72,8 +72,7 @@ function getArrayU8FromWasm0(ptr, len) {
*/
export function encode(data, width, height) {
try {
const retptr = wasm.__wbindgen_export_1.value - 16;
wasm.__wbindgen_export_1.value = retptr;
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
var ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
var len0 = WASM_VECTOR_LEN;
wasm.encode(retptr, ptr0, len0, width, height);
@@ -83,7 +82,7 @@ export function encode(data, width, height) {
wasm.__wbindgen_free(r0, r1 * 1);
return v1;
} finally {
wasm.__wbindgen_export_1.value += 16;
wasm.__wbindgen_add_to_stack_pointer(16);
}
}
@@ -113,7 +112,6 @@ export function decode(data) {
async function load(module, imports) {
if (typeof Response === 'function' && module instanceof Response) {
if (typeof WebAssembly.instantiateStreaming === 'function') {
try {
return await WebAssembly.instantiateStreaming(module, imports);
@@ -132,7 +130,6 @@ async function load(module, imports) {
return await WebAssembly.instantiate(bytes, imports);
} else {
const instance = await WebAssembly.instantiate(module, imports);
if (instance instanceof WebAssembly.Instance) {
@@ -146,7 +143,7 @@ async function load(module, imports) {
async function init(input) {
if (typeof input === 'undefined') {
input = import.meta.url.replace(/\.js$/, '_bg.wasm');
input = new URL('squoosh_png_bg.wasm', import.meta.url);
}
const imports = {};
imports.wbg = {};
@@ -164,6 +161,8 @@ async function init(input) {
input = fetch(input);
}
const { instance, module } = await load(await input, imports);
wasm = instance.exports;

Binary file not shown.

View File

@@ -4,4 +4,5 @@ export const memory: WebAssembly.Memory;
export function encode(a: number, b: number, c: number, d: number, e: number): void;
export function decode(a: number, b: number): number;
export function __wbindgen_free(a: number, b: number): void;
export function __wbindgen_add_to_stack_pointer(a: number): number;
export function __wbindgen_malloc(a: number): number;

View File

@@ -18,13 +18,19 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "console_error_panic_hook"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"wasm-bindgen",
]
@@ -61,7 +67,7 @@ version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
]
[[package]]
@@ -81,9 +87,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.18"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa"
checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
dependencies = [
"unicode-xid 0.2.1",
]
@@ -103,7 +109,7 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
dependencies = [
"proc-macro2 1.0.18",
"proc-macro2 1.0.27",
]
[[package]]
@@ -134,7 +140,7 @@ checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
name = "squoosh-resize"
version = "0.1.0"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"console_error_panic_hook",
"resize",
"wasm-bindgen",
@@ -144,11 +150,11 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.34"
version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936cae2873c940d92e697597c5eee105fb570cd5689c695806f672883653349b"
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
dependencies = [
"proc-macro2 1.0.18",
"proc-macro2 1.0.27",
"quote 1.0.7",
"unicode-xid 0.2.1",
]
@@ -167,24 +173,24 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "wasm-bindgen"
version = "0.2.64"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a634620115e4a229108b71bde263bb4220c483b3f07f5ba514ee8d15064c4c2"
checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.64"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e53963b583d18a5aa3aaae4b4c1cb535218246131ba22a71f05b518098571df"
checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2 1.0.18",
"proc-macro2 1.0.27",
"quote 1.0.7",
"syn",
"wasm-bindgen-shared",
@@ -196,7 +202,7 @@ version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83420b37346c311b9ed822af41ec2e82839bfe99867ec6c54e2da43b7538771c"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"futures",
"js-sys",
"wasm-bindgen",
@@ -205,9 +211,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.64"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fcfd5ef6eec85623b4c6e844293d4516470d8f19cd72d0d12246017eb9060b8"
checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4"
dependencies = [
"quote 1.0.7",
"wasm-bindgen-macro-support",
@@ -215,11 +221,11 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.64"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9adff9ee0e94b926ca81b57f57f86d5545cdcb1d259e21ec9bdd95b901754c75"
checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
dependencies = [
"proc-macro2 1.0.18",
"proc-macro2 1.0.27",
"quote 1.0.7",
"syn",
"wasm-bindgen-backend",
@@ -228,9 +234,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.64"
version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f7b90ea6c632dd06fd765d44542e234d5e63d9bb917ecd64d79778a13bd79ae"
checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
[[package]]
name = "wasm-bindgen-test"
@@ -273,7 +279,7 @@ version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"libc",
"memory_units",
"winapi",

View File

@@ -9,15 +9,16 @@
* @param {number} typ_idx
* @param {boolean} premultiply
* @param {boolean} color_space_conversion
* @returns {Uint8Array}
* @returns {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 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 type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
export interface InitOutput {
readonly memory: WebAssembly.Memory;
readonly resize: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number) => void;
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
readonly __wbindgen_malloc: (a: number) => number;
readonly __wbindgen_free: (a: number, b: number) => void;
}
@@ -31,4 +32,3 @@ export interface InitOutput {
* @returns {Promise<InitOutput>}
*/
export default function init (module_or_path?: InitInput | Promise<InitInput>): Promise<InitOutput>;

View File

@@ -26,8 +26,16 @@ function getInt32Memory0() {
return cachegetInt32Memory0;
}
function getArrayU8FromWasm0(ptr, len) {
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len);
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);
}
/**
* @param {Uint8Array} input_image
@@ -38,22 +46,26 @@ function getArrayU8FromWasm0(ptr, len) {
* @param {number} typ_idx
* @param {boolean} premultiply
* @param {boolean} color_space_conversion
* @returns {Uint8Array}
* @returns {Uint8ClampedArray}
*/
export function resize(input_image, input_width, input_height, output_width, output_height, typ_idx, premultiply, color_space_conversion) {
var ptr0 = passArray8ToWasm0(input_image, wasm.__wbindgen_malloc);
var len0 = WASM_VECTOR_LEN;
wasm.resize(8, ptr0, len0, input_width, input_height, output_width, output_height, typ_idx, premultiply, color_space_conversion);
var r0 = getInt32Memory0()[8 / 4 + 0];
var r1 = getInt32Memory0()[8 / 4 + 1];
var v1 = getArrayU8FromWasm0(r0, r1).slice();
wasm.__wbindgen_free(r0, r1 * 1);
return v1;
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
var ptr0 = passArray8ToWasm0(input_image, wasm.__wbindgen_malloc);
var len0 = WASM_VECTOR_LEN;
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();
wasm.__wbindgen_free(r0, r1 * 1);
return v1;
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
}
}
async function load(module, imports) {
if (typeof Response === 'function' && module instanceof Response) {
if (typeof WebAssembly.instantiateStreaming === 'function') {
try {
return await WebAssembly.instantiateStreaming(module, imports);
@@ -72,7 +84,6 @@ async function load(module, imports) {
return await WebAssembly.instantiate(bytes, imports);
} else {
const instance = await WebAssembly.instantiate(module, imports);
if (instance instanceof WebAssembly.Instance) {
@@ -86,7 +97,7 @@ async function load(module, imports) {
async function init(input) {
if (typeof input === 'undefined') {
input = import.meta.url.replace(/\.js$/, '_bg.wasm');
input = new URL('squoosh_resize_bg.wasm', import.meta.url);
}
const imports = {};
@@ -95,6 +106,8 @@ async function init(input) {
input = fetch(input);
}
const { instance, module } = await load(await input, imports);
wasm = instance.exports;

View File

@@ -2,5 +2,6 @@
/* 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,6 +8,7 @@ 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};
@@ -66,7 +67,7 @@ pub fn resize(
typ_idx: usize,
premultiply: bool,
color_space_conversion: bool,
) -> Vec<u8> {
) -> Clamped<Vec<u8>> {
let typ = match typ_idx {
0 => Type::Triangle,
1 => Type::Catrom,
@@ -91,7 +92,7 @@ pub fn resize(
typ,
);
resizer.resize(input_image.as_slice(), output_image.as_mut_slice());
return output_image;
return Clamped(output_image);
}
// Otherwise, we convert to f32 images to keep the
@@ -138,5 +139,5 @@ pub fn resize(
.clamp(0.0, 255.0) as u8;
}
return output_image;
return Clamped(output_image);
}

View File

@@ -1,5 +1,6 @@
CODEC_URL = https://github.com/google/butteraugli/archive/71b18b636b9c7d1ae0c1d3730b85b3c127eb4511.tar.gz
CODEC_DIR = node_modules/butteraugli
ENVIRONMENT = node
OUT_JS = visdif.js
OUT_WASM = $(OUT_JS:.js=.wasm)
@@ -8,19 +9,18 @@ OUT_WASM = $(OUT_JS:.js=.wasm)
all: $(OUT_JS)
%.js: $(CODEC_DIR)
%.js: visdif.cpp $(CODEC_DIR)/butteraugli/butteraugli.cc
$(CXX) \
-I $(CODEC_DIR) \
${CXXFLAGS} \
${LDFLAGS} \
--bind \
--closure 1 \
-s ALLOW_MEMORY_GROWTH=1 \
-s MODULARIZE=1 \
-s 'EXPORT_NAME="$(basename $(@F))"' \
-s ENVIRONMENT=$(ENVIRONMENT) \
-s EXPORT_ES6=1 \
-o $@ \
visdif.cpp \
$(CODEC_DIR)/butteraugli/butteraugli.cc
$+
$(CODEC_DIR)/butteraugli/butteraugli.cc: $(CODEC_DIR)
$(CODEC_DIR):
mkdir -p $@

View File

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

22
codecs/visdif/test.mjs Normal file
View File

@@ -0,0 +1,22 @@
import {dirname} from "path";
globalThis.__dirname = dirname(import.meta.url);
import { createRequire } from 'module';
globalThis.require = createRequire(import.meta.url);
import visdif from './visdif.js';
const {VisDiff} = await visdif({
locateFile() {
return new URL("./visdif.wasm", import.meta.url).pathname;
}
});
const comparator = new VisDiff(
new Uint8ClampedArray([0, 0, 0, 255]),
1,
1
);
const distance = comparator.distance(new Uint8ClampedArray([1,1,1,255]));
console.log({distance});

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,21 @@
import {dirname} from "path";
globalThis.__dirname = dirname(import.meta.url);
import { createRequire } from 'module';
globalThis.require = createRequire(import.meta.url);
import visdif from './visdif.js';
const {VisDiff} = await visdif({
locateFile() {
return new URL("./visdif.wasm", import.meta.url).pathname;
}
});
const comparator = new VisDiff(
new Uint8ClampedArray([0, 0, 0, 255]),
1,
1
);
const distance = comparator.distance(new Uint8ClampedArray([1,1,1,255]));
console.log({distance});

Binary file not shown.

View File

@@ -24,10 +24,6 @@ $(OUT_JS):
$(LD) \
$(LDFLAGS) \
--bind \
--closure 1 \
-s ALLOW_MEMORY_GROWTH=1 \
-s MODULARIZE=1 \
-s TEXTDECODER=2 \
-s ENVIRONMENT=$(ENVIRONMENT) \
-s EXPORT_ES6=1 \
-o $@ \

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

@@ -28,13 +28,8 @@ $(OUT_JS):
$(LD) \
$(LDFLAGS) \
--bind \
--closure 1 \
-s ALLOW_MEMORY_GROWTH=1 \
-s MODULARIZE=1 \
-s TEXTDECODER=2 \
-s ENVIRONMENT=$(ENVIRONMENT) \
-s EXPORT_ES6=1 \
-s EXPORT_NAME="$(basename $(@F))" \
-o $@ \
$+

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