Compare commits

..

7 Commits

Author SHA1 Message Date
Surma
d950f756c5 lol 2023-10-18 11:38:20 +00:00
robo-mop
003d5d125c Integrate QOI codec completely
* Adds code for encoders and decoders
* Cleans up some obsolete QOI-related code
2023-10-18 04:48:16 +05:30
robo-mop
71f341923a Fix QOI magic number 2023-10-18 04:48:16 +05:30
robo-mop
37cc236307 Clean up Makefile 2023-10-18 04:48:16 +05:30
Surma
8eaa04c8af Fix makefile 2023-10-17 12:15:09 +01:00
robo-mop
4a1bcec5af Integrate QOI into web-app 2023-10-16 20:24:07 +05:30
robo-mop
d2a656f0bb Add QOI skeleton 2023-10-16 20:24:07 +05:30
54 changed files with 533 additions and 639 deletions

2
.nvmrc
View File

@@ -1 +1 @@
20.16.0 14.15.1

View File

@@ -1,9 +1,9 @@
# using libavif from https://github.com/AOMediaCodec/libavif # libavif and libaom versions are from
LIBAVIF_URL = https://github.com/AOMediaCodec/libavif/archive/refs/tags/v1.0.1.tar.gz # google3/third_party/libavif/METADATA
LIBAVIF_PACKAGE = node_modules/libavif.tar.gz CODEC_URL = https://github.com/AOMediaCodec/libavif/archive/647c3c208cf152395d777c1bf7240d2ecf7df5a9.tar.gz
CODEC_PACKAGE = node_modules/libavif.tar.gz
# using libaom from https://aomedia.googlesource.com/aom LIBAOM_URL = https://aomedia.googlesource.com/aom/+archive/v3.6.0.tar.gz
LIBAOM_URL = https://aomedia.googlesource.com/aom/+archive/v3.7.0.tar.gz
LIBAOM_PACKAGE = node_modules/libaom.tar.gz LIBAOM_PACKAGE = node_modules/libaom.tar.gz
export CODEC_DIR = node_modules/libavif export CODEC_DIR = node_modules/libavif
@@ -11,14 +11,7 @@ export BUILD_DIR = node_modules/build
export LIBAOM_DIR = node_modules/libaom export LIBAOM_DIR = node_modules/libaom
override CFLAGS += "-Wno-unused-macros" override CFLAGS += "-Wno-unused-macros"
export
# We must build libsharpyuv from a specific libwebp commit
# See libavif/ext/libsharpyuv.cmd for more detail
LIBWEBP_URL_WITH_SHARPYUV = https://chromium.googlesource.com/webm/libwebp/+archive/e2c85878f6a33f29948b43d3492d9cdaf801aa54.tar.gz
LIBWEBP_DIR := $(CODEC_DIR)/ext/libwebp
LIBSHARPYUV_ST := $(LIBWEBP_DIR)/build_st/libsharpyuv.a
LIBSHARPYUV_MT := $(LIBWEBP_DIR)/build_mt/libsharpyuv.a
export LIBSHARPYUV := $(LIBWEBP_DIR)/build/libsharpyuv.a
OUT_ENC_JS = enc/avif_enc.js OUT_ENC_JS = enc/avif_enc.js
OUT_NODE_ENC_JS = enc/avif_node_enc.js OUT_NODE_ENC_JS = enc/avif_node_enc.js
@@ -35,11 +28,10 @@ HELPER_MAKEFLAGS := -f helper.Makefile
.PHONY: all clean .PHONY: all clean
all: $(OUT_ENC_JS) $(OUT_DEC_JS) $(OUT_ENC_MT_JS) all: $(OUT_ENC_JS) $(OUT_DEC_JS) $(OUT_ENC_MT_JS) $(OUT_NODE_ENC_JS) $(OUT_NODE_ENC_MT_JS) $(OUT_NODE_DEC_JS)
# ST-Encoding $(OUT_NODE_ENC_JS) $(OUT_NODE_ENC_MT_JS): ENVIRONMENT=node
$(OUT_ENC_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt $(LIBSHARPYUV_ST) $(OUT_NODE_ENC_JS) $(OUT_ENC_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt
mkdir -p $(LIBWEBP_DIR)/build && cp $(LIBSHARPYUV_ST) $(LIBSHARPYUV)
$(MAKE) \ $(MAKE) \
$(HELPER_MAKEFLAGS) \ $(HELPER_MAKEFLAGS) \
OUT_JS=$@ \ OUT_JS=$@ \
@@ -50,12 +42,9 @@ $(OUT_ENC_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLis
-DCONFIG_AV1_HIGHBITDEPTH=0 \ -DCONFIG_AV1_HIGHBITDEPTH=0 \
" \ " \
ENVIRONMENT=$(ENVIRONMENT) \ ENVIRONMENT=$(ENVIRONMENT) \
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_DECODE=0 -DAVIF_LOCAL_LIBSHARPYUV=ON" LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_DECODE=0"
# MT-Encoding $(OUT_ENC_MT_JS) $(OUT_NODE_ENC_MT_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt
# We need to run the ST and MT tasks sequentially to avoid conflicts with the copy of libsharpyuv in the build directory
$(OUT_ENC_MT_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt $(LIBSHARPYUV_MT) | $(OUT_ENC_JS)
mkdir -p $(LIBWEBP_DIR)/build && cp $(LIBSHARPYUV_MT) $(LIBSHARPYUV)
$(MAKE) \ $(MAKE) \
$(HELPER_MAKEFLAGS) \ $(HELPER_MAKEFLAGS) \
OUT_JS=$@ \ OUT_JS=$@ \
@@ -65,11 +54,11 @@ $(OUT_ENC_MT_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMake
-DCONFIG_AV1_HIGHBITDEPTH=0 \ -DCONFIG_AV1_HIGHBITDEPTH=0 \
" \ " \
ENVIRONMENT=$(ENVIRONMENT) \ ENVIRONMENT=$(ENVIRONMENT) \
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_DECODE=0 -DAVIF_LOCAL_LIBSHARPYUV=ON" \ LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_DECODE=0" \
OUT_FLAGS="-pthread" OUT_FLAGS="-pthread"
# Decoding $(OUT_NODE_DEC_JS): ENVIRONMENT=node
$(OUT_DEC_JS): $(OUT_DEC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt $(OUT_NODE_DEC_JS) $(OUT_DEC_JS): $(OUT_DEC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt
$(MAKE) \ $(MAKE) \
$(HELPER_MAKEFLAGS) \ $(HELPER_MAKEFLAGS) \
OUT_JS=$@ \ OUT_JS=$@ \
@@ -81,77 +70,22 @@ $(OUT_DEC_JS): $(OUT_DEC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLis
ENVIRONMENT=$(ENVIRONMENT) \ ENVIRONMENT=$(ENVIRONMENT) \
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_ENCODE=0" LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_ENCODE=0"
# LIBAOM EXTRACTION SECTION $(CODEC_PACKAGE):
mkdir -p $(@D)
curl -sL $(CODEC_URL) -o $@
# Download the libaom tarball
$(LIBAOM_PACKAGE): $(LIBAOM_PACKAGE):
mkdir -p $(@D) mkdir -p $(@D)
curl -sL $(LIBAOM_URL) -o $@ curl -sL $(LIBAOM_URL) -o $@
# Extract libaom from the tarball $(CODEC_DIR)/CMakeLists.txt: $(CODEC_PACKAGE)
mkdir -p $(@D)
tar xzm --strip 1 -C $(@D) -f $(CODEC_PACKAGE)
$(LIBAOM_DIR)/CMakeLists.txt: $(LIBAOM_PACKAGE) $(LIBAOM_DIR)/CMakeLists.txt: $(LIBAOM_PACKAGE)
mkdir -p $(@D) mkdir -p $(@D)
tar xzm -C $(@D) -f $(LIBAOM_PACKAGE) tar xzm -C $(@D) -f $(LIBAOM_PACKAGE)
# LIBAVIF EXTRACTION SECTION
# Download the libavif tarball
$(LIBAVIF_PACKAGE):
mkdir -p $(@D)
curl -sL $(LIBAVIF_URL) -o $@
# Extract libavif from the tarball
$(CODEC_DIR)/CMakeLists.txt: $(LIBAVIF_PACKAGE)
mkdir -p $(@D)
tar xzm --strip 1 -C $(@D) -f $(LIBAVIF_PACKAGE)
# Create libavif/ext/libwebp
$(LIBWEBP_DIR)/CMakeLists.txt: $(CODEC_DIR)/CMakeLists.txt
mkdir -p $(LIBWEBP_DIR)
curl -sL $(LIBWEBP_URL_WITH_SHARPYUV) \
| tar xzm -C $(LIBWEBP_DIR)
# Make libsharpyuv.a for ST-Encoding
$(LIBSHARPYUV_ST): $(LIBWEBP_DIR)/CMakeLists.txt
mkdir -p $(@D)
emcmake cmake \
-DWEBP_USE_THREAD=OFF \
-DWEBP_BUILD_ANIM_UTILS=OFF \
-DWEBP_BUILD_CWEBP=OFF \
-DWEBP_BUILD_DWEBP=OFF \
-DWEBP_BUILD_GIF2WEBP=OFF \
-DWEBP_BUILD_IMG2WEBP=OFF \
-DWEBP_BUILD_VWEBP=OFF \
-DWEBP_BUILD_WEBPINFO=OFF \
-DWEBP_BUILD_LIBWEBPMUX=OFF \
-DWEBP_BUILD_WEBPMUX=OFF \
-DWEBP_BUILD_EXTRAS=OFF \
-DBUILD_SHARED_LIBS=OFF \
-DCMAKE_BUILD_TYPE=Release \
-S $(LIBWEBP_DIR) \
-B $(@D)
$(MAKE) -C $(@D) sharpyuv
# Make libsharpyuv.a for MT-Encoding
$(LIBSHARPYUV_MT): $(LIBWEBP_DIR)/CMakeLists.txt
mkdir -p $(@D)
emcmake cmake \
-DWEBP_BUILD_ANIM_UTILS=OFF \
-DWEBP_BUILD_CWEBP=OFF \
-DWEBP_BUILD_DWEBP=OFF \
-DWEBP_BUILD_GIF2WEBP=OFF \
-DWEBP_BUILD_IMG2WEBP=OFF \
-DWEBP_BUILD_VWEBP=OFF \
-DWEBP_BUILD_WEBPINFO=OFF \
-DWEBP_BUILD_LIBWEBPMUX=OFF \
-DWEBP_BUILD_WEBPMUX=OFF \
-DWEBP_BUILD_EXTRAS=OFF \
-DBUILD_SHARED_LIBS=OFF \
-DCMAKE_BUILD_TYPE=Release \
-S $(LIBWEBP_DIR) \
-B $(@D)
$(MAKE) -C $(@D) sharpyuv
clean: clean:
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_ENC_JS) clean $(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_ENC_JS) clean
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_ENC_MT_JS) clean $(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_ENC_MT_JS) clean

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

View File

@@ -3,27 +3,15 @@
#include <emscripten/val.h> #include <emscripten/val.h>
#include "avif/avif.h" #include "avif/avif.h"
#include <memory>
#include <string>
#define RETURN_NULL_IF(expression) \
do { \
if (expression) \
return val::null(); \
} while (false)
using namespace emscripten; using namespace emscripten;
using AvifImagePtr = std::unique_ptr<avifImage, decltype(&avifImageDestroy)>;
using AvifEncoderPtr = std::unique_ptr<avifEncoder, decltype(&avifEncoderDestroy)>;
struct AvifOptions { struct AvifOptions {
// [0 - 100] // [0 - 63]
// 0 = worst quality // 0 = lossless
// 100 = lossless // 63 = worst quality
int quality; int cqLevel;
// As above, but -1 means 'use quality' // As above, but -1 means 'use cqLevel'
int qualityAlpha; int cqAlphaLevel;
// [0 - 6] // [0 - 6]
// Creates 2^n tiles in that dimension // Creates 2^n tiles in that dimension
int tileRowsLog2; int tileRowsLog2;
@@ -47,15 +35,12 @@ struct AvifOptions {
int tune; int tune;
// 0-50 // 0-50
int denoiseLevel; int denoiseLevel;
// toggles AVIF_CHROMA_DOWNSAMPLING_SHARP_YUV
bool enableSharpYUV;
}; };
thread_local const val Uint8Array = val::global("Uint8Array"); thread_local const val Uint8Array = val::global("Uint8Array");
val encode(std::string buffer, int width, int height, AvifOptions options) { val encode(std::string buffer, int width, int height, AvifOptions options) {
avifResult status; // To check the return status for avif API's avifRWData output = AVIF_DATA_EMPTY;
int depth = 8; int depth = 8;
avifPixelFormat format; avifPixelFormat format;
switch (options.subsample) { switch (options.subsample) {
@@ -73,13 +58,11 @@ val encode(std::string buffer, int width, int height, AvifOptions options) {
break; break;
} }
bool lossless = options.quality == AVIF_QUALITY_LOSSLESS && bool lossless = options.cqLevel == AVIF_QUANTIZER_LOSSLESS &&
(options.qualityAlpha == -1 || options.qualityAlpha == AVIF_QUALITY_LOSSLESS) && options.cqAlphaLevel <= AVIF_QUANTIZER_LOSSLESS &&
format == AVIF_PIXEL_FORMAT_YUV444; format == AVIF_PIXEL_FORMAT_YUV444;
// Smart pointer for the input image in YUV format avifImage* image = avifImageCreate(width, height, depth, format);
AvifImagePtr image(avifImageCreate(width, height, depth, format), avifImageDestroy);
RETURN_NULL_IF(image == nullptr);
if (lossless) { if (lossless) {
image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_IDENTITY; image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_IDENTITY;
@@ -90,49 +73,43 @@ val encode(std::string buffer, int width, int height, AvifOptions options) {
uint8_t* rgba = reinterpret_cast<uint8_t*>(const_cast<char*>(buffer.data())); uint8_t* rgba = reinterpret_cast<uint8_t*>(const_cast<char*>(buffer.data()));
avifRGBImage srcRGB; avifRGBImage srcRGB;
avifRGBImageSetDefaults(&srcRGB, image.get()); avifRGBImageSetDefaults(&srcRGB, image);
srcRGB.pixels = rgba; srcRGB.pixels = rgba;
srcRGB.rowBytes = width * 4; srcRGB.rowBytes = width * 4;
if (options.enableSharpYUV) { avifImageRGBToYUV(image, &srcRGB);
srcRGB.chromaDownsampling = AVIF_CHROMA_DOWNSAMPLING_SHARP_YUV;
}
status = avifImageRGBToYUV(image.get(), &srcRGB);
RETURN_NULL_IF(status != AVIF_RESULT_OK);
// Create a smart pointer for the encoder avifEncoder* encoder = avifEncoderCreate();
AvifEncoderPtr encoder(avifEncoderCreate(), avifEncoderDestroy);
RETURN_NULL_IF(encoder == nullptr);
if (lossless) { if (lossless) {
encoder->quality = AVIF_QUALITY_LOSSLESS; encoder->minQuantizer = AVIF_QUANTIZER_LOSSLESS;
encoder->qualityAlpha = AVIF_QUALITY_LOSSLESS; encoder->maxQuantizer = AVIF_QUANTIZER_LOSSLESS;
encoder->minQuantizerAlpha = AVIF_QUANTIZER_LOSSLESS;
encoder->maxQuantizerAlpha = AVIF_QUANTIZER_LOSSLESS;
} else { } else {
status = avifEncoderSetCodecSpecificOption(encoder.get(), "sharpness", encoder->minQuantizer = AVIF_QUANTIZER_BEST_QUALITY;
std::to_string(options.sharpness).c_str()); encoder->maxQuantizer = AVIF_QUANTIZER_WORST_QUALITY;
RETURN_NULL_IF(status != AVIF_RESULT_OK); encoder->minQuantizerAlpha = AVIF_QUANTIZER_BEST_QUALITY;
encoder->maxQuantizerAlpha = AVIF_QUANTIZER_WORST_QUALITY;
avifEncoderSetCodecSpecificOption(encoder, "end-usage", "q");
avifEncoderSetCodecSpecificOption(encoder, "cq-level", std::to_string(options.cqLevel).c_str());
avifEncoderSetCodecSpecificOption(encoder, "sharpness",
std::to_string(options.sharpness).c_str());
// Set base quality if (options.cqAlphaLevel != -1) {
encoder->quality = options.quality; avifEncoderSetCodecSpecificOption(encoder, "alpha:cq-level",
// Conditionally set alpha quality std::to_string(options.cqAlphaLevel).c_str());
if (options.qualityAlpha == -1) {
encoder->qualityAlpha = options.quality;
} else {
encoder->qualityAlpha = options.qualityAlpha;
} }
if (options.tune == 2 || (options.tune == 0 && options.quality >= 50)) { if (options.tune == 2 || (options.tune == 0 && options.cqLevel <= 32)) {
status = avifEncoderSetCodecSpecificOption(encoder.get(), "tune", "ssim"); avifEncoderSetCodecSpecificOption(encoder, "tune", "ssim");
RETURN_NULL_IF(status != AVIF_RESULT_OK);
} }
if (options.chromaDeltaQ) { if (options.chromaDeltaQ) {
status = avifEncoderSetCodecSpecificOption(encoder.get(), "color:enable-chroma-deltaq", "1"); avifEncoderSetCodecSpecificOption(encoder, "enable-chroma-deltaq", "1");
RETURN_NULL_IF(status != AVIF_RESULT_OK);
} }
status = avifEncoderSetCodecSpecificOption(encoder.get(), "color:denoise-noise-level", avifEncoderSetCodecSpecificOption(encoder, "color:denoise-noise-level",
std::to_string(options.denoiseLevel).c_str()); std::to_string(options.denoiseLevel).c_str());
RETURN_NULL_IF(status != AVIF_RESULT_OK);
} }
encoder->maxThreads = emscripten_num_logical_cores(); encoder->maxThreads = emscripten_num_logical_cores();
@@ -140,21 +117,22 @@ val encode(std::string buffer, int width, int height, AvifOptions options) {
encoder->tileColsLog2 = options.tileColsLog2; encoder->tileColsLog2 = options.tileColsLog2;
encoder->speed = options.speed; encoder->speed = options.speed;
avifRWData output = AVIF_DATA_EMPTY; avifResult encodeResult = avifEncoderWrite(encoder, image, &output);
avifResult encodeResult = avifEncoderWrite(encoder.get(), image.get(), &output);
auto js_result = val::null(); auto js_result = val::null();
if (encodeResult == AVIF_RESULT_OK) { if (encodeResult == AVIF_RESULT_OK) {
js_result = Uint8Array.new_(typed_memory_view(output.size, output.data)); js_result = Uint8Array.new_(typed_memory_view(output.size, output.data));
} }
avifImageDestroy(image);
avifEncoderDestroy(encoder);
avifRWDataFree(&output); avifRWDataFree(&output);
return js_result; return js_result;
} }
EMSCRIPTEN_BINDINGS(my_module) { EMSCRIPTEN_BINDINGS(my_module) {
value_object<AvifOptions>("AvifOptions") value_object<AvifOptions>("AvifOptions")
.field("quality", &AvifOptions::quality) .field("cqLevel", &AvifOptions::cqLevel)
.field("qualityAlpha", &AvifOptions::qualityAlpha) .field("cqAlphaLevel", &AvifOptions::cqAlphaLevel)
.field("tileRowsLog2", &AvifOptions::tileRowsLog2) .field("tileRowsLog2", &AvifOptions::tileRowsLog2)
.field("tileColsLog2", &AvifOptions::tileColsLog2) .field("tileColsLog2", &AvifOptions::tileColsLog2)
.field("speed", &AvifOptions::speed) .field("speed", &AvifOptions::speed)
@@ -162,8 +140,7 @@ EMSCRIPTEN_BINDINGS(my_module) {
.field("sharpness", &AvifOptions::sharpness) .field("sharpness", &AvifOptions::sharpness)
.field("tune", &AvifOptions::tune) .field("tune", &AvifOptions::tune)
.field("denoiseLevel", &AvifOptions::denoiseLevel) .field("denoiseLevel", &AvifOptions::denoiseLevel)
.field("subsample", &AvifOptions::subsample) .field("subsample", &AvifOptions::subsample);
.field("enableSharpYUV", &AvifOptions::enableSharpYUV);
function("encode", &encode); function("encode", &encode);
} }

View File

@@ -5,16 +5,15 @@ export const enum AVIFTune {
} }
export interface EncodeOptions { export interface EncodeOptions {
quality: number; cqLevel: number;
qualityAlpha: number;
denoiseLevel: number; denoiseLevel: number;
cqAlphaLevel: number;
tileRowsLog2: number; tileRowsLog2: number;
tileColsLog2: number; tileColsLog2: number;
speed: number; speed: number;
subsample: number; subsample: number;
chromaDeltaQ: boolean; chromaDeltaQ: boolean;
sharpness: number; sharpness: number;
enableSharpYUV: boolean;
tune: AVIFTune; tune: AVIFTune;
} }

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -1 +1 @@
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./avif_enc_mt.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance})}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,0,0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["__emscripten_thread_exit"](result)}}catch(ex){if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["__emscripten_thread_exit"](ex.status)}}else{throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["__emscripten_thread_exit"](-1)}postMessage({"cmd":"cancelDone"})}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}}; "use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};function moduleLoaded(){}self.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./avif_enc_mt.js")).then(function(exports){return exports.default(Module)}).then(function(instance){Module=instance;moduleLoaded()})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,0,0);var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();if(!initializedJS){Module["___embind_register_native_and_builtin_types"]();initializedJS=true}try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["PThread"].threadExit(result)}}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["PThread"].threadExit(ex.status)}}else{Module["PThread"].threadExit(-2);throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(Module["_pthread_self"]()){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -10,11 +10,8 @@
# $(LIBAVIF_FLAGS) # $(LIBAVIF_FLAGS)
# $(ENVIRONMENT) # $(ENVIRONMENT)
# $(OUT_JS) is something like "enc/avif_enc.js" or "enc/avif_enc_mt.js"
# so $(OUT_BUILD_DIR) will be "node_modules/build/enc/avif_enc[_mt]"
OUT_BUILD_DIR := $(BUILD_DIR)/$(basename $(OUT_JS)) OUT_BUILD_DIR := $(BUILD_DIR)/$(basename $(OUT_JS))
# We're making libavif and libaom for every node_modules/[enc|dec]/
CODEC_BUILD_DIR := $(OUT_BUILD_DIR)/libavif CODEC_BUILD_DIR := $(OUT_BUILD_DIR)/libavif
CODEC_OUT := $(CODEC_BUILD_DIR)/libavif.a CODEC_OUT := $(CODEC_BUILD_DIR)/libavif.a
@@ -28,13 +25,6 @@ OUT_WORKER=$(OUT_JS:.js=.worker.js)
all: $(OUT_JS) all: $(OUT_JS)
# Only add libsharpyuv as a dependency for encoders.
# Yes, that if statement is true for encoders.
ifneq (,$(findstring enc/, $(OUT_JS)))
$(OUT_JS): $(LIBSHARPYUV)
$(CODEC_OUT): $(LIBSHARPYUV)
endif
$(OUT_JS): $(OUT_CPP) $(LIBAOM_OUT) $(CODEC_OUT) $(OUT_JS): $(OUT_CPP) $(LIBAOM_OUT) $(CODEC_OUT)
$(CXX) \ $(CXX) \
-I $(CODEC_DIR)/include \ -I $(CODEC_DIR)/include \
@@ -42,7 +32,6 @@ $(OUT_JS): $(OUT_CPP) $(LIBAOM_OUT) $(CODEC_OUT)
$(LDFLAGS) \ $(LDFLAGS) \
$(OUT_FLAGS) \ $(OUT_FLAGS) \
--bind \ --bind \
-s ERROR_ON_UNDEFINED_SYMBOLS=0 \
-s ENVIRONMENT=$(ENVIRONMENT) \ -s ENVIRONMENT=$(ENVIRONMENT) \
-s EXPORT_ES6=1 \ -s EXPORT_ES6=1 \
-o $@ \ -o $@ \
@@ -50,7 +39,6 @@ $(OUT_JS): $(OUT_CPP) $(LIBAOM_OUT) $(CODEC_OUT)
$(CODEC_OUT): $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_OUT) $(CODEC_OUT): $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_OUT)
emcmake cmake \ emcmake cmake \
-DCMAKE_LIBRARY_PATH=$(LIBSHARPYUV_BUILD_DIR) \
-DCMAKE_BUILD_TYPE=Release \ -DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=0 \ -DBUILD_SHARED_LIBS=0 \
-DAVIF_CODEC_AOM=1 \ -DAVIF_CODEC_AOM=1 \

