Compare commits

..

1 Commits

Author SHA1 Message Date
Ingvar Stepanyan
8c18b4b28d Try Sentry integration 2020-12-11 12:55:32 +00:00
46 changed files with 463 additions and 295 deletions

View File

@@ -30,7 +30,7 @@ npm run build
You can run the development server with:
```sh
npm run dev
npm start
```
[squoosh]: https://squoosh.app

View File

@@ -183,13 +183,9 @@ function progressTracker(results) {
return tracker;
}
async function getInputFiles(paths) {
async function checkInputFilesValid(files) {
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);
@@ -206,13 +202,12 @@ async function getInputFiles(paths) {
validFiles.push(file);
}
}
return validFiles;
}
async function processFiles(files) {
files = await getInputFiles(files);
files = await checkInputFilesValid(files);
const parallelism = cpus().length;

View File

@@ -24,7 +24,7 @@ function jobPromise(worker, msg) {
export default class WorkerPool {
constructor(numWorkers, workerFile) {
this.numWorkers = numWorkers;
this.closing = false;
this.jobQueue = new TransformStream();
this.workerQueue = new TransformStream();
@@ -42,6 +42,7 @@ export default class WorkerPool {
while (true) {
const { value, done } = await reader.read();
if (done) {
this.workerQueue.writable.close();
await this._terminateAll();
return;
}
@@ -49,6 +50,12 @@ export default class WorkerPool {
const worker = await this._nextWorker();
jobPromise(worker, msg).then((result) => {
resolve(result);
// If we are in the process of closing, `workerQueue` is
// already closed and we cant requeue the worker.
if (this.closing) {
worker.terminate();
return;
}
const writer = this.workerQueue.writable.getWriter();
writer.write(worker);
writer.releaseLock();
@@ -64,15 +71,18 @@ export default class WorkerPool {
}
async _terminateAll() {
for (let n = 0; n < this.numWorkers; n++) {
while (true) {
const worker = await this._nextWorker();
if (!worker) {
return;
}
worker.terminate();
}
this.workerQueue.writable.close();
}
async join() {
this.jobQueue.writable.getWriter().close();
this.closing = true;
this.jobQueue.writable.close();
await this.done;
}

View File

@@ -1,5 +1,5 @@
CODEC_URL = https://gitlab.com/wg1/jpeg-xl.git
CODEC_VERSION = v0.2
CODEC_VERSION = 739e6cd1305fdec5acfa47ad414189b3d3ecb6a4
CODEC_DIR = node_modules/jxl
CODEC_BUILD_ROOT := $(CODEC_DIR)/build
CODEC_MT_BUILD_DIR := $(CODEC_BUILD_ROOT)/mt
@@ -41,6 +41,8 @@ $(OUT_JS):
-I $(CODEC_BUILD_DIR)/lib/include \
-I $(CODEC_DIR)/third_party/highway \
-I $(CODEC_DIR)/third_party/skcms \
-I $(CODEC_DIR)/third_party/brunsli \
-I $(CODEC_DIR)/third_party/brunsli/c/include \
--bind \
--closure 1 \
-s ALLOW_MEMORY_GROWTH=1 \
@@ -51,6 +53,9 @@ $(OUT_JS):
-s EXPORT_NAME="$(basename $(@F))" \
-o $@ \
$+ \
$(CODEC_BUILD_DIR)/artifacts/libbrunslienc-static.bc \
$(CODEC_BUILD_DIR)/artifacts/libbrunslicommon-static.bc \
$(CODEC_BUILD_DIR)/artifacts/libbrunslidec-static.bc \
$(CODEC_BUILD_DIR)/third_party/brotli/libbrotlidec-static.a \
$(CODEC_BUILD_DIR)/third_party/brotli/libbrotlienc-static.a \
$(CODEC_BUILD_DIR)/third_party/brotli/libbrotlicommon-static.a \

View File

@@ -69,7 +69,6 @@ val decode(std::string data) {
icc_profile.data(), icc_profile.size()));
auto float_pixels = std::make_unique<float[]>(component_count);
EXPECT_EQ(JXL_DEC_NEED_IMAGE_OUT_BUFFER, JxlDecoderProcessInput(dec.get(), &next_in, &avail_in));
EXPECT_EQ(JXL_DEC_SUCCESS, JxlDecoderSetImageOutBuffer(dec.get(), &format, float_pixels.get(),
component_count * sizeof(float)));
EXPECT_EQ(JXL_DEC_FULL_IMAGE, JxlDecoderProcessInput(dec.get(), &next_in, &avail_in));

Binary file not shown.

Binary file not shown.

View File

@@ -102,8 +102,8 @@ val encode(std::string image, int width, int height, JXLOptions options) {
auto result = jxl::ConvertImage(
jxl::Span<const uint8_t>(reinterpret_cast<const uint8_t*>(image.data()), image.size()), width,
height, jxl::ColorEncoding::SRGB(/*is_gray=*/false), /*has_alpha=*/true,
/*alpha_is_premultiplied=*/false, /*bits_per_sample=*/8, JXL_LITTLE_ENDIAN,
/*flipped_y=*/false, pool_ptr, main);
/*alpha_is_premultiplied=*/false, /*bits_per_alpha=*/8, /*bits_per_sample=*/8,
/*big_endian=*/false, /*flipped_y=*/false, pool_ptr, main);
if (!result) {
return val::null();

Binary file not shown.

View File

@@ -17,7 +17,7 @@ function Da(a){return 2*a.length}function Ea(a,b){for(var c=0,d="";!(c>=b/4);){v
function Ga(a){for(var b=0,c=0;c<a.length;++c){var d=a.charCodeAt(c);55296<=d&&57343>=d&&++c;b+=4}return b}function Ha(a,b){e().set(a,b)}var n,aa,ba,ca,fa,ha,ia,ka,ma;function u(a){n=a;D.HEAP8=aa=new Int8Array(a);D.HEAP16=ca=new Int16Array(a);D.HEAP32=ha=new Int32Array(a);D.HEAPU8=ba=new Uint8Array(a);D.HEAPU16=fa=new Uint16Array(a);D.HEAPU32=ia=new Uint32Array(a);D.HEAPF32=ka=new Float32Array(a);D.HEAPF64=ma=new Float64Array(a)}var Ia=D.INITIAL_MEMORY||16777216;
if(G)m=D.wasmMemory,n=D.buffer;else if(D.wasmMemory)m=D.wasmMemory;else if(m=new WebAssembly.Memory({initial:Ia/65536,maximum:32768,shared:!0}),!(m.buffer instanceof SharedArrayBuffer))throw J("requested a shared WebAssembly.Memory but the returned buffer is not a SharedArrayBuffer, indicating that while the browser has SharedArrayBuffer it does not have WebAssembly threads support - you may need to set a flag"),Error("bad memory");m&&(n=m.buffer);Ia=n.byteLength;u(n);var M,Ja=[],Ka=[],La=[],Ma=[];
function Na(){var a=D.preRun.shift();Ja.unshift(a)}var N=0,Oa=null,Pa=null;D.preloadedImages={};D.preloadedAudios={};function K(a){if(D.onAbort)D.onAbort(a);G&&console.error("Pthread aborting at "+Error().stack);J(a);va=!0;a=new WebAssembly.RuntimeError("abort("+a+"). Build with -s ASSERTIONS=1 for more info.");oa(a);throw a;}function Qa(){var a=O;return String.prototype.startsWith?a.startsWith("data:application/octet-stream;base64,"):0===a.indexOf("data:application/octet-stream;base64,")}var O="jxl_enc_mt.wasm";
Qa()||(O=qa(O));function Ra(){try{if(ta)return new Uint8Array(ta);if(ra)return ra(O);throw"both async and sync fetching of the wasm failed";}catch(a){K(a)}}function Sa(){return ta||"function"!==typeof fetch?Promise.resolve().then(Ra):fetch(O,{credentials:"same-origin"}).then(function(a){if(!a.ok)throw"failed to load wasm binary file at '"+O+"'";return a.arrayBuffer()}).catch(function(){return Ra()})}var Ua={60853:function(a,b){setTimeout(function(){Ta(a,b)},0)},60931:function(){throw"Canceled!";}};
Qa()||(O=qa(O));function Ra(){try{if(ta)return new Uint8Array(ta);if(ra)return ra(O);throw"both async and sync fetching of the wasm failed";}catch(a){K(a)}}function Sa(){return ta||"function"!==typeof fetch?Promise.resolve().then(Ra):fetch(O,{credentials:"same-origin"}).then(function(a){if(!a.ok)throw"failed to load wasm binary file at '"+O+"'";return a.arrayBuffer()}).catch(function(){return Ra()})}var Ua={60341:function(a,b){setTimeout(function(){Ta(a,b)},0)},60419:function(){throw"Canceled!";}};
function Va(a){for(;0<a.length;){var b=a.shift();if("function"==typeof b)b(D);else{var c=b.Bb;"number"===typeof c?void 0===b.Va?M.get(c)():M.get(c)(b.Va):c(void 0===b.Va?null:b.Va)}}}function Wa(a,b,c){var d;-1!=a.indexOf("j")?d=c&&c.length?D["dynCall_"+a].apply(null,[b].concat(c)):D["dynCall_"+a].call(null,b):d=M.get(b).apply(null,c);return d}D.dynCall=Wa;var P=0,Xa=0,Ya=0;function Za(a,b,c){P=a|0;Ya=b|0;Xa=c|0}D.registerPthreadPtr=Za;
function $a(a,b){if(0>=a||a>e().length||a&1||0>b)return-28;if(0==b)return 0;2147483647<=b&&(b=Infinity);var c=Atomics.load(A(),Q.rb>>2),d=0;if(c==a&&Atomics.compareExchange(A(),Q.rb>>2,c,0)==c&&(--b,d=1,0>=b))return 1;a=Atomics.notify(A(),a>>2,b);if(0<=a)return a+d;throw"Atomics.notify returned an unexpected value "+a;}D._emscripten_futex_wake=$a;
function ab(a){if(G)throw"Internal Error! cleanupThread() can only ever be called from main application thread!";if(!a)throw"Internal Error! Null pthread_ptr in cleanupThread!";A()[a+12>>2]=0;(a=Q.Oa[a])&&Q.bb(a.worker)}
@@ -98,7 +98,7 @@ D._emscripten_sync_run_in_main_thread_1=function(){return(D._emscripten_sync_run
D._emscripten_sync_run_in_main_thread_3=function(){return(D._emscripten_sync_run_in_main_thread_3=D.asm.va).apply(null,arguments)};var Ec=D._emscripten_sync_run_in_main_thread_4=function(){return(Ec=D._emscripten_sync_run_in_main_thread_4=D.asm.wa).apply(null,arguments)};D._emscripten_sync_run_in_main_thread_5=function(){return(D._emscripten_sync_run_in_main_thread_5=D.asm.xa).apply(null,arguments)};
D._emscripten_sync_run_in_main_thread_6=function(){return(D._emscripten_sync_run_in_main_thread_6=D.asm.ya).apply(null,arguments)};D._emscripten_sync_run_in_main_thread_7=function(){return(D._emscripten_sync_run_in_main_thread_7=D.asm.za).apply(null,arguments)};
var Ub=D._emscripten_run_in_main_runtime_thread_js=function(){return(Ub=D._emscripten_run_in_main_runtime_thread_js=D.asm.Aa).apply(null,arguments)},$b=D.__emscripten_call_on_thread=function(){return($b=D.__emscripten_call_on_thread=D.asm.Ba).apply(null,arguments)};D._emscripten_tls_init=function(){return(D._emscripten_tls_init=D.asm.Ca).apply(null,arguments)};D.dynCall_viijii=function(){return(D.dynCall_viijii=D.asm.Da).apply(null,arguments)};
D.dynCall_iiji=function(){return(D.dynCall_iiji=D.asm.Ea).apply(null,arguments)};D.dynCall_jiji=function(){return(D.dynCall_jiji=D.asm.Fa).apply(null,arguments)};D.dynCall_iiiiiijj=function(){return(D.dynCall_iiiiiijj=D.asm.Ga).apply(null,arguments)};D.dynCall_iiiiij=function(){return(D.dynCall_iiiiij=D.asm.Ha).apply(null,arguments)};D.dynCall_iiiiijj=function(){return(D.dynCall_iiiiijj=D.asm.Ia).apply(null,arguments)};var cb=D._main_thread_futex=3060568;D.PThread=Q;D.PThread=Q;D._pthread_self=pc;
D.dynCall_iiji=function(){return(D.dynCall_iiji=D.asm.Ea).apply(null,arguments)};D.dynCall_jiji=function(){return(D.dynCall_jiji=D.asm.Fa).apply(null,arguments)};D.dynCall_iiiiiijj=function(){return(D.dynCall_iiiiiijj=D.asm.Ga).apply(null,arguments)};D.dynCall_iiiiij=function(){return(D.dynCall_iiiiij=D.asm.Ha).apply(null,arguments)};D.dynCall_iiiiijj=function(){return(D.dynCall_iiiiijj=D.asm.Ia).apply(null,arguments)};var cb=D._main_thread_futex=3060056;D.PThread=Q;D.PThread=Q;D._pthread_self=pc;
D.wasmMemory=m;D.ExitStatus=Hc;var Ic;function Hc(a){this.name="ExitStatus";this.message="Program terminated with exit("+a+")";this.status=a}Pa=function Jc(){Ic||Kc();Ic||(Pa=Jc)};
function Kc(){function a(){if(!Ic&&(Ic=!0,D.calledRun=!0,!va)){Va(Ka);G||Va(La);na(D);if(D.onRuntimeInitialized)D.onRuntimeInitialized();if(!G){if(D.postRun)for("function"==typeof D.postRun&&(D.postRun=[D.postRun]);D.postRun.length;){var b=D.postRun.shift();Ma.unshift(b)}Va(Ma)}}}if(!(0<N)){if(!G){if(D.preRun)for("function"==typeof D.preRun&&(D.preRun=[D.preRun]);D.preRun.length;)Na();Va(Ja)}0<N||(D.setStatus?(D.setStatus("Running..."),setTimeout(function(){setTimeout(function(){D.setStatus("")},
1);a()},1)):a())}}D.run=Kc;if(D.preInit)for("function"==typeof D.preInit&&(D.preInit=[D.preInit]);0<D.preInit.length;)D.preInit.pop()();G||(noExitRuntime=!0);G?Q.Lb():Kc();

Binary file not shown.

View File

@@ -17,7 +17,7 @@ function Da(a){return 2*a.length}function Ea(a,b){for(var c=0,d="";!(c>=b/4);){v
function Ga(a){for(var b=0,c=0;c<a.length;++c){var d=a.charCodeAt(c);55296<=d&&57343>=d&&++c;b+=4}return b}function Ha(a,b){e().set(a,b)}var n,aa,ba,ca,fa,ha,ia,ka,ma;function u(a){n=a;D.HEAP8=aa=new Int8Array(a);D.HEAP16=ca=new Int16Array(a);D.HEAP32=ha=new Int32Array(a);D.HEAPU8=ba=new Uint8Array(a);D.HEAPU16=fa=new Uint16Array(a);D.HEAPU32=ia=new Uint32Array(a);D.HEAPF32=ka=new Float32Array(a);D.HEAPF64=ma=new Float64Array(a)}var Ia=D.INITIAL_MEMORY||16777216;
if(G)m=D.wasmMemory,n=D.buffer;else if(D.wasmMemory)m=D.wasmMemory;else if(m=new WebAssembly.Memory({initial:Ia/65536,maximum:32768,shared:!0}),!(m.buffer instanceof SharedArrayBuffer))throw J("requested a shared WebAssembly.Memory but the returned buffer is not a SharedArrayBuffer, indicating that while the browser has SharedArrayBuffer it does not have WebAssembly threads support - you may need to set a flag"),Error("bad memory");m&&(n=m.buffer);Ia=n.byteLength;u(n);var M,Ja=[],Ka=[],La=[],Ma=[];
function Na(){var a=D.preRun.shift();Ja.unshift(a)}var N=0,Oa=null,Pa=null;D.preloadedImages={};D.preloadedAudios={};function K(a){if(D.onAbort)D.onAbort(a);G&&console.error("Pthread aborting at "+Error().stack);J(a);va=!0;a=new WebAssembly.RuntimeError("abort("+a+"). Build with -s ASSERTIONS=1 for more info.");oa(a);throw a;}function Qa(){var a=O;return String.prototype.startsWith?a.startsWith("data:application/octet-stream;base64,"):0===a.indexOf("data:application/octet-stream;base64,")}var O="jxl_enc_mt_simd.wasm";
Qa()||(O=qa(O));function Ra(){try{if(ta)return new Uint8Array(ta);if(ra)return ra(O);throw"both async and sync fetching of the wasm failed";}catch(a){K(a)}}function Sa(){return ta||"function"!==typeof fetch?Promise.resolve().then(Ra):fetch(O,{credentials:"same-origin"}).then(function(a){if(!a.ok)throw"failed to load wasm binary file at '"+O+"'";return a.arrayBuffer()}).catch(function(){return Ra()})}var Ua={60933:function(a,b){setTimeout(function(){Ta(a,b)},0)},61011:function(){throw"Canceled!";}};
Qa()||(O=qa(O));function Ra(){try{if(ta)return new Uint8Array(ta);if(ra)return ra(O);throw"both async and sync fetching of the wasm failed";}catch(a){K(a)}}function Sa(){return ta||"function"!==typeof fetch?Promise.resolve().then(Ra):fetch(O,{credentials:"same-origin"}).then(function(a){if(!a.ok)throw"failed to load wasm binary file at '"+O+"'";return a.arrayBuffer()}).catch(function(){return Ra()})}var Ua={60389:function(a,b){setTimeout(function(){Ta(a,b)},0)},60467:function(){throw"Canceled!";}};
function Va(a){for(;0<a.length;){var b=a.shift();if("function"==typeof b)b(D);else{var c=b.Bb;"number"===typeof c?void 0===b.Va?M.get(c)():M.get(c)(b.Va):c(void 0===b.Va?null:b.Va)}}}function Wa(a,b,c){var d;-1!=a.indexOf("j")?d=c&&c.length?D["dynCall_"+a].apply(null,[b].concat(c)):D["dynCall_"+a].call(null,b):d=M.get(b).apply(null,c);return d}D.dynCall=Wa;var P=0,Xa=0,Ya=0;function Za(a,b,c){P=a|0;Ya=b|0;Xa=c|0}D.registerPthreadPtr=Za;
function $a(a,b){if(0>=a||a>e().length||a&1||0>b)return-28;if(0==b)return 0;2147483647<=b&&(b=Infinity);var c=Atomics.load(A(),Q.rb>>2),d=0;if(c==a&&Atomics.compareExchange(A(),Q.rb>>2,c,0)==c&&(--b,d=1,0>=b))return 1;a=Atomics.notify(A(),a>>2,b);if(0<=a)return a+d;throw"Atomics.notify returned an unexpected value "+a;}D._emscripten_futex_wake=$a;
function ab(a){if(G)throw"Internal Error! cleanupThread() can only ever be called from main application thread!";if(!a)throw"Internal Error! Null pthread_ptr in cleanupThread!";A()[a+12>>2]=0;(a=Q.Oa[a])&&Q.bb(a.worker)}
@@ -99,7 +99,7 @@ D._emscripten_sync_run_in_main_thread_1=function(){return(D._emscripten_sync_run
D._emscripten_sync_run_in_main_thread_3=function(){return(D._emscripten_sync_run_in_main_thread_3=D.asm.va).apply(null,arguments)};var Ec=D._emscripten_sync_run_in_main_thread_4=function(){return(Ec=D._emscripten_sync_run_in_main_thread_4=D.asm.wa).apply(null,arguments)};D._emscripten_sync_run_in_main_thread_5=function(){return(D._emscripten_sync_run_in_main_thread_5=D.asm.xa).apply(null,arguments)};
D._emscripten_sync_run_in_main_thread_6=function(){return(D._emscripten_sync_run_in_main_thread_6=D.asm.ya).apply(null,arguments)};D._emscripten_sync_run_in_main_thread_7=function(){return(D._emscripten_sync_run_in_main_thread_7=D.asm.za).apply(null,arguments)};
var Ub=D._emscripten_run_in_main_runtime_thread_js=function(){return(Ub=D._emscripten_run_in_main_runtime_thread_js=D.asm.Aa).apply(null,arguments)},$b=D.__emscripten_call_on_thread=function(){return($b=D.__emscripten_call_on_thread=D.asm.Ba).apply(null,arguments)};D._emscripten_tls_init=function(){return(D._emscripten_tls_init=D.asm.Ca).apply(null,arguments)};D.dynCall_viijii=function(){return(D.dynCall_viijii=D.asm.Da).apply(null,arguments)};
D.dynCall_iiji=function(){return(D.dynCall_iiji=D.asm.Ea).apply(null,arguments)};D.dynCall_jiji=function(){return(D.dynCall_jiji=D.asm.Fa).apply(null,arguments)};D.dynCall_iiiiiijj=function(){return(D.dynCall_iiiiiijj=D.asm.Ga).apply(null,arguments)};D.dynCall_iiiiij=function(){return(D.dynCall_iiiiij=D.asm.Ha).apply(null,arguments)};D.dynCall_iiiiijj=function(){return(D.dynCall_iiiiijj=D.asm.Ia).apply(null,arguments)};var cb=D._main_thread_futex=3060648;D.PThread=Q;D.PThread=Q;D._pthread_self=pc;
D.dynCall_iiji=function(){return(D.dynCall_iiji=D.asm.Ea).apply(null,arguments)};D.dynCall_jiji=function(){return(D.dynCall_jiji=D.asm.Fa).apply(null,arguments)};D.dynCall_iiiiiijj=function(){return(D.dynCall_iiiiiijj=D.asm.Ga).apply(null,arguments)};D.dynCall_iiiiij=function(){return(D.dynCall_iiiiij=D.asm.Ha).apply(null,arguments)};D.dynCall_iiiiijj=function(){return(D.dynCall_iiiiijj=D.asm.Ia).apply(null,arguments)};var cb=D._main_thread_futex=3060104;D.PThread=Q;D.PThread=Q;D._pthread_self=pc;
D.wasmMemory=m;D.ExitStatus=Hc;var Ic;function Hc(a){this.name="ExitStatus";this.message="Program terminated with exit("+a+")";this.status=a}Pa=function Jc(){Ic||Kc();Ic||(Pa=Jc)};
function Kc(){function a(){if(!Ic&&(Ic=!0,D.calledRun=!0,!va)){Va(Ka);G||Va(La);na(D);if(D.onRuntimeInitialized)D.onRuntimeInitialized();if(!G){if(D.postRun)for("function"==typeof D.postRun&&(D.postRun=[D.postRun]);D.postRun.length;){var b=D.postRun.shift();Ma.unshift(b)}Va(Ma)}}}if(!(0<N)){if(!G){if(D.preRun)for("function"==typeof D.preRun&&(D.preRun=[D.preRun]);D.preRun.length;)Na();Va(Ja)}0<N||(D.setStatus?(D.setStatus("Running..."),setTimeout(function(){setTimeout(function(){D.setStatus("")},
1);a()},1)):a())}}D.run=Kc;if(D.preInit)for("function"==typeof D.preInit&&(D.preInit=[D.preInit]);0<D.preInit.length;)D.preInit.pop()();G||(noExitRuntime=!0);G?Q.Lb():Kc();

Binary file not shown.

Binary file not shown.

View File

@@ -20,9 +20,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bit-vec"
version = "0.6.3"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
checksum = "5f0dc55f2d8a1a85650ac47858bb001b4c0dd73d79e3c455a842925e68d29cd3"
[[package]]
name = "bitflags"
@@ -56,9 +56,9 @@ checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
[[package]]
name = "cc"
version = "1.0.66"
version = "1.0.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
checksum = "f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40"
[[package]]
name = "cfg-if"
@@ -98,9 +98,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]]
name = "const_fn"
version = "0.4.5"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6"
checksum = "c478836e029dcef17fb47c89023448c64f781a046e0300e257ad8225ae59afab"
[[package]]
name = "crc"
@@ -143,9 +143,9 @@ dependencies = [
[[package]]
name = "crossbeam-epoch"
version = "0.9.1"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d"
checksum = "ec0f606a85340376eef0d6d8fec399e6d4a544d648386c6645eb6d0653b27d9f"
dependencies = [
"cfg-if 1.0.0",
"const_fn",
@@ -157,12 +157,13 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
version = "0.8.1"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"
checksum = "ec91540d98355f690a86367e566ecad2e9e579f230230eb7c21398372be73ea5"
dependencies = [
"autocfg",
"cfg-if 1.0.0",
"const_fn",
"lazy_static",
]
@@ -199,9 +200,9 @@ dependencies = [
[[package]]
name = "image"
version = "0.23.12"
version = "0.23.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ce04077ead78e39ae8610ad26216aed811996b043d47beed5090db674f9e9b5"
checksum = "b4f0a8345b33b082aedec2f4d7d4a926b845cee184cbe78b703413066564431b"
dependencies = [
"bytemuck",
"byteorder",
@@ -214,9 +215,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "1.6.1"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b"
checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2"
dependencies = [
"autocfg",
"hashbrown",
@@ -225,9 +226,9 @@ dependencies = [
[[package]]
name = "itertools"
version = "0.10.0"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319"
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
dependencies = [
"either",
]
@@ -240,24 +241,24 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.81"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
[[package]]
name = "libdeflate-sys"
version = "0.7.1"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a95fa4be7085dd06a8296dcc3f399f12ab8b0309c157dcaa90669130b175b97"
checksum = "2f5b1582a0ebf8c55a46166c04d7c66f6bb17add3a6cbf69a082ac2219f31671"
dependencies = [
"cc",
]
[[package]]
name = "libdeflater"
version = "0.7.1"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccc147465654929bf7b56518cc46d11701ba290f4ff94398ae3f89f1663cf60f"
checksum = "93edd93a53970951da84ef733a8b6e30189a8f8a9e19610f69e4cc5bb1f4d654"
dependencies = [
"libdeflate-sys",
]
@@ -273,9 +274,9 @@ dependencies = [
[[package]]
name = "memoffset"
version = "0.6.1"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa"
dependencies = [
"autocfg",
]
@@ -358,9 +359,9 @@ checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
[[package]]
name = "oxipng"
version = "4.0.3"
version = "4.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d0b53912a666fe2970f8ab254e283531c816aed16551ab66c52485eadb44e6"
checksum = "9fefb26bde273c3db896a313151301a69e698a7495ee577fe2168ed7065c29c4"
dependencies = [
"bit-vec",
"byteorder",
@@ -389,9 +390,9 @@ dependencies = [
[[package]]
name = "png"
version = "0.16.8"
version = "0.16.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6"
checksum = "dfe7f9f1c730833200b134370e1d5098964231af8450bce9b78ee3ab5278b970"
dependencies = [
"bitflags",
"crc32fast",
@@ -410,9 +411,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.8"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df"
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
dependencies = [
"proc-macro2",
]
@@ -477,9 +478,9 @@ dependencies = [
[[package]]
name = "semver-parser"
version = "0.10.2"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
checksum = "42ef146c2ad5e5f4b037cd6ce2ebb775401729b19a82040c1beac9d36c7d1428"
dependencies = [
"pest",
]
@@ -489,7 +490,6 @@ name = "squoosh-oxipng"
version = "0.1.0"
dependencies = [
"crossbeam-channel",
"libdeflater",
"log",
"once_cell",
"oxipng",
@@ -499,9 +499,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.58"
version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5"
checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac"
dependencies = [
"proc-macro2",
"quote",
@@ -522,19 +522,19 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "wasm-bindgen"
version = "0.2.69"
version = "0.2.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e"
checksum = "1ac64ead5ea5f05873d7c12b545865ca2b8d28adfc50a49b84770a3a97265d42"
dependencies = [
"cfg-if 1.0.0",
"cfg-if 0.1.10",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.69"
version = "0.2.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62"
checksum = "f22b422e2a757c35a73774860af8e112bff612ce6cb604224e8e47641a9e4f68"
dependencies = [
"bumpalo",
"lazy_static",
@@ -547,9 +547,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.69"
version = "0.2.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084"
checksum = "6b13312a745c08c469f0b292dd2fcd6411dba5f7160f593da6ef69b64e407038"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -557,9 +557,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.69"
version = "0.2.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549"
checksum = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe"
dependencies = [
"proc-macro2",
"quote",
@@ -570,6 +570,6 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.69"
version = "0.2.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158"
checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307"

View File

@@ -12,8 +12,7 @@ wasm-opt = ["-O", "--no-validation"]
crate-type = ["cdylib"]
[dependencies]
oxipng = { version = "4.0.1", default-features = false, features = ["libdeflater"] }
libdeflater = { version = "0.7.1", features = ["freestanding"] }
oxipng = { version = "4.0.0", default-features = false, features = ["libdeflater"] }
wasm-bindgen = "0.2.68"
log = { version = "0.4.11", features = ["release_max_level_off"] }
rayon = { version = "1.5.0", optional = true }

0
codecs/oxipng/build.sh Executable file → Normal file
View File

View File

@@ -22,6 +22,8 @@ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembl
export interface InitOutput {
readonly optimise: (a: number, b: number, c: number, d: number) => void;
readonly malloc: (a: number) => number;
readonly free: (a: number) => void;
readonly worker_initializer: (a: number) => number;
readonly start_main_thread: () => void;
readonly start_worker_thread: () => void;

View File

@@ -1,6 +1,8 @@
/* tslint:disable */
/* eslint-disable */
export function optimise(a: number, b: number, c: number, d: number): void;
export function malloc(a: number): number;
export function free(a: number): void;
export function worker_initializer(a: number): number;
export function start_main_thread(): void;
export function start_worker_thread(): void;

View File

@@ -12,6 +12,8 @@ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembl
export interface InitOutput {
readonly memory: WebAssembly.Memory;
readonly optimise: (a: number, b: number, c: number, d: number) => void;
readonly malloc: (a: number) => number;
readonly free: (a: number) => void;
readonly __wbindgen_malloc: (a: number) => number;
readonly __wbindgen_free: (a: number, b: number) => void;
}

View File

@@ -2,5 +2,7 @@
/* eslint-disable */
export const memory: WebAssembly.Memory;
export function optimise(a: number, b: number, c: number, d: number): void;
export function malloc(a: number): number;
export function free(a: number): void;
export function __wbindgen_malloc(a: number): number;
export function __wbindgen_free(a: number, b: number): void;

View File

@@ -1,6 +1,8 @@
use oxipng::AlphaOptim;
use wasm_bindgen::prelude::*;
mod malloc_shim;
#[cfg(feature = "parallel")]
pub mod parallel;

View File

@@ -0,0 +1,47 @@
//! This is a module that provides `malloc` and `free` for `libdeflate`.
//! These implementations are compatible with the standard signatures
//! but use Rust allocator instead of including libc one as well.
//!
//! Rust allocator APIs requires passing size and alignment to the
//! `dealloc` function. This is different from C API, which only
//! expects a pointer in `free` and expects allocators to take care of
//! storing any necessary information elsewhere.
//!
//! In order to simulate C API, we allocate a `size_and_data_ptr`
//! of size `sizeof(usize) + size` where `size` is the requested number
//! of bytes. Then, we store `size` at the beginning of the allocated
//! chunk (within those `sizeof(usize)` bytes) and return
//! `data_ptr = size_and_data_ptr + sizeof(usize)` to the calleer:
//!
//! [`size`][...actual data]
//! -^------------------ `size_and_data_ptr`
//! ---------^---------- `data_ptr`
//!
//! Then, in `free`, the caller gives us `data_ptr`. We can subtract
//! `sizeof(usize)` back and get the original `size_and_data_ptr`.
//! At this point we can read `size` back and call the Rust `dealloc`
//! for the whole allocated chunk.
//!
//! I've raised an upstream issue to hopefully make this easier in
//! future: https://github.com/ebiggers/libdeflate/issues/62
use std::alloc::*;
use std::mem::{align_of, size_of};
unsafe fn layout_for(size: usize) -> Layout {
Layout::from_size_align_unchecked(size_of::<usize>() + size, align_of::<usize>())
}
#[no_mangle]
pub unsafe extern "C" fn malloc(size: usize) -> *mut u8 {
let size_and_data_ptr = alloc(layout_for(size));
*(size_and_data_ptr as *mut usize) = size;
size_and_data_ptr.add(size_of::<usize>())
}
#[no_mangle]
pub unsafe extern "C" fn free(data_ptr: *mut u8) {
let size_and_data_ptr = data_ptr.sub(size_of::<usize>());
let size = *(size_and_data_ptr as *const usize);
dealloc(size_and_data_ptr, layout_for(size))
}

View File

@@ -6,12 +6,6 @@ version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820"
[[package]]
name = "bytemuck"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41aa2ec95ca3b5c54cf73c91acf06d24f4495d5f1b1c12506ae3483d646177ac"
[[package]]
name = "cfg-if"
version = "0.1.10"
@@ -108,21 +102,9 @@ dependencies = [
[[package]]
name = "resize"
version = "0.5.5"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2a08c42ea86684dc00256494c4eb8b54707890ddac50c05060a717f29669029"
dependencies = [
"rgb",
]
[[package]]
name = "rgb"
version = "0.8.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "287f3c3f8236abb92d8b7e36797f19159df4b58f0a658cc3fb6dd3004b1f3bd3"
dependencies = [
"bytemuck",
]
checksum = "b9e653e390eafbfebb2b3c5fcfbc90d801bc410d0de1f44f266ffbf2151d28aa"
[[package]]
name = "scoped-tls"

View File

@@ -14,7 +14,7 @@ default = ["console_error_panic_hook", "wee_alloc"]
[dependencies]
cfg-if = "0.1.2"
wasm-bindgen = "0.2.38"
resize = "0.5.5"
resize = "0.3.0"
# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires

View File

@@ -4,14 +4,20 @@ use std::io::Write;
fn main() -> std::io::Result<()> {
let mut srgb_to_linear_lut = String::from("static SRGB_TO_LINEAR_LUT: [f32; 256] = [");
let mut linear_to_srgb_lut = String::from("static LINEAR_TO_SRGB_LUT: [f32; 256] = [");
for i in 0..256 {
srgb_to_linear_lut.push_str(&format!("{0:.7}", srgb_to_linear((i as f32) / 255.0)));
srgb_to_linear_lut.push_str(",");
linear_to_srgb_lut.push_str(&format!("{0:.7}", linear_to_srgb((i as f32) / 255.0)));
linear_to_srgb_lut.push_str(",");
}
srgb_to_linear_lut.pop().unwrap();
linear_to_srgb_lut.pop().unwrap();
srgb_to_linear_lut.push_str("];");
linear_to_srgb_lut.push_str("];");
let mut file = std::fs::File::create("src/lut.inc")?;
file.write_all(srgb_to_linear_lut.as_bytes())?;
file.write_all(linear_to_srgb_lut.as_bytes())?;
Ok(())
}

View File

@@ -11,13 +11,38 @@
* @param {boolean} color_space_conversion
* @returns {Uint8Array}
*/
export function resize(input_image: Uint8Array, input_width: number, input_height: number, output_width: number, output_height: number, typ_idx: number, premultiply: boolean, color_space_conversion: boolean): Uint8Array;
export function resize(
input_image: Uint8Array,
input_width: number,
input_height: number,
output_width: number,
output_height: number,
typ_idx: number,
premultiply: boolean,
color_space_conversion: boolean,
): Uint8Array;
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
export type InitInput =
| RequestInfo
| URL
| Response
| BufferSource
| WebAssembly.Module;
export interface InitOutput {
readonly memory: WebAssembly.Memory;
readonly resize: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number) => void;
readonly resize: (
a: number,
b: number,
c: number,
d: number,
e: number,
f: number,
g: number,
h: number,
i: number,
j: number,
) => void;
readonly __wbindgen_malloc: (a: number) => number;
readonly __wbindgen_free: (a: number, b: number) => void;
}
@@ -30,5 +55,6 @@ export interface 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>;

View File

@@ -1,9 +1,11 @@
let wasm;
let cachegetUint8Memory0 = null;
function getUint8Memory0() {
if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) {
if (
cachegetUint8Memory0 === null ||
cachegetUint8Memory0.buffer !== wasm.memory.buffer
) {
cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer);
}
return cachegetUint8Memory0;
@@ -20,7 +22,10 @@ function passArray8ToWasm0(arg, malloc) {
let cachegetInt32Memory0 = null;
function getInt32Memory0() {
if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasm.memory.buffer) {
if (
cachegetInt32Memory0 === null ||
cachegetInt32Memory0.buffer !== wasm.memory.buffer
) {
cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer);
}
return cachegetInt32Memory0;
@@ -40,10 +45,30 @@ function getArrayU8FromWasm0(ptr, len) {
* @param {boolean} color_space_conversion
* @returns {Uint8Array}
*/
export function resize(input_image, input_width, input_height, output_width, output_height, typ_idx, premultiply, color_space_conversion) {
export function resize(
input_image,
input_width,
input_height,
output_width,
output_height,
typ_idx,
premultiply,
color_space_conversion,
) {
var ptr0 = passArray8ToWasm0(input_image, wasm.__wbindgen_malloc);
var len0 = WASM_VECTOR_LEN;
wasm.resize(8, ptr0, len0, input_width, input_height, output_width, output_height, typ_idx, premultiply, color_space_conversion);
wasm.resize(
8,
ptr0,
len0,
input_width,
input_height,
output_width,
output_height,
typ_idx,
premultiply,
color_space_conversion,
);
var r0 = getInt32Memory0()[8 / 4 + 0];
var r1 = getInt32Memory0()[8 / 4 + 1];
var v1 = getArrayU8FromWasm0(r0, r1).slice();
@@ -53,15 +78,15 @@ export function resize(input_image, input_width, input_height, output_width, out
async function load(module, imports) {
if (typeof Response === 'function' && module instanceof Response) {
if (typeof WebAssembly.instantiateStreaming === 'function') {
try {
return await WebAssembly.instantiateStreaming(module, imports);
} catch (e) {
if (module.headers.get('Content-Type') != 'application/wasm') {
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
console.warn(
'`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n',
e,
);
} else {
throw e;
}
@@ -70,14 +95,11 @@ async function load(module, imports) {
const bytes = await module.arrayBuffer();
return await WebAssembly.instantiate(bytes, imports);
} else {
const instance = await WebAssembly.instantiate(module, imports);
if (instance instanceof WebAssembly.Instance) {
return { instance, module };
} else {
return instance;
}
@@ -90,8 +112,11 @@ async function init(input) {
}
const imports = {};
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);
}
@@ -104,4 +129,3 @@ async function init(input) {
}
export default init;

View File

@@ -5,12 +5,12 @@ extern crate wasm_bindgen;
mod utils;
use cfg_if::cfg_if;
use resize::Pixel;
use resize::Pixel::RGBA;
use resize::Type;
use wasm_bindgen::prelude::*;
mod srgb;
use srgb::{linear_to_srgb, Clamp};
use srgb::Clamp;
cfg_if! {
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
@@ -27,17 +27,14 @@ include!("./lut.inc");
// If `with_space_conversion` is true, this function returns 2 functions that
// convert from sRGB to linear RGB and vice versa. If `with_space_conversion` is
// false, the 2 functions returned do nothing.
fn srgb_converter_funcs(with_space_conversion: bool) -> (fn(u8) -> f32, fn(f32) -> u8) {
fn converter_funcs(with_space_conversion: bool) -> ((fn(u8) -> f32), (fn(f32) -> u8)) {
if with_space_conversion {
(
|v| SRGB_TO_LINEAR_LUT[v as usize],
|v| (linear_to_srgb(v) * 255.0).clamp(0.0, 255.0) as u8,
|v| SRGB_TO_LINEAR_LUT[v as usize] * 255.0,
|v| (LINEAR_TO_SRGB_LUT[v as usize] * 255.0) as u8,
)
} else {
(
|v| (v as f32) / 255.0,
|v| (v * 255.0).clamp(0.0, 255.0) as u8,
)
(|v| v as f32, |v| v as u8)
}
}
@@ -47,18 +44,21 @@ fn srgb_converter_funcs(with_space_conversion: bool) -> (fn(u8) -> f32, fn(f32)
// false, the functions just return the channel value.
fn alpha_multiplier_funcs(
with_alpha_premultiplication: bool,
) -> (fn(f32, f32) -> f32, fn(f32, f32) -> f32) {
) -> ((fn(f32, u8) -> u8), (fn(u8, u8) -> f32)) {
if with_alpha_premultiplication {
(|v, a| v * a, |v, a| v / a)
(
|v, a| (v * (a as f32) / 255.0) as u8,
|v, a| ((v as f32) * 255.0 / (a as f32)).clamp(0.0, 255.0),
)
} else {
(|v, _a| v, |v, _a| v)
(|v, _a| v as u8, |v, _a| v as f32)
}
}
#[wasm_bindgen]
#[no_mangle]
pub fn resize(
input_image: Vec<u8>,
mut input_image: Vec<u8>,
input_width: usize,
input_height: usize,
output_width: usize,
@@ -77,64 +77,44 @@ pub fn resize(
let num_input_pixels = input_width * input_height;
let num_output_pixels = output_width * output_height;
let mut output_image = vec![0u8; num_output_pixels * 4];
// If both options are false, there is no preprocessing on the pixel values
// and we can skip the loop.
if !premultiply && !color_space_conversion {
let mut resizer = resize::new(
input_width,
input_height,
output_width,
output_height,
Pixel::RGBA,
typ,
);
resizer.resize(input_image.as_slice(), output_image.as_mut_slice());
return output_image;
}
// Otherwise, we convert to f32 images to keep the
// conversions as lossless and high-fidelity as possible.
let (to_linear, to_srgb) = srgb_converter_funcs(color_space_conversion);
let (to_linear, to_color_space) = converter_funcs(color_space_conversion);
let (premultiplier, demultiplier) = alpha_multiplier_funcs(premultiply);
let mut preprocessed_input_image: Vec<f32> = Vec::with_capacity(input_image.len());
preprocessed_input_image.resize(input_image.len(), 0.0f32);
// If both options are false, there is no preprocessing on the pixel valus
// and we can skip the loop.
if premultiply || color_space_conversion {
for i in 0..num_input_pixels {
for j in 0..3 {
preprocessed_input_image[4 * i + j] = premultiplier(
to_linear(input_image[4 * i + j]),
(input_image[4 * i + 3] as f32) / 255.0,
);
input_image[4 * i + j] =
premultiplier(to_linear(input_image[4 * i + j]), input_image[4 * i + 3]);
}
}
preprocessed_input_image[4 * i + 3] = (input_image[4 * i + 3] as f32) / 255.0;
}
let mut unprocessed_output_image = vec![0.0f32; num_output_pixels * 4];
let mut resizer = resize::new(
input_width,
input_height,
output_width,
output_height,
Pixel::RGBAF32,
RGBA,
typ,
);
resizer.resize(
preprocessed_input_image.as_slice(),
unprocessed_output_image.as_mut_slice(),
);
let mut output_image = Vec::<u8>::with_capacity(num_output_pixels * 4);
output_image.resize(num_output_pixels * 4, 0);
resizer.resize(input_image.as_slice(), output_image.as_mut_slice());
if premultiply || color_space_conversion {
for i in 0..num_output_pixels {
for j in 0..3 {
output_image[4 * i + j] = to_srgb(demultiplier(
unprocessed_output_image[4 * i + j],
unprocessed_output_image[4 * i + 3],
// We dont need to worry about division by zero, as division by zero
// is well-defined on floats to return ±Inf. ±Inf is converted to 0
// when casting to integers.
output_image[4 * i + j] = to_color_space(demultiplier(
output_image[4 * i + j],
output_image[4 * i + 3],
));
}
output_image[4 * i + 3] =
(unprocessed_output_image[4 * i + 3] * 255.0).clamp(0.0, 255.0) as u8;
}
}
return output_image;

Binary file not shown.

41
lib/data-url-plugin.js Normal file
View File

@@ -0,0 +1,41 @@
/**
* 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 { lookup as lookupMime } from 'mime-types';
const prefix = 'data-url:';
export default function dataURLPlugin() {
return {
name: 'data-url-plugin',
async resolveId(id, importer) {
if (!id.startsWith(prefix)) return;
return (
prefix + (await this.resolve(id.slice(prefix.length), importer)).id
);
},
async load(id) {
if (!id.startsWith(prefix)) return;
const realId = id.slice(prefix.length);
this.addWatchFile(realId);
const source = await fs.readFile(realId);
const type = lookupMime(realId) || 'text/plain';
return `export default 'data:${type};base64,${source.toString(
'base64',
)}';`;
},
};
}

5
missing-types.d.ts vendored
View File

@@ -32,6 +32,11 @@ declare module 'css:*' {
export default source;
}
declare module 'data-url:*' {
const url: string;
export default url;
}
declare var ga: {
(...args: any[]): void;
q: any[];

60
package-lock.json generated
View File

@@ -166,6 +166,63 @@
"picomatch": "^2.2.2"
}
},
"@sentry/browser": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.29.0.tgz",
"integrity": "sha512-kRlt1mE2wrYjspnIupNnPxqsUrRuy02SuXhbpP7J6uu8QasoEmJ78hk0hHz4jOZRmuWwfs2zIXD4tLGgWOKq8A==",
"requires": {
"@sentry/core": "5.29.0",
"@sentry/types": "5.29.0",
"@sentry/utils": "5.29.0",
"tslib": "^1.9.3"
}
},
"@sentry/core": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.29.0.tgz",
"integrity": "sha512-a1sZBJ2u3NG0YDlGvOTwUCWiNjhfmDtAQiKK1o6RIIbcrWy9TlSps7CYDkBP239Y3A4pnvohjEEKEP3v3L3LZQ==",
"requires": {
"@sentry/hub": "5.29.0",
"@sentry/minimal": "5.29.0",
"@sentry/types": "5.29.0",
"@sentry/utils": "5.29.0",
"tslib": "^1.9.3"
}
},
"@sentry/hub": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.29.0.tgz",
"integrity": "sha512-kcDPQsRG4cFdmqDh+TzjeO7lWYxU8s1dZYAbbl1J4uGKmhNB0J7I4ak4SGwTsXLY6fhbierxr6PRaoNojCxjPw==",
"requires": {
"@sentry/types": "5.29.0",
"@sentry/utils": "5.29.0",
"tslib": "^1.9.3"
}
},
"@sentry/minimal": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.29.0.tgz",
"integrity": "sha512-nhXofdjtO41/caiF1wk1oT3p/QuhOZDYdF/b29DoD2MiAMK9IjhhOXI/gqaRpDKkXlDvd95fDTcx4t/MqqcKXA==",
"requires": {
"@sentry/hub": "5.29.0",
"@sentry/types": "5.29.0",
"tslib": "^1.9.3"
}
},
"@sentry/types": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.29.0.tgz",
"integrity": "sha512-iDkxT/9sT3UF+Xb+JyLjZ5caMXsgLfRyV9VXQEiR2J6mgpMielj184d9jeF3bm/VMuAf/VFFqrHlcVsVgmrrMw=="
},
"@sentry/utils": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.29.0.tgz",
"integrity": "sha512-b2B1gshw2u3EHlAi84PuI5sfmLKXW1z9enMMhNuuNT/CoRp+g5kMAcUv/qYTws7UNnYSvTuVGuZG30v1e0hP9A==",
"requires": {
"@sentry/types": "5.29.0",
"tslib": "^1.9.3"
}
},
"@surma/rollup-plugin-off-main-thread": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-1.4.2.tgz",
@@ -6920,8 +6977,7 @@
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
"type-fest": {
"version": "0.11.0",

View File

@@ -55,6 +55,7 @@
"*.rs": "rustfmt"
},
"dependencies": {
"@sentry/browser": "^5.29.0",
"wasm-feature-detect": "^1.2.9"
}
}

View File

@@ -30,6 +30,7 @@ import emitFiles from './lib/emit-files-plugin';
import featurePlugin from './lib/feature-plugin';
import initialCssPlugin from './lib/initial-css-plugin';
import serviceWorkerPlugin from './lib/sw-plugin';
import dataURLPlugin from './lib/data-url-plugin';
import entryDataPlugin from './lib/entry-data-plugin';
function resolveFileUrl({ fileName }) {
@@ -81,6 +82,7 @@ export default async function ({ watch }) {
'codecs',
]),
urlPlugin(),
dataURLPlugin(),
cssPlugin(resolveFileUrl),
];

View File

@@ -12,10 +12,15 @@
*/
import { h, render } from 'preact';
import App from './App';
import { init as initSentry } from '@sentry/browser';
const root = document.getElementById('app') as HTMLElement;
async function main() {
initSentry({
dsn:
'https://1bf731600de64315b8ac4d38bf6b9c25@o482280.ingest.sentry.io/5532246',
});
if (!__PRODUCTION__) await import('preact/debug');
render(<App />, root);
}

View File

@@ -68,8 +68,6 @@ export default class TwoUp extends HTMLElement {
);
},
});
window.addEventListener('keydown', event => this._onKeyDown(event));
}
connectedCallback() {
@@ -96,29 +94,6 @@ export default class TwoUp extends HTMLElement {
}
}
// KeyDown event handler
private _onKeyDown(event: KeyboardEvent) {
if (event.code === 'Digit1' || event.code === 'Numpad1') {
this._position = 0;
this._relativePosition = 0;
this._setPosition();
} else if (event.code === 'Digit2' || event.code === 'Numpad2') {
const dimensionAxis = this.orientation === 'vertical' ? 'height' : 'width';
const bounds = this.getBoundingClientRect();
this._position = bounds[dimensionAxis] / 2;
this._relativePosition = (this._position / bounds[dimensionAxis]) / 2;
this._setPosition();
} else if (event.code === 'Digit3' || event.code === 'Numpad3') {
const dimensionAxis = this.orientation === 'vertical' ? 'height' : 'width';
const bounds = this.getBoundingClientRect();
this._position = bounds[dimensionAxis];
this._relativePosition = this._position / bounds[dimensionAxis];
this._setPosition();
}
}
private _resetPosition() {
// Set the initial position of the handle.
requestAnimationFrame(() => {

View File

@@ -604,7 +604,6 @@ export default class Compress extends Component<Props, State> {
const resizeState: Partial<ProcessorState['resize']> = {
width: decoded.width,
height: decoded.height,
method: vectorImage ? 'vector' : 'lanczos3',
// Disable resizing, to make it clearer to the user that something changed here
enabled: false,
};

View File

@@ -1,7 +1,6 @@
import type SnackBarElement from 'shared/custom-els/snack-bar';
import { get, set } from 'idb-keyval';
import { canDecodeImageType } from 'client/lazy-app/util';
import swUrl from 'service-worker:sw';
@@ -105,12 +104,6 @@ export async function mainAppLoaded() {
// If the user has already interacted, no need to tell the service worker anything.
const userInteracted = await get<boolean | undefined>('user-interacted');
if (userInteracted) return;
await Promise.all(
['avif', 'webp'].map(async (name) => {
let isSupported = await canDecodeImageType(`image/${name}`);
await set(`supports-${name}`, isSupported);
}),
);
set('user-interacted', true);
const serviceWorker = await getMostActiveServiceWorker();
if (!serviceWorker) return; // Service worker not installing yet.

BIN
src/sw/tiny.avif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 B

BIN
src/sw/tiny.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 B

View File

@@ -1,5 +1,6 @@
import { threads, simd } from 'wasm-feature-detect';
import { get } from 'idb-keyval';
import webpDataUrl from 'data-url:./tiny.webp';
import avifDataUrl from 'data-url:./tiny.avif';
// Give TypeScript the correct global.
declare var self: ServiceWorkerGlobalScope;
@@ -104,7 +105,7 @@ import wp2EncMtWasm from 'url:codecs/wp2/enc/wp2_enc_mt.wasm';
import * as wp2Enc from 'entry-data:codecs/wp2/enc/wp2_enc';
import wp2EncWasm from 'url:codecs/wp2/enc/wp2_enc.wasm';
export const theRest = async () => {
export const theRest = (async () => {
const [
supportsThreads,
supportsSimd,
@@ -113,8 +114,15 @@ export const theRest = async () => {
] = await Promise.all([
threads(),
simd(),
get('supports-webp'),
get('supports-avif'),
...[webpDataUrl, avifDataUrl].map(async (dataUrl) => {
if (!self.createImageBitmap) return false;
const response = await fetch(dataUrl);
const blob = await response.blob();
return createImageBitmap(blob).then(
() => true,
() => false,
);
}),
]);
const items = [
@@ -202,4 +210,4 @@ export const theRest = async () => {
}
return [...new Set(items)];
};
})();

View File

@@ -91,7 +91,7 @@ export async function cacheBasics(cacheName: string) {
export async function cacheAdditionalProcessors(cacheName: string) {
const cache = await caches.open(cacheName);
return cache.addAll(await theRest());
return cache.addAll(await theRest);
}
const nextMessageResolveMap = new Map<string, (() => void)[]>();