mirror of
https://github.com/GoogleChromeLabs/squoosh.git
synced 2025-11-12 16:57:26 +00:00
Compare commits
7 Commits
live
...
hotfix-avi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ecc864120e | ||
|
|
89d5d8063d | ||
|
|
2e8dd1e247 | ||
|
|
fc2e658feb | ||
|
|
43233e2c55 | ||
|
|
2467d0046e | ||
|
|
c58c4beb1a |
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -1,2 +1,2 @@
|
|||||||
/codecs/**/*.js linguist-generated -diff
|
/codecs/**/*.js linguist-generated=true
|
||||||
/codecs/*/pkg*/*.d.ts linguist-generated
|
/codecs/*/pkg*/*.d.ts linguist-generated=true
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
npx lint-staged
|
|
||||||
46
README.md
46
README.md
@@ -1,38 +1,36 @@
|
|||||||
# [Squoosh]!
|
# [Squoosh]!
|
||||||
|
|
||||||
[Squoosh] is an image compression web app that reduces image sizes through numerous formats.
|
[Squoosh] is an image compression web app that allows you to dive into the advanced options provided
|
||||||
|
by various image compressors.
|
||||||
|
|
||||||
|
# CLI
|
||||||
|
|
||||||
|
[Squoosh now has a CLI](https://github.com/GoogleChromeLabs/squoosh/tree/dev/cli) that allows you to compress many images at once.
|
||||||
|
|
||||||
# Privacy
|
# Privacy
|
||||||
|
|
||||||
Squoosh does not send your image to a server. All image compression processes locally.
|
Google Analytics is used to record the following:
|
||||||
|
|
||||||
However, Squoosh utilizes Google Analytics to collect the following:
|
- [Basic visit data](https://support.google.com/analytics/answer/6004245?ref_topic=2919631).
|
||||||
|
- Before and after image size once an image is downloaded. These values are rounded to the nearest
|
||||||
|
kilobyte.
|
||||||
|
- If install is available, when Squoosh is installed, and what method was used to install Squoosh.
|
||||||
|
|
||||||
- [Basic visitor data](https://support.google.com/analytics/answer/6004245?ref_topic=2919631).
|
Image compression is handled locally; no additional data is sent to the server.
|
||||||
- The before and after image size value.
|
|
||||||
- If Squoosh PWA, the type of Squoosh installation.
|
|
||||||
- If Squoosh PWA, the installation time and date.
|
|
||||||
|
|
||||||
# Developing
|
# Building locally
|
||||||
|
|
||||||
To develop for Squoosh:
|
Clone the repo, and:
|
||||||
|
|
||||||
1. Clone the repository
|
```sh
|
||||||
1. To install node packages, run:
|
npm install
|
||||||
```sh
|
npm run build
|
||||||
npm install
|
```
|
||||||
```
|
|
||||||
1. Then build the app by running:
|
|
||||||
```sh
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
1. After building, start the development server by running:
|
|
||||||
```sh
|
|
||||||
npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
# Contributing
|
You can run the development server with:
|
||||||
|
|
||||||
Squoosh is an open-source project that appreciates all community involvement. To contribute to the project, follow the [contribute guide](/CONTRIBUTING.md).
|
```sh
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
[squoosh]: https://squoosh.app
|
[squoosh]: https://squoosh.app
|
||||||
|
|||||||
3
cli/.gitignore
vendored
Normal file
3
cli/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
node_modules
|
||||||
|
build
|
||||||
|
.DS_Store
|
||||||
1
cli/.npmignore
Normal file
1
cli/.npmignore
Normal file
@@ -0,0 +1 @@
|
|||||||
|
node_modules
|
||||||
0
cli/.npmrc
Normal file
0
cli/.npmrc
Normal file
59
cli/README.md
Normal file
59
cli/README.md
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
# Squoosh CLI
|
||||||
|
|
||||||
|
Squoosh CLI is an _experimental_ way to run all the codecs you know from the [Squoosh] web app on your command line using WebAssembly. The Squoosh CLI uses a worker pool to parallelize processing images. This way you can apply the same codec to many images at once.
|
||||||
|
|
||||||
|
Squoosh CLI is currently not the fastest image compression tool in town and doesn’t aim to be. It is, however, fast enough to compress many images sufficiently quick at once.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
The Squoosh CLI can be used straight from the command line without installing using `npx`:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npx @squoosh/cli <options...>
|
||||||
|
```
|
||||||
|
|
||||||
|
Of course, you can also install the Squoosh CLI:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npm i -g @squoosh/cli
|
||||||
|
$ squoosh-cli <options...>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
Usage: squoosh-cli [options] <files...>
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-V, --version output the version number
|
||||||
|
-d, --output-dir <dir> Output directory (default: ".")
|
||||||
|
-s, --suffix <suffix> Append suffix to output files (default: "")
|
||||||
|
--max-optimizer-rounds <rounds> Maximum number of compressions to use for auto optimizations (default: "6")
|
||||||
|
--optimizer-butteraugli-target <butteraugli distance> Target Butteraugli distance for auto optimizer (default: "1.4")
|
||||||
|
--resize [config] Resize the image before compressing
|
||||||
|
--quant [config] Reduce the number of colors used (aka. paletting)
|
||||||
|
--rotate [config] Rotate image
|
||||||
|
--mozjpeg [config] Use MozJPEG to generate a .jpg file with the given configuration
|
||||||
|
--webp [config] Use WebP to generate a .webp file with the given configuration
|
||||||
|
--avif [config] Use AVIF to generate a .avif file with the given configuration
|
||||||
|
--jxl [config] Use JPEG-XL to generate a .jxl file with the given configuration
|
||||||
|
--wp2 [config] Use WebP2 to generate a .wp2 file with the given configuration
|
||||||
|
--oxipng [config] Use OxiPNG to generate a .png file with the given configuration
|
||||||
|
-h, --help display help for command
|
||||||
|
```
|
||||||
|
|
||||||
|
The default values for each `config` option can be found in the [`codecs.js`][codecs.js] file under `defaultEncoderOptions`. Every unspecified value will use the default value specified here. _Better documentation is needed here._
|
||||||
|
|
||||||
|
## Auto optimizer
|
||||||
|
|
||||||
|
Squoosh CLI has an _experimental_ auto optimizer that compresses an image as much as possible, trying to hit a specific [Butteraugli] target value. The higher the Butteraugli target value, the more artifacts can be introduced.
|
||||||
|
|
||||||
|
You can make use of the auto optimizer by using “auto” as the config object.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npx @squoosh/cli --wp2 auto test.png
|
||||||
|
```
|
||||||
|
|
||||||
|
[squoosh]: https://squoosh.app
|
||||||
|
[codecs.js]: https://github.com/GoogleChromeLabs/squoosh/blob/dev/cli/src/codecs.js
|
||||||
|
[butteraugli]: https://github.com/google/butteraugli
|
||||||
75
cli/lib/asset-plugin.js
Normal file
75
cli/lib/asset-plugin.js
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2020 Google Inc. All Rights Reserved.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { promises as fs } from "fs";
|
||||||
|
import { basename } from "path";
|
||||||
|
|
||||||
|
const defaultOpts = {
|
||||||
|
prefix: "asset-url"
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function assetPlugin(opts) {
|
||||||
|
opts = { ...defaultOpts, ...opts };
|
||||||
|
|
||||||
|
/** @type {Map<string, Buffer>} */
|
||||||
|
let assetIdToSourceBuffer;
|
||||||
|
|
||||||
|
const prefix = opts.prefix + ":";
|
||||||
|
return {
|
||||||
|
name: "asset-plugin",
|
||||||
|
buildStart() {
|
||||||
|
assetIdToSourceBuffer = new Map();
|
||||||
|
},
|
||||||
|
augmentChunkHash(info) {
|
||||||
|
// Get the sources for all assets imported by this chunk.
|
||||||
|
const buffers = Object.keys(info.modules)
|
||||||
|
.map(moduleId => assetIdToSourceBuffer.get(moduleId))
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
if (buffers.length === 0) return;
|
||||||
|
|
||||||
|
for (const moduleId of Object.keys(info.modules)) {
|
||||||
|
const buffer = assetIdToSourceBuffer.get(moduleId);
|
||||||
|
if (buffer) buffers.push(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
const combinedBuffer =
|
||||||
|
buffers.length === 1 ? buffers[0] : Buffer.concat(buffers);
|
||||||
|
|
||||||
|
return combinedBuffer;
|
||||||
|
},
|
||||||
|
async resolveId(id, importer) {
|
||||||
|
if (!id.startsWith(prefix)) return;
|
||||||
|
const realId = id.slice(prefix.length);
|
||||||
|
const resolveResult = await this.resolve(realId, importer);
|
||||||
|
|
||||||
|
if (!resolveResult) {
|
||||||
|
throw Error(`Cannot find ${realId}`);
|
||||||
|
}
|
||||||
|
// Add an additional .js to the end so it ends up with .js at the end in the _virtual folder.
|
||||||
|
return prefix + resolveResult.id + ".js";
|
||||||
|
},
|
||||||
|
async load(id) {
|
||||||
|
if (!id.startsWith(prefix)) return;
|
||||||
|
const realId = id.slice(prefix.length, -".js".length);
|
||||||
|
const source = await fs.readFile(realId);
|
||||||
|
assetIdToSourceBuffer.set(id, source);
|
||||||
|
this.addWatchFile(realId);
|
||||||
|
|
||||||
|
return `export default import.meta.ROLLUP_FILE_URL_${this.emitFile({
|
||||||
|
type: "asset",
|
||||||
|
source,
|
||||||
|
name: basename(realId)
|
||||||
|
})}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
12
cli/lib/autojson-plugin.js
Normal file
12
cli/lib/autojson-plugin.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { promises as fsp } from 'fs';
|
||||||
|
|
||||||
|
export default function autojsonPlugin() {
|
||||||
|
return {
|
||||||
|
name: 'autojson-plugin',
|
||||||
|
async load(id) {
|
||||||
|
if (id.endsWith('.json') && !id.startsWith('json:')) {
|
||||||
|
return 'export default ' + await fsp.readFile(id, 'utf8');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
38
cli/lib/json-plugin.js
Normal file
38
cli/lib/json-plugin.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { promises as fsp } from 'fs';
|
||||||
|
|
||||||
|
const prefix = 'json:';
|
||||||
|
|
||||||
|
const reservedKeys = ['public'];
|
||||||
|
|
||||||
|
export default function jsonPlugin() {
|
||||||
|
return {
|
||||||
|
name: 'json-plugin',
|
||||||
|
async resolveId(id, importer) {
|
||||||
|
if (!id.startsWith(prefix)) return;
|
||||||
|
const realId = id.slice(prefix.length);
|
||||||
|
const resolveResult = await this.resolve(realId, importer);
|
||||||
|
|
||||||
|
if (!resolveResult) {
|
||||||
|
throw Error(`Cannot find ${realId}`);
|
||||||
|
}
|
||||||
|
// Add an additional .js to the end so it ends up with .js at the end in the _virtual folder.
|
||||||
|
return prefix + resolveResult.id;
|
||||||
|
},
|
||||||
|
async load(id) {
|
||||||
|
if (!id.startsWith(prefix)) return;
|
||||||
|
const realId = id.slice(prefix.length);
|
||||||
|
const source = await fsp.readFile(realId, 'utf8');
|
||||||
|
|
||||||
|
let code = '';
|
||||||
|
for (const [key, value] of Object.entries(JSON.parse(source))) {
|
||||||
|
if (reservedKeys.includes(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
code += `
|
||||||
|
export const ${key} = ${JSON.stringify(value)};
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
2168
cli/package-lock.json
generated
Normal file
2168
cli/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
32
cli/package.json
Normal file
32
cli/package.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "@squoosh/cli",
|
||||||
|
"version": "0.6.0",
|
||||||
|
"description": "A CLI for Squoosh",
|
||||||
|
"public": true,
|
||||||
|
"bin": {
|
||||||
|
"squoosh-cli": "build/index.js",
|
||||||
|
"@squoosh/cli": "build/index.js"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "rollup -c"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
45
cli/rollup.config.js
Normal file
45
cli/rollup.config.js
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import resolve from '@rollup/plugin-node-resolve';
|
||||||
|
import cjs from '@rollup/plugin-commonjs';
|
||||||
|
import asset from './lib/asset-plugin.js';
|
||||||
|
import json from './lib/json-plugin.js';
|
||||||
|
import autojson from './lib/autojson-plugin.js';
|
||||||
|
import { getBabelOutputPlugin } from '@rollup/plugin-babel';
|
||||||
|
import { builtinModules } from 'module';
|
||||||
|
|
||||||
|
/** @type {import('rollup').RollupOptions} */
|
||||||
|
export default {
|
||||||
|
input: 'src/index.js',
|
||||||
|
output: {
|
||||||
|
dir: 'build',
|
||||||
|
format: 'cjs',
|
||||||
|
assetFileNames: '[name]-[hash][extname]',
|
||||||
|
// This is needed so the resulting `index.js` can be
|
||||||
|
// executed by `npx`.
|
||||||
|
banner: '#!/usr/bin/env node',
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
resolve(),
|
||||||
|
cjs(),
|
||||||
|
asset(),
|
||||||
|
autojson(),
|
||||||
|
json(),
|
||||||
|
getBabelOutputPlugin({
|
||||||
|
babelrc: false,
|
||||||
|
configFile: false,
|
||||||
|
minified: process.env.DEBUG != '',
|
||||||
|
comments: false,
|
||||||
|
presets: [
|
||||||
|
[
|
||||||
|
'@babel/preset-env',
|
||||||
|
{
|
||||||
|
targets: {
|
||||||
|
node: 12,
|
||||||
|
},
|
||||||
|
loose: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
external: builtinModules,
|
||||||
|
};
|
||||||
70
cli/src/auto-optimizer.js
Normal file
70
cli/src/auto-optimizer.js
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import { instantiateEmscriptenWasm } from "./emscripten-utils.js";
|
||||||
|
|
||||||
|
import visdif from "../../codecs/visdif/visdif.js";
|
||||||
|
import visdifWasm from "asset-url:../../codecs/visdif/visdif.wasm";
|
||||||
|
|
||||||
|
// `measure` is a (async) function that takes exactly one numeric parameter and
|
||||||
|
// returns a value. The function is assumed to be monotonic (an increase in `parameter`
|
||||||
|
// will result in an increase in the return value. The function uses binary search
|
||||||
|
// to find `parameter` such that `measure` returns `measureGoal`, within an error
|
||||||
|
// of `epsilon`. It will use at most `maxRounds` attempts.
|
||||||
|
export async function binarySearch(
|
||||||
|
measureGoal,
|
||||||
|
measure,
|
||||||
|
{ min = 0, max = 100, epsilon = 0.1, maxRounds = 8 } = {}
|
||||||
|
) {
|
||||||
|
let parameter = (max - min) / 2 + min;
|
||||||
|
let delta = (max - min) / 4;
|
||||||
|
let value;
|
||||||
|
let round = 1;
|
||||||
|
while (true) {
|
||||||
|
value = await measure(parameter);
|
||||||
|
if (Math.abs(value - measureGoal) < epsilon || round >= maxRounds) {
|
||||||
|
return { parameter, round, value };
|
||||||
|
}
|
||||||
|
if (value > measureGoal) {
|
||||||
|
parameter -= delta;
|
||||||
|
} else if (value < measureGoal) {
|
||||||
|
parameter += delta;
|
||||||
|
}
|
||||||
|
delta /= 2;
|
||||||
|
round++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function autoOptimize(
|
||||||
|
bitmapIn,
|
||||||
|
encode,
|
||||||
|
decode,
|
||||||
|
{ butteraugliDistanceGoal = 1.4, ...otherOpts } = {}
|
||||||
|
) {
|
||||||
|
const { VisDiff } = await instantiateEmscriptenWasm(visdif, visdifWasm);
|
||||||
|
|
||||||
|
const comparator = new VisDiff(
|
||||||
|
bitmapIn.data,
|
||||||
|
bitmapIn.width,
|
||||||
|
bitmapIn.height
|
||||||
|
);
|
||||||
|
|
||||||
|
let bitmapOut;
|
||||||
|
let binaryOut;
|
||||||
|
// Increasing quality means _decrease_ in Butteraugli distance.
|
||||||
|
// `binarySearch` assumes that increasing `parameter` will
|
||||||
|
// increase the metric value. So multipliy Butteraugli values by -1.
|
||||||
|
const { parameter } = await binarySearch(
|
||||||
|
-1 * butteraugliDistanceGoal,
|
||||||
|
async quality => {
|
||||||
|
binaryOut = await encode(bitmapIn, quality);
|
||||||
|
bitmapOut = await decode(binaryOut);
|
||||||
|
return -1 * comparator.distance(bitmapOut.data);
|
||||||
|
},
|
||||||
|
otherOpts
|
||||||
|
);
|
||||||
|
comparator.delete();
|
||||||
|
|
||||||
|
return {
|
||||||
|
bitmap: bitmapOut,
|
||||||
|
binary: binaryOut,
|
||||||
|
quality: parameter
|
||||||
|
};
|
||||||
|
}
|
||||||
361
cli/src/codecs.js
Normal file
361
cli/src/codecs.js
Normal file
@@ -0,0 +1,361 @@
|
|||||||
|
import { promises as fsp } from 'fs';
|
||||||
|
import { instantiateEmscriptenWasm, pathify } from './emscripten-utils.js';
|
||||||
|
|
||||||
|
// MozJPEG
|
||||||
|
import mozEnc from '../../codecs/mozjpeg/enc/mozjpeg_node_enc.js';
|
||||||
|
import mozEncWasm from 'asset-url:../../codecs/mozjpeg/enc/mozjpeg_node_enc.wasm';
|
||||||
|
import mozDec from '../../codecs/mozjpeg/dec/mozjpeg_node_dec.js';
|
||||||
|
import mozDecWasm from 'asset-url:../../codecs/mozjpeg/dec/mozjpeg_node_dec.wasm';
|
||||||
|
|
||||||
|
// WebP
|
||||||
|
import webpEnc from '../../codecs/webp/enc/webp_node_enc.js';
|
||||||
|
import webpEncWasm from 'asset-url:../../codecs/webp/enc/webp_node_enc.wasm';
|
||||||
|
import webpDec from '../../codecs/webp/dec/webp_node_dec.js';
|
||||||
|
import webpDecWasm from 'asset-url:../../codecs/webp/dec/webp_node_dec.wasm';
|
||||||
|
|
||||||
|
// AVIF
|
||||||
|
import avifEnc from '../../codecs/avif/enc/avif_node_enc.js';
|
||||||
|
import avifEncWasm from 'asset-url:../../codecs/avif/enc/avif_node_enc.wasm';
|
||||||
|
import avifDec from '../../codecs/avif/dec/avif_node_dec.js';
|
||||||
|
import avifDecWasm from 'asset-url:../../codecs/avif/dec/avif_node_dec.wasm';
|
||||||
|
|
||||||
|
// JXL
|
||||||
|
import jxlEnc from '../../codecs/jxl/enc/jxl_node_enc.js';
|
||||||
|
import jxlEncWasm from 'asset-url:../../codecs/jxl/enc/jxl_node_enc.wasm';
|
||||||
|
import jxlDec from '../../codecs/jxl/dec/jxl_node_dec.js';
|
||||||
|
import jxlDecWasm from 'asset-url:../../codecs/jxl/dec/jxl_node_dec.wasm';
|
||||||
|
|
||||||
|
// WP2
|
||||||
|
import wp2Enc from '../../codecs/wp2/enc/wp2_node_enc.js';
|
||||||
|
import wp2EncWasm from 'asset-url:../../codecs/wp2/enc/wp2_node_enc.wasm';
|
||||||
|
import wp2Dec from '../../codecs/wp2/dec/wp2_node_dec.js';
|
||||||
|
import wp2DecWasm from 'asset-url:../../codecs/wp2/dec/wp2_node_dec.wasm';
|
||||||
|
|
||||||
|
// PNG
|
||||||
|
import * as pngEncDec from '../../codecs/png/pkg/squoosh_png.js';
|
||||||
|
import pngEncDecWasm from 'asset-url:../../codecs/png/pkg/squoosh_png_bg.wasm';
|
||||||
|
const pngEncDecPromise = pngEncDec.default(
|
||||||
|
fsp.readFile(pathify(pngEncDecWasm)),
|
||||||
|
);
|
||||||
|
|
||||||
|
// OxiPNG
|
||||||
|
import * as oxipng from '../../codecs/oxipng/pkg/squoosh_oxipng.js';
|
||||||
|
import oxipngWasm from 'asset-url:../../codecs/oxipng/pkg/squoosh_oxipng_bg.wasm';
|
||||||
|
const oxipngPromise = oxipng.default(fsp.readFile(pathify(oxipngWasm)));
|
||||||
|
|
||||||
|
// Resize
|
||||||
|
import * as resize from '../../codecs/resize/pkg/squoosh_resize.js';
|
||||||
|
import resizeWasm from 'asset-url:../../codecs/resize/pkg/squoosh_resize_bg.wasm';
|
||||||
|
const resizePromise = resize.default(fsp.readFile(pathify(resizeWasm)));
|
||||||
|
|
||||||
|
// rotate
|
||||||
|
import rotateWasm from 'asset-url:../../codecs/rotate/rotate.wasm';
|
||||||
|
|
||||||
|
// ImageQuant
|
||||||
|
import imageQuant from '../../codecs/imagequant/imagequant_node.js';
|
||||||
|
import imageQuantWasm from 'asset-url:../../codecs/imagequant/imagequant_node.wasm';
|
||||||
|
const imageQuantPromise = instantiateEmscriptenWasm(imageQuant, imageQuantWasm);
|
||||||
|
|
||||||
|
// Our decoders currently rely on a `ImageData` global.
|
||||||
|
import ImageData from './image_data.js';
|
||||||
|
globalThis.ImageData = ImageData;
|
||||||
|
|
||||||
|
function resizeNameToIndex(name) {
|
||||||
|
switch (name) {
|
||||||
|
case 'triangle':
|
||||||
|
return 0;
|
||||||
|
case 'catrom':
|
||||||
|
return 1;
|
||||||
|
case 'mitchell':
|
||||||
|
return 2;
|
||||||
|
case 'lanczos3':
|
||||||
|
return 3;
|
||||||
|
default:
|
||||||
|
throw Error(`Unknown resize algorithm "${name}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resizeWithAspect({
|
||||||
|
input_width,
|
||||||
|
input_height,
|
||||||
|
target_width,
|
||||||
|
target_height,
|
||||||
|
}) {
|
||||||
|
if (!target_width && !target_height) {
|
||||||
|
throw Error('Need to specify at least width or height when resizing');
|
||||||
|
}
|
||||||
|
if (target_width && target_height) {
|
||||||
|
return { width: target_width, height: target_height };
|
||||||
|
}
|
||||||
|
if (!target_width) {
|
||||||
|
return {
|
||||||
|
width: Math.round((input_width / input_height) * target_height),
|
||||||
|
height: target_height,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!target_height) {
|
||||||
|
return {
|
||||||
|
width: target_width,
|
||||||
|
height: Math.round((input_height / input_width) * target_width),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const preprocessors = {
|
||||||
|
resize: {
|
||||||
|
name: 'Resize',
|
||||||
|
description: 'Resize the image before compressing',
|
||||||
|
instantiate: async () => {
|
||||||
|
await resizePromise;
|
||||||
|
return (
|
||||||
|
buffer,
|
||||||
|
input_width,
|
||||||
|
input_height,
|
||||||
|
{ width, height, method, premultiply, linearRGB },
|
||||||
|
) => {
|
||||||
|
({ width, height } = resizeWithAspect({
|
||||||
|
input_width,
|
||||||
|
input_height,
|
||||||
|
target_width: width,
|
||||||
|
target_height: height,
|
||||||
|
}));
|
||||||
|
return new ImageData(
|
||||||
|
resize.resize(
|
||||||
|
buffer,
|
||||||
|
input_width,
|
||||||
|
input_height,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
resizeNameToIndex(method),
|
||||||
|
premultiply,
|
||||||
|
linearRGB,
|
||||||
|
),
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
defaultOptions: {
|
||||||
|
method: 'lanczos3',
|
||||||
|
fitMethod: 'stretch',
|
||||||
|
premultiply: true,
|
||||||
|
linearRGB: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// // TODO: Need to handle SVGs and HQX
|
||||||
|
quant: {
|
||||||
|
name: 'ImageQuant',
|
||||||
|
description: 'Reduce the number of colors used (aka. paletting)',
|
||||||
|
instantiate: async () => {
|
||||||
|
const imageQuant = await imageQuantPromise;
|
||||||
|
return (buffer, width, height, { numColors, dither }) =>
|
||||||
|
new ImageData(
|
||||||
|
imageQuant.quantize(buffer, width, height, numColors, dither),
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
defaultOptions: {
|
||||||
|
numColors: 255,
|
||||||
|
dither: 1.0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rotate: {
|
||||||
|
name: 'Rotate',
|
||||||
|
description: 'Rotate image',
|
||||||
|
instantiate: async () => {
|
||||||
|
return async (buffer, width, height, { numRotations }) => {
|
||||||
|
const degrees = (numRotations * 90) % 360;
|
||||||
|
const sameDimensions = degrees == 0 || degrees == 180;
|
||||||
|
const size = width * height * 4;
|
||||||
|
const { instance } = await WebAssembly.instantiate(
|
||||||
|
await fsp.readFile(pathify(rotateWasm)),
|
||||||
|
);
|
||||||
|
const { memory } = instance.exports;
|
||||||
|
const additionalPagesNeeded = Math.ceil(
|
||||||
|
(size * 2 - memory.buffer.byteLength + 8) / (64 * 1024),
|
||||||
|
);
|
||||||
|
if (additionalPagesNeeded > 0) {
|
||||||
|
memory.grow(additionalPagesNeeded);
|
||||||
|
}
|
||||||
|
const view = new Uint8ClampedArray(memory.buffer);
|
||||||
|
view.set(buffer, 8);
|
||||||
|
instance.exports.rotate(width, height, degrees);
|
||||||
|
return new ImageData(
|
||||||
|
view.slice(size + 8, size * 2 + 8),
|
||||||
|
sameDimensions ? width : height,
|
||||||
|
sameDimensions ? height : width,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
defaultOptions: {
|
||||||
|
numRotations: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const codecs = {
|
||||||
|
mozjpeg: {
|
||||||
|
name: 'MozJPEG',
|
||||||
|
extension: 'jpg',
|
||||||
|
detectors: [/^\xFF\xD8\xFF/],
|
||||||
|
dec: () => instantiateEmscriptenWasm(mozDec, mozDecWasm),
|
||||||
|
enc: () => instantiateEmscriptenWasm(mozEnc, mozEncWasm),
|
||||||
|
defaultEncoderOptions: {
|
||||||
|
quality: 75,
|
||||||
|
baseline: false,
|
||||||
|
arithmetic: false,
|
||||||
|
progressive: true,
|
||||||
|
optimize_coding: true,
|
||||||
|
smoothing: 0,
|
||||||
|
color_space: 3 /*YCbCr*/,
|
||||||
|
quant_table: 3,
|
||||||
|
trellis_multipass: false,
|
||||||
|
trellis_opt_zero: false,
|
||||||
|
trellis_opt_table: false,
|
||||||
|
trellis_loops: 1,
|
||||||
|
auto_subsample: true,
|
||||||
|
chroma_subsample: 2,
|
||||||
|
separate_chroma_quality: false,
|
||||||
|
chroma_quality: 75,
|
||||||
|
},
|
||||||
|
autoOptimize: {
|
||||||
|
option: 'quality',
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
webp: {
|
||||||
|
name: 'WebP',
|
||||||
|
extension: 'webp',
|
||||||
|
detectors: [/^RIFF....WEBPVP8[LX ]/],
|
||||||
|
dec: () => instantiateEmscriptenWasm(webpDec, webpDecWasm),
|
||||||
|
enc: () => instantiateEmscriptenWasm(webpEnc, webpEncWasm),
|
||||||
|
defaultEncoderOptions: {
|
||||||
|
quality: 75,
|
||||||
|
target_size: 0,
|
||||||
|
target_PSNR: 0,
|
||||||
|
method: 4,
|
||||||
|
sns_strength: 50,
|
||||||
|
filter_strength: 60,
|
||||||
|
filter_sharpness: 0,
|
||||||
|
filter_type: 1,
|
||||||
|
partitions: 0,
|
||||||
|
segments: 4,
|
||||||
|
pass: 1,
|
||||||
|
show_compressed: 0,
|
||||||
|
preprocessing: 0,
|
||||||
|
autofilter: 0,
|
||||||
|
partition_limit: 0,
|
||||||
|
alpha_compression: 1,
|
||||||
|
alpha_filtering: 1,
|
||||||
|
alpha_quality: 100,
|
||||||
|
lossless: 0,
|
||||||
|
exact: 0,
|
||||||
|
image_hint: 0,
|
||||||
|
emulate_jpeg_size: 0,
|
||||||
|
thread_level: 0,
|
||||||
|
low_memory: 0,
|
||||||
|
near_lossless: 100,
|
||||||
|
use_delta_palette: 0,
|
||||||
|
use_sharp_yuv: 0,
|
||||||
|
},
|
||||||
|
autoOptimize: {
|
||||||
|
option: 'quality',
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
avif: {
|
||||||
|
name: 'AVIF',
|
||||||
|
extension: 'avif',
|
||||||
|
detectors: [/^\x00\x00\x00 ftypavif\x00\x00\x00\x00/],
|
||||||
|
dec: () => instantiateEmscriptenWasm(avifDec, avifDecWasm),
|
||||||
|
enc: () => instantiateEmscriptenWasm(avifEnc, avifEncWasm),
|
||||||
|
defaultEncoderOptions: {
|
||||||
|
minQuantizer: 33,
|
||||||
|
maxQuantizer: 63,
|
||||||
|
minQuantizerAlpha: 33,
|
||||||
|
maxQuantizerAlpha: 63,
|
||||||
|
tileColsLog2: 0,
|
||||||
|
tileRowsLog2: 0,
|
||||||
|
speed: 8,
|
||||||
|
subsample: 1,
|
||||||
|
},
|
||||||
|
autoOptimize: {
|
||||||
|
option: 'maxQuantizer',
|
||||||
|
min: 0,
|
||||||
|
max: 62,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
jxl: {
|
||||||
|
name: 'JPEG-XL',
|
||||||
|
extension: 'jxl',
|
||||||
|
detectors: [/^\xff\x0a/],
|
||||||
|
dec: () => instantiateEmscriptenWasm(jxlDec, jxlDecWasm),
|
||||||
|
enc: () => instantiateEmscriptenWasm(jxlEnc, jxlEncWasm),
|
||||||
|
defaultEncoderOptions: {
|
||||||
|
speed: 4,
|
||||||
|
quality: 75,
|
||||||
|
progressive: false,
|
||||||
|
epf: -1,
|
||||||
|
nearLossless: 0,
|
||||||
|
lossyPalette: false,
|
||||||
|
},
|
||||||
|
autoOptimize: {
|
||||||
|
option: 'quality',
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wp2: {
|
||||||
|
name: 'WebP2',
|
||||||
|
extension: 'wp2',
|
||||||
|
detectors: [/^\xF4\xFF\x6F/],
|
||||||
|
dec: () => instantiateEmscriptenWasm(wp2Dec, wp2DecWasm),
|
||||||
|
enc: () => instantiateEmscriptenWasm(wp2Enc, wp2EncWasm),
|
||||||
|
defaultEncoderOptions: {
|
||||||
|
quality: 75,
|
||||||
|
alpha_quality: 75,
|
||||||
|
effort: 5,
|
||||||
|
pass: 1,
|
||||||
|
sns: 50,
|
||||||
|
uv_mode: 0 /*UVMode.UVModeAuto*/,
|
||||||
|
csp_type: 0 /*Csp.kYCoCg*/,
|
||||||
|
error_diffusion: 0,
|
||||||
|
use_random_matrix: false,
|
||||||
|
},
|
||||||
|
autoOptimize: {
|
||||||
|
option: 'quality',
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
oxipng: {
|
||||||
|
name: 'OxiPNG',
|
||||||
|
extension: 'png',
|
||||||
|
detectors: [/^\x89PNG\x0D\x0A\x1A\x0A/],
|
||||||
|
dec: async () => {
|
||||||
|
await pngEncDecPromise;
|
||||||
|
return { decode: pngEncDec.decode };
|
||||||
|
},
|
||||||
|
enc: async () => {
|
||||||
|
await pngEncDecPromise;
|
||||||
|
await oxipngPromise;
|
||||||
|
return {
|
||||||
|
encode: (buffer, width, height, opts) => {
|
||||||
|
const simplePng = pngEncDec.encode(new Uint8Array(buffer), width, height);
|
||||||
|
return oxipng.optimise(simplePng, opts.level);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
defaultEncoderOptions: {
|
||||||
|
level: 2,
|
||||||
|
},
|
||||||
|
autoOptimize: {
|
||||||
|
option: 'level',
|
||||||
|
min: 6,
|
||||||
|
max: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
16
cli/src/emscripten-utils.js
Normal file
16
cli/src/emscripten-utils.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
export function pathify(path) {
|
||||||
|
if (path.startsWith('file://')) {
|
||||||
|
path = fileURLToPath(path);
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function instantiateEmscriptenWasm(factory, path) {
|
||||||
|
return factory({
|
||||||
|
locateFile() {
|
||||||
|
return pathify(path);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
7
cli/src/image_data.js
Normal file
7
cli/src/image_data.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export default class ImageData {
|
||||||
|
constructor(data, width, height) {
|
||||||
|
this.data = data;
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
}
|
||||||
362
cli/src/index.js
Normal file
362
cli/src/index.js
Normal file
@@ -0,0 +1,362 @@
|
|||||||
|
import { program } from 'commander';
|
||||||
|
import JSON5 from 'json5';
|
||||||
|
import { isMainThread } from 'worker_threads';
|
||||||
|
import { cpus } from 'os';
|
||||||
|
import { extname, join, basename } 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';
|
||||||
|
|
||||||
|
function clamp(v, min, max) {
|
||||||
|
if (v < min) return min;
|
||||||
|
if (v > max) return max;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
const suffix = ['B', 'KB', 'MB'];
|
||||||
|
function prettyPrintSize(size) {
|
||||||
|
const base = Math.floor(Math.log2(size) / 10);
|
||||||
|
const index = clamp(base, 0, 2);
|
||||||
|
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 = {};
|
||||||
|
tracker.spinner = spinner;
|
||||||
|
tracker.progressOffset = 0;
|
||||||
|
tracker.totalOffset = 0;
|
||||||
|
let status = '';
|
||||||
|
tracker.setStatus = (text) => {
|
||||||
|
status = text || '';
|
||||||
|
update();
|
||||||
|
};
|
||||||
|
let progress = '';
|
||||||
|
tracker.setProgress = (done, total) => {
|
||||||
|
spinner.prefixText = kleur.dim(`${done}/${total}`);
|
||||||
|
const completeness =
|
||||||
|
(tracker.progressOffset + done) / (tracker.totalOffset + total);
|
||||||
|
progress = kleur.cyan(
|
||||||
|
`▐${'▨'.repeat((completeness * 10) | 0).padEnd(10, '╌')}▌ `,
|
||||||
|
);
|
||||||
|
update();
|
||||||
|
};
|
||||||
|
function update() {
|
||||||
|
spinner.text = progress + kleur.bold(status) + getResultsText();
|
||||||
|
}
|
||||||
|
tracker.finish = (text) => {
|
||||||
|
spinner.succeed(kleur.bold(text) + getResultsText());
|
||||||
|
};
|
||||||
|
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,
|
||||||
|
)}`;
|
||||||
|
const percent = ((outputSize / result.size) * 100).toPrecision(3);
|
||||||
|
out += ` (${kleur[outputSize > result.size ? 'red' : 'green'](
|
||||||
|
percent + '%',
|
||||||
|
)})`;
|
||||||
|
if (infoText) out += kleur.yellow(infoText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out || '\n';
|
||||||
|
}
|
||||||
|
spinner.start();
|
||||||
|
return tracker;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 file of files) {
|
||||||
|
try {
|
||||||
|
await fsp.stat(file);
|
||||||
|
} catch (err) {
|
||||||
|
if (err.code === 'ENOENT') {
|
||||||
|
console.warn(
|
||||||
|
`Warning: Input file does not exist: ${resolvePath(file)}`,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validFiles.push(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return validFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function processFiles(files) {
|
||||||
|
files = await getInputFiles(files);
|
||||||
|
|
||||||
|
const parallelism = cpus().length;
|
||||||
|
|
||||||
|
const results = new Map();
|
||||||
|
const progress = progressTracker(results);
|
||||||
|
|
||||||
|
progress.setStatus('Decoding...');
|
||||||
|
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 });
|
||||||
|
|
||||||
|
let decoded = 0;
|
||||||
|
let decodedFiles = await Promise.all(
|
||||||
|
files.map(async (file) => {
|
||||||
|
const result = await workerPool.dispatchJob({
|
||||||
|
operation: 'decode',
|
||||||
|
file,
|
||||||
|
});
|
||||||
|
results.set(file, {
|
||||||
|
file: result.file,
|
||||||
|
size: result.size,
|
||||||
|
outputs: [],
|
||||||
|
});
|
||||||
|
progress.setProgress(++decoded, files.length);
|
||||||
|
return result;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const [preprocessorName, value] of Object.entries(preprocessors)) {
|
||||||
|
if (!program[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,
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
progress.progressOffset = decoded;
|
||||||
|
progress.setStatus('Encoding ' + kleur.dim(`(${parallelism} 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 [encName, value] of Object.entries(supportedFormats)) {
|
||||||
|
if (!program[encName]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const encParam =
|
||||||
|
typeof program[encName] === 'string' ? program[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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
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);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
94
cli/src/worker_pool.js
Normal file
94
cli/src/worker_pool.js
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
import { Worker, parentPort } from 'worker_threads';
|
||||||
|
import { TransformStream } from 'web-streams-polyfill';
|
||||||
|
|
||||||
|
function uuid() {
|
||||||
|
return Array.from({ length: 16 }, () =>
|
||||||
|
Math.floor(Math.random() * 256).toString(16),
|
||||||
|
).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function jobPromise(worker, msg) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const id = uuid();
|
||||||
|
worker.postMessage({ msg, id });
|
||||||
|
worker.on('message', function f({ result, id: rid }) {
|
||||||
|
if (rid !== id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
worker.off('message', f);
|
||||||
|
resolve(result);
|
||||||
|
});
|
||||||
|
worker.on('error', (error) => console.error('Worker error: ', error));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class WorkerPool {
|
||||||
|
constructor(numWorkers, workerFile) {
|
||||||
|
this.numWorkers = numWorkers;
|
||||||
|
this.jobQueue = new TransformStream();
|
||||||
|
this.workerQueue = new TransformStream();
|
||||||
|
|
||||||
|
const writer = this.workerQueue.writable.getWriter();
|
||||||
|
for (let i = 0; i < numWorkers; i++) {
|
||||||
|
writer.write(new Worker(workerFile));
|
||||||
|
}
|
||||||
|
writer.releaseLock();
|
||||||
|
|
||||||
|
this.done = this._readLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
async _readLoop() {
|
||||||
|
const reader = this.jobQueue.readable.getReader();
|
||||||
|
while (true) {
|
||||||
|
const { value, done } = await reader.read();
|
||||||
|
if (done) {
|
||||||
|
await this._terminateAll();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { msg, resolve } = value;
|
||||||
|
const worker = await this._nextWorker();
|
||||||
|
jobPromise(worker, msg).then((result) => {
|
||||||
|
resolve(result);
|
||||||
|
const writer = this.workerQueue.writable.getWriter();
|
||||||
|
writer.write(worker);
|
||||||
|
writer.releaseLock();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async _nextWorker() {
|
||||||
|
const reader = this.workerQueue.readable.getReader();
|
||||||
|
const { value, done } = await reader.read();
|
||||||
|
reader.releaseLock();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _terminateAll() {
|
||||||
|
for (let n = 0; n < this.numWorkers; n++) {
|
||||||
|
const worker = await this._nextWorker();
|
||||||
|
worker.terminate();
|
||||||
|
}
|
||||||
|
this.workerQueue.writable.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
async join() {
|
||||||
|
this.jobQueue.writable.getWriter().close();
|
||||||
|
await this.done;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatchJob(msg) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const writer = this.jobQueue.writable.getWriter();
|
||||||
|
writer.write({ msg, resolve });
|
||||||
|
writer.releaseLock();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static useThisThreadAsWorker(cb) {
|
||||||
|
parentPort.on('message', async (data) => {
|
||||||
|
const { msg, id } = data;
|
||||||
|
const result = await cb(msg);
|
||||||
|
parentPort.postMessage({ result, id });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,7 +14,6 @@
|
|||||||
// for comlink
|
// for comlink
|
||||||
"src/features/**/worker/**/*",
|
"src/features/**/worker/**/*",
|
||||||
"src/features-worker/**/*",
|
"src/features-worker/**/*",
|
||||||
"src/features/worker-utils/**/*",
|
"src/features/worker-utils/**/*"
|
||||||
"src/worker-shared/**/*"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,23 @@
|
|||||||
# using libavif from https://github.com/AOMediaCodec/libavif
|
CODEC_URL = https://github.com/AOMediaCodec/libavif/archive/31d7c6d1e32cf467ac24fb8c7a76c4902a4c00db.tar.gz
|
||||||
LIBAVIF_URL = https://github.com/AOMediaCodec/libavif/archive/refs/tags/v1.0.1.tar.gz
|
CODEC_PACKAGE = node_modules/libavif.tar.gz
|
||||||
LIBAVIF_PACKAGE = node_modules/libavif.tar.gz
|
|
||||||
|
|
||||||
# using libaom from https://aomedia.googlesource.com/aom
|
LIBAOM_URL = https://aomedia.googlesource.com/aom/+archive/4a8e276e3e0ef3c76083f3975d5caa85bc9593ce.tar.gz
|
||||||
LIBAOM_URL = https://aomedia.googlesource.com/aom/+archive/v3.7.0.tar.gz
|
|
||||||
LIBAOM_PACKAGE = node_modules/libaom.tar.gz
|
LIBAOM_PACKAGE = node_modules/libaom.tar.gz
|
||||||
|
|
||||||
export CODEC_DIR = node_modules/libavif
|
export CODEC_DIR = node_modules/libavif
|
||||||
export BUILD_DIR = node_modules/build
|
export BUILD_DIR = node_modules/build
|
||||||
export LIBAOM_DIR = node_modules/libaom
|
export LIBAOM_DIR = node_modules/libaom
|
||||||
|
|
||||||
override CFLAGS += "-Wno-unused-macros"
|
export CFLAGS += -g
|
||||||
|
export CXXFLAGS += -g
|
||||||
# We must build libsharpyuv from a specific libwebp commit
|
|
||||||
# See libavif/ext/libsharpyuv.cmd for more detail
|
|
||||||
LIBWEBP_URL_WITH_SHARPYUV = https://chromium.googlesource.com/webm/libwebp/+archive/e2c85878f6a33f29948b43d3492d9cdaf801aa54.tar.gz
|
|
||||||
LIBWEBP_DIR := $(CODEC_DIR)/ext/libwebp
|
|
||||||
LIBSHARPYUV_ST := $(LIBWEBP_DIR)/build_st/libsharpyuv.a
|
|
||||||
LIBSHARPYUV_MT := $(LIBWEBP_DIR)/build_mt/libsharpyuv.a
|
|
||||||
export LIBSHARPYUV := $(LIBWEBP_DIR)/build/libsharpyuv.a
|
|
||||||
|
|
||||||
OUT_ENC_JS = enc/avif_enc.js
|
OUT_ENC_JS = enc/avif_enc.js
|
||||||
OUT_NODE_ENC_JS = enc/avif_node_enc.js
|
OUT_NODE_ENC_JS = enc/avif_node_enc.js
|
||||||
OUT_ENC_MT_JS = enc/avif_enc_mt.js
|
OUT_ENC_MT_JS = enc/avif_enc_mt.js
|
||||||
OUT_NODE_ENC_MT_JS = enc/avif_node_enc_mt.js
|
|
||||||
OUT_DEC_JS = dec/avif_dec.js
|
OUT_DEC_JS = dec/avif_dec.js
|
||||||
OUT_NODE_DEC_JS = dec/avif_node_dec.js
|
OUT_NODE_DEC_JS = dec/avif_node_dec.js
|
||||||
|
|
||||||
|
OUT_ENC_CPP = enc/avif_enc.cpp
|
||||||
OUT_ENC_CPP = enc/avif_enc.cpp
|
OUT_ENC_CPP = enc/avif_enc.cpp
|
||||||
OUT_DEC_CPP = dec/avif_dec.cpp
|
OUT_DEC_CPP = dec/avif_dec.cpp
|
||||||
ENVIRONMENT = worker
|
ENVIRONMENT = worker
|
||||||
@@ -35,11 +26,10 @@ HELPER_MAKEFLAGS := -f helper.Makefile
|
|||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
|
|
||||||
all: $(OUT_ENC_JS) $(OUT_DEC_JS) $(OUT_ENC_MT_JS)
|
all: $(OUT_ENC_JS) $(OUT_DEC_JS) $(OUT_ENC_MT_JS) $(OUT_NODE_ENC_JS) $(OUT_NODE_DEC_JS)
|
||||||
|
|
||||||
# ST-Encoding
|
$(OUT_NODE_ENC_JS): ENVIRONMENT=node
|
||||||
$(OUT_ENC_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt $(LIBSHARPYUV_ST)
|
$(OUT_NODE_ENC_JS) $(OUT_ENC_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt
|
||||||
mkdir -p $(LIBWEBP_DIR)/build && cp $(LIBSHARPYUV_ST) $(LIBSHARPYUV)
|
|
||||||
$(MAKE) \
|
$(MAKE) \
|
||||||
$(HELPER_MAKEFLAGS) \
|
$(HELPER_MAKEFLAGS) \
|
||||||
OUT_JS=$@ \
|
OUT_JS=$@ \
|
||||||
@@ -50,12 +40,9 @@ $(OUT_ENC_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLis
|
|||||||
-DCONFIG_AV1_HIGHBITDEPTH=0 \
|
-DCONFIG_AV1_HIGHBITDEPTH=0 \
|
||||||
" \
|
" \
|
||||||
ENVIRONMENT=$(ENVIRONMENT) \
|
ENVIRONMENT=$(ENVIRONMENT) \
|
||||||
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_DECODE=0 -DAVIF_LOCAL_LIBSHARPYUV=ON"
|
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_DECODE=0"
|
||||||
|
|
||||||
# MT-Encoding
|
$(OUT_ENC_MT_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt
|
||||||
# We need to run the ST and MT tasks sequentially to avoid conflicts with the copy of libsharpyuv in the build directory
|
|
||||||
$(OUT_ENC_MT_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt $(LIBSHARPYUV_MT) | $(OUT_ENC_JS)
|
|
||||||
mkdir -p $(LIBWEBP_DIR)/build && cp $(LIBSHARPYUV_MT) $(LIBSHARPYUV)
|
|
||||||
$(MAKE) \
|
$(MAKE) \
|
||||||
$(HELPER_MAKEFLAGS) \
|
$(HELPER_MAKEFLAGS) \
|
||||||
OUT_JS=$@ \
|
OUT_JS=$@ \
|
||||||
@@ -65,11 +52,11 @@ $(OUT_ENC_MT_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMake
|
|||||||
-DCONFIG_AV1_HIGHBITDEPTH=0 \
|
-DCONFIG_AV1_HIGHBITDEPTH=0 \
|
||||||
" \
|
" \
|
||||||
ENVIRONMENT=$(ENVIRONMENT) \
|
ENVIRONMENT=$(ENVIRONMENT) \
|
||||||
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_DECODE=0 -DAVIF_LOCAL_LIBSHARPYUV=ON" \
|
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_DECODE=0" \
|
||||||
OUT_FLAGS="-pthread"
|
OUT_FLAGS="-pthread -s PROXY_TO_PTHREAD=1 -g"
|
||||||
|
|
||||||
# Decoding
|
$(OUT_NODE_DEC_JS): ENVIRONMENT=node
|
||||||
$(OUT_DEC_JS): $(OUT_DEC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt
|
$(OUT_NODE_DEC_JS) $(OUT_DEC_JS): $(OUT_DEC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt
|
||||||
$(MAKE) \
|
$(MAKE) \
|
||||||
$(HELPER_MAKEFLAGS) \
|
$(HELPER_MAKEFLAGS) \
|
||||||
OUT_JS=$@ \
|
OUT_JS=$@ \
|
||||||
@@ -81,81 +68,23 @@ $(OUT_DEC_JS): $(OUT_DEC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLis
|
|||||||
ENVIRONMENT=$(ENVIRONMENT) \
|
ENVIRONMENT=$(ENVIRONMENT) \
|
||||||
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_ENCODE=0"
|
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_ENCODE=0"
|
||||||
|
|
||||||
# LIBAOM EXTRACTION SECTION
|
$(CODEC_PACKAGE):
|
||||||
|
mkdir -p $(@D)
|
||||||
|
curl -sL $(CODEC_URL) -o $@
|
||||||
|
|
||||||
# Download the libaom tarball
|
|
||||||
$(LIBAOM_PACKAGE):
|
$(LIBAOM_PACKAGE):
|
||||||
mkdir -p $(@D)
|
mkdir -p $(@D)
|
||||||
curl -sL $(LIBAOM_URL) -o $@
|
curl -sL $(LIBAOM_URL) -o $@
|
||||||
|
|
||||||
# Extract libaom from the tarball
|
$(CODEC_DIR)/CMakeLists.txt: $(CODEC_PACKAGE)
|
||||||
|
mkdir -p $(@D)
|
||||||
|
tar xzm --strip 1 -C $(@D) -f $(CODEC_PACKAGE)
|
||||||
|
|
||||||
$(LIBAOM_DIR)/CMakeLists.txt: $(LIBAOM_PACKAGE)
|
$(LIBAOM_DIR)/CMakeLists.txt: $(LIBAOM_PACKAGE)
|
||||||
mkdir -p $(@D)
|
mkdir -p $(@D)
|
||||||
tar xzm -C $(@D) -f $(LIBAOM_PACKAGE)
|
tar xzm -C $(@D) -f $(LIBAOM_PACKAGE)
|
||||||
|
|
||||||
# LIBAVIF EXTRACTION SECTION
|
|
||||||
|
|
||||||
# Download the libavif tarball
|
|
||||||
$(LIBAVIF_PACKAGE):
|
|
||||||
mkdir -p $(@D)
|
|
||||||
curl -sL $(LIBAVIF_URL) -o $@
|
|
||||||
|
|
||||||
# Extract libavif from the tarball
|
|
||||||
$(CODEC_DIR)/CMakeLists.txt: $(LIBAVIF_PACKAGE)
|
|
||||||
mkdir -p $(@D)
|
|
||||||
tar xzm --strip 1 -C $(@D) -f $(LIBAVIF_PACKAGE)
|
|
||||||
|
|
||||||
# Create libavif/ext/libwebp
|
|
||||||
$(LIBWEBP_DIR)/CMakeLists.txt: $(CODEC_DIR)/CMakeLists.txt
|
|
||||||
mkdir -p $(LIBWEBP_DIR)
|
|
||||||
curl -sL $(LIBWEBP_URL_WITH_SHARPYUV) \
|
|
||||||
| tar xzm -C $(LIBWEBP_DIR)
|
|
||||||
|
|
||||||
# Make libsharpyuv.a for ST-Encoding
|
|
||||||
$(LIBSHARPYUV_ST): $(LIBWEBP_DIR)/CMakeLists.txt
|
|
||||||
mkdir -p $(@D)
|
|
||||||
emcmake cmake \
|
|
||||||
-DWEBP_USE_THREAD=OFF \
|
|
||||||
-DWEBP_BUILD_ANIM_UTILS=OFF \
|
|
||||||
-DWEBP_BUILD_CWEBP=OFF \
|
|
||||||
-DWEBP_BUILD_DWEBP=OFF \
|
|
||||||
-DWEBP_BUILD_GIF2WEBP=OFF \
|
|
||||||
-DWEBP_BUILD_IMG2WEBP=OFF \
|
|
||||||
-DWEBP_BUILD_VWEBP=OFF \
|
|
||||||
-DWEBP_BUILD_WEBPINFO=OFF \
|
|
||||||
-DWEBP_BUILD_LIBWEBPMUX=OFF \
|
|
||||||
-DWEBP_BUILD_WEBPMUX=OFF \
|
|
||||||
-DWEBP_BUILD_EXTRAS=OFF \
|
|
||||||
-DBUILD_SHARED_LIBS=OFF \
|
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
|
||||||
-S $(LIBWEBP_DIR) \
|
|
||||||
-B $(@D)
|
|
||||||
$(MAKE) -C $(@D) sharpyuv
|
|
||||||
|
|
||||||
# Make libsharpyuv.a for MT-Encoding
|
|
||||||
$(LIBSHARPYUV_MT): $(LIBWEBP_DIR)/CMakeLists.txt
|
|
||||||
mkdir -p $(@D)
|
|
||||||
emcmake cmake \
|
|
||||||
-DWEBP_BUILD_ANIM_UTILS=OFF \
|
|
||||||
-DWEBP_BUILD_CWEBP=OFF \
|
|
||||||
-DWEBP_BUILD_DWEBP=OFF \
|
|
||||||
-DWEBP_BUILD_GIF2WEBP=OFF \
|
|
||||||
-DWEBP_BUILD_IMG2WEBP=OFF \
|
|
||||||
-DWEBP_BUILD_VWEBP=OFF \
|
|
||||||
-DWEBP_BUILD_WEBPINFO=OFF \
|
|
||||||
-DWEBP_BUILD_LIBWEBPMUX=OFF \
|
|
||||||
-DWEBP_BUILD_WEBPMUX=OFF \
|
|
||||||
-DWEBP_BUILD_EXTRAS=OFF \
|
|
||||||
-DBUILD_SHARED_LIBS=OFF \
|
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
|
||||||
-S $(LIBWEBP_DIR) \
|
|
||||||
-B $(@D)
|
|
||||||
$(MAKE) -C $(@D) sharpyuv
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_ENC_JS) clean
|
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_ENC_JS) clean
|
||||||
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_ENC_MT_JS) clean
|
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_ENC_MT_JS) clean
|
||||||
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_ENC_NODE_JS) clean
|
|
||||||
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_ENC_NODE_MT_JS) clean
|
|
||||||
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_DEC_JS) clean
|
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_DEC_JS) clean
|
||||||
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_DEV_NODE_JS) clean
|
|
||||||
|
|||||||
2816
codecs/avif/dec/avif_dec.js
generated
2816
codecs/avif/dec/avif_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
2806
codecs/avif/dec/avif_node_dec.js
generated
2806
codecs/avif/dec/avif_node_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -3,27 +3,16 @@
|
|||||||
#include <emscripten/val.h>
|
#include <emscripten/val.h>
|
||||||
#include "avif/avif.h"
|
#include "avif/avif.h"
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#define RETURN_NULL_IF(expression) \
|
|
||||||
do { \
|
|
||||||
if (expression) \
|
|
||||||
return val::null(); \
|
|
||||||
} while (false)
|
|
||||||
|
|
||||||
using namespace emscripten;
|
using namespace emscripten;
|
||||||
|
|
||||||
using AvifImagePtr = std::unique_ptr<avifImage, decltype(&avifImageDestroy)>;
|
|
||||||
using AvifEncoderPtr = std::unique_ptr<avifEncoder, decltype(&avifEncoderDestroy)>;
|
|
||||||
|
|
||||||
struct AvifOptions {
|
struct AvifOptions {
|
||||||
// [0 - 100]
|
// [0 - 63]
|
||||||
// 0 = worst quality
|
// 0 = lossless
|
||||||
// 100 = lossless
|
// 63 = worst quality
|
||||||
int quality;
|
int minQuantizer;
|
||||||
// As above, but -1 means 'use quality'
|
int maxQuantizer;
|
||||||
int qualityAlpha;
|
int minQuantizerAlpha;
|
||||||
|
int maxQuantizerAlpha;
|
||||||
// [0 - 6]
|
// [0 - 6]
|
||||||
// Creates 2^n tiles in that dimension
|
// Creates 2^n tiles in that dimension
|
||||||
int tileRowsLog2;
|
int tileRowsLog2;
|
||||||
@@ -37,25 +26,12 @@ struct AvifOptions {
|
|||||||
// 2 = 4:2:2
|
// 2 = 4:2:2
|
||||||
// 3 = 4:4:4
|
// 3 = 4:4:4
|
||||||
int subsample;
|
int subsample;
|
||||||
// Extra chroma compression
|
|
||||||
bool chromaDeltaQ;
|
|
||||||
// 0-7
|
|
||||||
int sharpness;
|
|
||||||
// 0 = auto
|
|
||||||
// 1 = PSNR
|
|
||||||
// 2 = SSIM
|
|
||||||
int tune;
|
|
||||||
// 0-50
|
|
||||||
int denoiseLevel;
|
|
||||||
// toggles AVIF_CHROMA_DOWNSAMPLING_SHARP_YUV
|
|
||||||
bool enableSharpYUV;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
thread_local const val Uint8Array = val::global("Uint8Array");
|
thread_local const val Uint8Array = val::global("Uint8Array");
|
||||||
|
|
||||||
val encode(std::string buffer, int width, int height, AvifOptions options) {
|
val encode(std::string buffer, int width, int height, AvifOptions options) {
|
||||||
avifResult status; // To check the return status for avif API's
|
avifRWData output = AVIF_DATA_EMPTY;
|
||||||
|
|
||||||
int depth = 8;
|
int depth = 8;
|
||||||
avifPixelFormat format;
|
avifPixelFormat format;
|
||||||
switch (options.subsample) {
|
switch (options.subsample) {
|
||||||
@@ -73,97 +49,56 @@ val encode(std::string buffer, int width, int height, AvifOptions options) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lossless = options.quality == AVIF_QUALITY_LOSSLESS &&
|
avifImage* image = avifImageCreate(width, height, depth, format);
|
||||||
(options.qualityAlpha == -1 || options.qualityAlpha == AVIF_QUALITY_LOSSLESS) &&
|
|
||||||
format == AVIF_PIXEL_FORMAT_YUV444;
|
|
||||||
|
|
||||||
// Smart pointer for the input image in YUV format
|
if (options.maxQuantizer == AVIF_QUANTIZER_LOSSLESS &&
|
||||||
AvifImagePtr image(avifImageCreate(width, height, depth, format), avifImageDestroy);
|
options.minQuantizer == AVIF_QUANTIZER_LOSSLESS &&
|
||||||
RETURN_NULL_IF(image == nullptr);
|
options.minQuantizerAlpha == AVIF_QUANTIZER_LOSSLESS &&
|
||||||
|
options.maxQuantizerAlpha == AVIF_QUANTIZER_LOSSLESS && format == AVIF_PIXEL_FORMAT_YUV444) {
|
||||||
if (lossless) {
|
|
||||||
image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_IDENTITY;
|
image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_IDENTITY;
|
||||||
} else {
|
} else {
|
||||||
image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT601;
|
image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT709;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* rgba = reinterpret_cast<uint8_t*>(const_cast<char*>(buffer.data()));
|
uint8_t* rgba = (uint8_t*)buffer.c_str();
|
||||||
|
|
||||||
avifRGBImage srcRGB;
|
avifRGBImage srcRGB;
|
||||||
avifRGBImageSetDefaults(&srcRGB, image.get());
|
avifRGBImageSetDefaults(&srcRGB, image);
|
||||||
srcRGB.pixels = rgba;
|
srcRGB.pixels = rgba;
|
||||||
srcRGB.rowBytes = width * 4;
|
srcRGB.rowBytes = width * 4;
|
||||||
if (options.enableSharpYUV) {
|
avifImageRGBToYUV(image, &srcRGB);
|
||||||
srcRGB.chromaDownsampling = AVIF_CHROMA_DOWNSAMPLING_SHARP_YUV;
|
|
||||||
}
|
|
||||||
status = avifImageRGBToYUV(image.get(), &srcRGB);
|
|
||||||
RETURN_NULL_IF(status != AVIF_RESULT_OK);
|
|
||||||
|
|
||||||
// Create a smart pointer for the encoder
|
|
||||||
AvifEncoderPtr encoder(avifEncoderCreate(), avifEncoderDestroy);
|
|
||||||
RETURN_NULL_IF(encoder == nullptr);
|
|
||||||
|
|
||||||
if (lossless) {
|
|
||||||
encoder->quality = AVIF_QUALITY_LOSSLESS;
|
|
||||||
encoder->qualityAlpha = AVIF_QUALITY_LOSSLESS;
|
|
||||||
} else {
|
|
||||||
status = avifEncoderSetCodecSpecificOption(encoder.get(), "sharpness",
|
|
||||||
std::to_string(options.sharpness).c_str());
|
|
||||||
RETURN_NULL_IF(status != AVIF_RESULT_OK);
|
|
||||||
|
|
||||||
// Set base quality
|
|
||||||
encoder->quality = options.quality;
|
|
||||||
// Conditionally set alpha quality
|
|
||||||
if (options.qualityAlpha == -1) {
|
|
||||||
encoder->qualityAlpha = options.quality;
|
|
||||||
} else {
|
|
||||||
encoder->qualityAlpha = options.qualityAlpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.tune == 2 || (options.tune == 0 && options.quality >= 50)) {
|
|
||||||
status = avifEncoderSetCodecSpecificOption(encoder.get(), "tune", "ssim");
|
|
||||||
RETURN_NULL_IF(status != AVIF_RESULT_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.chromaDeltaQ) {
|
|
||||||
status = avifEncoderSetCodecSpecificOption(encoder.get(), "color:enable-chroma-deltaq", "1");
|
|
||||||
RETURN_NULL_IF(status != AVIF_RESULT_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = avifEncoderSetCodecSpecificOption(encoder.get(), "color:denoise-noise-level",
|
|
||||||
std::to_string(options.denoiseLevel).c_str());
|
|
||||||
RETURN_NULL_IF(status != AVIF_RESULT_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
avifEncoder* encoder = avifEncoderCreate();
|
||||||
encoder->maxThreads = emscripten_num_logical_cores();
|
encoder->maxThreads = emscripten_num_logical_cores();
|
||||||
|
encoder->minQuantizer = options.minQuantizer;
|
||||||
|
encoder->maxQuantizer = options.maxQuantizer;
|
||||||
|
encoder->minQuantizerAlpha = options.minQuantizerAlpha;
|
||||||
|
encoder->maxQuantizerAlpha = options.maxQuantizerAlpha;
|
||||||
encoder->tileRowsLog2 = options.tileRowsLog2;
|
encoder->tileRowsLog2 = options.tileRowsLog2;
|
||||||
encoder->tileColsLog2 = options.tileColsLog2;
|
encoder->tileColsLog2 = options.tileColsLog2;
|
||||||
encoder->speed = options.speed;
|
encoder->speed = options.speed;
|
||||||
|
avifResult encodeResult = avifEncoderWrite(encoder, image, &output);
|
||||||
avifRWData output = AVIF_DATA_EMPTY;
|
|
||||||
avifResult encodeResult = avifEncoderWrite(encoder.get(), image.get(), &output);
|
|
||||||
auto js_result = val::null();
|
auto js_result = val::null();
|
||||||
if (encodeResult == AVIF_RESULT_OK) {
|
if (encodeResult == AVIF_RESULT_OK) {
|
||||||
js_result = Uint8Array.new_(typed_memory_view(output.size, output.data));
|
js_result = Uint8Array.new_(typed_memory_view(output.size, output.data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
avifImageDestroy(image);
|
||||||
|
avifEncoderDestroy(encoder);
|
||||||
avifRWDataFree(&output);
|
avifRWDataFree(&output);
|
||||||
return js_result;
|
return js_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_BINDINGS(my_module) {
|
EMSCRIPTEN_BINDINGS(my_module) {
|
||||||
value_object<AvifOptions>("AvifOptions")
|
value_object<AvifOptions>("AvifOptions")
|
||||||
.field("quality", &AvifOptions::quality)
|
.field("minQuantizer", &AvifOptions::minQuantizer)
|
||||||
.field("qualityAlpha", &AvifOptions::qualityAlpha)
|
.field("maxQuantizer", &AvifOptions::maxQuantizer)
|
||||||
|
.field("minQuantizerAlpha", &AvifOptions::minQuantizerAlpha)
|
||||||
|
.field("maxQuantizerAlpha", &AvifOptions::maxQuantizerAlpha)
|
||||||
.field("tileRowsLog2", &AvifOptions::tileRowsLog2)
|
.field("tileRowsLog2", &AvifOptions::tileRowsLog2)
|
||||||
.field("tileColsLog2", &AvifOptions::tileColsLog2)
|
.field("tileColsLog2", &AvifOptions::tileColsLog2)
|
||||||
.field("speed", &AvifOptions::speed)
|
.field("speed", &AvifOptions::speed)
|
||||||
.field("chromaDeltaQ", &AvifOptions::chromaDeltaQ)
|
.field("subsample", &AvifOptions::subsample);
|
||||||
.field("sharpness", &AvifOptions::sharpness)
|
|
||||||
.field("tune", &AvifOptions::tune)
|
|
||||||
.field("denoiseLevel", &AvifOptions::denoiseLevel)
|
|
||||||
.field("subsample", &AvifOptions::subsample)
|
|
||||||
.field("enableSharpYUV", &AvifOptions::enableSharpYUV);
|
|
||||||
|
|
||||||
function("encode", &encode);
|
function("encode", &encode);
|
||||||
}
|
}
|
||||||
|
|||||||
17
codecs/avif/enc/avif_enc.d.ts
vendored
17
codecs/avif/enc/avif_enc.d.ts
vendored
@@ -1,21 +1,12 @@
|
|||||||
export const enum AVIFTune {
|
|
||||||
auto,
|
|
||||||
psnr,
|
|
||||||
ssim,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EncodeOptions {
|
export interface EncodeOptions {
|
||||||
quality: number;
|
minQuantizer: number;
|
||||||
qualityAlpha: number;
|
maxQuantizer: number;
|
||||||
denoiseLevel: number;
|
minQuantizerAlpha: number;
|
||||||
|
maxQuantizerAlpha: number;
|
||||||
tileRowsLog2: number;
|
tileRowsLog2: number;
|
||||||
tileColsLog2: number;
|
tileColsLog2: number;
|
||||||
speed: number;
|
speed: number;
|
||||||
subsample: number;
|
subsample: number;
|
||||||
chromaDeltaQ: boolean;
|
|
||||||
sharpness: number;
|
|
||||||
enableSharpYUV: boolean;
|
|
||||||
tune: AVIFTune;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AVIFModule extends EmscriptenWasm.Module {
|
export interface AVIFModule extends EmscriptenWasm.Module {
|
||||||
|
|||||||
3032
codecs/avif/enc/avif_enc.js
generated
3032
codecs/avif/enc/avif_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
4004
codecs/avif/enc/avif_enc_mt.js
generated
4004
codecs/avif/enc/avif_enc_mt.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
145
codecs/avif/enc/avif_enc_mt.worker.js
generated
145
codecs/avif/enc/avif_enc_mt.worker.js
generated
@@ -1 +1,144 @@
|
|||||||
"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};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})}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["__emscripten_thread_exit"](result)}}catch(ex){if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["__emscripten_thread_exit"](ex.status)}}else{throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["__emscripten_thread_exit"](-1)}postMessage({"cmd":"cancelDone"})}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}};
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright 2015 The Emscripten Authors
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Pthread Web Worker startup routine:
|
||||||
|
// This is the entry point file that is loaded first by each Web Worker
|
||||||
|
// that executes pthreads on the Emscripten application.
|
||||||
|
|
||||||
|
// Thread-local:
|
||||||
|
var threadInfoStruct = 0; // Info area for this thread in Emscripten HEAP (shared). If zero, this worker is not currently hosting an executing pthread.
|
||||||
|
var selfThreadId = 0; // The ID of this thread. 0 if not hosting a pthread.
|
||||||
|
var parentThreadId = 0; // The ID of the parent pthread that launched this thread.
|
||||||
|
var initializedJS = false; // Guard variable for one-time init of the JS state (currently only embind types registration)
|
||||||
|
|
||||||
|
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) {
|
||||||
|
// Instantiate from the module posted from the main thread.
|
||||||
|
// We can just use sync instantiation in the worker.
|
||||||
|
var instance = new WebAssembly.Instance(Module['wasmModule'], info);
|
||||||
|
// We don't need the module anymore; new threads will be spawned from the main thread.
|
||||||
|
Module['wasmModule'] = null;
|
||||||
|
receiveInstance(instance); // The second 'module' parameter is intentionally null here, we don't need to keep a ref to the Module object from here.
|
||||||
|
return instance.exports;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onmessage = function(e) {
|
||||||
|
try {
|
||||||
|
if (e.data.cmd === 'load') { // Preload command that is called once per worker to parse and load the Emscripten code.
|
||||||
|
|
||||||
|
// Module and memory were sent from main thread
|
||||||
|
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') {
|
||||||
|
// This worker was idle, and now should start executing its pthread entry
|
||||||
|
// point.
|
||||||
|
// performance.now() is specced to return a wallclock time in msecs since
|
||||||
|
// that Web Worker/main thread launched. However for pthreads this can
|
||||||
|
// cause subtle problems in emscripten_get_now() as this essentially
|
||||||
|
// would measure time from pthread_create(), meaning that the clocks
|
||||||
|
// between each threads would be wildly out of sync. Therefore sync all
|
||||||
|
// pthreads to the clock on the main browser thread, so that different
|
||||||
|
// threads see a somewhat coherent clock across each of them
|
||||||
|
// (+/- 0.1msecs in testing).
|
||||||
|
Module['__performance_now_clock_drift'] = performance.now() - e.data.time;
|
||||||
|
threadInfoStruct = e.data.threadInfoStruct;
|
||||||
|
|
||||||
|
// Pass the thread address inside the asm.js scope to store it for fast access that avoids the need for a FFI out.
|
||||||
|
Module['registerPthreadPtr'](threadInfoStruct, /*isMainBrowserThread=*/0, /*isMainRuntimeThread=*/0);
|
||||||
|
|
||||||
|
selfThreadId = e.data.selfThreadId;
|
||||||
|
parentThreadId = e.data.parentThreadId;
|
||||||
|
// Establish the stack frame for this thread in global scope
|
||||||
|
// The stack grows downwards
|
||||||
|
var max = e.data.stackBase;
|
||||||
|
var top = e.data.stackBase + e.data.stackSize;
|
||||||
|
// Also call inside JS module to set up the stack frame for this pthread in JS module scope
|
||||||
|
Module['establishStackSpace'](top, max);
|
||||||
|
Module['_emscripten_tls_init']();
|
||||||
|
|
||||||
|
Module['PThread'].receiveObjectTransfer(e.data);
|
||||||
|
Module['PThread'].setThreadStatus(Module['_pthread_self'](), 1/*EM_THREAD_STATUS_RUNNING*/);
|
||||||
|
|
||||||
|
// Embind must initialize itself on all threads, as it generates support JS.
|
||||||
|
// We only do this once per worker since they get reused
|
||||||
|
if (!initializedJS) {
|
||||||
|
Module['___embind_register_native_and_builtin_types']();
|
||||||
|
initializedJS = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// pthread entry points are always of signature 'void *ThreadMain(void *arg)'
|
||||||
|
// Native codebases sometimes spawn threads with other thread entry point signatures,
|
||||||
|
// such as void ThreadMain(void *arg), void *ThreadMain(), or void ThreadMain().
|
||||||
|
// That is not acceptable per C/C++ specification, but x86 compiler ABI extensions
|
||||||
|
// enable that to work. If you find the following line to crash, either change the signature
|
||||||
|
// to "proper" void *ThreadMain(void *arg) form, or try linking with the Emscripten linker
|
||||||
|
// flag -s EMULATE_FUNCTION_POINTER_CASTS=1 to add in emulation for this x86 ABI extension.
|
||||||
|
var result = Module['dynCall']('ii', e.data.start_routine, [e.data.arg]);
|
||||||
|
|
||||||
|
// The thread might have finished without calling pthread_exit(). If so, then perform the exit operation ourselves.
|
||||||
|
// (This is a no-op if explicit pthread_exit() had been called prior.)
|
||||||
|
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); // Mark the thread as no longer running.
|
||||||
|
Module['_emscripten_futex_wake'](threadInfoStruct + 0 /*C_STRUCTS.pthread.threadStatus*/, 0x7FFFFFFF/*INT_MAX*/); // Wake all threads waiting on this thread to finish.
|
||||||
|
if (!(ex instanceof Module['ExitStatus'])) throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (e.data.cmd === 'cancel') { // Main thread is asking for a pthread_cancel() on this thread.
|
||||||
|
if (threadInfoStruct) {
|
||||||
|
Module['PThread'].threadCancel();
|
||||||
|
}
|
||||||
|
} else if (e.data.target === 'setimmediate') {
|
||||||
|
// no-op
|
||||||
|
} else if (e.data.cmd === 'processThreadQueue') {
|
||||||
|
if (threadInfoStruct) { // If this thread is actually running?
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
3022
codecs/avif/enc/avif_node_enc.js
generated
3022
codecs/avif/enc/avif_node_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
16
codecs/avif/enc/avif_node_enc_mt.js
generated
16
codecs/avif/enc/avif_node_enc_mt.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
1
codecs/avif/enc/avif_node_enc_mt.worker.js
generated
1
codecs/avif/enc/avif_node_enc_mt.worker.js
generated
@@ -1 +0,0 @@
|
|||||||
"use strict";var Module={};if(typeof process==="object"&&typeof process.versions==="object"&&typeof process.versions.node==="string"){var nodeWorkerThreads=require("worker_threads");var parentPort=nodeWorkerThreads.parentPort;parentPort.on("message",function(data){onmessage({data:data})});var nodeFS=require("fs");Object.assign(global,{self:global,require:require,Module:Module,location:{href:__filename},Worker:nodeWorkerThreads.Worker,importScripts:function(f){(0,eval)(nodeFS.readFileSync(f,"utf8"))},postMessage:function(msg){parentPort.postMessage(msg)},performance:global.performance||{now:function(){return Date.now()}}})}var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./avif_node_enc_mt.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,0,0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
|
||||||
@@ -10,11 +10,8 @@
|
|||||||
# $(LIBAVIF_FLAGS)
|
# $(LIBAVIF_FLAGS)
|
||||||
# $(ENVIRONMENT)
|
# $(ENVIRONMENT)
|
||||||
|
|
||||||
# $(OUT_JS) is something like "enc/avif_enc.js" or "enc/avif_enc_mt.js"
|
|
||||||
# so $(OUT_BUILD_DIR) will be "node_modules/build/enc/avif_enc[_mt]"
|
|
||||||
OUT_BUILD_DIR := $(BUILD_DIR)/$(basename $(OUT_JS))
|
OUT_BUILD_DIR := $(BUILD_DIR)/$(basename $(OUT_JS))
|
||||||
|
|
||||||
# We're making libavif and libaom for every node_modules/[enc|dec]/
|
|
||||||
CODEC_BUILD_DIR := $(OUT_BUILD_DIR)/libavif
|
CODEC_BUILD_DIR := $(OUT_BUILD_DIR)/libavif
|
||||||
CODEC_OUT := $(CODEC_BUILD_DIR)/libavif.a
|
CODEC_OUT := $(CODEC_BUILD_DIR)/libavif.a
|
||||||
|
|
||||||
@@ -28,13 +25,6 @@ OUT_WORKER=$(OUT_JS:.js=.worker.js)
|
|||||||
|
|
||||||
all: $(OUT_JS)
|
all: $(OUT_JS)
|
||||||
|
|
||||||
# Only add libsharpyuv as a dependency for encoders.
|
|
||||||
# Yes, that if statement is true for encoders.
|
|
||||||
ifneq (,$(findstring enc/, $(OUT_JS)))
|
|
||||||
$(OUT_JS): $(LIBSHARPYUV)
|
|
||||||
$(CODEC_OUT): $(LIBSHARPYUV)
|
|
||||||
endif
|
|
||||||
|
|
||||||
$(OUT_JS): $(OUT_CPP) $(LIBAOM_OUT) $(CODEC_OUT)
|
$(OUT_JS): $(OUT_CPP) $(LIBAOM_OUT) $(CODEC_OUT)
|
||||||
$(CXX) \
|
$(CXX) \
|
||||||
-I $(CODEC_DIR)/include \
|
-I $(CODEC_DIR)/include \
|
||||||
@@ -42,16 +32,18 @@ $(OUT_JS): $(OUT_CPP) $(LIBAOM_OUT) $(CODEC_OUT)
|
|||||||
$(LDFLAGS) \
|
$(LDFLAGS) \
|
||||||
$(OUT_FLAGS) \
|
$(OUT_FLAGS) \
|
||||||
--bind \
|
--bind \
|
||||||
-s ERROR_ON_UNDEFINED_SYMBOLS=0 \
|
-s ALLOW_MEMORY_GROWTH=1 \
|
||||||
|
-s MODULARIZE=1 \
|
||||||
|
-s TEXTDECODER=2 \
|
||||||
-s ENVIRONMENT=$(ENVIRONMENT) \
|
-s ENVIRONMENT=$(ENVIRONMENT) \
|
||||||
-s EXPORT_ES6=1 \
|
-s EXPORT_ES6=1 \
|
||||||
|
-s EXPORT_NAME="$(basename $(@F))" \
|
||||||
-o $@ \
|
-o $@ \
|
||||||
$+
|
$+
|
||||||
|
|
||||||
$(CODEC_OUT): $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_OUT)
|
$(CODEC_OUT): $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_OUT)
|
||||||
emcmake cmake \
|
emcmake cmake \
|
||||||
-DCMAKE_LIBRARY_PATH=$(LIBSHARPYUV_BUILD_DIR) \
|
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
|
||||||
-DBUILD_SHARED_LIBS=0 \
|
-DBUILD_SHARED_LIBS=0 \
|
||||||
-DAVIF_CODEC_AOM=1 \
|
-DAVIF_CODEC_AOM=1 \
|
||||||
-DAOM_LIBRARY=$(LIBAOM_OUT) \
|
-DAOM_LIBRARY=$(LIBAOM_OUT) \
|
||||||
@@ -63,7 +55,7 @@ $(CODEC_OUT): $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_OUT)
|
|||||||
|
|
||||||
$(LIBAOM_OUT): $(LIBAOM_DIR)/CMakeLists.txt
|
$(LIBAOM_OUT): $(LIBAOM_DIR)/CMakeLists.txt
|
||||||
emcmake cmake \
|
emcmake cmake \
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||||
-DENABLE_CCACHE=0 \
|
-DENABLE_CCACHE=0 \
|
||||||
-DAOM_TARGET_CPU=generic \
|
-DAOM_TARGET_CPU=generic \
|
||||||
-DENABLE_DOCS=0 \
|
-DENABLE_DOCS=0 \
|
||||||
|
|||||||
@@ -1,17 +1,9 @@
|
|||||||
FROM emscripten/emsdk:2.0.34
|
FROM emscripten/emsdk:2.0.8
|
||||||
RUN apt-get update && apt-get install -qqy autoconf libtool pkg-config
|
RUN apt-get update && apt-get install -qqy autoconf libtool pkg-config
|
||||||
ENV CFLAGS "-O3 -flto"
|
ENV CFLAGS "-O3 -flto -s FILESYSTEM=0"
|
||||||
ENV CXXFLAGS "${CFLAGS} -std=c++17"
|
ENV CXXFLAGS "${CFLAGS} -std=c++17"
|
||||||
ENV LDFLAGS "${CFLAGS} \
|
ENV LDFLAGS "${CFLAGS} -s PTHREAD_POOL_SIZE=navigator.hardwareConcurrency"
|
||||||
-s FILESYSTEM=0 \
|
# Build and cache standard libraries with these flags
|
||||||
-s PTHREAD_POOL_SIZE=navigator.hardwareConcurrency \
|
RUN emcc ${CXXFLAGS} --bind -xc++ /dev/null -o /dev/null
|
||||||
-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
|
WORKDIR /src
|
||||||
CMD ["sh", "-c", "emmake make -j`nproc`"]
|
CMD ["sh", "-c", "emmake make -j`nproc`"]
|
||||||
|
|||||||
54
codecs/hqx/Cargo.lock
generated
54
codecs/hqx/Cargo.lock
generated
@@ -12,19 +12,13 @@ version = "0.1.10"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "console_error_panic_hook"
|
name = "console_error_panic_hook"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211"
|
checksum = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10",
|
"cfg-if",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -69,7 +63,7 @@ version = "0.4.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
|
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -89,9 +83,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.27"
|
version = "1.0.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
|
checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid 0.2.1",
|
"unicode-xid 0.2.1",
|
||||||
]
|
]
|
||||||
@@ -111,7 +105,7 @@ version = "1.0.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
|
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.27",
|
"proc-macro2 1.0.19",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -124,7 +118,7 @@ checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
|
|||||||
name = "squooshhqx"
|
name = "squooshhqx"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10",
|
"cfg-if",
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
"hqx",
|
"hqx",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@@ -134,11 +128,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.72"
|
version = "1.0.35"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
|
checksum = "fb7f4c519df8c117855e19dd8cc851e89eb746fe7a73f0157e0d95fdec5369b0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.27",
|
"proc-macro2 1.0.19",
|
||||||
"quote 1.0.7",
|
"quote 1.0.7",
|
||||||
"unicode-xid 0.2.1",
|
"unicode-xid 0.2.1",
|
||||||
]
|
]
|
||||||
@@ -157,24 +151,24 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.74"
|
version = "0.2.65"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
|
checksum = "f3edbcc9536ab7eababcc6d2374a0b7bfe13a2b6d562c5e07f370456b1a8f33d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if",
|
||||||
"wasm-bindgen-macro",
|
"wasm-bindgen-macro",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-backend"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.74"
|
version = "0.2.65"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900"
|
checksum = "89ed2fb8c84bfad20ea66b26a3743f3e7ba8735a69fe7d95118c33ec8fc1244d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
"proc-macro2 1.0.27",
|
"proc-macro2 1.0.19",
|
||||||
"quote 1.0.7",
|
"quote 1.0.7",
|
||||||
"syn",
|
"syn",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
@@ -186,7 +180,7 @@ version = "0.3.27"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "83420b37346c311b9ed822af41ec2e82839bfe99867ec6c54e2da43b7538771c"
|
checksum = "83420b37346c311b9ed822af41ec2e82839bfe99867ec6c54e2da43b7538771c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10",
|
"cfg-if",
|
||||||
"futures",
|
"futures",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@@ -195,9 +189,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.74"
|
version = "0.2.65"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4"
|
checksum = "eb071268b031a64d92fc6cf691715ca5a40950694d8f683c5bb43db7c730929e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote 1.0.7",
|
"quote 1.0.7",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
@@ -205,11 +199,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.74"
|
version = "0.2.65"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
|
checksum = "cf592c807080719d1ff2f245a687cbadb3ed28b2077ed7084b47aba8b691f2c6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.27",
|
"proc-macro2 1.0.19",
|
||||||
"quote 1.0.7",
|
"quote 1.0.7",
|
||||||
"syn",
|
"syn",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
@@ -218,9 +212,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.74"
|
version = "0.2.65"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
|
checksum = "72b6c0220ded549d63860c78c38f3bcc558d1ca3f4efa74942c536ddbbb55e87"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-test"
|
name = "wasm-bindgen-test"
|
||||||
@@ -263,7 +257,7 @@ version = "0.4.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e"
|
checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"memory_units",
|
"memory_units",
|
||||||
"winapi",
|
"winapi",
|
||||||
|
|||||||
4
codecs/hqx/pkg/squooshhqx.js
generated
4
codecs/hqx/pkg/squooshhqx.js
generated
@@ -54,6 +54,7 @@ export function resize(input_image, input_width, input_height, factor) {
|
|||||||
|
|
||||||
async function load(module, imports) {
|
async function load(module, imports) {
|
||||||
if (typeof Response === 'function' && module instanceof Response) {
|
if (typeof Response === 'function' && module instanceof Response) {
|
||||||
|
|
||||||
if (typeof WebAssembly.instantiateStreaming === 'function') {
|
if (typeof WebAssembly.instantiateStreaming === 'function') {
|
||||||
try {
|
try {
|
||||||
return await WebAssembly.instantiateStreaming(module, imports);
|
return await WebAssembly.instantiateStreaming(module, imports);
|
||||||
@@ -72,6 +73,7 @@ async function load(module, imports) {
|
|||||||
return await WebAssembly.instantiate(bytes, imports);
|
return await WebAssembly.instantiate(bytes, imports);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const instance = await WebAssembly.instantiate(module, imports);
|
const instance = await WebAssembly.instantiate(module, imports);
|
||||||
|
|
||||||
if (instance instanceof WebAssembly.Instance) {
|
if (instance instanceof WebAssembly.Instance) {
|
||||||
@@ -94,8 +96,6 @@ async function init(input) {
|
|||||||
input = fetch(input);
|
input = fetch(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const { instance, module } = await load(await input, imports);
|
const { instance, module } = await load(await input, imports);
|
||||||
|
|
||||||
wasm = instance.exports;
|
wasm = instance.exports;
|
||||||
|
|||||||
Binary file not shown.
@@ -17,6 +17,10 @@ $(OUT_JS): $(CODEC_OUT)
|
|||||||
${CXXFLAGS} \
|
${CXXFLAGS} \
|
||||||
${LDFLAGS} \
|
${LDFLAGS} \
|
||||||
--bind \
|
--bind \
|
||||||
|
--closure 1 \
|
||||||
|
-s ALLOW_MEMORY_GROWTH=1 \
|
||||||
|
-s MODULARIZE=1 \
|
||||||
|
-s TEXTDECODER=2 \
|
||||||
-s ENVIRONMENT=$(ENVIRONMENT) \
|
-s ENVIRONMENT=$(ENVIRONMENT) \
|
||||||
-s EXPORT_ES6=1 \
|
-s EXPORT_ES6=1 \
|
||||||
-o $@ \
|
-o $@ \
|
||||||
|
|||||||
43
codecs/imagequant/imagequant.js
generated
43
codecs/imagequant/imagequant.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
42
codecs/imagequant/imagequant_node.js
generated
42
codecs/imagequant/imagequant_node.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1,5 +1,5 @@
|
|||||||
CODEC_URL = https://github.com/libjxl/libjxl.git
|
CODEC_URL = https://gitlab.com/wg1/jpeg-xl.git
|
||||||
CODEC_VERSION = 9f544641ec83f6abd9da598bdd08178ee8a003e0
|
CODEC_VERSION = 5175d11717f3c48cf506a2c0e0afb070392ae296
|
||||||
CODEC_DIR = node_modules/jxl
|
CODEC_DIR = node_modules/jxl
|
||||||
CODEC_BUILD_ROOT := $(CODEC_DIR)/build
|
CODEC_BUILD_ROOT := $(CODEC_DIR)/build
|
||||||
CODEC_MT_BUILD_DIR := $(CODEC_BUILD_ROOT)/mt
|
CODEC_MT_BUILD_DIR := $(CODEC_BUILD_ROOT)/mt
|
||||||
@@ -28,10 +28,6 @@ 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.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
|
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.
|
# Compile multithreaded wrappers with -pthread.
|
||||||
enc/jxl_enc_mt.js enc/jxl_enc_mt_simd.js: CXXFLAGS+=-pthread
|
enc/jxl_enc_mt.js enc/jxl_enc_mt_simd.js: CXXFLAGS+=-pthread
|
||||||
|
|
||||||
@@ -46,8 +42,13 @@ $(OUT_JS):
|
|||||||
-I $(CODEC_DIR)/third_party/highway \
|
-I $(CODEC_DIR)/third_party/highway \
|
||||||
-I $(CODEC_DIR)/third_party/skcms \
|
-I $(CODEC_DIR)/third_party/skcms \
|
||||||
--bind \
|
--bind \
|
||||||
|
--closure 1 \
|
||||||
|
-s ALLOW_MEMORY_GROWTH=1 \
|
||||||
|
-s MODULARIZE=1 \
|
||||||
|
-s TEXTDECODER=2 \
|
||||||
-s ENVIRONMENT=$(ENVIRONMENT) \
|
-s ENVIRONMENT=$(ENVIRONMENT) \
|
||||||
-s EXPORT_ES6=1 \
|
-s EXPORT_ES6=1 \
|
||||||
|
-s EXPORT_NAME="$(basename $(@F))" \
|
||||||
-o $@ \
|
-o $@ \
|
||||||
$+ \
|
$+ \
|
||||||
$(CODEC_BUILD_DIR)/third_party/brotli/libbrotlidec-static.a \
|
$(CODEC_BUILD_DIR)/third_party/brotli/libbrotlidec-static.a \
|
||||||
@@ -72,14 +73,10 @@ $(CODEC_MT_SIMD_BUILD_DIR)/Makefile: CXXFLAGS+=-msimd128
|
|||||||
-DJPEGXL_ENABLE_BENCHMARK=0 \
|
-DJPEGXL_ENABLE_BENCHMARK=0 \
|
||||||
-DJPEGXL_ENABLE_EXAMPLES=0 \
|
-DJPEGXL_ENABLE_EXAMPLES=0 \
|
||||||
-DBUILD_TESTING=0 \
|
-DBUILD_TESTING=0 \
|
||||||
-DCMAKE_CROSSCOMPILING_EMULATOR=node \
|
|
||||||
-B $(@D) \
|
-B $(@D) \
|
||||||
$(<D)
|
$(<D)
|
||||||
emcc -Wall -O3 -o $(CODEC_DIR)/third_party/skcms/skcms.cc.o -I$(CODEC_DIR)/third_party/skcms -c $(CODEC_DIR)/third_party/skcms/skcms.cc
|
|
||||||
llvm-ar rc $(CODEC_BUILD_DIR)/third_party/libskcms.a $(CODEC_DIR)/third_party/skcms/skcms.cc.o
|
|
||||||
rm $(CODEC_DIR)/third_party/skcms/skcms.cc.o
|
|
||||||
|
|
||||||
$(CODEC_DIR)/CMakeLists.txt:
|
$(CODEC_DIR)/CMakeLists.txt:
|
||||||
$(RM) -r $(@D)
|
$(RM) -r $(@D)
|
||||||
git init $(@D)
|
git init $(@D)
|
||||||
git -C $(@D) fetch $(CODEC_URL) $(CODEC_VERSION) --depth 1
|
git -C $(@D) fetch $(CODEC_URL) $(CODEC_VERSION) --depth 1
|
||||||
|
|||||||
56
codecs/jxl/dec/jxl_dec.js
generated
56
codecs/jxl/dec/jxl_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
56
codecs/jxl/dec/jxl_node_dec.js
generated
56
codecs/jxl/dec/jxl_node_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -2,23 +2,22 @@
|
|||||||
#include <emscripten/val.h>
|
#include <emscripten/val.h>
|
||||||
|
|
||||||
#include "lib/jxl/base/thread_pool_internal.h"
|
#include "lib/jxl/base/thread_pool_internal.h"
|
||||||
#include "lib/jxl/enc_external_image.h"
|
|
||||||
#include "lib/jxl/enc_file.h"
|
#include "lib/jxl/enc_file.h"
|
||||||
#include "lib/jxl/enc_color_management.h"
|
#include "lib/jxl/external_image.h"
|
||||||
|
|
||||||
using namespace emscripten;
|
using namespace emscripten;
|
||||||
|
|
||||||
thread_local const val Uint8Array = val::global("Uint8Array");
|
thread_local const val Uint8Array = val::global("Uint8Array");
|
||||||
|
|
||||||
struct JXLOptions {
|
struct JXLOptions {
|
||||||
int effort;
|
// 1 = slowest
|
||||||
|
// 7 = fastest
|
||||||
|
int speed;
|
||||||
float quality;
|
float quality;
|
||||||
bool progressive;
|
bool progressive;
|
||||||
int epf;
|
int epf;
|
||||||
|
int nearLossless;
|
||||||
bool lossyPalette;
|
bool lossyPalette;
|
||||||
size_t decodingSpeedTier;
|
|
||||||
float photonNoiseIso;
|
|
||||||
bool lossyModular;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
val encode(std::string image, int width, int height, JXLOptions options) {
|
val encode(std::string image, int width, int height, JXLOptions options) {
|
||||||
@@ -33,35 +32,24 @@ val encode(std::string image, int width, int height, JXLOptions options) {
|
|||||||
pool_ptr = &pool;
|
pool_ptr = &pool;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size_t st = 10 - options.effort;
|
|
||||||
cparams.speed_tier = jxl::SpeedTier(st);
|
|
||||||
|
|
||||||
cparams.epf = options.epf;
|
cparams.epf = options.epf;
|
||||||
cparams.decoding_speed_tier = options.decodingSpeedTier;
|
cparams.speed_tier = static_cast<jxl::SpeedTier>(options.speed);
|
||||||
cparams.photon_noise_iso = options.photonNoiseIso;
|
cparams.near_lossless = options.nearLossless;
|
||||||
|
|
||||||
if (options.lossyPalette) {
|
if (options.lossyPalette) {
|
||||||
cparams.lossy_palette = true;
|
cparams.lossy_palette = true;
|
||||||
cparams.palette_colors = 0;
|
cparams.palette_colors = 0;
|
||||||
cparams.options.predictor = jxl::Predictor::Zero;
|
cparams.options.predictor = jxl::Predictor::Zero;
|
||||||
// Near-lossless assumes -R 0
|
|
||||||
cparams.responsive = 0;
|
|
||||||
cparams.modular_mode = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float quality = options.quality;
|
float quality = options.quality;
|
||||||
|
|
||||||
// Quality settings roughly match libjpeg qualities.
|
// Quality settings roughly match libjpeg qualities.
|
||||||
if (options.lossyModular || quality == 100) {
|
if (quality < 7 || quality == 100) {
|
||||||
cparams.modular_mode = true;
|
cparams.modular_mode = true;
|
||||||
// Internal modular quality to roughly match VarDCT size.
|
// Internal modular quality to roughly match VarDCT size.
|
||||||
if (quality < 7) {
|
cparams.quality_pair.first = cparams.quality_pair.second =
|
||||||
cparams.quality_pair.first = cparams.quality_pair.second =
|
std::min(35 + (quality - 7) * 3.0f, 100.0f);
|
||||||
std::min(35 + (quality - 7) * 3.0f, 100.0f);
|
|
||||||
} else {
|
|
||||||
cparams.quality_pair.first = cparams.quality_pair.second =
|
|
||||||
std::min(35 + (quality - 7) * 65.f / 93.f, 100.0f);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
cparams.modular_mode = false;
|
cparams.modular_mode = false;
|
||||||
if (quality >= 30) {
|
if (quality >= 30) {
|
||||||
@@ -87,6 +75,12 @@ val encode(std::string image, int width, int height, JXLOptions options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cparams.near_lossless) {
|
||||||
|
// Near-lossless assumes -R 0
|
||||||
|
cparams.responsive = 0;
|
||||||
|
cparams.modular_mode = true;
|
||||||
|
}
|
||||||
|
|
||||||
io.metadata.m.SetAlphaBits(8);
|
io.metadata.m.SetAlphaBits(8);
|
||||||
if (!io.metadata.size.Set(width, height)) {
|
if (!io.metadata.size.Set(width, height)) {
|
||||||
return val::null();
|
return val::null();
|
||||||
@@ -94,18 +88,18 @@ val encode(std::string image, int width, int height, JXLOptions options) {
|
|||||||
|
|
||||||
uint8_t* inBuffer = (uint8_t*)image.c_str();
|
uint8_t* inBuffer = (uint8_t*)image.c_str();
|
||||||
|
|
||||||
auto result = jxl::ConvertFromExternal(
|
auto result = jxl::ConvertImage(
|
||||||
jxl::Span<const uint8_t>(reinterpret_cast<const uint8_t*>(image.data()), image.size()), width,
|
jxl::Span<const uint8_t>(reinterpret_cast<const uint8_t*>(image.data()), image.size()), width,
|
||||||
height, jxl::ColorEncoding::SRGB(/*is_gray=*/false), /*has_alpha=*/true,
|
height, jxl::ColorEncoding::SRGB(/*is_gray=*/false), /*has_alpha=*/true,
|
||||||
/*alpha_is_premultiplied=*/false, /*bits_per_sample=*/8, /*endiannes=*/JXL_LITTLE_ENDIAN,
|
/*alpha_is_premultiplied=*/false, /*bits_per_sample=*/8, /*endiannes=*/JXL_LITTLE_ENDIAN,
|
||||||
/*flipped_y=*/false, pool_ptr, main, /*(only true if bits_per_sample==32) float_in=*/false);
|
/*flipped_y=*/false, pool_ptr, main);
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return val::null();
|
return val::null();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto js_result = val::null();
|
auto js_result = val::null();
|
||||||
if (EncodeFile(cparams, &io, &passes_enc_state, &bytes, jxl::GetJxlCms(), /*aux=*/nullptr, pool_ptr)) {
|
if (EncodeFile(cparams, &io, &passes_enc_state, &bytes, /*aux=*/nullptr, pool_ptr)) {
|
||||||
js_result = Uint8Array.new_(typed_memory_view(bytes.size(), bytes.data()));
|
js_result = Uint8Array.new_(typed_memory_view(bytes.size(), bytes.data()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,13 +108,11 @@ val encode(std::string image, int width, int height, JXLOptions options) {
|
|||||||
|
|
||||||
EMSCRIPTEN_BINDINGS(my_module) {
|
EMSCRIPTEN_BINDINGS(my_module) {
|
||||||
value_object<JXLOptions>("JXLOptions")
|
value_object<JXLOptions>("JXLOptions")
|
||||||
.field("effort", &JXLOptions::effort)
|
.field("speed", &JXLOptions::speed)
|
||||||
.field("quality", &JXLOptions::quality)
|
.field("quality", &JXLOptions::quality)
|
||||||
.field("progressive", &JXLOptions::progressive)
|
.field("progressive", &JXLOptions::progressive)
|
||||||
|
.field("nearLossless", &JXLOptions::nearLossless)
|
||||||
.field("lossyPalette", &JXLOptions::lossyPalette)
|
.field("lossyPalette", &JXLOptions::lossyPalette)
|
||||||
.field("decodingSpeedTier", &JXLOptions::decodingSpeedTier)
|
|
||||||
.field("photonNoiseIso", &JXLOptions::photonNoiseIso)
|
|
||||||
.field("lossyModular", &JXLOptions::lossyModular)
|
|
||||||
.field("epf", &JXLOptions::epf);
|
.field("epf", &JXLOptions::epf);
|
||||||
|
|
||||||
function("encode", &encode);
|
function("encode", &encode);
|
||||||
|
|||||||
6
codecs/jxl/enc/jxl_enc.d.ts
vendored
6
codecs/jxl/enc/jxl_enc.d.ts
vendored
@@ -1,12 +1,10 @@
|
|||||||
export interface EncodeOptions {
|
export interface EncodeOptions {
|
||||||
effort: number;
|
speed: number;
|
||||||
quality: number;
|
quality: number;
|
||||||
progressive: boolean;
|
progressive: boolean;
|
||||||
epf: number;
|
epf: number;
|
||||||
|
nearLossless: number;
|
||||||
lossyPalette: boolean;
|
lossyPalette: boolean;
|
||||||
decodingSpeedTier: number;
|
|
||||||
photonNoiseIso: number;
|
|
||||||
lossyModular: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface JXLModule extends EmscriptenWasm.Module {
|
export interface JXLModule extends EmscriptenWasm.Module {
|
||||||
|
|||||||
69
codecs/jxl/enc/jxl_enc.js
generated
69
codecs/jxl/enc/jxl_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
109
codecs/jxl/enc/jxl_enc_mt.js
generated
109
codecs/jxl/enc/jxl_enc_mt.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
2
codecs/jxl/enc/jxl_enc_mt.worker.js
generated
2
codecs/jxl/enc/jxl_enc_mt.worker.js
generated
@@ -1 +1 @@
|
|||||||
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./jxl_enc_mt.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,0,0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
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}};
|
||||||
|
|||||||
110
codecs/jxl/enc/jxl_enc_mt_simd.js
generated
110
codecs/jxl/enc/jxl_enc_mt_simd.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
2
codecs/jxl/enc/jxl_enc_mt_simd.worker.js
generated
2
codecs/jxl/enc/jxl_enc_mt_simd.worker.js
generated
@@ -1 +1 @@
|
|||||||
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./jxl_enc_mt_simd.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,0,0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
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}};
|
||||||
|
|||||||
69
codecs/jxl/enc/jxl_node_enc.js
generated
69
codecs/jxl/enc/jxl_node_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -22,7 +22,11 @@ enc/mozjpeg_node_enc.js dec/mozjpeg_node_dec.js: ENVIRONMENT = node
|
|||||||
-I $(CODEC_DIR) \
|
-I $(CODEC_DIR) \
|
||||||
${CXXFLAGS} \
|
${CXXFLAGS} \
|
||||||
${LDFLAGS} \
|
${LDFLAGS} \
|
||||||
|
--closure 1 \
|
||||||
--bind \
|
--bind \
|
||||||
|
-s ALLOW_MEMORY_GROWTH=1 \
|
||||||
|
-s MODULARIZE=1 \
|
||||||
|
-s TEXTDECODER=2 \
|
||||||
-s ENVIRONMENT=$(ENVIRONMENT) \
|
-s ENVIRONMENT=$(ENVIRONMENT) \
|
||||||
-s EXPORT_ES6=1 \
|
-s EXPORT_ES6=1 \
|
||||||
-o $@ \
|
-o $@ \
|
||||||
|
|||||||
44
codecs/mozjpeg/dec/mozjpeg_node_dec.js
generated
44
codecs/mozjpeg/dec/mozjpeg_node_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -141,7 +141,6 @@ 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_EOB_OPT, opts.trellis_opt_zero);
|
||||||
jpeg_c_set_bool_param(&cinfo, JBOOLEAN_TRELLIS_Q_OPT, opts.trellis_opt_table);
|
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_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
|
// A little hacky to build a string for this, but it means we can use
|
||||||
// set_quality_ratings which does some useful heuristic stuff.
|
// set_quality_ratings which does some useful heuristic stuff.
|
||||||
@@ -158,11 +157,6 @@ val encode(std::string image_in, int image_width, int image_height, MozJpegOptio
|
|||||||
if (!opts.auto_subsample && opts.color_space == JCS_YCbCr) {
|
if (!opts.auto_subsample && opts.color_space == JCS_YCbCr) {
|
||||||
cinfo.comp_info[0].h_samp_factor = opts.chroma_subsample;
|
cinfo.comp_info[0].h_samp_factor = opts.chroma_subsample;
|
||||||
cinfo.comp_info[0].v_samp_factor = opts.chroma_subsample;
|
cinfo.comp_info[0].v_samp_factor = opts.chroma_subsample;
|
||||||
|
|
||||||
if (opts.chroma_subsample > 2) {
|
|
||||||
// Otherwise encoding fails.
|
|
||||||
jpeg_c_set_int_param(&cinfo, JINT_DC_SCAN_OPT_MODE, 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!opts.baseline && opts.progressive) {
|
if (!opts.baseline && opts.progressive) {
|
||||||
|
|||||||
46
codecs/mozjpeg/enc/mozjpeg_enc.js
generated
46
codecs/mozjpeg/enc/mozjpeg_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
47
codecs/mozjpeg/enc/mozjpeg_node_enc.js
generated
47
codecs/mozjpeg/enc/mozjpeg_node_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
460
codecs/oxipng/Cargo.lock
generated
460
codecs/oxipng/Cargo.lock
generated
@@ -1,6 +1,16 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
[[package]]
|
||||||
|
name = "adler"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adler32"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
@@ -9,16 +19,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitvec"
|
name = "bit-vec"
|
||||||
version = "1.0.1"
|
version = "0.6.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
|
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
||||||
dependencies = [
|
|
||||||
"funty",
|
[[package]]
|
||||||
"radium",
|
name = "bitflags"
|
||||||
"tap",
|
version = "1.2.1"
|
||||||
"wyz",
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
]
|
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "build_const"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
@@ -28,9 +44,15 @@ checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.14.0"
|
version = "1.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6"
|
checksum = "41aa2ec95ca3b5c54cf73c91acf06d24f4495d5f1b1c12506ae3483d646177ac"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
@@ -38,6 +60,12 @@ version = "1.0.66"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
|
checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@@ -45,44 +73,107 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-channel"
|
name = "cloudflare-zlib"
|
||||||
version = "0.5.10"
|
version = "0.2.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "82a9b73a36529d9c47029b9fb3a6f0ea3cc916a261195352ba19e770fc1748b2"
|
checksum = "f5ed63a019d55bacd15cadcbcb96bf41b16281417fff393bdb55fa84255fe4b9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cloudflare-zlib-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cloudflare-zlib-sys"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7e195cb274a0d6ee87e718838a09baecd7cbc9f6075dac256a84cb5842739c06"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "color_quant"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "const_fn"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc"
|
||||||
|
version = "1.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb"
|
||||||
|
dependencies = [
|
||||||
|
"build_const",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc32fast"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-channel"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-deque"
|
name = "crossbeam-deque"
|
||||||
version = "0.8.4"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751"
|
checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 1.0.0",
|
||||||
"crossbeam-epoch",
|
"crossbeam-epoch",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-epoch"
|
name = "crossbeam-epoch"
|
||||||
version = "0.9.17"
|
version = "0.9.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d"
|
checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"cfg-if 1.0.0",
|
||||||
"cfg-if",
|
"const_fn",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
|
"lazy_static",
|
||||||
|
"memoffset",
|
||||||
|
"scopeguard",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.18"
|
version = "0.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c"
|
checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"autocfg",
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "deflate"
|
||||||
|
version = "0.8.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174"
|
||||||
|
dependencies = [
|
||||||
|
"adler32",
|
||||||
|
"byteorder",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -91,42 +182,54 @@ version = "1.6.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "equivalent"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "funty"
|
|
||||||
version = "2.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.14.3"
|
version = "0.9.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.1.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "image"
|
||||||
|
version = "0.23.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7ce04077ead78e39ae8610ad26216aed811996b043d47beed5090db674f9e9b5"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
"byteorder",
|
||||||
|
"color_quant",
|
||||||
|
"num-iter",
|
||||||
|
"num-rational",
|
||||||
|
"num-traits",
|
||||||
|
"png",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.1.0"
|
version = "1.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"autocfg",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
"rayon",
|
"rayon",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "itertools"
|
||||||
version = "0.3.48"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc9f84f9b115ce7843d60706df1422a916680bfdfcbdb0447c5614ff9d7e4d78"
|
checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wasm-bindgen",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -136,51 +239,171 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libdeflate-sys"
|
name = "libc"
|
||||||
version = "1.19.0"
|
version = "0.2.81"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "67921a7f85100c1559efc3d1c7c472091b7da05f304b4bbd5356f075e97f1cc2"
|
checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libdeflate-sys"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4a95fa4be7085dd06a8296dcc3f399f12ab8b0309c157dcaa90669130b175b97"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libdeflater"
|
name = "libdeflater"
|
||||||
version = "1.19.0"
|
version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3a31b22f662350ec294b13859f935aea772ba7b2bc8776269f4a5627308eab7d"
|
checksum = "ccc147465654929bf7b56518cc46d11701ba290f4ff94398ae3f89f1663cf60f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libdeflate-sys",
|
"libdeflate-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.20"
|
version = "0.4.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 0.1.10",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memoffset"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435"
|
||||||
|
dependencies = [
|
||||||
|
"adler32",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d"
|
||||||
|
dependencies = [
|
||||||
|
"adler",
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-iter"
|
||||||
|
version = "0.1.42"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rational"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_cpus"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxipng"
|
name = "oxipng"
|
||||||
version = "9.0.0"
|
version = "4.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28e5c341ef78a228e47a551bfd15ff885d8c501af49f953358763a538c01f14d"
|
checksum = "50d0b53912a666fe2970f8ab254e283531c816aed16551ab66c52485eadb44e6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitvec",
|
"bit-vec",
|
||||||
|
"byteorder",
|
||||||
|
"cloudflare-zlib",
|
||||||
|
"crc",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
|
"image",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
"itertools",
|
||||||
"libdeflater",
|
"libdeflater",
|
||||||
"log",
|
"log",
|
||||||
|
"miniz_oxide 0.4.3",
|
||||||
"rayon",
|
"rayon",
|
||||||
"rgb",
|
"rgb",
|
||||||
"rustc-hash",
|
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "pest"
|
||||||
version = "1.0.26"
|
version = "2.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
|
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
|
||||||
|
dependencies = [
|
||||||
|
"ucd-trie",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "png"
|
||||||
|
version = "0.16.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"crc32fast",
|
||||||
|
"deflate",
|
||||||
|
"miniz_oxide 0.3.7",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
@@ -194,83 +417,91 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "radium"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon"
|
name = "rayon"
|
||||||
version = "1.8.0"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
|
checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"crossbeam-deque",
|
||||||
"either",
|
"either",
|
||||||
"rayon-core",
|
"rayon-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon-core"
|
name = "rayon-core"
|
||||||
version = "1.12.0"
|
version = "1.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
|
checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"crossbeam-channel",
|
||||||
"crossbeam-deque",
|
"crossbeam-deque",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
|
"lazy_static",
|
||||||
|
"num_cpus",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rgb"
|
name = "rgb"
|
||||||
version = "0.8.37"
|
version = "0.8.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8"
|
checksum = "287f3c3f8236abb92d8b7e36797f19159df4b58f0a658cc3fb6dd3004b1f3bd3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustc-hash"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc_version"
|
||||||
version = "0.4.0"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
checksum = "65c94201b44764d6d1f7e37c15a8289ed55e546c1762c7f1d57f616966e0c181"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "scopeguard"
|
||||||
version = "1.0.21"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
|
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spmc"
|
name = "semver"
|
||||||
version = "0.3.0"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "02a8428da277a8e3a15271d79943e80ccc2ef254e78813a166a08d65e4c3ece5"
|
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
|
||||||
|
dependencies = [
|
||||||
|
"semver-parser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver-parser"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
|
||||||
|
dependencies = [
|
||||||
|
"pest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "squoosh-oxipng"
|
name = "squoosh-oxipng"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"crossbeam-channel",
|
||||||
|
"libdeflater",
|
||||||
"log",
|
"log",
|
||||||
|
"once_cell",
|
||||||
"oxipng",
|
"oxipng",
|
||||||
|
"rayon",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-rayon",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.72"
|
version = "1.0.58"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
|
checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -278,10 +509,10 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tap"
|
name = "ucd-trie"
|
||||||
version = "1.0.1"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
@@ -291,19 +522,19 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.74"
|
version = "0.2.69"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
|
checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 1.0.0",
|
||||||
"wasm-bindgen-macro",
|
"wasm-bindgen-macro",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-backend"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.74"
|
version = "0.2.69"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900"
|
checksum = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@@ -316,9 +547,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.74"
|
version = "0.2.69"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4"
|
checksum = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
@@ -326,9 +557,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.74"
|
version = "0.2.69"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
|
checksum = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -337,29 +568,8 @@ dependencies = [
|
|||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-rayon"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3069d2a42e7a7e3bfde668f84adb5fbc35701ca2b39b27a064cbd5ede4e78194"
|
|
||||||
dependencies = [
|
|
||||||
"js-sys",
|
|
||||||
"rayon",
|
|
||||||
"spmc",
|
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.74"
|
version = "0.2.69"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
|
checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wyz"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
|
|
||||||
dependencies = [
|
|
||||||
"tap",
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -12,14 +12,17 @@ wasm-opt = ["-O", "--no-validation"]
|
|||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
oxipng = { version = "9.0", default-features = false, features = ["freestanding"] }
|
oxipng = { version = "4.0.1", default-features = false, features = ["libdeflater"] }
|
||||||
wasm-bindgen = "0.2.73"
|
libdeflater = { version = "0.7.1", features = ["freestanding"] }
|
||||||
|
wasm-bindgen = "0.2.68"
|
||||||
log = { version = "0.4.11", features = ["release_max_level_off"] }
|
log = { version = "0.4.11", features = ["release_max_level_off"] }
|
||||||
wasm-bindgen-rayon = { version = "1.0", optional = true }
|
rayon = { version = "1.5.0", optional = true }
|
||||||
|
once_cell = { version = "1.5.2", optional = true }
|
||||||
|
crossbeam-channel = { version = "0.5.0", optional = true }
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
opt-level = "s"
|
opt-level = "s"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
parallel = ["oxipng/parallel", "wasm-bindgen-rayon"]
|
parallel = ["oxipng/parallel", "rayon", "crossbeam-channel", "once_cell"]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# OxiPNG
|
# OxiPNG
|
||||||
|
|
||||||
- Source: <https://github.com/shssoichiro/oxipng>
|
- Source: <https://github.com/shssoichiro/oxipng>
|
||||||
- Version: v9.0.0
|
- Version: v3.0.0
|
||||||
- License: MIT
|
- License: MIT
|
||||||
|
|||||||
@@ -5,5 +5,7 @@ set -e
|
|||||||
rm -rf pkg,{-parallel}
|
rm -rf pkg,{-parallel}
|
||||||
export CFLAGS="${CFLAGS} -DUNALIGNED_ACCESS_IS_FAST=1"
|
export CFLAGS="${CFLAGS} -DUNALIGNED_ACCESS_IS_FAST=1"
|
||||||
wasm-pack build -t web
|
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
|
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
|
rm pkg{,-parallel}/.gitignore
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "oxipng",
|
"name": "oxipng",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "RUST_IMG=rustlang/rust@sha256:5fd16a5576c22c8fdd5d659247755999e426c04de8dcf18a41ea446c5f253309 ../build-rust.sh ./build.sh"
|
"build": "RUST_IMG=rustlang/rust@sha256:744aeea5a38f95aa7a96ec37269a65f0c6197a1cdd87d6534e12bb869141d807 ../build-rust.sh ./build.sh"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# OxiPNG
|
# OxiPNG
|
||||||
|
|
||||||
- Source: <https://github.com/shssoichiro/oxipng>
|
- Source: <https://github.com/shssoichiro/oxipng>
|
||||||
- Version: v9.0.0
|
- Version: v3.0.0
|
||||||
- License: MIT
|
- License: MIT
|
||||||
|
|||||||
@@ -11,7 +11,5 @@
|
|||||||
],
|
],
|
||||||
"module": "squoosh_oxipng.js",
|
"module": "squoosh_oxipng.js",
|
||||||
"types": "squoosh_oxipng.d.ts",
|
"types": "squoosh_oxipng.d.ts",
|
||||||
"sideEffects": [
|
"sideEffects": false
|
||||||
"./snippets/*"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
44
codecs/oxipng/pkg-parallel/squoosh_oxipng.d.ts
generated
vendored
44
codecs/oxipng/pkg-parallel/squoosh_oxipng.d.ts
generated
vendored
@@ -1,52 +1,31 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
/**
|
/**
|
||||||
* @param {Uint8ClampedArray} data
|
* @param {Uint8Array} data
|
||||||
* @param {number} width
|
|
||||||
* @param {number} height
|
|
||||||
* @param {number} level
|
* @param {number} level
|
||||||
* @param {boolean} interlace
|
|
||||||
* @returns {Uint8Array}
|
* @returns {Uint8Array}
|
||||||
*/
|
*/
|
||||||
export function optimise(data: Uint8ClampedArray, width: number, height: number, level: number, interlace: boolean): Uint8Array;
|
export function optimise(data: Uint8Array, level: number): Uint8Array;
|
||||||
/**
|
/**
|
||||||
* @param {number} num_threads
|
* @param {number} num
|
||||||
* @returns {Promise<any>}
|
* @returns {any}
|
||||||
*/
|
*/
|
||||||
export function initThreadPool(num_threads: number): Promise<any>;
|
export function worker_initializer(num: number): any;
|
||||||
/**
|
|
||||||
* @param {number} receiver
|
|
||||||
*/
|
|
||||||
export function wbg_rayon_start_worker(receiver: number): void;
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export class wbg_rayon_PoolBuilder {
|
export function start_main_thread(): void;
|
||||||
free(): void;
|
|
||||||
/**
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
numThreads(): number;
|
|
||||||
/**
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
receiver(): number;
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
build(): void;
|
export function start_worker_thread(): void;
|
||||||
}
|
|
||||||
|
|
||||||
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
||||||
|
|
||||||
export interface InitOutput {
|
export interface InitOutput {
|
||||||
readonly optimise: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
readonly optimise: (a: number, b: number, c: number, d: number) => void;
|
||||||
readonly __wbg_wbg_rayon_poolbuilder_free: (a: number) => void;
|
readonly worker_initializer: (a: number) => number;
|
||||||
readonly wbg_rayon_poolbuilder_numThreads: (a: number) => number;
|
readonly start_main_thread: () => void;
|
||||||
readonly wbg_rayon_poolbuilder_receiver: (a: number) => number;
|
readonly start_worker_thread: () => void;
|
||||||
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_export_0: WebAssembly.Memory;
|
||||||
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
|
|
||||||
readonly __wbindgen_malloc: (a: number) => number;
|
readonly __wbindgen_malloc: (a: number) => number;
|
||||||
readonly __wbindgen_free: (a: number, b: number) => void;
|
readonly __wbindgen_free: (a: number, b: number) => void;
|
||||||
readonly __wbindgen_start: () => void;
|
readonly __wbindgen_start: () => void;
|
||||||
@@ -62,3 +41,4 @@ export interface InitOutput {
|
|||||||
* @returns {Promise<InitOutput>}
|
* @returns {Promise<InitOutput>}
|
||||||
*/
|
*/
|
||||||
export default function init (module_or_path?: InitInput | Promise<InitInput>, maybe_memory?: WebAssembly.Memory): Promise<InitOutput>;
|
export default function init (module_or_path?: InitInput | Promise<InitInput>, maybe_memory?: WebAssembly.Memory): Promise<InitOutput>;
|
||||||
|
|
||||||
120
codecs/oxipng/pkg-parallel/squoosh_oxipng.js
generated
120
codecs/oxipng/pkg-parallel/squoosh_oxipng.js
generated
@@ -1,6 +1,21 @@
|
|||||||
import { startWorkers } from './snippets/wasm-bindgen-rayon-3d2df09ebec17a22/src/workerHelpers.js';
|
|
||||||
|
|
||||||
let wasm;
|
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 });
|
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
||||||
|
|
||||||
@@ -18,21 +33,6 @@ function getStringFromWasm0(ptr, len) {
|
|||||||
return cachedTextDecoder.decode(getUint8Memory0().slice(ptr, 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;
|
let WASM_VECTOR_LEN = 0;
|
||||||
|
|
||||||
function passArray8ToWasm0(arg, malloc) {
|
function passArray8ToWasm0(arg, malloc) {
|
||||||
@@ -54,26 +54,24 @@ function getArrayU8FromWasm0(ptr, len) {
|
|||||||
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len);
|
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param {Uint8ClampedArray} data
|
* @param {Uint8Array} data
|
||||||
* @param {number} width
|
|
||||||
* @param {number} height
|
|
||||||
* @param {number} level
|
* @param {number} level
|
||||||
* @param {boolean} interlace
|
|
||||||
* @returns {Uint8Array}
|
* @returns {Uint8Array}
|
||||||
*/
|
*/
|
||||||
export function optimise(data, width, height, level, interlace) {
|
export function optimise(data, level) {
|
||||||
try {
|
try {
|
||||||
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
const retptr = wasm.__wbindgen_export_1.value - 16;
|
||||||
|
wasm.__wbindgen_export_1.value = retptr;
|
||||||
var ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
|
var ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
|
||||||
var len0 = WASM_VECTOR_LEN;
|
var len0 = WASM_VECTOR_LEN;
|
||||||
wasm.optimise(retptr, ptr0, len0, width, height, level, interlace);
|
wasm.optimise(retptr, ptr0, len0, level);
|
||||||
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
||||||
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
||||||
var v1 = getArrayU8FromWasm0(r0, r1).slice();
|
var v1 = getArrayU8FromWasm0(r0, r1).slice();
|
||||||
wasm.__wbindgen_free(r0, r1 * 1);
|
wasm.__wbindgen_free(r0, r1 * 1);
|
||||||
return v1;
|
return v1;
|
||||||
} finally {
|
} finally {
|
||||||
wasm.__wbindgen_add_to_stack_pointer(16);
|
wasm.__wbindgen_export_1.value += 16;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,66 +89,29 @@ function takeObject(idx) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param {number} num_threads
|
* @param {number} num
|
||||||
* @returns {Promise<any>}
|
* @returns {any}
|
||||||
*/
|
*/
|
||||||
export function initThreadPool(num_threads) {
|
export function worker_initializer(num) {
|
||||||
var ret = wasm.initThreadPool(num_threads);
|
var ret = wasm.worker_initializer(num);
|
||||||
return takeObject(ret);
|
return takeObject(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number} receiver
|
|
||||||
*/
|
*/
|
||||||
export function wbg_rayon_start_worker(receiver) {
|
export function start_main_thread() {
|
||||||
wasm.wbg_rayon_start_worker(receiver);
|
wasm.start_main_thread();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export class wbg_rayon_PoolBuilder {
|
export function start_worker_thread() {
|
||||||
|
wasm.start_worker_thread();
|
||||||
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) {
|
async function load(module, imports, maybe_memory) {
|
||||||
if (typeof Response === 'function' && module instanceof Response) {
|
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') {
|
if (typeof WebAssembly.instantiateStreaming === 'function') {
|
||||||
try {
|
try {
|
||||||
return await WebAssembly.instantiateStreaming(module, imports);
|
return await WebAssembly.instantiateStreaming(module, imports);
|
||||||
@@ -169,6 +130,7 @@ async function load(module, imports) {
|
|||||||
return await WebAssembly.instantiate(bytes, imports);
|
return await WebAssembly.instantiate(bytes, imports);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
memory = imports.wbg.memory = maybe_memory;
|
||||||
const instance = await WebAssembly.instantiate(module, imports);
|
const instance = await WebAssembly.instantiate(module, imports);
|
||||||
|
|
||||||
if (instance instanceof WebAssembly.Instance) {
|
if (instance instanceof WebAssembly.Instance) {
|
||||||
@@ -182,13 +144,10 @@ async function load(module, imports) {
|
|||||||
|
|
||||||
async function init(input, maybe_memory) {
|
async function init(input, maybe_memory) {
|
||||||
if (typeof input === 'undefined') {
|
if (typeof input === 'undefined') {
|
||||||
input = new URL('squoosh_oxipng_bg.wasm', import.meta.url);
|
input = import.meta.url.replace(/\.js$/, '_bg.wasm');
|
||||||
}
|
}
|
||||||
const imports = {};
|
const imports = {};
|
||||||
imports.wbg = {};
|
imports.wbg = {};
|
||||||
imports.wbg.__wbindgen_throw = function(arg0, arg1) {
|
|
||||||
throw new Error(getStringFromWasm0(arg0, arg1));
|
|
||||||
};
|
|
||||||
imports.wbg.__wbindgen_module = function() {
|
imports.wbg.__wbindgen_module = function() {
|
||||||
var ret = init.__wbindgen_wasm_module;
|
var ret = init.__wbindgen_wasm_module;
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
@@ -197,18 +156,19 @@ async function init(input, maybe_memory) {
|
|||||||
var ret = wasm.__wbindgen_export_0;
|
var ret = wasm.__wbindgen_export_0;
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
};
|
};
|
||||||
imports.wbg.__wbg_startWorkers_914655bb4d5bb5e1 = function(arg0, arg1, arg2) {
|
imports.wbg.__wbg_of_6510501edc06d65e = function(arg0, arg1) {
|
||||||
var ret = startWorkers(takeObject(arg0), takeObject(arg1), wbg_rayon_PoolBuilder.__wrap(arg2));
|
var ret = Array.of(takeObject(arg0), takeObject(arg1));
|
||||||
return addHeapObject(ret);
|
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)) {
|
if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
|
||||||
input = fetch(input);
|
input = fetch(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
imports.wbg.memory = maybe_memory || new WebAssembly.Memory({initial:17,maximum:16384,shared:true});
|
const { instance, module } = await load(await input, imports, maybe_memory);
|
||||||
|
|
||||||
const { instance, module } = await load(await input, imports);
|
|
||||||
|
|
||||||
wasm = instance.exports;
|
wasm = instance.exports;
|
||||||
init.__wbindgen_wasm_module = module;
|
init.__wbindgen_wasm_module = module;
|
||||||
|
|||||||
Binary file not shown.
12
codecs/oxipng/pkg-parallel/squoosh_oxipng_bg.wasm.d.ts
generated
vendored
12
codecs/oxipng/pkg-parallel/squoosh_oxipng_bg.wasm.d.ts
generated
vendored
@@ -1,14 +1,10 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
export function optimise(a: number, b: number, c: number, d: number, e: number, f: number, g: number): void;
|
export function optimise(a: number, b: number, c: number, d: number): void;
|
||||||
export function __wbg_wbg_rayon_poolbuilder_free(a: number): void;
|
export function worker_initializer(a: number): number;
|
||||||
export function wbg_rayon_poolbuilder_numThreads(a: number): number;
|
export function start_main_thread(): void;
|
||||||
export function wbg_rayon_poolbuilder_receiver(a: number): number;
|
export function start_worker_thread(): void;
|
||||||
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 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_malloc(a: number): number;
|
||||||
export function __wbindgen_free(a: number, b: number): void;
|
export function __wbindgen_free(a: number, b: number): void;
|
||||||
export function __wbindgen_start(): void;
|
export function __wbindgen_start(): void;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# OxiPNG
|
# OxiPNG
|
||||||
|
|
||||||
- Source: <https://github.com/shssoichiro/oxipng>
|
- Source: <https://github.com/shssoichiro/oxipng>
|
||||||
- Version: v9.0.0
|
- Version: v3.0.0
|
||||||
- License: MIT
|
- License: MIT
|
||||||
|
|||||||
@@ -11,7 +11,5 @@
|
|||||||
],
|
],
|
||||||
"module": "squoosh_oxipng.js",
|
"module": "squoosh_oxipng.js",
|
||||||
"types": "squoosh_oxipng.d.ts",
|
"types": "squoosh_oxipng.d.ts",
|
||||||
"sideEffects": [
|
"sideEffects": false
|
||||||
"./snippets/*"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
11
codecs/oxipng/pkg/squoosh_oxipng.d.ts
generated
vendored
11
codecs/oxipng/pkg/squoosh_oxipng.d.ts
generated
vendored
@@ -1,21 +1,17 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
/**
|
/**
|
||||||
* @param {Uint8ClampedArray} data
|
* @param {Uint8Array} data
|
||||||
* @param {number} width
|
|
||||||
* @param {number} height
|
|
||||||
* @param {number} level
|
* @param {number} level
|
||||||
* @param {boolean} interlace
|
|
||||||
* @returns {Uint8Array}
|
* @returns {Uint8Array}
|
||||||
*/
|
*/
|
||||||
export function optimise(data: Uint8ClampedArray, width: number, height: number, level: number, interlace: boolean): Uint8Array;
|
export function optimise(data: Uint8Array, level: number): Uint8Array;
|
||||||
|
|
||||||
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
||||||
|
|
||||||
export interface InitOutput {
|
export interface InitOutput {
|
||||||
readonly memory: WebAssembly.Memory;
|
readonly memory: WebAssembly.Memory;
|
||||||
readonly optimise: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
readonly optimise: (a: number, b: number, c: number, d: number) => void;
|
||||||
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
|
|
||||||
readonly __wbindgen_malloc: (a: number) => number;
|
readonly __wbindgen_malloc: (a: number) => number;
|
||||||
readonly __wbindgen_free: (a: number, b: number) => void;
|
readonly __wbindgen_free: (a: number, b: number) => void;
|
||||||
}
|
}
|
||||||
@@ -29,3 +25,4 @@ export interface InitOutput {
|
|||||||
* @returns {Promise<InitOutput>}
|
* @returns {Promise<InitOutput>}
|
||||||
*/
|
*/
|
||||||
export default function init (module_or_path?: InitInput | Promise<InitInput>): Promise<InitOutput>;
|
export default function init (module_or_path?: InitInput | Promise<InitInput>): Promise<InitOutput>;
|
||||||
|
|
||||||
20
codecs/oxipng/pkg/squoosh_oxipng.js
generated
20
codecs/oxipng/pkg/squoosh_oxipng.js
generated
@@ -38,31 +38,30 @@ function getArrayU8FromWasm0(ptr, len) {
|
|||||||
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len);
|
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param {Uint8ClampedArray} data
|
* @param {Uint8Array} data
|
||||||
* @param {number} width
|
|
||||||
* @param {number} height
|
|
||||||
* @param {number} level
|
* @param {number} level
|
||||||
* @param {boolean} interlace
|
|
||||||
* @returns {Uint8Array}
|
* @returns {Uint8Array}
|
||||||
*/
|
*/
|
||||||
export function optimise(data, width, height, level, interlace) {
|
export function optimise(data, level) {
|
||||||
try {
|
try {
|
||||||
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
const retptr = wasm.__wbindgen_export_0.value - 16;
|
||||||
|
wasm.__wbindgen_export_0.value = retptr;
|
||||||
var ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
|
var ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
|
||||||
var len0 = WASM_VECTOR_LEN;
|
var len0 = WASM_VECTOR_LEN;
|
||||||
wasm.optimise(retptr, ptr0, len0, width, height, level, interlace);
|
wasm.optimise(retptr, ptr0, len0, level);
|
||||||
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
||||||
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
||||||
var v1 = getArrayU8FromWasm0(r0, r1).slice();
|
var v1 = getArrayU8FromWasm0(r0, r1).slice();
|
||||||
wasm.__wbindgen_free(r0, r1 * 1);
|
wasm.__wbindgen_free(r0, r1 * 1);
|
||||||
return v1;
|
return v1;
|
||||||
} finally {
|
} finally {
|
||||||
wasm.__wbindgen_add_to_stack_pointer(16);
|
wasm.__wbindgen_export_0.value += 16;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function load(module, imports) {
|
async function load(module, imports) {
|
||||||
if (typeof Response === 'function' && module instanceof Response) {
|
if (typeof Response === 'function' && module instanceof Response) {
|
||||||
|
|
||||||
if (typeof WebAssembly.instantiateStreaming === 'function') {
|
if (typeof WebAssembly.instantiateStreaming === 'function') {
|
||||||
try {
|
try {
|
||||||
return await WebAssembly.instantiateStreaming(module, imports);
|
return await WebAssembly.instantiateStreaming(module, imports);
|
||||||
@@ -81,6 +80,7 @@ async function load(module, imports) {
|
|||||||
return await WebAssembly.instantiate(bytes, imports);
|
return await WebAssembly.instantiate(bytes, imports);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const instance = await WebAssembly.instantiate(module, imports);
|
const instance = await WebAssembly.instantiate(module, imports);
|
||||||
|
|
||||||
if (instance instanceof WebAssembly.Instance) {
|
if (instance instanceof WebAssembly.Instance) {
|
||||||
@@ -94,7 +94,7 @@ async function load(module, imports) {
|
|||||||
|
|
||||||
async function init(input) {
|
async function init(input) {
|
||||||
if (typeof input === 'undefined') {
|
if (typeof input === 'undefined') {
|
||||||
input = new URL('squoosh_oxipng_bg.wasm', import.meta.url);
|
input = import.meta.url.replace(/\.js$/, '_bg.wasm');
|
||||||
}
|
}
|
||||||
const imports = {};
|
const imports = {};
|
||||||
imports.wbg = {};
|
imports.wbg = {};
|
||||||
@@ -106,8 +106,6 @@ async function init(input) {
|
|||||||
input = fetch(input);
|
input = fetch(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const { instance, module } = await load(await input, imports);
|
const { instance, module } = await load(await input, imports);
|
||||||
|
|
||||||
wasm = instance.exports;
|
wasm = instance.exports;
|
||||||
|
|||||||
Binary file not shown.
3
codecs/oxipng/pkg/squoosh_oxipng_bg.wasm.d.ts
generated
vendored
3
codecs/oxipng/pkg/squoosh_oxipng_bg.wasm.d.ts
generated
vendored
@@ -1,7 +1,6 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
export const memory: WebAssembly.Memory;
|
export const memory: WebAssembly.Memory;
|
||||||
export function optimise(a: number, b: number, c: number, d: number, e: number, f: number, g: number): void;
|
export function optimise(a: number, b: number, c: number, d: number): void;
|
||||||
export function __wbindgen_add_to_stack_pointer(a: number): number;
|
|
||||||
export function __wbindgen_malloc(a: number): number;
|
export function __wbindgen_malloc(a: number): number;
|
||||||
export function __wbindgen_free(a: number, b: number): void;
|
export function __wbindgen_free(a: number, b: number): void;
|
||||||
|
|||||||
@@ -1,27 +1,19 @@
|
|||||||
#[cfg(feature = "parallel")]
|
use oxipng::AlphaOptim;
|
||||||
pub use wasm_bindgen_rayon::init_thread_pool;
|
|
||||||
|
|
||||||
use oxipng::{BitDepth, ColorType, Interlacing};
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use wasm_bindgen::Clamped;
|
|
||||||
|
#[cfg(feature = "parallel")]
|
||||||
|
pub mod parallel;
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn optimise(
|
pub fn optimise(data: &[u8], level: u8) -> Vec<u8> {
|
||||||
data: Clamped<Vec<u8>>,
|
|
||||||
width: u32,
|
|
||||||
height: u32,
|
|
||||||
level: u8,
|
|
||||||
interlace: bool,
|
|
||||||
) -> Vec<u8> {
|
|
||||||
let mut options = oxipng::Options::from_preset(level);
|
let mut options = oxipng::Options::from_preset(level);
|
||||||
options.optimize_alpha = true;
|
options.alphas.insert(AlphaOptim::Black);
|
||||||
options.interlace = Some(if interlace {
|
options.alphas.insert(AlphaOptim::White);
|
||||||
Interlacing::Adam7
|
options.alphas.insert(AlphaOptim::Up);
|
||||||
} else {
|
options.alphas.insert(AlphaOptim::Down);
|
||||||
Interlacing::None
|
options.alphas.insert(AlphaOptim::Left);
|
||||||
});
|
options.alphas.insert(AlphaOptim::Right);
|
||||||
|
|
||||||
let raw = oxipng::RawImage::new(width, height, ColorType::RGBA, BitDepth::Eight, data.0)
|
options.deflate = oxipng::Deflaters::Libdeflater;
|
||||||
.unwrap_throw();
|
oxipng::optimize_from_memory(data, &options).unwrap_throw()
|
||||||
raw.create_optimized_png(&options).unwrap_throw()
|
|
||||||
}
|
}
|
||||||
|
|||||||
62
codecs/oxipng/src/parallel.rs
Normal file
62
codecs/oxipng/src/parallel.rs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
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()
|
||||||
|
}
|
||||||
56
codecs/png/Cargo.lock
generated
56
codecs/png/Cargo.lock
generated
@@ -18,12 +18,6 @@ version = "3.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820"
|
checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bytemuck"
|
|
||||||
version = "1.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bed57e2090563b83ba8f83366628ce535a7584c9afa4c9fc0612a03925c6df58"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.3.4"
|
version = "1.3.4"
|
||||||
@@ -36,19 +30,13 @@ version = "0.1.10"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "crc32fast"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
|
checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -82,7 +70,7 @@ version = "0.4.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -108,9 +96,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.27"
|
version = "1.0.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
|
checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
@@ -124,30 +112,20 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rgb"
|
|
||||||
version = "0.8.25"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "287f3c3f8236abb92d8b7e36797f19159df4b58f0a658cc3fb6dd3004b1f3bd3"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "squoosh-png"
|
name = "squoosh-png"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"png",
|
"png",
|
||||||
"rgb",
|
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.72"
|
version = "1.0.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
|
checksum = "936cae2873c940d92e697597c5eee105fb570cd5689c695806f672883653349b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -162,19 +140,19 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.74"
|
version = "0.2.68"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
|
checksum = "1ac64ead5ea5f05873d7c12b545865ca2b8d28adfc50a49b84770a3a97265d42"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if",
|
||||||
"wasm-bindgen-macro",
|
"wasm-bindgen-macro",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-backend"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.74"
|
version = "0.2.68"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900"
|
checksum = "f22b422e2a757c35a73774860af8e112bff612ce6cb604224e8e47641a9e4f68"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@@ -187,9 +165,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.74"
|
version = "0.2.68"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4"
|
checksum = "6b13312a745c08c469f0b292dd2fcd6411dba5f7160f593da6ef69b64e407038"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
@@ -197,9 +175,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.74"
|
version = "0.2.68"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
|
checksum = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -210,9 +188,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.74"
|
version = "0.2.68"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
|
checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ crate-type = ["cdylib"]
|
|||||||
png = "0.16.7"
|
png = "0.16.7"
|
||||||
wasm-bindgen = "0.2.68"
|
wasm-bindgen = "0.2.68"
|
||||||
web-sys = { version = "0.3.45", features = ["ImageData"] }
|
web-sys = { version = "0.3.45", features = ["ImageData"] }
|
||||||
rgb = "0.8.25"
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
|||||||
31
codecs/png/pkg/squoosh_png.js
generated
31
codecs/png/pkg/squoosh_png.js
generated
@@ -1,22 +1,6 @@
|
|||||||
|
|
||||||
let wasm;
|
let wasm;
|
||||||
|
|
||||||
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
|
||||||
|
|
||||||
cachedTextDecoder.decode();
|
|
||||||
|
|
||||||
let cachegetUint8Memory0 = null;
|
|
||||||
function getUint8Memory0() {
|
|
||||||
if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) {
|
|
||||||
cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer);
|
|
||||||
}
|
|
||||||
return cachegetUint8Memory0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getStringFromWasm0(ptr, len) {
|
|
||||||
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
|
|
||||||
}
|
|
||||||
|
|
||||||
let cachegetUint8ClampedMemory0 = null;
|
let cachegetUint8ClampedMemory0 = null;
|
||||||
function getUint8ClampedMemory0() {
|
function getUint8ClampedMemory0() {
|
||||||
if (cachegetUint8ClampedMemory0 === null || cachegetUint8ClampedMemory0.buffer !== wasm.memory.buffer) {
|
if (cachegetUint8ClampedMemory0 === null || cachegetUint8ClampedMemory0.buffer !== wasm.memory.buffer) {
|
||||||
@@ -44,6 +28,14 @@ function addHeapObject(obj) {
|
|||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let cachegetUint8Memory0 = null;
|
||||||
|
function getUint8Memory0() {
|
||||||
|
if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) {
|
||||||
|
cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer);
|
||||||
|
}
|
||||||
|
return cachegetUint8Memory0;
|
||||||
|
}
|
||||||
|
|
||||||
let WASM_VECTOR_LEN = 0;
|
let WASM_VECTOR_LEN = 0;
|
||||||
|
|
||||||
function passArray8ToWasm0(arg, malloc) {
|
function passArray8ToWasm0(arg, malloc) {
|
||||||
@@ -112,6 +104,7 @@ export function decode(data) {
|
|||||||
|
|
||||||
async function load(module, imports) {
|
async function load(module, imports) {
|
||||||
if (typeof Response === 'function' && module instanceof Response) {
|
if (typeof Response === 'function' && module instanceof Response) {
|
||||||
|
|
||||||
if (typeof WebAssembly.instantiateStreaming === 'function') {
|
if (typeof WebAssembly.instantiateStreaming === 'function') {
|
||||||
try {
|
try {
|
||||||
return await WebAssembly.instantiateStreaming(module, imports);
|
return await WebAssembly.instantiateStreaming(module, imports);
|
||||||
@@ -130,6 +123,7 @@ async function load(module, imports) {
|
|||||||
return await WebAssembly.instantiate(bytes, imports);
|
return await WebAssembly.instantiate(bytes, imports);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const instance = await WebAssembly.instantiate(module, imports);
|
const instance = await WebAssembly.instantiate(module, imports);
|
||||||
|
|
||||||
if (instance instanceof WebAssembly.Instance) {
|
if (instance instanceof WebAssembly.Instance) {
|
||||||
@@ -153,16 +147,11 @@ async function init(input) {
|
|||||||
var ret = new ImageData(v0, arg2 >>> 0, arg3 >>> 0);
|
var ret = new ImageData(v0, arg2 >>> 0, arg3 >>> 0);
|
||||||
return addHeapObject(ret);
|
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)) {
|
if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
|
||||||
input = fetch(input);
|
input = fetch(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const { instance, module } = await load(await input, imports);
|
const { instance, module } = await load(await input, imports);
|
||||||
|
|
||||||
wasm = instance.exports;
|
wasm = instance.exports;
|
||||||
|
|||||||
Binary file not shown.
@@ -1,7 +1,5 @@
|
|||||||
use rgb::{
|
use std::io::Cursor;
|
||||||
alt::{GRAY8, GRAYA8},
|
|
||||||
AsPixels, FromSlice, RGB8, RGBA8,
|
|
||||||
};
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use wasm_bindgen::Clamped;
|
use wasm_bindgen::Clamped;
|
||||||
|
|
||||||
@@ -20,61 +18,38 @@ extern "C" {
|
|||||||
) -> ImageData;
|
) -> ImageData;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen(catch)]
|
||||||
pub fn encode(data: &[u8], width: u32, height: u32) -> Vec<u8> {
|
pub fn encode(data: &[u8], width: u32, height: u32) -> Vec<u8> {
|
||||||
let mut buffer = Vec::new();
|
let mut buffer = Cursor::new(Vec::<u8>::new());
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut encoder = png::Encoder::new(&mut buffer, width, height);
|
let mut encoder = png::Encoder::new(&mut buffer, width, height);
|
||||||
encoder.set_color(png::ColorType::RGBA);
|
encoder.set_color(png::ColorType::RGBA);
|
||||||
encoder.set_depth(png::BitDepth::Eight);
|
encoder.set_depth(png::BitDepth::Eight);
|
||||||
let mut writer = encoder.write_header().unwrap_throw();
|
let mut writer = encoder.write_header().unwrap();
|
||||||
writer.write_image_data(data).unwrap_throw();
|
writer.write_image_data(data).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer
|
buffer.into_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert pixels in-place within buffer containing source data but preallocated
|
#[wasm_bindgen(catch)]
|
||||||
// for entire [num_pixels * sizeof(RGBA)].
|
pub fn decode(data: &[u8]) -> ImageData {
|
||||||
// This works because all the color types are <= RGBA by size.
|
let mut decoder = png::Decoder::new(Cursor::new(data));
|
||||||
fn expand_pixels<Src: Copy>(buf: &mut [u8], to_rgba: impl Fn(Src) -> RGBA8)
|
decoder.set_transformations(png::Transformations::EXPAND);
|
||||||
where
|
let (info, mut reader) = decoder.read_info().unwrap();
|
||||||
[u8]: AsPixels<Src> + FromSlice<u8>,
|
|
||||||
{
|
|
||||||
assert!(std::mem::size_of::<Src>() <= std::mem::size_of::<RGBA8>());
|
|
||||||
let num_pixels = buf.len() / 4;
|
|
||||||
for i in (0..num_pixels).rev() {
|
|
||||||
let src_pixel = buf.as_pixels()[i];
|
|
||||||
buf.as_rgba_mut()[i] = to_rgba(src_pixel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub fn decode(mut data: &[u8]) -> ImageData {
|
|
||||||
let mut decoder = png::Decoder::new(&mut data);
|
|
||||||
decoder.set_transformations(
|
|
||||||
png::Transformations::EXPAND | // Turn paletted images into RGB
|
|
||||||
png::Transformations::PACKING | // Turn images <8bit to 8bit
|
|
||||||
png::Transformations::STRIP_16, // Turn 16bit into 8 bit
|
|
||||||
);
|
|
||||||
let (info, mut reader) = decoder.read_info().unwrap_throw();
|
|
||||||
let num_pixels = (info.width * info.height) as usize;
|
let num_pixels = (info.width * info.height) as usize;
|
||||||
let mut buf = vec![0; num_pixels * 4];
|
let mut buf = vec![0; num_pixels * 4];
|
||||||
reader.next_frame(&mut buf).unwrap_throw();
|
reader.next_frame(&mut buf).unwrap();
|
||||||
|
|
||||||
// Transformations::EXPAND will expand indexed palettes and lower-bit
|
// Transformations::EXPAND will make sure color_type is either
|
||||||
// grayscales to higher color types, but we still need to transform
|
// RGBA or RGB. If it’s RGB, we need inject an alpha channel.
|
||||||
// the rest to RGBA.
|
if info.color_type == png::ColorType::RGB {
|
||||||
match info.color_type {
|
for i in (0..num_pixels).rev() {
|
||||||
png::ColorType::RGBA => {}
|
buf[i * 4 + 0] = buf[i * 3 + 0];
|
||||||
png::ColorType::RGB => expand_pixels(&mut buf, RGB8::into),
|
buf[i * 4 + 1] = buf[i * 3 + 1];
|
||||||
png::ColorType::GrayscaleAlpha => expand_pixels(&mut buf, GRAYA8::into),
|
buf[i * 4 + 2] = buf[i * 3 + 2];
|
||||||
png::ColorType::Grayscale => {
|
buf[i * 4 + 3] = 255;
|
||||||
expand_pixels(&mut buf, |gray: GRAY8| GRAYA8::from(gray).into())
|
|
||||||
}
|
|
||||||
png::ColorType::Indexed => {
|
|
||||||
unreachable!("Found indexed color type, but expected it to be already expanded")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
CODEC_URL = https://github.com/phoboslab/qoi/archive/8d35d93cdca85d2868246c2a8a80a1e2c16ba2a8.tar.gz
|
|
||||||
|
|
||||||
CODEC_DIR = node_modules/qoi
|
|
||||||
CODEC_BUILD_DIR:= $(CODEC_DIR)/build
|
|
||||||
ENVIRONMENT = worker
|
|
||||||
|
|
||||||
OUT_JS = enc/qoi_enc.js dec/qoi_dec.js
|
|
||||||
OUT_WASM := $(OUT_JS:.js=.wasm)
|
|
||||||
|
|
||||||
.PHONY: all clean
|
|
||||||
|
|
||||||
all: $(OUT_JS)
|
|
||||||
|
|
||||||
$(filter enc/%,$(OUT_JS)): enc/qoi_enc.o
|
|
||||||
$(filter dec/%,$(OUT_JS)): dec/qoi_dec.o
|
|
||||||
|
|
||||||
# ALL .js FILES
|
|
||||||
$(OUT_JS):
|
|
||||||
$(LD) \
|
|
||||||
$(LDFLAGS) \
|
|
||||||
--bind \
|
|
||||||
-s ENVIRONMENT=$(ENVIRONMENT) \
|
|
||||||
-s EXPORT_ES6=1 \
|
|
||||||
-o $@ \
|
|
||||||
$+
|
|
||||||
|
|
||||||
# ALL .o FILES
|
|
||||||
%.o: %.cpp $(CODEC_DIR)
|
|
||||||
$(CXX) -c \
|
|
||||||
$(CXXFLAGS) \
|
|
||||||
-I $(CODEC_DIR) \
|
|
||||||
-o $@ \
|
|
||||||
$<
|
|
||||||
|
|
||||||
# CREATE DIRECTORY
|
|
||||||
$(CODEC_DIR):
|
|
||||||
mkdir -p $(CODEC_DIR)
|
|
||||||
curl -sL $(CODEC_URL) | tar xz --strip 1 -C $(CODEC_DIR)
|
|
||||||
|
|
||||||
clean:
|
|
||||||
$(RM) $(OUT_JS) $(OUT_WASM)
|
|
||||||
$(MAKE) -C $(CODEC_DIR) clean
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
#include <emscripten/bind.h>
|
|
||||||
#include <emscripten/val.h>
|
|
||||||
|
|
||||||
#define QOI_IMPLEMENTATION
|
|
||||||
#include "qoi.h"
|
|
||||||
|
|
||||||
using namespace emscripten;
|
|
||||||
|
|
||||||
thread_local const val Uint8ClampedArray = val::global("Uint8ClampedArray");
|
|
||||||
thread_local const val ImageData = val::global("ImageData");
|
|
||||||
|
|
||||||
val decode(std::string qoiimage) {
|
|
||||||
qoi_desc desc;
|
|
||||||
uint8_t* rgba = (uint8_t*)qoi_decode(qoiimage.c_str(), qoiimage.length(), &desc, 4);
|
|
||||||
|
|
||||||
// Resultant width and height stored in descriptor
|
|
||||||
int decodedWidth = desc.width;
|
|
||||||
int decodedHeight = desc.height;
|
|
||||||
|
|
||||||
val result = ImageData.new_(
|
|
||||||
Uint8ClampedArray.new_(typed_memory_view(4 * decodedWidth * decodedHeight, rgba)),
|
|
||||||
decodedWidth, decodedHeight);
|
|
||||||
free(rgba);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_BINDINGS(my_module) {
|
|
||||||
function("decode", &decode);
|
|
||||||
}
|
|
||||||
7
codecs/qoi/dec/qoi_dec.d.ts
vendored
7
codecs/qoi/dec/qoi_dec.d.ts
vendored
@@ -1,7 +0,0 @@
|
|||||||
export interface QOIModule extends EmscriptenWasm.Module {
|
|
||||||
decode(data: BufferSource): ImageData | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare var moduleFactory: EmscriptenWasm.ModuleFactory<QOIModule>;
|
|
||||||
|
|
||||||
export default moduleFactory;
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user