View File

@@ -1,4 +1,4 @@
FROM emscripten/emsdk:2.0.34 FROM emscripten/emsdk:2.0.23
RUN apt-get update && apt-get install -qqy autoconf libtool pkg-config RUN apt-get update && apt-get install -qqy autoconf libtool pkg-config
ENV CFLAGS "-O3 -flto" ENV CFLAGS "-O3 -flto"
ENV CXXFLAGS "${CFLAGS} -std=c++17" ENV CXXFLAGS "${CFLAGS} -std=c++17"

409
codecs/oxipng/Cargo.lock generated
View File

@@ -2,6 +2,18 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "adler"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
[[package]]
name = "adler32"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.0.1" version = "1.0.1"
@@ -9,16 +21,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]] [[package]]
name = "bitvec" name = "bit-vec"
version = "1.0.1" version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
dependencies = [
"funty", [[package]]
"radium", name = "bitflags"
"tap", version = "1.2.1"
"wyz", source = "registry+https://github.com/rust-lang/crates.io-index"
] checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "build_const"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39"
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
@@ -28,9 +46,15 @@ checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820"
[[package]] [[package]]
name = "bytemuck" name = "bytemuck"
version = "1.14.0" version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" checksum = "41aa2ec95ca3b5c54cf73c91acf06d24f4495d5f1b1c12506ae3483d646177ac"
[[package]]
name = "byteorder"
version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
[[package]] [[package]]
name = "cc" name = "cc"
@@ -38,6 +62,12 @@ version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
@@ -45,44 +75,107 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "crossbeam-channel" name = "cloudflare-zlib"
version = "0.5.10" version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82a9b73a36529d9c47029b9fb3a6f0ea3cc916a261195352ba19e770fc1748b2" checksum = "f5ed63a019d55bacd15cadcbcb96bf41b16281417fff393bdb55fa84255fe4b9"
dependencies = [ dependencies = [
"cfg-if", "cloudflare-zlib-sys",
]
[[package]]
name = "cloudflare-zlib-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e195cb274a0d6ee87e718838a09baecd7cbc9f6075dac256a84cb5842739c06"
dependencies = [
"cc",
]
[[package]]
name = "color_quant"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]]
name = "const_fn"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6"
[[package]]
name = "crc"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb"
dependencies = [
"build_const",
]
[[package]]
name = "crc32fast"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]] [[package]]
name = "crossbeam-deque" name = "crossbeam-deque"
version = "0.8.4" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"crossbeam-epoch", "crossbeam-epoch",
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]] [[package]]
name = "crossbeam-epoch" name = "crossbeam-epoch"
version = "0.9.17" version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d" checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d"
dependencies = [ dependencies = [
"autocfg", "cfg-if 1.0.0",
"cfg-if", "const_fn",
"crossbeam-utils", "crossbeam-utils",
"lazy_static",
"memoffset",
"scopeguard",
] ]
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.18" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"
dependencies = [ dependencies = [
"cfg-if", "autocfg",
"cfg-if 1.0.0",
"lazy_static",
]
[[package]]
name = "deflate"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174"
dependencies = [
"adler32",
"byteorder",
] ]
[[package]] [[package]]
@@ -91,35 +184,56 @@ version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "funty"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.14.3" version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
[[package]]
name = "hermit-abi"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
dependencies = [
"libc",
]
[[package]]
name = "image"
version = "0.23.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ce04077ead78e39ae8610ad26216aed811996b043d47beed5090db674f9e9b5"
dependencies = [
"bytemuck",
"byteorder",
"color_quant",
"num-iter",
"num-rational",
"num-traits",
"png",
]
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.1.0" version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b"
dependencies = [ dependencies = [
"equivalent", "autocfg",
"hashbrown", "hashbrown",
"rayon", "rayon",
] ]
[[package]]
name = "itertools"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319"
dependencies = [
"either",
]
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.48" version = "0.3.48"
@@ -136,46 +250,160 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libdeflate-sys" name = "libc"
version = "1.19.0" version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67921a7f85100c1559efc3d1c7c472091b7da05f304b4bbd5356f075e97f1cc2" checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
[[package]]
name = "libdeflate-sys"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a95fa4be7085dd06a8296dcc3f399f12ab8b0309c157dcaa90669130b175b97"
dependencies = [ dependencies = [
"cc", "cc",
] ]
[[package]] [[package]]
name = "libdeflater" name = "libdeflater"
version = "1.19.0" version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a31b22f662350ec294b13859f935aea772ba7b2bc8776269f4a5627308eab7d" checksum = "ccc147465654929bf7b56518cc46d11701ba290f4ff94398ae3f89f1663cf60f"
dependencies = [ dependencies = [
"libdeflate-sys", "libdeflate-sys",
] ]
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.20" version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
dependencies = [
"cfg-if 0.1.10",
]
[[package]]
name = "memoffset"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
dependencies = [
"autocfg",
]
[[package]]
name = "miniz_oxide"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435"
dependencies = [
"adler32",
]
[[package]]
name = "miniz_oxide"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d"
dependencies = [
"adler",
"autocfg",
]
[[package]]
name = "num-integer"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
dependencies = [
"hermit-abi",
"libc",
]
[[package]] [[package]]
name = "oxipng" name = "oxipng"
version = "9.0.0" version = "4.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28e5c341ef78a228e47a551bfd15ff885d8c501af49f953358763a538c01f14d" checksum = "50d0b53912a666fe2970f8ab254e283531c816aed16551ab66c52485eadb44e6"
dependencies = [ dependencies = [
"bitvec", "bit-vec",
"byteorder",
"cloudflare-zlib",
"crc",
"crossbeam-channel", "crossbeam-channel",
"image",
"indexmap", "indexmap",
"itertools",
"libdeflater", "libdeflater",
"log", "log",
"miniz_oxide 0.4.3",
"rayon", "rayon",
"rgb", "rgb",
"rustc-hash",
"rustc_version", "rustc_version",
] ]
[[package]]
name = "pest"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
dependencies = [
"ucd-trie",
]
[[package]]
name = "png"
version = "0.16.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6"
dependencies = [
"bitflags",
"crc32fast",
"deflate",
"miniz_oxide 0.3.7",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.26" version = "1.0.26"
@@ -194,61 +422,72 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "radium"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]] [[package]]
name = "rayon" name = "rayon"
version = "1.8.0" version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674"
dependencies = [ dependencies = [
"autocfg",
"crossbeam-deque",
"either", "either",
"rayon-core", "rayon-core",
] ]
[[package]] [[package]]
name = "rayon-core" name = "rayon-core"
version = "1.12.0" version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
dependencies = [ dependencies = [
"crossbeam-channel",
"crossbeam-deque", "crossbeam-deque",
"crossbeam-utils", "crossbeam-utils",
"lazy_static",
"num_cpus",
] ]
[[package]] [[package]]
name = "rgb" name = "rgb"
version = "0.8.37" version = "0.8.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8" checksum = "287f3c3f8236abb92d8b7e36797f19159df4b58f0a658cc3fb6dd3004b1f3bd3"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
] ]
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]] [[package]]
name = "rustc_version" name = "rustc_version"
version = "0.4.0" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" checksum = "65c94201b44764d6d1f7e37c15a8289ed55e546c1762c7f1d57f616966e0c181"
dependencies = [ dependencies = [
"semver", "semver",
] ]
[[package]] [[package]]
name = "semver" name = "scopeguard"
version = "1.0.21" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "semver"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
dependencies = [
"pest",
]
[[package]] [[package]]
name = "spmc" name = "spmc"
@@ -260,6 +499,7 @@ checksum = "02a8428da277a8e3a15271d79943e80ccc2ef254e78813a166a08d65e4c3ece5"
name = "squoosh-oxipng" name = "squoosh-oxipng"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"libdeflater",
"log", "log",
"oxipng", "oxipng",
"wasm-bindgen", "wasm-bindgen",
@@ -278,10 +518,10 @@ dependencies = [
] ]
[[package]] [[package]]
name = "tap" name = "ucd-trie"
version = "1.0.1" version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
@@ -295,7 +535,7 @@ version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"wasm-bindgen-macro", "wasm-bindgen-macro",
] ]
@@ -354,12 +594,3 @@ name = "wasm-bindgen-shared"
version = "0.2.74" version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f" checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
[[package]]
name = "wyz"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
dependencies = [
"tap",
]

