mirror of
https://github.com/GoogleChromeLabs/squoosh.git
synced 2025-11-12 16:57:26 +00:00
Compare commits
53 Commits
urls-bug
...
visdif-err
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5bc80e66ec | ||
|
|
b1f50cd27c | ||
|
|
3d136016e2 | ||
|
|
14a715e952 | ||
|
|
324b04d398 | ||
|
|
eb76fbc4bc | ||
|
|
1d292468b0 | ||
|
|
828f9a5eeb | ||
|
|
5595525c8a | ||
|
|
5e14444b13 | ||
|
|
3d58c616af | ||
|
|
d7090042a6 | ||
|
|
be3249bf2f | ||
|
|
1b59c3f47a | ||
|
|
9a37cc7959 | ||
|
|
ffb9135a7a | ||
|
|
5707eeff41 | ||
|
|
a18ed360eb | ||
|
|
011d0c2099 | ||
|
|
89105bbb22 | ||
|
|
5f7c619413 | ||
|
|
3ec7d4db16 | ||
|
|
8ef8cef522 | ||
|
|
f6431d8147 | ||
|
|
be037754ce | ||
|
|
32107124e6 | ||
|
|
1af5d1fa7b | ||
|
|
08adfba8be | ||
|
|
5df04f6419 | ||
|
|
cf570a4d3f | ||
|
|
2aa691339c | ||
|
|
9fcb4a4c55 | ||
|
|
18e3d77aef | ||
|
|
6a4982bf4c | ||
|
|
c7b998a877 | ||
|
|
e5b2030666 | ||
|
|
0e09d0b33f | ||
|
|
ed03a37fb8 | ||
|
|
2bc4ab8fd6 | ||
|
|
2037fe8964 | ||
|
|
d07c57ecaa | ||
|
|
e7d55bf903 | ||
|
|
687cf5aae2 | ||
|
|
d63823d196 | ||
|
|
7d111b6a43 | ||
|
|
426f31e548 | ||
|
|
dd0adba6b1 | ||
|
|
30445927ea | ||
|
|
31b263fc27 | ||
|
|
fc590918ed | ||
|
|
c4783b03df | ||
|
|
8f9c0ff0e7 | ||
|
|
40c81ef782 |
@@ -10,6 +10,9 @@ export CODEC_DIR = node_modules/libavif
|
||||
export BUILD_DIR = node_modules/build
|
||||
export LIBAOM_DIR = node_modules/libaom
|
||||
|
||||
override CFLAGS += "-Wno-unused-macros"
|
||||
export
|
||||
|
||||
OUT_ENC_JS = enc/avif_enc.js
|
||||
OUT_NODE_ENC_JS = enc/avif_node_enc.js
|
||||
OUT_ENC_MT_JS = enc/avif_enc_mt.js
|
||||
|
||||
43
codecs/avif/dec/avif_dec.js
generated
43
codecs/avif/dec/avif_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
43
codecs/avif/dec/avif_node_dec.js
generated
43
codecs/avif/dec/avif_node_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
49
codecs/avif/enc/avif_enc.js
generated
49
codecs/avif/enc/avif_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
82
codecs/avif/enc/avif_enc_mt.js
generated
82
codecs/avif/enc/avif_enc_mt.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
2
codecs/avif/enc/avif_enc_mt.worker.js
generated
2
codecs/avif/enc/avif_enc_mt.worker.js
generated
@@ -1 +1 @@
|
||||
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./avif_enc_mt.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,/*isMainBrowserThread=*/0,/*isMainRuntimeThread=*/0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
||||
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./avif_enc_mt.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,0,0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
||||
|
||||
48
codecs/avif/enc/avif_node_enc.js
generated
48
codecs/avif/enc/avif_node_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1,13 +1,13 @@
|
||||
FROM emscripten/emsdk:2.0.21
|
||||
FROM emscripten/emsdk:2.0.23
|
||||
RUN apt-get update && apt-get install -qqy autoconf libtool pkg-config
|
||||
ENV CFLAGS "-O3 -flto"
|
||||
ENV CXXFLAGS "${CFLAGS} -std=c++17"
|
||||
ENV LDFLAGS "${CFLAGS} \
|
||||
--closure 1 \
|
||||
-s FILESYSTEM=0 \
|
||||
-s PTHREAD_POOL_SIZE=navigator.hardwareConcurrency \
|
||||
-s ALLOW_MEMORY_GROWTH=1 \
|
||||
-s TEXTDECODER=2 \
|
||||
-s NODEJS_CATCH_EXIT=0 -s NODEJS_CATCH_REJECTION=0 \
|
||||
"
|
||||
# Build and cache standard libraries with these flags + Embind.
|
||||
RUN emcc ${CXXFLAGS} ${LDFLAGS} --bind -xc++ /dev/null -o /dev/null
|
||||
|
||||
41
codecs/imagequant/imagequant.js
generated
41
codecs/imagequant/imagequant.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
41
codecs/imagequant/imagequant_node.js
generated
41
codecs/imagequant/imagequant_node.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
42
codecs/jxl/dec/jxl_dec.js
generated
42
codecs/jxl/dec/jxl_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
42
codecs/jxl/dec/jxl_node_dec.js
generated
42
codecs/jxl/dec/jxl_node_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
55
codecs/jxl/enc/jxl_enc.js
generated
55
codecs/jxl/enc/jxl_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
91
codecs/jxl/enc/jxl_enc_mt.js
generated
91
codecs/jxl/enc/jxl_enc_mt.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
2
codecs/jxl/enc/jxl_enc_mt.worker.js
generated
2
codecs/jxl/enc/jxl_enc_mt.worker.js
generated
@@ -1 +1 @@
|
||||
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./jxl_enc_mt.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,/*isMainBrowserThread=*/0,/*isMainRuntimeThread=*/0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
||||
"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}};
|
||||
|
||||
91
codecs/jxl/enc/jxl_enc_mt_simd.js
generated
91
codecs/jxl/enc/jxl_enc_mt_simd.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
2
codecs/jxl/enc/jxl_enc_mt_simd.worker.js
generated
2
codecs/jxl/enc/jxl_enc_mt_simd.worker.js
generated
@@ -1 +1 @@
|
||||
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./jxl_enc_mt_simd.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,/*isMainBrowserThread=*/0,/*isMainRuntimeThread=*/0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
||||
"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}};
|
||||
|
||||
56
codecs/jxl/enc/jxl_node_enc.js
generated
56
codecs/jxl/enc/jxl_node_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
43
codecs/mozjpeg/dec/mozjpeg_node_dec.js
generated
43
codecs/mozjpeg/dec/mozjpeg_node_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
45
codecs/mozjpeg/enc/mozjpeg_enc.js
generated
45
codecs/mozjpeg/enc/mozjpeg_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
45
codecs/mozjpeg/enc/mozjpeg_node_enc.js
generated
45
codecs/mozjpeg/enc/mozjpeg_node_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
4
codecs/resize/pkg/squoosh_resize.d.ts
generated
vendored
4
codecs/resize/pkg/squoosh_resize.d.ts
generated
vendored
@@ -9,9 +9,9 @@
|
||||
* @param {number} typ_idx
|
||||
* @param {boolean} premultiply
|
||||
* @param {boolean} color_space_conversion
|
||||
* @returns {Uint8Array}
|
||||
* @returns {Uint8ClampedArray}
|
||||
*/
|
||||
export function resize(input_image: Uint8Array, input_width: number, input_height: number, output_width: number, output_height: number, typ_idx: number, premultiply: boolean, color_space_conversion: boolean): Uint8Array;
|
||||
export function resize(input_image: Uint8Array, input_width: number, input_height: number, output_width: number, output_height: number, typ_idx: number, premultiply: boolean, color_space_conversion: boolean): Uint8ClampedArray;
|
||||
|
||||
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
||||
|
||||
|
||||
16
codecs/resize/pkg/squoosh_resize.js
generated
16
codecs/resize/pkg/squoosh_resize.js
generated
@@ -26,8 +26,16 @@ function getInt32Memory0() {
|
||||
return cachegetInt32Memory0;
|
||||
}
|
||||
|
||||
function getArrayU8FromWasm0(ptr, len) {
|
||||
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len);
|
||||
let cachegetUint8ClampedMemory0 = null;
|
||||
function getUint8ClampedMemory0() {
|
||||
if (cachegetUint8ClampedMemory0 === null || cachegetUint8ClampedMemory0.buffer !== wasm.memory.buffer) {
|
||||
cachegetUint8ClampedMemory0 = new Uint8ClampedArray(wasm.memory.buffer);
|
||||
}
|
||||
return cachegetUint8ClampedMemory0;
|
||||
}
|
||||
|
||||
function getClampedArrayU8FromWasm0(ptr, len) {
|
||||
return getUint8ClampedMemory0().subarray(ptr / 1, ptr / 1 + len);
|
||||
}
|
||||
/**
|
||||
* @param {Uint8Array} input_image
|
||||
@@ -38,7 +46,7 @@ function getArrayU8FromWasm0(ptr, len) {
|
||||
* @param {number} typ_idx
|
||||
* @param {boolean} premultiply
|
||||
* @param {boolean} color_space_conversion
|
||||
* @returns {Uint8Array}
|
||||
* @returns {Uint8ClampedArray}
|
||||
*/
|
||||
export function resize(input_image, input_width, input_height, output_width, output_height, typ_idx, premultiply, color_space_conversion) {
|
||||
try {
|
||||
@@ -48,7 +56,7 @@ export function resize(input_image, input_width, input_height, output_width, out
|
||||
wasm.resize(retptr, ptr0, len0, input_width, input_height, output_width, output_height, typ_idx, premultiply, color_space_conversion);
|
||||
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
||||
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
||||
var v1 = getArrayU8FromWasm0(r0, r1).slice();
|
||||
var v1 = getClampedArrayU8FromWasm0(r0, r1).slice();
|
||||
wasm.__wbindgen_free(r0, r1 * 1);
|
||||
return v1;
|
||||
} finally {
|
||||
|
||||
Binary file not shown.
7
codecs/resize/pkg/squoosh_resize_bg.wasm.d.ts
generated
vendored
Normal file
7
codecs/resize/pkg/squoosh_resize_bg.wasm.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export const memory: WebAssembly.Memory;
|
||||
export function resize(a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number): void;
|
||||
export function __wbindgen_add_to_stack_pointer(a: number): number;
|
||||
export function __wbindgen_malloc(a: number): number;
|
||||
export function __wbindgen_free(a: number, b: number): void;
|
||||
@@ -8,6 +8,7 @@ use cfg_if::cfg_if;
|
||||
use resize::Pixel;
|
||||
use resize::Type;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen::Clamped;
|
||||
|
||||
mod srgb;
|
||||
use srgb::{linear_to_srgb, Clamp};
|
||||
@@ -66,7 +67,7 @@ pub fn resize(
|
||||
typ_idx: usize,
|
||||
premultiply: bool,
|
||||
color_space_conversion: bool,
|
||||
) -> Vec<u8> {
|
||||
) -> Clamped<Vec<u8>> {
|
||||
let typ = match typ_idx {
|
||||
0 => Type::Triangle,
|
||||
1 => Type::Catrom,
|
||||
@@ -91,7 +92,7 @@ pub fn resize(
|
||||
typ,
|
||||
);
|
||||
resizer.resize(input_image.as_slice(), output_image.as_mut_slice());
|
||||
return output_image;
|
||||
return Clamped(output_image);
|
||||
}
|
||||
|
||||
// Otherwise, we convert to f32 images to keep the
|
||||
@@ -138,5 +139,5 @@ pub fn resize(
|
||||
.clamp(0.0, 255.0) as u8;
|
||||
}
|
||||
|
||||
return output_image;
|
||||
return Clamped(output_image);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"name": "avif",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "../build-cpp.sh"
|
||||
}
|
||||
|
||||
22
codecs/visdif/test.mjs
Normal file
22
codecs/visdif/test.mjs
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
import {dirname} from "path";
|
||||
globalThis.__dirname = dirname(import.meta.url);
|
||||
import { createRequire } from 'module';
|
||||
|
||||
globalThis.require = createRequire(import.meta.url);
|
||||
import visdif from './visdif.js';
|
||||
|
||||
const {VisDiff} = await visdif({
|
||||
locateFile() {
|
||||
return new URL("./visdif.wasm", import.meta.url).pathname;
|
||||
}
|
||||
});
|
||||
|
||||
const comparator = new VisDiff(
|
||||
new Uint8ClampedArray([0, 0, 0, 255]),
|
||||
1,
|
||||
1
|
||||
);
|
||||
|
||||
const distance = comparator.distance(new Uint8ClampedArray([1,1,1,255]));
|
||||
console.log({distance});
|
||||
55
codecs/visdif/visdif.js
generated
55
codecs/visdif/visdif.js
generated
File diff suppressed because one or more lines are too long
21
codecs/visdif/visdif.test.mjs
Normal file
21
codecs/visdif/visdif.test.mjs
Normal file
@@ -0,0 +1,21 @@
|
||||
import {dirname} from "path";
|
||||
globalThis.__dirname = dirname(import.meta.url);
|
||||
import { createRequire } from 'module';
|
||||
|
||||
globalThis.require = createRequire(import.meta.url);
|
||||
import visdif from './visdif.js';
|
||||
|
||||
const {VisDiff} = await visdif({
|
||||
locateFile() {
|
||||
return new URL("./visdif.wasm", import.meta.url).pathname;
|
||||
}
|
||||
});
|
||||
|
||||
const comparator = new VisDiff(
|
||||
new Uint8ClampedArray([0, 0, 0, 255]),
|
||||
1,
|
||||
1
|
||||
);
|
||||
|
||||
const distance = comparator.distance(new Uint8ClampedArray([1,1,1,255]));
|
||||
console.log({distance});
|
||||
Binary file not shown.
41
codecs/webp/dec/webp_dec.js
generated
41
codecs/webp/dec/webp_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
41
codecs/webp/dec/webp_node_dec.js
generated
41
codecs/webp/dec/webp_node_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
45
codecs/webp/enc/webp_enc.js
generated
45
codecs/webp/enc/webp_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
45
codecs/webp/enc/webp_enc_simd.js
generated
45
codecs/webp/enc/webp_enc_simd.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
44
codecs/webp/enc/webp_node_enc.js
generated
44
codecs/webp/enc/webp_node_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
42
codecs/wp2/dec/wp2_dec.js
generated
42
codecs/wp2/dec/wp2_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
41
codecs/wp2/dec/wp2_node_dec.js
generated
41
codecs/wp2/dec/wp2_node_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
46
codecs/wp2/enc/wp2_enc.js
generated
46
codecs/wp2/enc/wp2_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
79
codecs/wp2/enc/wp2_enc_mt.js
generated
79
codecs/wp2/enc/wp2_enc_mt.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
2
codecs/wp2/enc/wp2_enc_mt.worker.js
generated
2
codecs/wp2/enc/wp2_enc_mt.worker.js
generated
@@ -1 +1 @@
|
||||
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./wp2_enc_mt.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,/*isMainBrowserThread=*/0,/*isMainRuntimeThread=*/0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
||||
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./wp2_enc_mt.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,0,0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
||||
|
||||
79
codecs/wp2/enc/wp2_enc_mt_simd.js
generated
79
codecs/wp2/enc/wp2_enc_mt_simd.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
2
codecs/wp2/enc/wp2_enc_mt_simd.worker.js
generated
2
codecs/wp2/enc/wp2_enc_mt_simd.worker.js
generated
@@ -1 +1 @@
|
||||
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./wp2_enc_mt_simd.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,/*isMainBrowserThread=*/0,/*isMainRuntimeThread=*/0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
||||
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./wp2_enc_mt_simd.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,0,0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};
|
||||
|
||||
46
codecs/wp2/enc/wp2_node_enc.js
generated
46
codecs/wp2/enc/wp2_node_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -39,9 +39,9 @@ The returned `image` object is a representation of the original image, that you
|
||||
When an image has been ingested, you can start preprocessing it and encoding it to other formats. This example will resize the image and then encode it to a `.jpg` and `.jxl` image:
|
||||
|
||||
```js
|
||||
await image.decoded; //Wait until the image is decoded before running preprocessors
|
||||
await image.decoded; //Wait until the image is decoded before running preprocessors.
|
||||
|
||||
const preprocessOptions: {
|
||||
const preprocessOptions = {
|
||||
resize: {
|
||||
enabled: true,
|
||||
width: 100,
|
||||
@@ -50,7 +50,7 @@ const preprocessOptions: {
|
||||
}
|
||||
await image.preprocess(preprocessOptions);
|
||||
|
||||
const encodeOptions: {
|
||||
const encodeOptions = {
|
||||
mozjpeg: {}, //an empty object means 'use default settings'
|
||||
jxl: {
|
||||
quality: 90,
|
||||
@@ -81,7 +81,7 @@ When you have encoded an image, you normally want to write it to a file.
|
||||
This example takes an image that has been encoded as a `jpg` and writes it to a file:
|
||||
|
||||
```js
|
||||
const rawEncodedImage = (await image.encodedWidth.mozjpeg).binary;
|
||||
const rawEncodedImage = (await image.encodedWith.mozjpeg).binary;
|
||||
|
||||
fs.writeFile('/path/to/new/image.jpg', rawEncodedImage);
|
||||
```
|
||||
|
||||
133
libsquoosh/lib/simple-ts.js
Normal file
133
libsquoosh/lib/simple-ts.js
Normal file
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* Copyright 2020 Google Inc. All Rights Reserved.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { spawn } from 'child_process';
|
||||
import { relative, join } from 'path';
|
||||
import { promises as fsp } from 'fs';
|
||||
import { promisify } from 'util';
|
||||
|
||||
import * as ts from 'typescript';
|
||||
import glob from 'glob';
|
||||
import { sync as whichSync } from 'which';
|
||||
|
||||
const globP = promisify(glob);
|
||||
|
||||
const tscPath = whichSync('tsc');
|
||||
|
||||
const extRe = /\.tsx?$/;
|
||||
|
||||
function loadConfig(mainPath) {
|
||||
const fileName = ts.findConfigFile(mainPath, ts.sys.fileExists);
|
||||
if (!fileName) throw Error('tsconfig not found');
|
||||
const text = ts.sys.readFile(fileName);
|
||||
const loadedConfig = ts.parseConfigFileTextToJson(fileName, text).config;
|
||||
const parsedTsConfig = ts.parseJsonConfigFileContent(
|
||||
loadedConfig,
|
||||
ts.sys,
|
||||
process.cwd(),
|
||||
undefined,
|
||||
fileName,
|
||||
);
|
||||
return parsedTsConfig;
|
||||
}
|
||||
|
||||
export default function simpleTS(mainPath, { noBuild, watch } = {}) {
|
||||
const config = loadConfig(mainPath);
|
||||
const args = ['-b', mainPath];
|
||||
|
||||
let tsBuildDone;
|
||||
|
||||
async function watchBuiltFiles(rollupContext) {
|
||||
const matches = await globP(config.options.outDir + '/**/*.js');
|
||||
for (const match of matches) rollupContext.addWatchFile(match);
|
||||
}
|
||||
|
||||
async function tsBuild(rollupContext) {
|
||||
if (tsBuildDone) {
|
||||
// Watch lists are cleared on each build, so we need to rewatch all the JS files.
|
||||
await watchBuiltFiles(rollupContext);
|
||||
return tsBuildDone;
|
||||
}
|
||||
if (noBuild) {
|
||||
return (tsBuildDone = Promise.resolve());
|
||||
}
|
||||
tsBuildDone = Promise.resolve().then(async () => {
|
||||
await new Promise((resolve) => {
|
||||
const proc = spawn(tscPath, args, {
|
||||
stdio: 'inherit',
|
||||
});
|
||||
|
||||
proc.on('exit', (code) => {
|
||||
if (code !== 0) {
|
||||
throw Error('TypeScript build failed');
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
await watchBuiltFiles(rollupContext);
|
||||
|
||||
if (watch) {
|
||||
tsBuildDone.then(() => {
|
||||
spawn(tscPath, [...args, '--watch', '--preserveWatchOutput'], {
|
||||
stdio: 'inherit',
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return tsBuildDone;
|
||||
}
|
||||
|
||||
return {
|
||||
name: 'simple-ts',
|
||||
resolveId(id, importer) {
|
||||
// If there isn't an importer, it's an entry point, so we don't need to resolve it relative
|
||||
// to something.
|
||||
if (!importer) return null;
|
||||
|
||||
const tsResolve = ts.resolveModuleName(
|
||||
id,
|
||||
importer,
|
||||
config.options,
|
||||
ts.sys,
|
||||
);
|
||||
|
||||
if (
|
||||
// It didn't find anything
|
||||
!tsResolve.resolvedModule ||
|
||||
// Or if it's linking to a definition file, it's something in node_modules,
|
||||
// or something local like css.d.ts
|
||||
tsResolve.resolvedModule.extension === '.d.ts'
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
return tsResolve.resolvedModule.resolvedFileName;
|
||||
},
|
||||
async load(id) {
|
||||
if (!extRe.test(id)) return null;
|
||||
|
||||
// TypeScript building is deferred until the first TS file load.
|
||||
// This allows prerequisites to happen first,
|
||||
// such as css.d.ts generation in css-plugin.
|
||||
await tsBuild(this);
|
||||
|
||||
// Look for the JS equivalent in the tmp folder
|
||||
const newId = join(
|
||||
config.options.outDir,
|
||||
relative(config.options.rootDir, id),
|
||||
).replace(extRe, '.js');
|
||||
|
||||
return fsp.readFile(newId, { encoding: 'utf8' });
|
||||
},
|
||||
};
|
||||
}
|
||||
18
libsquoosh/libsquoosh.test.mjs
Normal file
18
libsquoosh/libsquoosh.test.mjs
Normal file
@@ -0,0 +1,18 @@
|
||||
import { ImagePool } from './build/index.js';
|
||||
|
||||
console.log("Starting");
|
||||
const imagePool = new ImagePool();
|
||||
// const imagePath = '/Users/surma/Downloads/happy_dog.png';
|
||||
const imagePath = './squoosh.png';
|
||||
console.log("INgesting");
|
||||
const image = imagePool.ingestImage(imagePath);
|
||||
console.log("Decoding");
|
||||
await image.decoded;
|
||||
const encodeOptions = {
|
||||
mozjpeg: 'auto',
|
||||
};
|
||||
console.log("Encoding");
|
||||
await image.encode(encodeOptions);
|
||||
console.log("Closing");
|
||||
await imagePool.close();
|
||||
console.log("Done");
|
||||
27
libsquoosh/package-lock.json
generated
27
libsquoosh/package-lock.json
generated
@@ -1125,9 +1125,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "15.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.1.tgz",
|
||||
"integrity": "sha512-TMkXt0Ck1y0KKsGr9gJtWGjttxlZnnvDtphxUOSd0bfaR6Q1jle+sPvrzNR1urqYTWMinoKvjKfXUGsumaO1PA==",
|
||||
"version": "15.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.6.1.tgz",
|
||||
"integrity": "sha512-7EIraBEyRHEe7CH+Fm1XvgqU6uwZN8Q7jppJGcqjROMT29qhAuuOxYB1uEY5UMYQKEmA5D+5tBnhdaPXSsLONA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/resolve": {
|
||||
@@ -1492,6 +1492,12 @@
|
||||
"@types/estree": "*"
|
||||
}
|
||||
},
|
||||
"isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
|
||||
"dev": true
|
||||
},
|
||||
"jest-worker": {
|
||||
"version": "26.6.2",
|
||||
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
|
||||
@@ -1826,6 +1832,12 @@
|
||||
"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
|
||||
"dev": true
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz",
|
||||
"integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==",
|
||||
"dev": true
|
||||
},
|
||||
"unicode-canonical-property-names-ecmascript": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
|
||||
@@ -1859,6 +1871,15 @@
|
||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.0.3.tgz",
|
||||
"integrity": "sha512-d2H/t0eqRNM4w2WvmTdoeIvzAUSpK7JmATB8Nr2lb7nQ9BTIJVjbQ/TRFVEh2gUH1HwclPdoPtfMoFfetXaZnA=="
|
||||
},
|
||||
"which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"isexe": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"version": "0.2.3",
|
||||
"description": "A Node library for Squoosh",
|
||||
"public": true,
|
||||
"main": "/build/index.js",
|
||||
"main": "./build/index.js",
|
||||
"files": [
|
||||
"/build/*"
|
||||
],
|
||||
@@ -22,7 +22,10 @@
|
||||
"@rollup/plugin-babel": "^5.3.0",
|
||||
"@rollup/plugin-commonjs": "^18.0.0",
|
||||
"@rollup/plugin-node-resolve": "^11.2.1",
|
||||
"@types/node": "^15.6.1",
|
||||
"rollup": "^2.46.0",
|
||||
"rollup-plugin-terser": "^7.0.2"
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"typescript": "^4.1.3",
|
||||
"which": "^2.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import cjs from '@rollup/plugin-commonjs';
|
||||
import simpleTS from './lib/simple-ts';
|
||||
import asset from './lib/asset-plugin.js';
|
||||
import json from './lib/json-plugin.js';
|
||||
import autojson from './lib/autojson-plugin.js';
|
||||
@@ -20,6 +21,7 @@ export default {
|
||||
asset(),
|
||||
autojson(),
|
||||
json(),
|
||||
simpleTS('.'),
|
||||
getBabelOutputPlugin({
|
||||
babelrc: false,
|
||||
configFile: false,
|
||||
|
||||
BIN
libsquoosh/squoosh.png
Normal file
BIN
libsquoosh/squoosh.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
132
libsquoosh/src/WebAssembly.d.ts
vendored
Normal file
132
libsquoosh/src/WebAssembly.d.ts
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* WebAssembly definitions are not available in `@types/node` yet,
|
||||
* so these are copied from `lib.dom.d.ts`
|
||||
*/
|
||||
declare namespace WebAssembly {
|
||||
interface CompileError {}
|
||||
|
||||
var CompileError: {
|
||||
prototype: CompileError;
|
||||
new (): CompileError;
|
||||
};
|
||||
|
||||
interface Global {
|
||||
value: any;
|
||||
valueOf(): any;
|
||||
}
|
||||
|
||||
var Global: {
|
||||
prototype: Global;
|
||||
new (descriptor: GlobalDescriptor, v?: any): Global;
|
||||
};
|
||||
|
||||
interface Instance {
|
||||
readonly exports: Exports;
|
||||
}
|
||||
|
||||
var Instance: {
|
||||
prototype: Instance;
|
||||
new (module: Module, importObject?: Imports): Instance;
|
||||
};
|
||||
|
||||
interface LinkError {}
|
||||
|
||||
var LinkError: {
|
||||
prototype: LinkError;
|
||||
new (): LinkError;
|
||||
};
|
||||
|
||||
interface Memory {
|
||||
readonly buffer: ArrayBuffer;
|
||||
grow(delta: number): number;
|
||||
}
|
||||
|
||||
var Memory: {
|
||||
prototype: Memory;
|
||||
new (descriptor: MemoryDescriptor): Memory;
|
||||
};
|
||||
|
||||
interface Module {}
|
||||
|
||||
var Module: {
|
||||
prototype: Module;
|
||||
new (bytes: BufferSource): Module;
|
||||
customSections(moduleObject: Module, sectionName: string): ArrayBuffer[];
|
||||
exports(moduleObject: Module): ModuleExportDescriptor[];
|
||||
imports(moduleObject: Module): ModuleImportDescriptor[];
|
||||
};
|
||||
|
||||
interface RuntimeError {}
|
||||
|
||||
var RuntimeError: {
|
||||
prototype: RuntimeError;
|
||||
new (): RuntimeError;
|
||||
};
|
||||
|
||||
interface Table {
|
||||
readonly length: number;
|
||||
get(index: number): Function | null;
|
||||
grow(delta: number): number;
|
||||
set(index: number, value: Function | null): void;
|
||||
}
|
||||
|
||||
var Table: {
|
||||
prototype: Table;
|
||||
new (descriptor: TableDescriptor): Table;
|
||||
};
|
||||
|
||||
interface GlobalDescriptor {
|
||||
mutable?: boolean;
|
||||
value: ValueType;
|
||||
}
|
||||
|
||||
interface MemoryDescriptor {
|
||||
initial: number;
|
||||
maximum?: number;
|
||||
}
|
||||
|
||||
interface ModuleExportDescriptor {
|
||||
kind: ImportExportKind;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface ModuleImportDescriptor {
|
||||
kind: ImportExportKind;
|
||||
module: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface TableDescriptor {
|
||||
element: TableKind;
|
||||
initial: number;
|
||||
maximum?: number;
|
||||
}
|
||||
|
||||
interface WebAssemblyInstantiatedSource {
|
||||
instance: Instance;
|
||||
module: Module;
|
||||
}
|
||||
|
||||
type ImportExportKind = 'function' | 'global' | 'memory' | 'table';
|
||||
type TableKind = 'anyfunc';
|
||||
type ValueType = 'f32' | 'f64' | 'i32' | 'i64';
|
||||
type ExportValue = Function | Global | Memory | Table;
|
||||
type Exports = Record<string, ExportValue>;
|
||||
type ImportValue = ExportValue | number;
|
||||
type ModuleImports = Record<string, ImportValue>;
|
||||
type Imports = Record<string, ModuleImports>;
|
||||
function compile(bytes: BufferSource): Promise<Module>;
|
||||
// `compileStreaming` does not exist in NodeJS
|
||||
// function compileStreaming(source: Response | Promise<Response>): Promise<Module>;
|
||||
function instantiate(
|
||||
bytes: BufferSource,
|
||||
importObject?: Imports,
|
||||
): Promise<WebAssemblyInstantiatedSource>;
|
||||
function instantiate(
|
||||
moduleObject: Module,
|
||||
importObject?: Imports,
|
||||
): Promise<Instance>;
|
||||
// `instantiateStreaming` does not exist in NodeJS
|
||||
// function instantiateStreaming(response: Response | PromiseLike<Response>, importObject?: Imports): Promise<WebAssemblyInstantiatedSource>;
|
||||
function validate(bytes: BufferSource): boolean;
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import visdifWasm from 'asset-url:../../codecs/visdif/visdif.wasm';
|
||||
export async function binarySearch(
|
||||
measureGoal,
|
||||
measure,
|
||||
{ min = 0, max = 100, epsilon = 0.1, maxRounds = 8 } = {},
|
||||
{ min = 0, max = 100, epsilon = 0.1, maxRounds = 6 } = {},
|
||||
) {
|
||||
let parameter = (max - min) / 2 + min;
|
||||
let delta = (max - min) / 4;
|
||||
|
||||
@@ -1,6 +1,37 @@
|
||||
import { promises as fsp } from 'fs';
|
||||
import { instantiateEmscriptenWasm, pathify } from './emscripten-utils.js';
|
||||
|
||||
interface RotateModuleInstance {
|
||||
exports: {
|
||||
memory: WebAssembly.Memory;
|
||||
rotate(width: number, height: number, rotate: number): void;
|
||||
};
|
||||
}
|
||||
|
||||
interface ResizeWithAspectParams {
|
||||
input_width: number;
|
||||
input_height: number;
|
||||
target_width: number;
|
||||
target_height: number;
|
||||
}
|
||||
|
||||
interface ResizeInstantiateOptions {
|
||||
width: number;
|
||||
height: number;
|
||||
method: string;
|
||||
premultiply: boolean;
|
||||
linearRGB: boolean;
|
||||
}
|
||||
|
||||
declare global {
|
||||
// Needed for being able to use ImageData as type in codec types
|
||||
type ImageData = typeof import('./image_data.js');
|
||||
// Needed for being able to assign to `globalThis.ImageData`
|
||||
var ImageData: ImageData['constructor'];
|
||||
}
|
||||
|
||||
import type { QuantizerModule } from '../../codecs/imagequant/imagequant.js';
|
||||
|
||||
// MozJPEG
|
||||
import mozEnc from '../../codecs/mozjpeg/enc/mozjpeg_node_enc.js';
|
||||
import mozEncWasm from 'asset-url:../../codecs/mozjpeg/enc/mozjpeg_node_enc.wasm';
|
||||
@@ -51,16 +82,22 @@ const resizePromise = resize.default(fsp.readFile(pathify(resizeWasm)));
|
||||
// rotate
|
||||
import rotateWasm from 'asset-url:../../codecs/rotate/rotate.wasm';
|
||||
|
||||
// TODO(ergunsh): Type definitions of some modules do not exist
|
||||
// Figure out creating type definitions for them and remove `allowJs` rule
|
||||
// We shouldn't need to use Promise<QuantizerModule> below after getting type definitions for imageQuant
|
||||
// ImageQuant
|
||||
import imageQuant from '../../codecs/imagequant/imagequant_node.js';
|
||||
import imageQuantWasm from 'asset-url:../../codecs/imagequant/imagequant_node.wasm';
|
||||
const imageQuantPromise = instantiateEmscriptenWasm(imageQuant, imageQuantWasm);
|
||||
const imageQuantPromise: Promise<QuantizerModule> = instantiateEmscriptenWasm(
|
||||
imageQuant,
|
||||
imageQuantWasm,
|
||||
);
|
||||
|
||||
// Our decoders currently rely on a `ImageData` global.
|
||||
import ImageData from './image_data.js';
|
||||
globalThis.ImageData = ImageData;
|
||||
|
||||
function resizeNameToIndex(name) {
|
||||
function resizeNameToIndex(name: string) {
|
||||
switch (name) {
|
||||
case 'triangle':
|
||||
return 0;
|
||||
@@ -80,25 +117,26 @@ function resizeWithAspect({
|
||||
input_height,
|
||||
target_width,
|
||||
target_height,
|
||||
}) {
|
||||
}: ResizeWithAspectParams): { width: number; height: number } {
|
||||
if (!target_width && !target_height) {
|
||||
throw Error('Need to specify at least width or height when resizing');
|
||||
}
|
||||
|
||||
if (target_width && target_height) {
|
||||
return { width: target_width, height: target_height };
|
||||
}
|
||||
|
||||
if (!target_width) {
|
||||
return {
|
||||
width: Math.round((input_width / input_height) * target_height),
|
||||
height: target_height,
|
||||
};
|
||||
}
|
||||
if (!target_height) {
|
||||
return {
|
||||
width: target_width,
|
||||
height: Math.round((input_height / input_width) * target_width),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
width: target_width,
|
||||
height: Math.round((input_height / input_width) * target_width),
|
||||
};
|
||||
}
|
||||
|
||||
export const preprocessors = {
|
||||
@@ -108,10 +146,16 @@ export const preprocessors = {
|
||||
instantiate: async () => {
|
||||
await resizePromise;
|
||||
return (
|
||||
buffer,
|
||||
input_width,
|
||||
input_height,
|
||||
{ width, height, method, premultiply, linearRGB },
|
||||
buffer: Uint8Array,
|
||||
input_width: number,
|
||||
input_height: number,
|
||||
{
|
||||
width,
|
||||
height,
|
||||
method,
|
||||
premultiply,
|
||||
linearRGB,
|
||||
}: ResizeInstantiateOptions,
|
||||
) => {
|
||||
({ width, height } = resizeWithAspect({
|
||||
input_width,
|
||||
@@ -148,7 +192,12 @@ export const preprocessors = {
|
||||
description: 'Reduce the number of colors used (aka. paletting)',
|
||||
instantiate: async () => {
|
||||
const imageQuant = await imageQuantPromise;
|
||||
return (buffer, width, height, { numColors, dither }) =>
|
||||
return (
|
||||
buffer: Uint8Array,
|
||||
width: number,
|
||||
height: number,
|
||||
{ numColors, dither }: { numColors: number; dither: number },
|
||||
) =>
|
||||
new ImageData(
|
||||
imageQuant.quantize(buffer, width, height, numColors, dither),
|
||||
width,
|
||||
@@ -164,13 +213,18 @@ export const preprocessors = {
|
||||
name: 'Rotate',
|
||||
description: 'Rotate image',
|
||||
instantiate: async () => {
|
||||
return async (buffer, width, height, { numRotations }) => {
|
||||
return async (
|
||||
buffer: Uint8Array,
|
||||
width: number,
|
||||
height: number,
|
||||
{ numRotations }: { numRotations: number },
|
||||
) => {
|
||||
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 instance = (
|
||||
await WebAssembly.instantiate(await fsp.readFile(pathify(rotateWasm)))
|
||||
).instance as RotateModuleInstance;
|
||||
const { memory } = instance.exports;
|
||||
const additionalPagesNeeded = Math.ceil(
|
||||
(size * 2 - memory.buffer.byteLength + 8) / (64 * 1024),
|
||||
@@ -286,8 +340,8 @@ export const codecs = {
|
||||
},
|
||||
autoOptimize: {
|
||||
option: 'cqLevel',
|
||||
min: 0,
|
||||
max: 62,
|
||||
min: 62,
|
||||
max: 0,
|
||||
},
|
||||
},
|
||||
jxl: {
|
||||
@@ -346,13 +400,18 @@ export const codecs = {
|
||||
await pngEncDecPromise;
|
||||
await oxipngPromise;
|
||||
return {
|
||||
encode: (buffer, width, height, opts) => {
|
||||
encode: (
|
||||
buffer: Uint8Array,
|
||||
width: number,
|
||||
height: number,
|
||||
opts: { level: number },
|
||||
) => {
|
||||
const simplePng = pngEncDec.encode(
|
||||
new Uint8Array(buffer),
|
||||
width,
|
||||
height,
|
||||
);
|
||||
return oxipng.optimise(simplePng, opts.level);
|
||||
return oxipng.optimise(simplePng, opts.level, false);
|
||||
},
|
||||
};
|
||||
},
|
||||
@@ -1,13 +1,16 @@
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
export function pathify(path) {
|
||||
export function pathify(path: string): string {
|
||||
if (path.startsWith('file://')) {
|
||||
path = fileURLToPath(path);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
export function instantiateEmscriptenWasm(factory, path) {
|
||||
export function instantiateEmscriptenWasm<T extends EmscriptenWasm.Module>(
|
||||
factory: EmscriptenWasm.ModuleFactory<T>,
|
||||
path: string,
|
||||
): Promise<T> {
|
||||
return factory({
|
||||
locateFile() {
|
||||
return pathify(path);
|
||||
@@ -1,7 +0,0 @@
|
||||
export default class ImageData {
|
||||
constructor(data, width, height) {
|
||||
this.data = data;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
}
|
||||
11
libsquoosh/src/image_data.ts
Normal file
11
libsquoosh/src/image_data.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export default class ImageData {
|
||||
readonly data: Uint8ClampedArray;
|
||||
readonly width: number;
|
||||
readonly height: number;
|
||||
|
||||
constructor(data: Uint8ClampedArray, width: number, height: number) {
|
||||
this.data = data;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
}
|
||||
@@ -180,9 +180,9 @@ class Image {
|
||||
encName,
|
||||
encConfig,
|
||||
optimizerButteraugliTarget: Number(
|
||||
encodeOptions.optimizerButteraugliTarget,
|
||||
encodeOptions.optimizerButteraugliTarget ?? 1.4,
|
||||
),
|
||||
maxOptimizerRounds: Number(encodeOptions.maxOptimizerRounds),
|
||||
maxOptimizerRounds: Number(encodeOptions.maxOptimizerRounds ?? 6),
|
||||
});
|
||||
}
|
||||
await Promise.all(Object.values(this.encodedWith));
|
||||
|
||||
38
libsquoosh/src/missing-types.d.ts
vendored
Normal file
38
libsquoosh/src/missing-types.d.ts
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
/// <reference path="../../missing-types.d.ts" />
|
||||
|
||||
declare module 'asset-url:*' {
|
||||
const value: string;
|
||||
export default value;
|
||||
}
|
||||
|
||||
// Somehow TS picks up definitions from the module itself
|
||||
// instead of using `asset-url:*`. It is probably related to
|
||||
// specifity of the module declaration and these declarations below fix it
|
||||
declare module 'asset-url:../../codecs/png/pkg/squoosh_png_bg.wasm' {
|
||||
const value: string;
|
||||
export default value;
|
||||
}
|
||||
|
||||
declare module 'asset-url:../../codecs/oxipng/pkg/squoosh_oxipng_bg.wasm' {
|
||||
const value: string;
|
||||
export default value;
|
||||
}
|
||||
|
||||
declare module 'asset-url:../../codecs/resize/pkg/squoosh_resize_bg.wasm' {
|
||||
const value: string;
|
||||
export default value;
|
||||
}
|
||||
|
||||
// These don't exist in NodeJS types so we're not able to use them but they are referenced in some emscripten and codec types
|
||||
// Thus, we need to explicitly assign them to be `never`
|
||||
// We're also not able to use the APIs that use these types
|
||||
// So, if we want to use those APIs we need to supply its dependencies ourselves
|
||||
// However, probably those APIs are more suited to be used in web (i.e. there can be other
|
||||
// dependencies to web APIs that might not work in Node)
|
||||
type RequestInfo = never;
|
||||
type Response = never;
|
||||
type WebGLRenderingContext = never;
|
||||
type MessageEvent = never;
|
||||
|
||||
type BufferSource = ArrayBufferView | ArrayBuffer;
|
||||
type URL = import('url').URL;
|
||||
9
libsquoosh/tsconfig.json
Normal file
9
libsquoosh/tsconfig.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../generic-tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"lib": ["esnext"],
|
||||
"types": ["node"],
|
||||
"allowJs": true
|
||||
},
|
||||
"include": ["src/**/*", "../codecs/**/*"]
|
||||
}
|
||||
8799
package-lock.json
generated
8799
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -33,11 +33,23 @@ import initialCssPlugin from './lib/initial-css-plugin';
|
||||
import serviceWorkerPlugin from './lib/sw-plugin';
|
||||
import dataURLPlugin from './lib/data-url-plugin';
|
||||
import entryDataPlugin, { fileNameToURL } from './lib/entry-data-plugin';
|
||||
import dedent from 'dedent';
|
||||
|
||||
function resolveFileUrl({ fileName }) {
|
||||
return JSON.stringify(fileNameToURL(fileName));
|
||||
}
|
||||
|
||||
function resolveImportMetaUrlInStaticBuild(property, { moduleId }) {
|
||||
if (property !== 'url') return;
|
||||
throw new Error(dedent`
|
||||
Attempted to use a \`new URL(..., import.meta.url)\` pattern in ${path.relative(
|
||||
process.cwd(),
|
||||
moduleId,
|
||||
)} for URL that needs to end up in static HTML.
|
||||
This is currently unsupported.
|
||||
`);
|
||||
}
|
||||
|
||||
const dir = '.tmp/build';
|
||||
const staticPath = 'static/c/[name]-[hash][extname]';
|
||||
const jsPath = staticPath.replace('[extname]', '.js');
|
||||
@@ -100,7 +112,7 @@ export default async function ({ watch }) {
|
||||
},
|
||||
preserveModules: true,
|
||||
plugins: [
|
||||
{ resolveFileUrl },
|
||||
{ resolveFileUrl, resolveImportMeta: resolveImportMetaUrlInStaticBuild },
|
||||
clientBundlePlugin(
|
||||
{
|
||||
external: ['worker_threads'],
|
||||
|
||||
@@ -34,6 +34,8 @@ export default class TwoUp extends HTMLElement {
|
||||
*/
|
||||
private _everConnected = false;
|
||||
|
||||
private _resizeObserver?: ResizeObserver;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._handle.className = styles.twoUpHandle;
|
||||
@@ -45,13 +47,6 @@ export default class TwoUp extends HTMLElement {
|
||||
childList: true,
|
||||
});
|
||||
|
||||
// Watch for element size changes.
|
||||
if ('ResizeObserver' in window) {
|
||||
new ResizeObserver(() => this._resetPosition()).observe(this);
|
||||
} else {
|
||||
window.addEventListener('resize', () => this._resetPosition());
|
||||
}
|
||||
|
||||
// Watch for pointers on the handle.
|
||||
const pointerTracker: PointerTracker = new PointerTracker(this._handle, {
|
||||
start: (_, event) => {
|
||||
@@ -68,8 +63,6 @@ export default class TwoUp extends HTMLElement {
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
window.addEventListener('keydown', (event) => this._onKeyDown(event));
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
@@ -84,12 +77,23 @@ export default class TwoUp extends HTMLElement {
|
||||
}</svg>
|
||||
`}</div>`;
|
||||
|
||||
// Watch for element size changes.
|
||||
this._resizeObserver = new ResizeObserver(() => this._resetPosition());
|
||||
this._resizeObserver.observe(this);
|
||||
|
||||
window.addEventListener('keydown', this._onKeyDown);
|
||||
|
||||
if (!this._everConnected) {
|
||||
this._resetPosition();
|
||||
this._everConnected = true;
|
||||
}
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
window.removeEventListener('keydown', this._onKeyDown);
|
||||
if (this._resizeObserver) this._resizeObserver.disconnect();
|
||||
}
|
||||
|
||||
attributeChangedCallback(name: string) {
|
||||
if (name === orientationAttr) {
|
||||
this._resetPosition();
|
||||
@@ -97,7 +101,7 @@ export default class TwoUp extends HTMLElement {
|
||||
}
|
||||
|
||||
// KeyDown event handler
|
||||
private _onKeyDown(event: KeyboardEvent) {
|
||||
private _onKeyDown = (event: KeyboardEvent) => {
|
||||
const target = event.target;
|
||||
if (target instanceof HTMLElement && target.closest('input')) return;
|
||||
|
||||
@@ -122,7 +126,7 @@ export default class TwoUp extends HTMLElement {
|
||||
this._relativePosition = this._position / bounds[dimensionAxis];
|
||||
this._setPosition();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private _resetPosition() {
|
||||
// Set the initial position of the handle.
|
||||
|
||||
@@ -5,7 +5,7 @@ import './custom-els/PinchZoom';
|
||||
import './custom-els/TwoUp';
|
||||
import * as style from './style.css';
|
||||
import 'add-css:./style.css';
|
||||
import { shallowEqual, drawDataToCanvas } from '../../util';
|
||||
import { shallowEqual } from '../../util';
|
||||
import {
|
||||
ToggleBackgroundIcon,
|
||||
AddIcon,
|
||||
@@ -18,6 +18,7 @@ import type { PreprocessorState } from '../../feature-meta';
|
||||
import { cleanSet } from '../../util/clean-modify';
|
||||
import type { SourceImage } from '../../Compress';
|
||||
import { linkRef } from 'shared/prerendered-app/util';
|
||||
import { drawDataToCanvas } from 'client/lazy-app/util/canvas';
|
||||
|
||||
interface Props {
|
||||
source?: SourceImage;
|
||||
|
||||
@@ -4,7 +4,6 @@ import * as style from './style.css';
|
||||
import 'add-css:./style.css';
|
||||
import {
|
||||
blobToImg,
|
||||
drawableToImageData,
|
||||
blobToText,
|
||||
builtinDecode,
|
||||
sniffMimeType,
|
||||
@@ -33,6 +32,7 @@ import WorkerBridge from '../worker-bridge';
|
||||
import { resize } from 'features/processors/resize/client';
|
||||
import type SnackBarElement from 'shared/custom-els/snack-bar';
|
||||
import { generateCliInvocation } from '../util/cli';
|
||||
import { drawableToImageData } from '../util/canvas';
|
||||
|
||||
export type OutputType = EncoderType | 'identity';
|
||||
|
||||
@@ -377,6 +377,7 @@ export default class Compress extends Component<Props, State> {
|
||||
|
||||
componentWillUnmount(): void {
|
||||
updateDocumentTitle({ loading: false });
|
||||
this.widthQuery.removeListener(this.onMobileWidthChange);
|
||||
this.mainAbortController.abort();
|
||||
for (const controller of this.sideAbortControllers) {
|
||||
controller.abort();
|
||||
|
||||
154
src/client/lazy-app/util/canvas.ts
Normal file
154
src/client/lazy-app/util/canvas.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
/** Replace the contents of a canvas with the given data */
|
||||
export function drawDataToCanvas(canvas: HTMLCanvasElement, data: ImageData) {
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) throw Error('Canvas not initialized');
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.putImageData(data, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode some image data in a given format using the browser's encoders
|
||||
*
|
||||
* @param {ImageData} data
|
||||
* @param {string} type A mime type, eg image/jpeg.
|
||||
* @param {number} [quality] Between 0-1.
|
||||
*/
|
||||
export async function canvasEncode(
|
||||
data: ImageData,
|
||||
type: string,
|
||||
quality?: number,
|
||||
): Promise<Blob> {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = data.width;
|
||||
canvas.height = data.height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) throw Error('Canvas not initialized');
|
||||
ctx.putImageData(data, 0, 0);
|
||||
|
||||
let blob: Blob | null;
|
||||
|
||||
if ('toBlob' in canvas) {
|
||||
blob = await new Promise<Blob | null>((r) =>
|
||||
canvas.toBlob(r, type, quality),
|
||||
);
|
||||
} else {
|
||||
// Welcome to Edge.
|
||||
// TypeScript thinks `canvas` is 'never', so it needs casting.
|
||||
const dataUrl = (canvas as HTMLCanvasElement).toDataURL(type, quality);
|
||||
const result = /data:([^;]+);base64,(.*)$/.exec(dataUrl);
|
||||
|
||||
if (!result) throw Error('Data URL reading failed');
|
||||
|
||||
const outputType = result[1];
|
||||
const binaryStr = atob(result[2]);
|
||||
const data = new Uint8Array(binaryStr.length);
|
||||
|
||||
for (let i = 0; i < data.length; i += 1) {
|
||||
data[i] = binaryStr.charCodeAt(i);
|
||||
}
|
||||
|
||||
blob = new Blob([data], { type: outputType });
|
||||
}
|
||||
|
||||
if (!blob) throw Error('Encoding failed');
|
||||
return blob;
|
||||
}
|
||||
|
||||
interface DrawableToImageDataOptions {
|
||||
width?: number;
|
||||
height?: number;
|
||||
sx?: number;
|
||||
sy?: number;
|
||||
sw?: number;
|
||||
sh?: number;
|
||||
}
|
||||
|
||||
function getWidth(
|
||||
drawable: ImageBitmap | HTMLImageElement | VideoFrame,
|
||||
): number {
|
||||
if ('displayWidth' in drawable) {
|
||||
return drawable.displayWidth;
|
||||
}
|
||||
return drawable.width;
|
||||
}
|
||||
|
||||
function getHeight(
|
||||
drawable: ImageBitmap | HTMLImageElement | VideoFrame,
|
||||
): number {
|
||||
if ('displayHeight' in drawable) {
|
||||
return drawable.displayHeight;
|
||||
}
|
||||
return drawable.height;
|
||||
}
|
||||
|
||||
export function drawableToImageData(
|
||||
drawable: ImageBitmap | HTMLImageElement | VideoFrame,
|
||||
opts: DrawableToImageDataOptions = {},
|
||||
): ImageData {
|
||||
const {
|
||||
width = getWidth(drawable),
|
||||
height = getHeight(drawable),
|
||||
sx = 0,
|
||||
sy = 0,
|
||||
sw = getWidth(drawable),
|
||||
sh = getHeight(drawable),
|
||||
} = opts;
|
||||
|
||||
// Make canvas same size as image
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
// Draw image onto canvas
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) throw new Error('Could not create canvas context');
|
||||
ctx.drawImage(drawable, sx, sy, sw, sh, 0, 0, width, height);
|
||||
return ctx.getImageData(0, 0, width, height);
|
||||
}
|
||||
|
||||
export type BuiltinResizeMethod = 'pixelated' | 'low' | 'medium' | 'high';
|
||||
|
||||
export function builtinResize(
|
||||
data: ImageData,
|
||||
sx: number,
|
||||
sy: number,
|
||||
sw: number,
|
||||
sh: number,
|
||||
dw: number,
|
||||
dh: number,
|
||||
method: BuiltinResizeMethod,
|
||||
): ImageData {
|
||||
const canvasSource = document.createElement('canvas');
|
||||
canvasSource.width = data.width;
|
||||
canvasSource.height = data.height;
|
||||
drawDataToCanvas(canvasSource, data);
|
||||
|
||||
const canvasDest = document.createElement('canvas');
|
||||
canvasDest.width = dw;
|
||||
canvasDest.height = dh;
|
||||
const ctx = canvasDest.getContext('2d');
|
||||
if (!ctx) throw new Error('Could not create canvas context');
|
||||
|
||||
if (method === 'pixelated') {
|
||||
ctx.imageSmoothingEnabled = false;
|
||||
} else {
|
||||
ctx.imageSmoothingQuality = method;
|
||||
}
|
||||
|
||||
ctx.drawImage(canvasSource, sx, sy, sw, sh, 0, 0, dw, dh);
|
||||
return ctx.getImageData(0, 0, dw, dh);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether <canvas> can encode to a particular type.
|
||||
*/
|
||||
export async function canvasEncodeTest(mimeType: string): Promise<boolean> {
|
||||
try {
|
||||
const blob = await canvasEncode(new ImageData(1, 1), mimeType);
|
||||
// According to the spec, the blob should be null if the format isn't supported…
|
||||
if (!blob) return false;
|
||||
// …but Safari & Firefox fall back to PNG, so we need to check the mime type.
|
||||
return blob.type === mimeType;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
import * as WebCodecs from '../util/web-codecs';
|
||||
import { drawableToImageData } from './canvas';
|
||||
|
||||
/**
|
||||
* Compare two objects, returning a boolean indicating if
|
||||
@@ -23,62 +24,6 @@ export function shallowEqual(one: any, two: any) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Replace the contents of a canvas with the given data */
|
||||
export function drawDataToCanvas(canvas: HTMLCanvasElement, data: ImageData) {
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) throw Error('Canvas not initialized');
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.putImageData(data, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode some image data in a given format using the browser's encoders
|
||||
*
|
||||
* @param {ImageData} data
|
||||
* @param {string} type A mime type, eg image/jpeg.
|
||||
* @param {number} [quality] Between 0-1.
|
||||
*/
|
||||
export async function canvasEncode(
|
||||
data: ImageData,
|
||||
type: string,
|
||||
quality?: number,
|
||||
): Promise<Blob> {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = data.width;
|
||||
canvas.height = data.height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) throw Error('Canvas not initialized');
|
||||
ctx.putImageData(data, 0, 0);
|
||||
|
||||
let blob: Blob | null;
|
||||
|
||||
if ('toBlob' in canvas) {
|
||||
blob = await new Promise<Blob | null>((r) =>
|
||||
canvas.toBlob(r, type, quality),
|
||||
);
|
||||
} else {
|
||||
// Welcome to Edge.
|
||||
// TypeScript thinks `canvas` is 'never', so it needs casting.
|
||||
const dataUrl = (canvas as HTMLCanvasElement).toDataURL(type, quality);
|
||||
const result = /data:([^;]+);base64,(.*)$/.exec(dataUrl);
|
||||
|
||||
if (!result) throw Error('Data URL reading failed');
|
||||
|
||||
const outputType = result[1];
|
||||
const binaryStr = atob(result[2]);
|
||||
const data = new Uint8Array(binaryStr.length);
|
||||
|
||||
for (let i = 0; i < data.length; i += 1) {
|
||||
data[i] = binaryStr.charCodeAt(i);
|
||||
}
|
||||
|
||||
blob = new Blob([data], { type: outputType });
|
||||
}
|
||||
|
||||
if (!blob) throw Error('Encoding failed');
|
||||
return blob;
|
||||
}
|
||||
|
||||
async function decodeImage(url: string): Promise<HTMLImageElement> {
|
||||
const img = new Image();
|
||||
img.decoding = 'async';
|
||||
@@ -186,57 +131,6 @@ export async function blobToImg(blob: Blob): Promise<HTMLImageElement> {
|
||||
}
|
||||
}
|
||||
|
||||
interface DrawableToImageDataOptions {
|
||||
width?: number;
|
||||
height?: number;
|
||||
sx?: number;
|
||||
sy?: number;
|
||||
sw?: number;
|
||||
sh?: number;
|
||||
}
|
||||
|
||||
function getWidth(
|
||||
drawable: ImageBitmap | HTMLImageElement | VideoFrame,
|
||||
): number {
|
||||
if ('displayWidth' in drawable) {
|
||||
return drawable.displayWidth;
|
||||
}
|
||||
return drawable.width;
|
||||
}
|
||||
|
||||
function getHeight(
|
||||
drawable: ImageBitmap | HTMLImageElement | VideoFrame,
|
||||
): number {
|
||||
if ('displayHeight' in drawable) {
|
||||
return drawable.displayHeight;
|
||||
}
|
||||
return drawable.height;
|
||||
}
|
||||
|
||||
export function drawableToImageData(
|
||||
drawable: ImageBitmap | HTMLImageElement | VideoFrame,
|
||||
opts: DrawableToImageDataOptions = {},
|
||||
): ImageData {
|
||||
const {
|
||||
width = getWidth(drawable),
|
||||
height = getHeight(drawable),
|
||||
sx = 0,
|
||||
sy = 0,
|
||||
sw = getWidth(drawable),
|
||||
sh = getHeight(drawable),
|
||||
} = opts;
|
||||
|
||||
// Make canvas same size as image
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
// Draw image onto canvas
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) throw new Error('Could not create canvas context');
|
||||
ctx.drawImage(drawable, sx, sy, sw, sh, 0, 0, width, height);
|
||||
return ctx.getImageData(0, 0, width, height);
|
||||
}
|
||||
|
||||
export async function builtinDecode(
|
||||
signal: AbortSignal,
|
||||
blob: Blob,
|
||||
@@ -259,39 +153,6 @@ export async function builtinDecode(
|
||||
return drawableToImageData(drawable);
|
||||
}
|
||||
|
||||
export type BuiltinResizeMethod = 'pixelated' | 'low' | 'medium' | 'high';
|
||||
|
||||
export function builtinResize(
|
||||
data: ImageData,
|
||||
sx: number,
|
||||
sy: number,
|
||||
sw: number,
|
||||
sh: number,
|
||||
dw: number,
|
||||
dh: number,
|
||||
method: BuiltinResizeMethod,
|
||||
): ImageData {
|
||||
const canvasSource = document.createElement('canvas');
|
||||
canvasSource.width = data.width;
|
||||
canvasSource.height = data.height;
|
||||
drawDataToCanvas(canvasSource, data);
|
||||
|
||||
const canvasDest = document.createElement('canvas');
|
||||
canvasDest.width = dw;
|
||||
canvasDest.height = dh;
|
||||
const ctx = canvasDest.getContext('2d');
|
||||
if (!ctx) throw new Error('Could not create canvas context');
|
||||
|
||||
if (method === 'pixelated') {
|
||||
ctx.imageSmoothingEnabled = false;
|
||||
} else {
|
||||
ctx.imageSmoothingQuality = method;
|
||||
}
|
||||
|
||||
ctx.drawImage(canvasSource, sx, sy, sw, sh, 0, 0, dw, dh);
|
||||
return ctx.getImageData(0, 0, dw, dh);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param field An HTMLInputElement, but the casting is done here to tidy up onChange.
|
||||
* @param defaultVal Value to return if 'field' doesn't exist.
|
||||
@@ -434,18 +295,3 @@ export async function abortable<T>(
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether <canvas> can encode to a particular type.
|
||||
*/
|
||||
export async function canvasEncodeTest(mimeType: string): Promise<boolean> {
|
||||
try {
|
||||
const blob = await canvasEncode(new ImageData(1, 1), mimeType);
|
||||
// According to the spec, the blob should be null if the format isn't supported…
|
||||
if (!blob) return false;
|
||||
// …but Safari & Firefox fall back to PNG, so we need to check the mime type.
|
||||
return blob.type === mimeType;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import { drawableToImageData } from 'client/lazy-app/util';
|
||||
import { drawableToImageData } from '../canvas';
|
||||
|
||||
const hasImageDecoder = typeof ImageDecoder !== 'undefined';
|
||||
|
||||
export async function isTypeSupported(mimeType: string): Promise<boolean> {
|
||||
if (!hasImageDecoder) {
|
||||
if (!hasImageDecoder) return false;
|
||||
// Some old versions of this API threw here.
|
||||
// It only impacted folks with experimental web platform flags enabled in Chrome 90.
|
||||
// The API was updated in Chrome 91.
|
||||
try {
|
||||
return await ImageDecoder.isTypeSupported(mimeType);
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
return ImageDecoder.isTypeSupported(mimeType);
|
||||
}
|
||||
|
||||
export async function decode(
|
||||
blob: Blob | File,
|
||||
mimeType: string,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { canvasEncodeTest, canvasEncode } from 'client/lazy-app/util';
|
||||
import { canvasEncodeTest, canvasEncode } from 'client/lazy-app/util/canvas';
|
||||
import WorkerBridge from 'client/lazy-app/worker-bridge';
|
||||
import { EncodeOptions, mimeType } from '../shared/meta';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { canvasEncode } from 'client/lazy-app/util';
|
||||
import { canvasEncode } from 'client/lazy-app/util/canvas';
|
||||
import WorkerBridge from 'client/lazy-app/worker-bridge';
|
||||
import { qualityOption } from 'features/client-utils';
|
||||
import { mimeType, EncodeOptions } from '../shared/meta';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { canvasEncode } from 'client/lazy-app/util';
|
||||
import { canvasEncode } from 'client/lazy-app/util/canvas';
|
||||
import WorkerBridge from 'client/lazy-app/worker-bridge';
|
||||
import { EncodeOptions, mimeType } from '../shared/meta';
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { canvasEncode } from 'client/lazy-app/util/canvas';
|
||||
import {
|
||||
canvasEncode,
|
||||
abortable,
|
||||
blobToArrayBuffer,
|
||||
inputFieldChecked,
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
builtinResize,
|
||||
BuiltinResizeMethod,
|
||||
drawableToImageData,
|
||||
} from 'client/lazy-app/util';
|
||||
} from 'client/lazy-app/util/canvas';
|
||||
import {
|
||||
BrowserResizeOptions,
|
||||
VectorResizeOptions,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user