View File

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

View File

@@ -1,5 +1,5 @@
# OxiPNG # OxiPNG
- Source: <https://github.com/shssoichiro/oxipng> - Source: <https://github.com/shssoichiro/oxipng>
- Version: v9.0.0 - Version: v3.0.0
- License: MIT - License: MIT

View File

@@ -5,5 +5,5 @@ set -e
rm -rf pkg,{-parallel} rm -rf pkg,{-parallel}
export CFLAGS="${CFLAGS} -DUNALIGNED_ACCESS_IS_FAST=1" export CFLAGS="${CFLAGS} -DUNALIGNED_ACCESS_IS_FAST=1"
wasm-pack build -t web wasm-pack build -t web
RUSTFLAGS='-C target-feature=+atomics,+bulk-memory' wasm-pack build -t web -d pkg-parallel . -- -Z build-std=panic_abort,std --features=parallel RUSTFLAGS='-C target-feature=+atomics,+bulk-memory' wasm-pack build -t web -d pkg-parallel -- -Z build-std=panic_abort,std --features=parallel
rm pkg{,-parallel}/.gitignore rm pkg{,-parallel}/.gitignore

View File

@@ -1,6 +1,6 @@
{ {
"name": "oxipng", "name": "oxipng",
"scripts": { "scripts": {
"build": "RUST_IMG=rustlang/rust@sha256:5fd16a5576c22c8fdd5d659247755999e426c04de8dcf18a41ea446c5f253309 ../build-rust.sh ./build.sh" "build": "RUST_IMG=rustlang/rust@sha256:744aeea5a38f95aa7a96ec37269a65f0c6197a1cdd87d6534e12bb869141d807 ../build-rust.sh ./build.sh"
} }
} }

View File

@@ -1,5 +1,5 @@
# OxiPNG # OxiPNG
- Source: <https://github.com/shssoichiro/oxipng> - Source: <https://github.com/shssoichiro/oxipng>
- Version: v9.0.0 - Version: v3.0.0
- License: MIT - License: MIT

View File

@@ -11,7 +11,5 @@
], ],
"module": "squoosh_oxipng.js", "module": "squoosh_oxipng.js",
"types": "squoosh_oxipng.d.ts", "types": "squoosh_oxipng.d.ts",
"sideEffects": [ "sideEffects": false
"./snippets/*"
]
} }

View File

@@ -1,14 +1,12 @@
/* tslint:disable */ /* tslint:disable */
/* eslint-disable */ /* eslint-disable */
/** /**
* @param {Uint8ClampedArray} data * @param {Uint8Array} data
* @param {number} width
* @param {number} height
* @param {number} level * @param {number} level
* @param {boolean} interlace * @param {boolean} interlace
* @returns {Uint8Array} * @returns {Uint8Array}
*/ */
export function optimise(data: Uint8ClampedArray, width: number, height: number, level: number, interlace: boolean): Uint8Array; export function optimise(data: Uint8Array, level: number, interlace: boolean): Uint8Array;
/** /**
* @param {number} num_threads * @param {number} num_threads
* @returns {Promise<any>} * @returns {Promise<any>}
@@ -38,7 +36,8 @@ export class wbg_rayon_PoolBuilder {
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module; export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
export interface InitOutput { export interface InitOutput {
readonly optimise: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void; readonly __wasm_init_memory: () => void;
readonly optimise: (a: number, b: number, c: number, d: number, e: number) => void;
readonly __wbg_wbg_rayon_poolbuilder_free: (a: number) => void; readonly __wbg_wbg_rayon_poolbuilder_free: (a: number) => void;
readonly wbg_rayon_poolbuilder_numThreads: (a: number) => number; readonly wbg_rayon_poolbuilder_numThreads: (a: number) => number;
readonly wbg_rayon_poolbuilder_receiver: (a: number) => number; readonly wbg_rayon_poolbuilder_receiver: (a: number) => number;

View File

@@ -54,19 +54,17 @@ function getArrayU8FromWasm0(ptr, len) {
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len); return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len);
} }
/** /**
* @param {Uint8ClampedArray} data * @param {Uint8Array} data
* @param {number} width
* @param {number} height
* @param {number} level * @param {number} level
* @param {boolean} interlace * @param {boolean} interlace
* @returns {Uint8Array} * @returns {Uint8Array}
*/ */
export function optimise(data, width, height, level, interlace) { export function optimise(data, level, interlace) {
try { try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
var ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc); var ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
var len0 = WASM_VECTOR_LEN; var len0 = WASM_VECTOR_LEN;
wasm.optimise(retptr, ptr0, len0, width, height, level, interlace); wasm.optimise(retptr, ptr0, len0, level, interlace);
var r0 = getInt32Memory0()[retptr / 4 + 0]; var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1]; var r1 = getInt32Memory0()[retptr / 4 + 1];
var v1 = getArrayU8FromWasm0(r0, r1).slice(); var v1 = getArrayU8FromWasm0(r0, r1).slice();

View File

@@ -1,6 +1,7 @@
/* tslint:disable */ /* tslint:disable */
/* eslint-disable */ /* eslint-disable */
export function optimise(a: number, b: number, c: number, d: number, e: number, f: number, g: number): void; export function __wasm_init_memory(): void;
export function optimise(a: number, b: number, c: number, d: number, e: number): void;
export function __wbg_wbg_rayon_poolbuilder_free(a: number): void; export function __wbg_wbg_rayon_poolbuilder_free(a: number): void;
export function wbg_rayon_poolbuilder_numThreads(a: number): number; export function wbg_rayon_poolbuilder_numThreads(a: number): number;
export function wbg_rayon_poolbuilder_receiver(a: number): number; export function wbg_rayon_poolbuilder_receiver(a: number): number;

View File

@@ -1,5 +1,5 @@
# OxiPNG # OxiPNG
- Source: <https://github.com/shssoichiro/oxipng> - Source: <https://github.com/shssoichiro/oxipng>
- Version: v9.0.0 - Version: v3.0.0
- License: MIT - License: MIT

View File

@@ -11,7 +11,5 @@
], ],
"module": "squoosh_oxipng.js", "module": "squoosh_oxipng.js",
"types": "squoosh_oxipng.d.ts", "types": "squoosh_oxipng.d.ts",
"sideEffects": [ "sideEffects": false
"./snippets/*"
]
} }

View File

@@ -1,20 +1,18 @@
/* tslint:disable */ /* tslint:disable */
/* eslint-disable */ /* eslint-disable */
/** /**
* @param {Uint8ClampedArray} data * @param {Uint8Array} data
* @param {number} width
* @param {number} height
* @param {number} level * @param {number} level
* @param {boolean} interlace * @param {boolean} interlace
* @returns {Uint8Array} * @returns {Uint8Array}
*/ */
export function optimise(data: Uint8ClampedArray, width: number, height: number, level: number, interlace: boolean): Uint8Array; export function optimise(data: Uint8Array, level: number, interlace: boolean): Uint8Array;
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module; export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
export interface InitOutput { export interface InitOutput {
readonly memory: WebAssembly.Memory; readonly memory: WebAssembly.Memory;
readonly optimise: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void; readonly optimise: (a: number, b: number, c: number, d: number, e: number) => void;
readonly __wbindgen_add_to_stack_pointer: (a: number) => number; readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
readonly __wbindgen_malloc: (a: number) => number; readonly __wbindgen_malloc: (a: number) => number;
readonly __wbindgen_free: (a: number, b: number) => void; readonly __wbindgen_free: (a: number, b: number) => void;

View File

@@ -38,19 +38,17 @@ function getArrayU8FromWasm0(ptr, len) {
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len); return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len);
} }
/** /**
* @param {Uint8ClampedArray} data * @param {Uint8Array} data
* @param {number} width
* @param {number} height
* @param {number} level * @param {number} level
* @param {boolean} interlace * @param {boolean} interlace
* @returns {Uint8Array} * @returns {Uint8Array}
*/ */
export function optimise(data, width, height, level, interlace) { export function optimise(data, level, interlace) {
try { try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
var ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc); var ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
var len0 = WASM_VECTOR_LEN; var len0 = WASM_VECTOR_LEN;
wasm.optimise(retptr, ptr0, len0, width, height, level, interlace); wasm.optimise(retptr, ptr0, len0, level, interlace);
var r0 = getInt32Memory0()[retptr / 4 + 0]; var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1]; var r1 = getInt32Memory0()[retptr / 4 + 1];
var v1 = getArrayU8FromWasm0(r0, r1).slice(); var v1 = getArrayU8FromWasm0(r0, r1).slice();

View File

@@ -1,7 +1,7 @@
/* tslint:disable */ /* tslint:disable */
/* eslint-disable */ /* eslint-disable */
export const memory: WebAssembly.Memory; export const memory: WebAssembly.Memory;
export function optimise(a: number, b: number, c: number, d: number, e: number, f: number, g: number): void; export function optimise(a: number, b: number, c: number, d: number, e: number): void;
export function __wbindgen_add_to_stack_pointer(a: number): number; export function __wbindgen_add_to_stack_pointer(a: number): number;
export function __wbindgen_malloc(a: number): number; export function __wbindgen_malloc(a: number): number;
export function __wbindgen_free(a: number, b: number): void; export function __wbindgen_free(a: number, b: number): void;

View File

@@ -1,27 +1,20 @@
#[cfg(feature = "parallel")] #[cfg(feature = "parallel")]
pub use wasm_bindgen_rayon::init_thread_pool; pub use wasm_bindgen_rayon::init_thread_pool;
use oxipng::{BitDepth, ColorType, Interlacing}; use oxipng::AlphaOptim;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use wasm_bindgen::Clamped;
#[wasm_bindgen] #[wasm_bindgen]
pub fn optimise( pub fn optimise(data: &[u8], level: u8, interlace: bool) -> Vec<u8> {
data: Clamped<Vec<u8>>,
width: u32,
height: u32,
level: u8,
interlace: bool,
) -> Vec<u8> {
let mut options = oxipng::Options::from_preset(level); let mut options = oxipng::Options::from_preset(level);
options.optimize_alpha = true; options.alphas.insert(AlphaOptim::Black);
options.interlace = Some(if interlace { options.alphas.insert(AlphaOptim::White);
Interlacing::Adam7 options.alphas.insert(AlphaOptim::Up);
} else { options.alphas.insert(AlphaOptim::Down);
Interlacing::None options.alphas.insert(AlphaOptim::Left);
}); options.alphas.insert(AlphaOptim::Right);
options.interlace = Some(if interlace { 1 } else { 0 });
let raw = oxipng::RawImage::new(width, height, ColorType::RGBA, BitDepth::Eight, data.0) options.deflate = oxipng::Deflaters::Libdeflater;
.unwrap_throw(); oxipng::optimize_from_memory(data, &options).unwrap_throw()
raw.create_optimized_png(&options).unwrap_throw()
} }

View File

@@ -20,7 +20,6 @@ val decode(std::string qoiimage) {
val result = ImageData.new_( val result = ImageData.new_(
Uint8ClampedArray.new_(typed_memory_view(4 * decodedWidth * decodedHeight, rgba)), Uint8ClampedArray.new_(typed_memory_view(4 * decodedWidth * decodedHeight, rgba)),
decodedWidth, decodedHeight); decodedWidth, decodedHeight);
free(rgba);
return result; return result;
} }

Binary file not shown.

View File

@@ -1,6 +1,8 @@
#include <emscripten/bind.h> #include <emscripten/bind.h>
#include <emscripten/val.h> #include <emscripten/val.h>
#include <vector>
#define QOI_IMPLEMENTATION #define QOI_IMPLEMENTATION
#include "qoi.h" #include "qoi.h"
@@ -15,17 +17,24 @@ val encode(std::string buffer, int width, int height, QoiOptions options) {
qoi_desc desc; qoi_desc desc;
desc.width = width; desc.width = width;
desc.height = height; desc.height = height;
desc.channels = 4; desc.channels = 3;
desc.colorspace = QOI_SRGB; desc.colorspace = QOI_SRGB;
uint8_t* encodedData = (uint8_t*)qoi_encode(buffer.c_str(), &desc, &compressedSizeInBytes); auto rgba_buffer = buffer.c_str();
auto num_pixels = width * height;
std::vector<uint8_t> rgb_buffer(num_pixels * 3);
for(auto i = 0; i < num_pixels; i ++) {
rgb_buffer[i*3 + 0] = rgba_buffer[i*4 +0];
rgb_buffer[i*3 + 1] = rgba_buffer[i*4 +1];
rgb_buffer[i*3 + 2] = rgba_buffer[i*4 +2];
}
void* encodedData = qoi_encode(rgb_buffer.data(), &desc, &compressedSizeInBytes);
if (encodedData == NULL) if (encodedData == NULL)
return val::null(); return val::null();
auto js_result = auto js_result =
Uint8Array.new_(typed_memory_view(compressedSizeInBytes, (const uint8_t*)encodedData)); Uint8Array.new_(typed_memory_view(compressedSizeInBytes, (const uint8_t*)encodedData));
free(encodedData);
return js_result; return js_result;
} }

Binary file not shown.

View File

@@ -2,7 +2,7 @@ ARG RUST_IMG=rust:1.47
FROM emscripten/emsdk:2.0.8 AS wasm-tools FROM emscripten/emsdk:2.0.8 AS wasm-tools
WORKDIR /opt/wasm-tools WORKDIR /opt/wasm-tools
RUN wget -qO- https://github.com/rustwasm/wasm-pack/releases/download/v0.12.1/wasm-pack-v0.12.1-x86_64-unknown-linux-musl.tar.gz | tar -xzf - --strip 1 RUN wget -qO- https://github.com/rustwasm/wasm-pack/releases/download/v0.9.1/wasm-pack-v0.9.1-x86_64-unknown-linux-musl.tar.gz | tar -xzf - --strip 1
FROM $RUST_IMG AS rust FROM $RUST_IMG AS rust
ARG RUST_IMG ARG RUST_IMG

View File

@@ -10,12 +10,12 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { posix, isAbsolute, resolve } from 'path'; import { posix as pathUtils, isAbsolute } from 'path';
export default function resolveDirs(paths) { export default function resolveDirs(paths) {
const pathBaseDir = paths.map((path) => [ const pathBaseDir = paths.map((path) => [
posix.basename(path), pathUtils.basename(path),
posix.dirname(path), pathUtils.dirname(path),
]); ]);
return { return {
@@ -31,7 +31,7 @@ export default function resolveDirs(paths) {
throw new Error(`Couldn't find ${'./' + id}`); throw new Error(`Couldn't find ${'./' + id}`);
} }
if (isAbsolute(resolveResult.id)) return resolveResult.id; if (isAbsolute(resolveResult.id)) return resolveResult.id;
return resolve(resolveResult.id); return pathUtils.resolve(resolveResult.id);
}, },
}; };
} }

View File

@@ -64,7 +64,6 @@ export default function simpleTS(mainPath, { noBuild, watch } = {}) {
await new Promise((resolve) => { await new Promise((resolve) => {
const proc = spawn(tscPath, args, { const proc = spawn(tscPath, args, {
stdio: 'inherit', stdio: 'inherit',
shell: true,
}); });
proc.on('exit', (code) => { proc.on('exit', (code) => {

252
package-lock.json generated
View File

@@ -12,7 +12,6 @@
"@rollup/plugin-commonjs": "^17.0.0", "@rollup/plugin-commonjs": "^17.0.0",
"@rollup/plugin-node-resolve": "^11.1.0", "@rollup/plugin-node-resolve": "^11.1.0",
"@rollup/plugin-replace": "^2.3.4", "@rollup/plugin-replace": "^2.3.4",
"@rollup/plugin-terser": "^0.4.4",
"@surma/rollup-plugin-off-main-thread": "^2.2.2", "@surma/rollup-plugin-off-main-thread": "^2.2.2",
"@types/dedent": "^0.7.0", "@types/dedent": "^0.7.0",
"@types/mime-types": "^2.1.1", "@types/mime-types": "^2.1.1",
@@ -150,70 +149,6 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.24"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/set-array": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/source-map": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@nodelib/fs.scandir": { "node_modules/@nodelib/fs.scandir": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
@@ -310,39 +245,6 @@
"magic-string": "^0.25.7" "magic-string": "^0.25.7"
} }
}, },
"node_modules/@rollup/plugin-terser": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz",
"integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==",
"dev": true,
"license": "MIT",
"dependencies": {
"serialize-javascript": "^6.0.1",
"smob": "^1.0.0",
"terser": "^5.17.4"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"rollup": "^2.0.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
}
}
},
"node_modules/@rollup/plugin-terser/node_modules/serialize-javascript": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"randombytes": "^2.1.0"
}
},
"node_modules/@rollup/pluginutils": { "node_modules/@rollup/pluginutils": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
@@ -502,19 +404,6 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/acorn": {
"version": "8.12.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
"integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
"dev": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/aggregate-error": { "node_modules/aggregate-error": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz",
@@ -871,11 +760,10 @@
} }
}, },
"node_modules/buffer-from": { "node_modules/buffer-from": {
"version": "1.1.2", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true, "dev": true
"license": "MIT"
}, },
"node_modules/builtin-modules": { "node_modules/builtin-modules": {
"version": "3.2.0", "version": "3.2.0",
@@ -7996,13 +7884,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/smob": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz",
"integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==",
"dev": true,
"license": "MIT"
},
"node_modules/source-map": { "node_modules/source-map": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -8013,11 +7894,10 @@
} }
}, },
"node_modules/source-map-support": { "node_modules/source-map-support": {
"version": "0.5.21", "version": "0.5.19",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"buffer-from": "^1.0.0", "buffer-from": "^1.0.0",
"source-map": "^0.6.0" "source-map": "^0.6.0"
@@ -8528,16 +8408,14 @@
} }
}, },
"node_modules/terser": { "node_modules/terser": {
"version": "5.31.4", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.31.4.tgz", "resolved": "https://registry.npmjs.org/terser/-/terser-5.3.1.tgz",
"integrity": "sha512-3OU03GgblDgu0g+sdnsVzhBPxnjV+WJuMmocN1qBBZDQ3ia7jZQSAkePeKbPlYAejGXUTYe1CmSaUeV51mvaIw==", "integrity": "sha512-yD80f4hdwCWTH5mojzxe1q8bN1oJbsK/vfJGLcPZM/fl+/jItIVNKhFIHqqR71OipFWMLgj3Kc+GIp6CeIqfnA==",
"dev": true, "dev": true,
"license": "BSD-2-Clause",
"dependencies": { "dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.8.2",
"commander": "^2.20.0", "commander": "^2.20.0",
"source-map-support": "~0.5.20" "source-map": "~0.6.1",
"source-map-support": "~0.5.12"
}, },
"bin": { "bin": {
"terser": "bin/terser" "terser": "bin/terser"
@@ -8878,55 +8756,6 @@
} }
} }
}, },
"@jridgewell/gen-mapping": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
"dev": true,
"requires": {
"@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.24"
}
},
"@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true
},
"@jridgewell/set-array": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"dev": true
},
"@jridgewell/source-map": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
"dev": true,
"requires": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25"
}
},
"@jridgewell/sourcemap-codec": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
"dev": true
},
"@jridgewell/trace-mapping": {
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"dev": true,
"requires": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"@nodelib/fs.scandir": { "@nodelib/fs.scandir": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
@@ -9012,28 +8841,6 @@
"magic-string": "^0.25.7" "magic-string": "^0.25.7"
} }
}, },
"@rollup/plugin-terser": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz",
"integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==",
"dev": true,
"requires": {
"serialize-javascript": "^6.0.1",
"smob": "^1.0.0",
"terser": "^5.17.4"
},
"dependencies": {
"serialize-javascript": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
"dev": true,
"requires": {
"randombytes": "^2.1.0"
}
}
}
},
"@rollup/pluginutils": { "@rollup/pluginutils": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
@@ -9179,12 +8986,6 @@
"negotiator": "0.6.2" "negotiator": "0.6.2"
} }
}, },
"acorn": {
"version": "8.12.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
"integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
"dev": true
},
"aggregate-error": { "aggregate-error": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz",
@@ -9473,9 +9274,9 @@
} }
}, },
"buffer-from": { "buffer-from": {
"version": "1.1.2", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true "dev": true
}, },
"builtin-modules": { "builtin-modules": {
@@ -15394,12 +15195,6 @@
"is-fullwidth-code-point": "^3.0.0" "is-fullwidth-code-point": "^3.0.0"
} }
}, },
"smob": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz",
"integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==",
"dev": true
},
"source-map": { "source-map": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -15407,9 +15202,9 @@
"dev": true "dev": true
}, },
"source-map-support": { "source-map-support": {
"version": "0.5.21", "version": "0.5.19",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
"dev": true, "dev": true,
"requires": { "requires": {
"buffer-from": "^1.0.0", "buffer-from": "^1.0.0",
@@ -15830,15 +15625,14 @@
} }
}, },
"terser": { "terser": {
"version": "5.31.4", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.31.4.tgz", "resolved": "https://registry.npmjs.org/terser/-/terser-5.3.1.tgz",
"integrity": "sha512-3OU03GgblDgu0g+sdnsVzhBPxnjV+WJuMmocN1qBBZDQ3ia7jZQSAkePeKbPlYAejGXUTYe1CmSaUeV51mvaIw==", "integrity": "sha512-yD80f4hdwCWTH5mojzxe1q8bN1oJbsK/vfJGLcPZM/fl+/jItIVNKhFIHqqR71OipFWMLgj3Kc+GIp6CeIqfnA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.8.2",
"commander": "^2.20.0", "commander": "^2.20.0",
"source-map-support": "~0.5.20" "source-map": "~0.6.1",
"source-map-support": "~0.5.12"
}, },
"dependencies": { "dependencies": {
"commander": { "commander": {

View File

@@ -15,7 +15,6 @@
"@rollup/plugin-commonjs": "^17.0.0", "@rollup/plugin-commonjs": "^17.0.0",
"@rollup/plugin-node-resolve": "^11.1.0", "@rollup/plugin-node-resolve": "^11.1.0",
"@rollup/plugin-replace": "^2.3.4", "@rollup/plugin-replace": "^2.3.4",
"@rollup/plugin-terser": "^0.4.4",
"@surma/rollup-plugin-off-main-thread": "^2.2.2", "@surma/rollup-plugin-off-main-thread": "^2.2.2",
"@types/dedent": "^0.7.0", "@types/dedent": "^0.7.0",
"@types/mime-types": "^2.1.1", "@types/mime-types": "^2.1.1",
@@ -44,10 +43,11 @@
"preact-render-to-string": "^5.1.11", "preact-render-to-string": "^5.1.11",
"prettier": "^2.4.1", "prettier": "^2.4.1",
"rollup": "^2.38.0", "rollup": "^2.38.0",
"rollup-plugin-terser": "^7.0.2",
"serve": "^11.3.2", "serve": "^11.3.2",
"typescript": "^4.4.4", "typescript": "^4.4.4",
"wasm-feature-detect": "^1.2.11", "which": "^2.0.2",
"which": "^2.0.2" "wasm-feature-detect": "^1.2.11"
}, },
"lint-staged": { "lint-staged": {
"*.{js,css,json,md,ts,tsx}": "prettier --write", "*.{js,css,json,md,ts,tsx}": "prettier --write",

View File

@@ -15,7 +15,7 @@ import { promises as fsp } from 'fs';
import del from 'del'; import del from 'del';
import resolve from '@rollup/plugin-node-resolve'; import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs'; import commonjs from '@rollup/plugin-commonjs';
import terser from '@rollup/plugin-terser'; import { terser } from 'rollup-plugin-terser';
import OMT from '@surma/rollup-plugin-off-main-thread'; import OMT from '@surma/rollup-plugin-off-main-thread';
import replace from '@rollup/plugin-replace'; import replace from '@rollup/plugin-replace';
import { importMetaAssets } from '@web/rollup-plugin-import-meta-assets'; import { importMetaAssets } from '@web/rollup-plugin-import-meta-assets';

View File

@@ -1,11 +1,12 @@
import qoiDecoder, { QOIModule } from 'codecs/qoi/dec/qoi_dec'; import type { QOIModule } from 'codecs/qoi/dec/qoi_dec';
import { initEmscriptenModule, blobToArrayBuffer } from 'features/worker-utils'; import { initEmscriptenModule, blobToArrayBuffer } from 'features/worker-utils';
let emscriptenModule: Promise<QOIModule>; let emscriptenModule: Promise<QOIModule>;
export default async function decode(blob: Blob): Promise<ImageData> { export default async function decode(blob: Blob): Promise<ImageData> {
if (!emscriptenModule) { if (!emscriptenModule) {
emscriptenModule = initEmscriptenModule(qoiDecoder); const decoder = await import('codecs/qoi/dec/qoi_dec');
emscriptenModule = initEmscriptenModule(decoder.default);
} }
const [module, data] = await Promise.all([ const [module, data] = await Promise.all([

View File

@@ -1,4 +1,4 @@
import { EncodeOptions, AVIFTune, defaultOptions } from '../shared/meta'; import { EncodeOptions, defaultOptions, AVIFTune } from '../shared/meta';
import type WorkerBridge from 'client/lazy-app/worker-bridge'; import type WorkerBridge from 'client/lazy-app/worker-bridge';
import { h, Component } from 'preact'; import { h, Component } from 'preact';
import { preventDefault, shallowEqual } from 'client/lazy-app/util'; import { preventDefault, shallowEqual } from 'client/lazy-app/util';
@@ -36,20 +36,12 @@ interface State {
effort: number; effort: number;
sharpness: number; sharpness: number;
denoiseLevel: number; denoiseLevel: number;
aqMode: number;
tune: AVIFTune; tune: AVIFTune;
enableSharpYUV: boolean;
} }
/** const maxQuant = 63;
* AVIF quality ranges from 0 (worst) to 100 (lossless). const maxSpeed = 10;
* Since lossless is a separate checkbox, we cap user-inputted quality at 99
*
* AVIF speed ranges from 0 (slowest) to 10 (fastest).
* We display it as 'effort' to the user since it conveys the speed-size tradeoff
* much better: speed = 10 - effort
*/
const MAX_QUALITY = 100;
const MAX_EFFORT = 10;
export class Options extends Component<Props, State> { export class Options extends Component<Props, State> {
static getDerivedStateFromProps( static getDerivedStateFromProps(
@@ -63,28 +55,34 @@ export class Options extends Component<Props, State> {
const { options } = props; const { options } = props;
const lossless = const lossless =
options.quality === MAX_QUALITY && options.cqLevel === 0 &&
(options.qualityAlpha == -1 || options.qualityAlpha == MAX_QUALITY) && options.cqAlphaLevel <= 0 &&
options.subsample == 3; options.subsample == 3;
const separateAlpha = options.qualityAlpha !== -1; const separateAlpha = options.cqAlphaLevel !== -1;
const cqLevel = lossless ? defaultOptions.cqLevel : options.cqLevel;
// Create default form state from options // Create default form state from options
return { return {
options, options,
lossless, lossless,
quality: lossless ? defaultOptions.quality : options.quality, quality: maxQuant - cqLevel,
separateAlpha, separateAlpha,
alphaQuality: separateAlpha ? options.qualityAlpha : options.quality, alphaQuality:
subsample: options.subsample, maxQuant -
(separateAlpha ? options.cqAlphaLevel : defaultOptions.cqLevel),
subsample:
options.subsample === 0 || lossless
? defaultOptions.subsample
: options.subsample,
tileRows: options.tileRowsLog2, tileRows: options.tileRowsLog2,
tileCols: options.tileColsLog2, tileCols: options.tileColsLog2,
effort: MAX_EFFORT - options.speed, effort: maxSpeed - options.speed,
chromaDeltaQ: options.chromaDeltaQ, chromaDeltaQ: options.chromaDeltaQ,
sharpness: options.sharpness, sharpness: options.sharpness,
denoiseLevel: options.denoiseLevel, denoiseLevel: options.denoiseLevel,
tune: options.tune, tune: options.tune,
enableSharpYUV: options.enableSharpYUV,
}; };
} }
@@ -122,21 +120,20 @@ export class Options extends Component<Props, State> {
}; };
const newOptions: EncodeOptions = { const newOptions: EncodeOptions = {
quality: optionState.lossless ? MAX_QUALITY : optionState.quality, cqLevel: optionState.lossless ? 0 : maxQuant - optionState.quality,
qualityAlpha: cqAlphaLevel:
optionState.lossless || !optionState.separateAlpha optionState.lossless || !optionState.separateAlpha
? -1 // Set qualityAlpha to quality ? -1
: optionState.alphaQuality, : maxQuant - optionState.alphaQuality,
// Always set to 4:4:4 if lossless // Always set to 4:4:4 if lossless
subsample: optionState.lossless ? 3 : optionState.subsample, subsample: optionState.lossless ? 3 : optionState.subsample,
tileColsLog2: optionState.tileCols, tileColsLog2: optionState.tileCols,
tileRowsLog2: optionState.tileRows, tileRowsLog2: optionState.tileRows,
speed: MAX_EFFORT - optionState.effort, speed: maxSpeed - optionState.effort,
chromaDeltaQ: optionState.chromaDeltaQ, chromaDeltaQ: optionState.chromaDeltaQ,
sharpness: optionState.sharpness, sharpness: optionState.sharpness,
denoiseLevel: optionState.denoiseLevel, denoiseLevel: optionState.denoiseLevel,
tune: optionState.tune, tune: optionState.tune,
enableSharpYUV: optionState.enableSharpYUV,
}; };
// Updating options, so we don't recalculate in getDerivedStateFromProps. // Updating options, so we don't recalculate in getDerivedStateFromProps.
@@ -170,7 +167,6 @@ export class Options extends Component<Props, State> {
sharpness, sharpness,
denoiseLevel, denoiseLevel,
tune, tune,
enableSharpYUV,
}: State, }: State,
) { ) {
return ( return (
@@ -187,7 +183,7 @@ export class Options extends Component<Props, State> {
<div class={style.optionOneCell}> <div class={style.optionOneCell}>
<Range <Range
min="0" min="0"
max={MAX_QUALITY - 1} // MAX_QUALITY would mean lossless max="63"
value={quality} value={quality}
onInput={this._inputChange('quality', 'number')} onInput={this._inputChange('quality', 'number')}
> >
@@ -215,26 +211,11 @@ export class Options extends Component<Props, State> {
value={subsample} value={subsample}
onChange={this._inputChange('subsample', 'number')} onChange={this._inputChange('subsample', 'number')}
> >
<option value="0">4:0:0</option> <option value="1">Half</option>
<option value="1">4:2:0</option> {/*<option value="2">4:2:2</option>*/}
<option value="2">4:2:2</option> <option value="3">Off</option>
<option value="3">4:4:4</option>
</Select> </Select>
</label> </label>
<Expander>
{subsample === 1 && (
<label class={style.optionToggle}>
Sharp YUV Downsampling
<Checkbox
checked={enableSharpYUV}
onChange={this._inputChange(
'enableSharpYUV',
'boolean',
)}
/>
</label>
)}
</Expander>
<label class={style.optionToggle}> <label class={style.optionToggle}>
Separate alpha quality Separate alpha quality
<Checkbox <Checkbox
@@ -247,7 +228,7 @@ export class Options extends Component<Props, State> {
<div class={style.optionOneCell}> <div class={style.optionOneCell}>
<Range <Range
min="0" min="0"
max={MAX_QUALITY - 1} // MAX_QUALITY would mean lossless max="63"
value={alphaQuality} value={alphaQuality}
onInput={this._inputChange( onInput={this._inputChange(
'alphaQuality', 'alphaQuality',
@@ -326,7 +307,7 @@ export class Options extends Component<Props, State> {
<div class={style.optionOneCell}> <div class={style.optionOneCell}>
<Range <Range
min="0" min="0"
max={MAX_EFFORT} max="10"
value={effort} value={effort}
onInput={this._inputChange('effort', 'number')} onInput={this._inputChange('effort', 'number')}
> >

View File

@@ -18,8 +18,8 @@ export const label = 'AVIF';
export const mimeType = 'image/avif'; export const mimeType = 'image/avif';
export const extension = 'avif'; export const extension = 'avif';
export const defaultOptions: EncodeOptions = { export const defaultOptions: EncodeOptions = {
quality: 50, cqLevel: 33,
qualityAlpha: -1, cqAlphaLevel: -1,
denoiseLevel: 0, denoiseLevel: 0,
tileColsLog2: 0, tileColsLog2: 0,
tileRowsLog2: 0, tileRowsLog2: 0,
@@ -28,5 +28,4 @@ export const defaultOptions: EncodeOptions = {
chromaDeltaQ: false, chromaDeltaQ: false,
sharpness: 0, sharpness: 0,
tune: AVIFTune.auto, tune: AVIFTune.auto,
enableSharpYUV: false,
}; };

View File

@@ -1,4 +1,9 @@
import { inputFieldChecked } from 'client/lazy-app/util'; import { canvasEncode } from 'client/lazy-app/util/canvas';
import {
abortable,
blobToArrayBuffer,
inputFieldChecked,
} from 'client/lazy-app/util';
import { EncodeOptions } from '../shared/meta'; import { EncodeOptions } from '../shared/meta';
import type WorkerBridge from 'client/lazy-app/worker-bridge'; import type WorkerBridge from 'client/lazy-app/worker-bridge';
import { h, Component } from 'preact'; import { h, Component } from 'preact';
@@ -13,7 +18,9 @@ export async function encode(
imageData: ImageData, imageData: ImageData,
options: EncodeOptions, options: EncodeOptions,
) { ) {
return workerBridge.oxipngEncode(signal, imageData, options); const pngBlob = await abortable(signal, canvasEncode(imageData, 'image/png'));
const pngBuffer = await abortable(signal, blobToArrayBuffer(pngBlob));
return workerBridge.oxipngEncode(signal, pngBuffer, options);
} }
type Props = { type Props = {
@@ -49,7 +56,7 @@ export class Options extends Component<Props, {}> {
<Range <Range
name="level" name="level"
min="0" min="0"
max="6" max="3"
step="1" step="1"
value={options.level} value={options.level}
onInput={this.onChange} onInput={this.onChange}

View File

@@ -35,7 +35,7 @@ async function initST() {
let wasmReady: ReturnType<typeof initMT | typeof initST>; let wasmReady: ReturnType<typeof initMT | typeof initST>;
export default async function encode( export default async function encode(
data: ImageData, data: ArrayBuffer,
options: EncodeOptions, options: EncodeOptions,
): Promise<ArrayBuffer> { ): Promise<ArrayBuffer> {
if (!wasmReady) { if (!wasmReady) {
@@ -45,11 +45,6 @@ export default async function encode(
} }
const optimise = await wasmReady; const optimise = await wasmReady;
return optimise( return optimise(new Uint8Array(data), options.level, options.interlace)
data.data, .buffer;
data.width,
data.height,
options.level,
options.interlace,
).buffer;
} }

View File

@@ -1,5 +1,6 @@
import { EncodeOptions } from '../shared/meta'; import { EncodeOptions } from '../shared/meta';
import type WorkerBridge from 'client/lazy-app/worker-bridge'; import type WorkerBridge from 'client/lazy-app/worker-bridge';
import { h, Component, Fragment } from 'preact';
export function encode( export function encode(
signal: AbortSignal, signal: AbortSignal,
@@ -9,3 +10,14 @@ export function encode(
) { ) {
return workerBridge.qoiEncode(signal, imageData, options); return workerBridge.qoiEncode(signal, imageData, options);
} }
interface Props {
options: EncodeOptions;
onChange(newOptions: EncodeOptions): void;
}
export class Options extends Component<Props, {}> {
render() {
return <Fragment></Fragment>;
}
}

View File

@@ -10,22 +10,18 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import qoiEncoder, { QoiModule } from 'codecs/qoi/enc/qoi_enc'; import qoi_enc, { QoiModule } from 'codecs/qoi/enc/qoi_enc';
import type { EncodeOptions } from '../shared/meta'; import { EncodeOptions } from '../shared/meta';
import { initEmscriptenModule } from 'features/worker-utils'; import { initEmscriptenModule } from 'features/worker-utils';
let emscriptenModule: Promise<QoiModule>; let emscriptenModule: Promise<QoiModule>;
async function init() {
return initEmscriptenModule(qoiEncoder);
}
export default async function encode( export default async function encode(
data: ImageData, data: ImageData,
options: EncodeOptions, options: EncodeOptions,
): Promise<ArrayBuffer> { ): Promise<ArrayBuffer> {
if (!emscriptenModule) { if (!emscriptenModule) {
emscriptenModule = init(); emscriptenModule = initEmscriptenModule(qoi_enc);
} }
const module = await emscriptenModule; const module = await emscriptenModule;

View File

@@ -18,14 +18,3 @@ html {
/* Old stuff: */ /* Old stuff: */
--button-fg: rgb(95, 180, 228); --button-fg: rgb(95, 180, 228);
} }
@media (dynamic-range: high) {
@supports (color: oklch(0% 0 0)) {
html {
--pink: oklch(75% 0.3 3);
--hot-pink: oklch(65% 0.3 3);
--blue: oklch(75% 0.3 248);
--deep-blue: oklch(65% 0.3 248);
}
}
}