forked from external-repos/squoosh
Compare commits
38 Commits
threading-
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8d35e0fb6 | ||
|
|
5f72c2ed74 | ||
|
|
19beb1a7ab | ||
|
|
e2514df601 | ||
|
|
9db572e446 | ||
|
|
42ef430cee | ||
|
|
df7b622413 | ||
|
|
5649427670 | ||
|
|
1b24d2f3fa | ||
|
|
e4322bcbc3 | ||
|
|
e217740e53 | ||
|
|
d87eff7645 | ||
|
|
f374068fb2 | ||
|
|
ecc715fe55 | ||
|
|
82caed4277 | ||
|
|
a7dff9475d | ||
|
|
d168f7a447 | ||
|
|
edf9cb755e | ||
|
|
a7503e69a2 | ||
|
|
5a9733563e | ||
|
|
2000e16ba2 | ||
|
|
7dbe0a7714 | ||
|
|
25bc43e409 | ||
|
|
cee51bf355 | ||
|
|
8d6daf0fc4 | ||
|
|
61209d0b62 | ||
|
|
d0b4855022 | ||
|
|
6cb64a59ca | ||
|
|
979fba0af1 | ||
|
|
b1df3e1d54 | ||
|
|
4f6138d97d | ||
|
|
6b6e3724d2 | ||
|
|
8ac5e6f678 | ||
|
|
a930e8d928 | ||
|
|
c814700cd2 | ||
|
|
dfdf2a7f71 | ||
|
|
cd336909fc | ||
|
|
a8bc48f94c |
@@ -1,9 +1,9 @@
|
|||||||
# libavif and libaom versions are from
|
# using libavif from https://github.com/AOMediaCodec/libavif
|
||||||
# https://docs.google.com/document/d/1wEEA5rRU7wT54k41u3qyZIZHDCJArIMzLuzsrLAwaK8/edit
|
LIBAVIF_URL = https://github.com/AOMediaCodec/libavif/archive/refs/tags/v1.0.1.tar.gz
|
||||||
CODEC_URL = https://github.com/AOMediaCodec/libavif/archive/1c39e772c2c0d687691dd4b589a12c323f5f767d.tar.gz
|
LIBAVIF_PACKAGE = node_modules/libavif.tar.gz
|
||||||
CODEC_PACKAGE = node_modules/libavif.tar.gz
|
|
||||||
|
|
||||||
LIBAOM_URL = https://aomedia.googlesource.com/aom/+archive/v3.1.0.tar.gz
|
# using libaom from https://aomedia.googlesource.com/aom
|
||||||
|
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,7 +11,14 @@ 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
|
||||||
@@ -28,10 +35,11 @@ HELPER_MAKEFLAGS := -f helper.Makefile
|
|||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
|
|
||||||
all: $(OUT_ENC_JS) $(OUT_DEC_JS) $(OUT_ENC_MT_JS) $(OUT_NODE_ENC_JS) $(OUT_NODE_ENC_MT_JS) $(OUT_NODE_DEC_JS)
|
all: $(OUT_ENC_JS) $(OUT_DEC_JS) $(OUT_ENC_MT_JS)
|
||||||
|
|
||||||
$(OUT_NODE_ENC_JS) $(OUT_NODE_ENC_MT_JS): ENVIRONMENT=node
|
# ST-Encoding
|
||||||
$(OUT_NODE_ENC_JS) $(OUT_ENC_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt
|
$(OUT_ENC_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt $(LIBSHARPYUV_ST)
|
||||||
|
mkdir -p $(LIBWEBP_DIR)/build && cp $(LIBSHARPYUV_ST) $(LIBSHARPYUV)
|
||||||
$(MAKE) \
|
$(MAKE) \
|
||||||
$(HELPER_MAKEFLAGS) \
|
$(HELPER_MAKEFLAGS) \
|
||||||
OUT_JS=$@ \
|
OUT_JS=$@ \
|
||||||
@@ -42,9 +50,12 @@ $(OUT_NODE_ENC_JS) $(OUT_ENC_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(L
|
|||||||
-DCONFIG_AV1_HIGHBITDEPTH=0 \
|
-DCONFIG_AV1_HIGHBITDEPTH=0 \
|
||||||
" \
|
" \
|
||||||
ENVIRONMENT=$(ENVIRONMENT) \
|
ENVIRONMENT=$(ENVIRONMENT) \
|
||||||
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_DECODE=0"
|
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_DECODE=0 -DAVIF_LOCAL_LIBSHARPYUV=ON"
|
||||||
|
|
||||||
$(OUT_ENC_MT_JS) $(OUT_NODE_ENC_MT_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt
|
# MT-Encoding
|
||||||
|
# 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=$@ \
|
||||||
@@ -54,11 +65,11 @@ $(OUT_ENC_MT_JS) $(OUT_NODE_ENC_MT_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.t
|
|||||||
-DCONFIG_AV1_HIGHBITDEPTH=0 \
|
-DCONFIG_AV1_HIGHBITDEPTH=0 \
|
||||||
" \
|
" \
|
||||||
ENVIRONMENT=$(ENVIRONMENT) \
|
ENVIRONMENT=$(ENVIRONMENT) \
|
||||||
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_DECODE=0" \
|
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_DECODE=0 -DAVIF_LOCAL_LIBSHARPYUV=ON" \
|
||||||
OUT_FLAGS="-pthread"
|
OUT_FLAGS="-pthread"
|
||||||
|
|
||||||
$(OUT_NODE_DEC_JS): ENVIRONMENT=node
|
# Decoding
|
||||||
$(OUT_NODE_DEC_JS) $(OUT_DEC_JS): $(OUT_DEC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt
|
$(OUT_DEC_JS): $(OUT_DEC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt
|
||||||
$(MAKE) \
|
$(MAKE) \
|
||||||
$(HELPER_MAKEFLAGS) \
|
$(HELPER_MAKEFLAGS) \
|
||||||
OUT_JS=$@ \
|
OUT_JS=$@ \
|
||||||
@@ -70,22 +81,77 @@ $(OUT_NODE_DEC_JS) $(OUT_DEC_JS): $(OUT_DEC_CPP) $(CODEC_DIR)/CMakeLists.txt $(L
|
|||||||
ENVIRONMENT=$(ENVIRONMENT) \
|
ENVIRONMENT=$(ENVIRONMENT) \
|
||||||
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_ENCODE=0"
|
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_ENCODE=0"
|
||||||
|
|
||||||
$(CODEC_PACKAGE):
|
# LIBAOM EXTRACTION SECTION
|
||||||
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 $@
|
||||||
|
|
||||||
$(CODEC_DIR)/CMakeLists.txt: $(CODEC_PACKAGE)
|
# Extract libaom from the tarball
|
||||||
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
|
||||||
|
|||||||
2
codecs/avif/dec/avif_dec.js
generated
2
codecs/avif/dec/avif_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
2
codecs/avif/dec/avif_node_dec.js
generated
2
codecs/avif/dec/avif_node_dec.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -3,15 +3,27 @@
|
|||||||
#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 - 63]
|
// [0 - 100]
|
||||||
// 0 = lossless
|
// 0 = worst quality
|
||||||
// 63 = worst quality
|
// 100 = lossless
|
||||||
int cqLevel;
|
int quality;
|
||||||
// As above, but -1 means 'use cqLevel'
|
// As above, but -1 means 'use quality'
|
||||||
int cqAlphaLevel;
|
int qualityAlpha;
|
||||||
// [0 - 6]
|
// [0 - 6]
|
||||||
// Creates 2^n tiles in that dimension
|
// Creates 2^n tiles in that dimension
|
||||||
int tileRowsLog2;
|
int tileRowsLog2;
|
||||||
@@ -35,12 +47,15 @@ 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) {
|
||||||
avifRWData output = AVIF_DATA_EMPTY;
|
avifResult status; // To check the return status for avif API's
|
||||||
|
|
||||||
int depth = 8;
|
int depth = 8;
|
||||||
avifPixelFormat format;
|
avifPixelFormat format;
|
||||||
switch (options.subsample) {
|
switch (options.subsample) {
|
||||||
@@ -58,11 +73,13 @@ val encode(std::string buffer, int width, int height, AvifOptions options) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lossless = options.cqLevel == AVIF_QUANTIZER_LOSSLESS &&
|
bool lossless = options.quality == AVIF_QUALITY_LOSSLESS &&
|
||||||
options.cqAlphaLevel <= AVIF_QUANTIZER_LOSSLESS &&
|
(options.qualityAlpha == -1 || options.qualityAlpha == AVIF_QUALITY_LOSSLESS) &&
|
||||||
format == AVIF_PIXEL_FORMAT_YUV444;
|
format == AVIF_PIXEL_FORMAT_YUV444;
|
||||||
|
|
||||||
avifImage* image = avifImageCreate(width, height, depth, format);
|
// Smart pointer for the input image in YUV 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;
|
||||||
@@ -73,43 +90,49 @@ 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);
|
avifRGBImageSetDefaults(&srcRGB, image.get());
|
||||||
srcRGB.pixels = rgba;
|
srcRGB.pixels = rgba;
|
||||||
srcRGB.rowBytes = width * 4;
|
srcRGB.rowBytes = width * 4;
|
||||||
avifImageRGBToYUV(image, &srcRGB);
|
if (options.enableSharpYUV) {
|
||||||
|
srcRGB.chromaDownsampling = AVIF_CHROMA_DOWNSAMPLING_SHARP_YUV;
|
||||||
|
}
|
||||||
|
status = avifImageRGBToYUV(image.get(), &srcRGB);
|
||||||
|
RETURN_NULL_IF(status != AVIF_RESULT_OK);
|
||||||
|
|
||||||
avifEncoder* encoder = avifEncoderCreate();
|
// Create a smart pointer for the encoder
|
||||||
|
AvifEncoderPtr encoder(avifEncoderCreate(), avifEncoderDestroy);
|
||||||
|
RETURN_NULL_IF(encoder == nullptr);
|
||||||
|
|
||||||
if (lossless) {
|
if (lossless) {
|
||||||
encoder->minQuantizer = AVIF_QUANTIZER_LOSSLESS;
|
encoder->quality = AVIF_QUALITY_LOSSLESS;
|
||||||
encoder->maxQuantizer = AVIF_QUANTIZER_LOSSLESS;
|
encoder->qualityAlpha = AVIF_QUALITY_LOSSLESS;
|
||||||
encoder->minQuantizerAlpha = AVIF_QUANTIZER_LOSSLESS;
|
|
||||||
encoder->maxQuantizerAlpha = AVIF_QUANTIZER_LOSSLESS;
|
|
||||||
} else {
|
} else {
|
||||||
encoder->minQuantizer = AVIF_QUANTIZER_BEST_QUALITY;
|
status = avifEncoderSetCodecSpecificOption(encoder.get(), "sharpness",
|
||||||
encoder->maxQuantizer = AVIF_QUANTIZER_WORST_QUALITY;
|
|
||||||
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());
|
std::to_string(options.sharpness).c_str());
|
||||||
|
RETURN_NULL_IF(status != AVIF_RESULT_OK);
|
||||||
|
|
||||||
if (options.cqAlphaLevel != -1) {
|
// Set base quality
|
||||||
avifEncoderSetCodecSpecificOption(encoder, "alpha:cq-level",
|
encoder->quality = options.quality;
|
||||||
std::to_string(options.cqAlphaLevel).c_str());
|
// Conditionally set alpha quality
|
||||||
|
if (options.qualityAlpha == -1) {
|
||||||
|
encoder->qualityAlpha = options.quality;
|
||||||
|
} else {
|
||||||
|
encoder->qualityAlpha = options.qualityAlpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.tune == 2 || (options.tune == 0 && options.cqLevel <= 32)) {
|
if (options.tune == 2 || (options.tune == 0 && options.quality >= 50)) {
|
||||||
avifEncoderSetCodecSpecificOption(encoder, "tune", "ssim");
|
status = avifEncoderSetCodecSpecificOption(encoder.get(), "tune", "ssim");
|
||||||
|
RETURN_NULL_IF(status != AVIF_RESULT_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.chromaDeltaQ) {
|
if (options.chromaDeltaQ) {
|
||||||
avifEncoderSetCodecSpecificOption(encoder, "enable-chroma-deltaq", "1");
|
status = avifEncoderSetCodecSpecificOption(encoder.get(), "color:enable-chroma-deltaq", "1");
|
||||||
|
RETURN_NULL_IF(status != AVIF_RESULT_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
avifEncoderSetCodecSpecificOption(encoder, "color:denoise-noise-level",
|
status = avifEncoderSetCodecSpecificOption(encoder.get(), "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();
|
||||||
@@ -117,22 +140,21 @@ 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;
|
||||||
|
|
||||||
avifResult encodeResult = avifEncoderWrite(encoder, image, &output);
|
avifRWData output = AVIF_DATA_EMPTY;
|
||||||
|
avifResult encodeResult = avifEncoderWrite(encoder.get(), image.get(), &output);
|
||||||
auto js_result = val::null();
|
auto js_result = val::null();
|
||||||
if (encodeResult == AVIF_RESULT_OK) {
|
if (encodeResult == AVIF_RESULT_OK) {
|
||||||
js_result = Uint8Array.new_(typed_memory_view(output.size, output.data));
|
js_result = Uint8Array.new_(typed_memory_view(output.size, output.data));
|
||||||
}
|
}
|
||||||
|
|
||||||
avifImageDestroy(image);
|
|
||||||
avifEncoderDestroy(encoder);
|
|
||||||
avifRWDataFree(&output);
|
avifRWDataFree(&output);
|
||||||
return js_result;
|
return js_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_BINDINGS(my_module) {
|
EMSCRIPTEN_BINDINGS(my_module) {
|
||||||
value_object<AvifOptions>("AvifOptions")
|
value_object<AvifOptions>("AvifOptions")
|
||||||
.field("cqLevel", &AvifOptions::cqLevel)
|
.field("quality", &AvifOptions::quality)
|
||||||
.field("cqAlphaLevel", &AvifOptions::cqAlphaLevel)
|
.field("qualityAlpha", &AvifOptions::qualityAlpha)
|
||||||
.field("tileRowsLog2", &AvifOptions::tileRowsLog2)
|
.field("tileRowsLog2", &AvifOptions::tileRowsLog2)
|
||||||
.field("tileColsLog2", &AvifOptions::tileColsLog2)
|
.field("tileColsLog2", &AvifOptions::tileColsLog2)
|
||||||
.field("speed", &AvifOptions::speed)
|
.field("speed", &AvifOptions::speed)
|
||||||
@@ -140,7 +162,8 @@ 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);
|
||||||
}
|
}
|
||||||
|
|||||||
5
codecs/avif/enc/avif_enc.d.ts
vendored
5
codecs/avif/enc/avif_enc.d.ts
vendored
@@ -5,15 +5,16 @@ export const enum AVIFTune {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface EncodeOptions {
|
export interface EncodeOptions {
|
||||||
cqLevel: number;
|
quality: 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
codecs/avif/enc/avif_enc.js
generated
2
codecs/avif/enc/avif_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
2
codecs/avif/enc/avif_enc_mt.js
generated
2
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,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}};
|
"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}};
|
||||||
|
|||||||
2
codecs/avif/enc/avif_node_enc.js
generated
2
codecs/avif/enc/avif_node_enc.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
2
codecs/avif/enc/avif_node_enc_mt.js
generated
2
codecs/avif/enc/avif_node_enc_mt.js
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -10,8 +10,11 @@
|
|||||||
# $(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
|
||||||
|
|
||||||
@@ -25,6 +28,13 @@ 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 \
|
||||||
@@ -32,6 +42,7 @@ $(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 $@ \
|
||||||
@@ -39,6 +50,7 @@ $(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 \
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM emscripten/emsdk:2.0.23
|
FROM emscripten/emsdk:2.0.34
|
||||||
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"
|
||||||
|
|||||||
407
codecs/oxipng/Cargo.lock
generated
407
codecs/oxipng/Cargo.lock
generated
@@ -2,18 +2,6 @@
|
|||||||
# 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"
|
||||||
@@ -21,22 +9,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-vec"
|
name = "bitvec"
|
||||||
version = "0.6.3"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
|
||||||
|
dependencies = [
|
||||||
[[package]]
|
"funty",
|
||||||
name = "bitflags"
|
"radium",
|
||||||
version = "1.2.1"
|
"tap",
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
"wyz",
|
||||||
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"
|
||||||
@@ -46,15 +28,9 @@ checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.4.1"
|
version = "1.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "41aa2ec95ca3b5c54cf73c91acf06d24f4495d5f1b1c12506ae3483d646177ac"
|
checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6"
|
||||||
|
|
||||||
[[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"
|
||||||
@@ -62,120 +38,51 @@ 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"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cloudflare-zlib"
|
|
||||||
version = "0.2.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f5ed63a019d55bacd15cadcbcb96bf41b16281417fff393bdb55fa84255fe4b9"
|
|
||||||
dependencies = [
|
|
||||||
"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]]
|
[[package]]
|
||||||
name = "crossbeam-channel"
|
name = "crossbeam-channel"
|
||||||
version = "0.5.0"
|
version = "0.5.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
|
checksum = "82a9b73a36529d9c47029b9fb3a6f0ea3cc916a261195352ba19e770fc1748b2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-deque"
|
name = "crossbeam-deque"
|
||||||
version = "0.8.0"
|
version = "0.8.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
|
checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if",
|
||||||
"crossbeam-epoch",
|
"crossbeam-epoch",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-epoch"
|
name = "crossbeam-epoch"
|
||||||
version = "0.9.1"
|
version = "0.9.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d"
|
checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"autocfg",
|
||||||
"const_fn",
|
"cfg-if",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
"lazy_static",
|
|
||||||
"memoffset",
|
|
||||||
"scopeguard",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.1"
|
version = "0.8.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"
|
checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"cfg-if",
|
||||||
"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]]
|
||||||
@@ -184,56 +91,35 @@ 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.9.1"
|
version = "0.14.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
|
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||||
|
|
||||||
[[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 = "1.6.1"
|
version = "2.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b"
|
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"equivalent",
|
||||||
"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"
|
||||||
@@ -249,161 +135,47 @@ version = "1.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libc"
|
|
||||||
version = "0.2.81"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libdeflate-sys"
|
name = "libdeflate-sys"
|
||||||
version = "0.7.1"
|
version = "1.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4a95fa4be7085dd06a8296dcc3f399f12ab8b0309c157dcaa90669130b175b97"
|
checksum = "67921a7f85100c1559efc3d1c7c472091b7da05f304b4bbd5356f075e97f1cc2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libdeflater"
|
name = "libdeflater"
|
||||||
version = "0.7.1"
|
version = "1.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ccc147465654929bf7b56518cc46d11701ba290f4ff94398ae3f89f1663cf60f"
|
checksum = "3a31b22f662350ec294b13859f935aea772ba7b2bc8776269f4a5627308eab7d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libdeflate-sys",
|
"libdeflate-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.11"
|
version = "0.4.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
|
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||||
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 = "4.0.3"
|
version = "9.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "50d0b53912a666fe2970f8ab254e283531c816aed16551ab66c52485eadb44e6"
|
checksum = "28e5c341ef78a228e47a551bfd15ff885d8c501af49f953358763a538c01f14d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit-vec",
|
"bitvec",
|
||||||
"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"
|
||||||
@@ -423,71 +195,60 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon"
|
name = "radium"
|
||||||
version = "1.5.0"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674"
|
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
|
||||||
"crossbeam-deque",
|
|
||||||
"either",
|
"either",
|
||||||
"rayon-core",
|
"rayon-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon-core"
|
name = "rayon-core"
|
||||||
version = "1.9.0"
|
version = "1.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
|
checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
|
||||||
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.25"
|
version = "0.8.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "287f3c3f8236abb92d8b7e36797f19159df4b58f0a658cc3fb6dd3004b1f3bd3"
|
checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc-hash"
|
||||||
version = "0.3.0"
|
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 = "65c94201b44764d6d1f7e37c15a8289ed55e546c1762c7f1d57f616966e0c181"
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc_version"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scopeguard"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "0.11.0"
|
version = "1.0.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
|
checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
|
||||||
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"
|
||||||
@@ -499,7 +260,6 @@ 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",
|
||||||
@@ -518,10 +278,10 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ucd-trie"
|
name = "tap"
|
||||||
version = "0.1.3"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
|
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
@@ -535,7 +295,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 1.0.0",
|
"cfg-if",
|
||||||
"wasm-bindgen-macro",
|
"wasm-bindgen-macro",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -594,3 +354,12 @@ 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",
|
||||||
|
]
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ wasm-opt = ["-O", "--no-validation"]
|
|||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
oxipng = { version = "4.0.3", default-features = false, features = ["libdeflater"] }
|
oxipng = { version = "9.0", default-features = false, features = ["freestanding"] }
|
||||||
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 }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# OxiPNG
|
# OxiPNG
|
||||||
|
|
||||||
- Source: <https://github.com/shssoichiro/oxipng>
|
- Source: <https://github.com/shssoichiro/oxipng>
|
||||||
- Version: v3.0.0
|
- Version: v9.0.0
|
||||||
- License: MIT
|
- License: MIT
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "oxipng",
|
"name": "oxipng",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "RUST_IMG=rustlang/rust@sha256:744aeea5a38f95aa7a96ec37269a65f0c6197a1cdd87d6534e12bb869141d807 ../build-rust.sh ./build.sh"
|
"build": "RUST_IMG=rustlang/rust@sha256:5fd16a5576c22c8fdd5d659247755999e426c04de8dcf18a41ea446c5f253309 ../build-rust.sh ./build.sh"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# OxiPNG
|
# OxiPNG
|
||||||
|
|
||||||
- Source: <https://github.com/shssoichiro/oxipng>
|
- Source: <https://github.com/shssoichiro/oxipng>
|
||||||
- Version: v3.0.0
|
- Version: v9.0.0
|
||||||
- License: MIT
|
- License: MIT
|
||||||
|
|||||||
@@ -11,5 +11,7 @@
|
|||||||
],
|
],
|
||||||
"module": "squoosh_oxipng.js",
|
"module": "squoosh_oxipng.js",
|
||||||
"types": "squoosh_oxipng.d.ts",
|
"types": "squoosh_oxipng.d.ts",
|
||||||
"sideEffects": false
|
"sideEffects": [
|
||||||
|
"./snippets/*"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
9
codecs/oxipng/pkg-parallel/squoosh_oxipng.d.ts
generated
vendored
9
codecs/oxipng/pkg-parallel/squoosh_oxipng.d.ts
generated
vendored
@@ -1,12 +1,14 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
/**
|
/**
|
||||||
* @param {Uint8Array} data
|
* @param {Uint8ClampedArray} 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: Uint8Array, level: number, interlace: boolean): Uint8Array;
|
export function optimise(data: Uint8ClampedArray, width: number, height: number, level: number, interlace: boolean): Uint8Array;
|
||||||
/**
|
/**
|
||||||
* @param {number} num_threads
|
* @param {number} num_threads
|
||||||
* @returns {Promise<any>}
|
* @returns {Promise<any>}
|
||||||
@@ -36,8 +38,7 @@ 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 __wasm_init_memory: () => void;
|
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 __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;
|
||||||
|
|||||||
8
codecs/oxipng/pkg-parallel/squoosh_oxipng.js
generated
8
codecs/oxipng/pkg-parallel/squoosh_oxipng.js
generated
@@ -54,17 +54,19 @@ function getArrayU8FromWasm0(ptr, len) {
|
|||||||
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len);
|
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param {Uint8Array} data
|
* @param {Uint8ClampedArray} 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, level, interlace) {
|
export function optimise(data, width, height, 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, level, interlace);
|
wasm.optimise(retptr, ptr0, len0, width, height, 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();
|
||||||
|
|||||||
Binary file not shown.
3
codecs/oxipng/pkg-parallel/squoosh_oxipng_bg.wasm.d.ts
generated
vendored
3
codecs/oxipng/pkg-parallel/squoosh_oxipng_bg.wasm.d.ts
generated
vendored
@@ -1,7 +1,6 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
export function __wasm_init_memory(): void;
|
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 __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;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# OxiPNG
|
# OxiPNG
|
||||||
|
|
||||||
- Source: <https://github.com/shssoichiro/oxipng>
|
- Source: <https://github.com/shssoichiro/oxipng>
|
||||||
- Version: v3.0.0
|
- Version: v9.0.0
|
||||||
- License: MIT
|
- License: MIT
|
||||||
|
|||||||
@@ -11,5 +11,7 @@
|
|||||||
],
|
],
|
||||||
"module": "squoosh_oxipng.js",
|
"module": "squoosh_oxipng.js",
|
||||||
"types": "squoosh_oxipng.d.ts",
|
"types": "squoosh_oxipng.d.ts",
|
||||||
"sideEffects": false
|
"sideEffects": [
|
||||||
|
"./snippets/*"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
8
codecs/oxipng/pkg/squoosh_oxipng.d.ts
generated
vendored
8
codecs/oxipng/pkg/squoosh_oxipng.d.ts
generated
vendored
@@ -1,18 +1,20 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
/**
|
/**
|
||||||
* @param {Uint8Array} data
|
* @param {Uint8ClampedArray} 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: Uint8Array, level: number, interlace: boolean): Uint8Array;
|
export function optimise(data: Uint8ClampedArray, width: number, height: number, 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) => void;
|
readonly optimise: (a: number, b: number, c: number, d: number, e: number, f: number, g: 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;
|
||||||
|
|||||||
8
codecs/oxipng/pkg/squoosh_oxipng.js
generated
8
codecs/oxipng/pkg/squoosh_oxipng.js
generated
@@ -38,17 +38,19 @@ function getArrayU8FromWasm0(ptr, len) {
|
|||||||
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len);
|
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param {Uint8Array} data
|
* @param {Uint8ClampedArray} 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, level, interlace) {
|
export function optimise(data, width, height, 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, level, interlace);
|
wasm.optimise(retptr, ptr0, len0, width, height, 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();
|
||||||
|
|||||||
Binary file not shown.
2
codecs/oxipng/pkg/squoosh_oxipng_bg.wasm.d.ts
generated
vendored
2
codecs/oxipng/pkg/squoosh_oxipng_bg.wasm.d.ts
generated
vendored
@@ -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): void;
|
export function optimise(a: number, b: number, c: number, d: number, e: number, f: number, g: 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;
|
||||||
|
|||||||
@@ -1,20 +1,27 @@
|
|||||||
#[cfg(feature = "parallel")]
|
#[cfg(feature = "parallel")]
|
||||||
pub use wasm_bindgen_rayon::init_thread_pool;
|
pub use wasm_bindgen_rayon::init_thread_pool;
|
||||||
|
|
||||||
use oxipng::AlphaOptim;
|
use oxipng::{BitDepth, ColorType, Interlacing};
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
use wasm_bindgen::Clamped;
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn optimise(data: &[u8], level: u8, interlace: bool) -> Vec<u8> {
|
pub fn optimise(
|
||||||
|
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.alphas.insert(AlphaOptim::Black);
|
options.optimize_alpha = true;
|
||||||
options.alphas.insert(AlphaOptim::White);
|
options.interlace = Some(if interlace {
|
||||||
options.alphas.insert(AlphaOptim::Up);
|
Interlacing::Adam7
|
||||||
options.alphas.insert(AlphaOptim::Down);
|
} else {
|
||||||
options.alphas.insert(AlphaOptim::Left);
|
Interlacing::None
|
||||||
options.alphas.insert(AlphaOptim::Right);
|
});
|
||||||
options.interlace = Some(if interlace { 1 } else { 0 });
|
|
||||||
|
|
||||||
options.deflate = oxipng::Deflaters::Libdeflater;
|
let raw = oxipng::RawImage::new(width, height, ColorType::RGBA, BitDepth::Eight, data.0)
|
||||||
oxipng::optimize_from_memory(data, &options).unwrap_throw()
|
.unwrap_throw();
|
||||||
|
raw.create_optimized_png(&options).unwrap_throw()
|
||||||
}
|
}
|
||||||
|
|||||||
42
codecs/qoi/Makefile
Normal file
42
codecs/qoi/Makefile
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
CODEC_URL = https://github.com/phoboslab/qoi/archive/8d35d93cdca85d2868246c2a8a80a1e2c16ba2a8.tar.gz
|
||||||
|
|
||||||
|
CODEC_DIR = node_modules/qoi
|
||||||
|
CODEC_BUILD_DIR:= $(CODEC_DIR)/build
|
||||||
|
ENVIRONMENT = worker
|
||||||
|
|
||||||
|
OUT_JS = enc/qoi_enc.js dec/qoi_dec.js
|
||||||
|
OUT_WASM := $(OUT_JS:.js=.wasm)
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
all: $(OUT_JS)
|
||||||
|
|
||||||
|
$(filter enc/%,$(OUT_JS)): enc/qoi_enc.o
|
||||||
|
$(filter dec/%,$(OUT_JS)): dec/qoi_dec.o
|
||||||
|
|
||||||
|
# ALL .js FILES
|
||||||
|
$(OUT_JS):
|
||||||
|
$(LD) \
|
||||||
|
$(LDFLAGS) \
|
||||||
|
--bind \
|
||||||
|
-s ENVIRONMENT=$(ENVIRONMENT) \
|
||||||
|
-s EXPORT_ES6=1 \
|
||||||
|
-o $@ \
|
||||||
|
$+
|
||||||
|
|
||||||
|
# ALL .o FILES
|
||||||
|
%.o: %.cpp $(CODEC_DIR)
|
||||||
|
$(CXX) -c \
|
||||||
|
$(CXXFLAGS) \
|
||||||
|
-I $(CODEC_DIR) \
|
||||||
|
-o $@ \
|
||||||
|
$<
|
||||||
|
|
||||||
|
# CREATE DIRECTORY
|
||||||
|
$(CODEC_DIR):
|
||||||
|
mkdir -p $(CODEC_DIR)
|
||||||
|
curl -sL $(CODEC_URL) | tar xz --strip 1 -C $(CODEC_DIR)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) $(OUT_JS) $(OUT_WASM)
|
||||||
|
$(MAKE) -C $(CODEC_DIR) clean
|
||||||
30
codecs/qoi/dec/qoi_dec.cpp
Normal file
30
codecs/qoi/dec/qoi_dec.cpp
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#include <emscripten/bind.h>
|
||||||
|
#include <emscripten/val.h>
|
||||||
|
|
||||||
|
#define QOI_IMPLEMENTATION
|
||||||
|
#include "qoi.h"
|
||||||
|
|
||||||
|
using namespace emscripten;
|
||||||
|
|
||||||
|
thread_local const val Uint8ClampedArray = val::global("Uint8ClampedArray");
|
||||||
|
thread_local const val ImageData = val::global("ImageData");
|
||||||
|
|
||||||
|
val decode(std::string qoiimage) {
|
||||||
|
qoi_desc desc;
|
||||||
|
uint8_t* rgba = (uint8_t*)qoi_decode(qoiimage.c_str(), qoiimage.length(), &desc, 4);
|
||||||
|
|
||||||
|
// Resultant width and height stored in descriptor
|
||||||
|
int decodedWidth = desc.width;
|
||||||
|
int decodedHeight = desc.height;
|
||||||
|
|
||||||
|
val result = ImageData.new_(
|
||||||
|
Uint8ClampedArray.new_(typed_memory_view(4 * decodedWidth * decodedHeight, rgba)),
|
||||||
|
decodedWidth, decodedHeight);
|
||||||
|
free(rgba);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_BINDINGS(my_module) {
|
||||||
|
function("decode", &decode);
|
||||||
|
}
|
||||||
7
codecs/qoi/dec/qoi_dec.d.ts
vendored
Normal file
7
codecs/qoi/dec/qoi_dec.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export interface QOIModule extends EmscriptenWasm.Module {
|
||||||
|
decode(data: BufferSource): ImageData | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var moduleFactory: EmscriptenWasm.ModuleFactory<QOIModule>;
|
||||||
|
|
||||||
|
export default moduleFactory;
|
||||||
16
codecs/qoi/dec/qoi_dec.js
generated
Normal file
16
codecs/qoi/dec/qoi_dec.js
generated
Normal file
File diff suppressed because one or more lines are too long
BIN
codecs/qoi/dec/qoi_dec.wasm
Normal file
BIN
codecs/qoi/dec/qoi_dec.wasm
Normal file
Binary file not shown.
36
codecs/qoi/enc/qoi_enc.cpp
Normal file
36
codecs/qoi/enc/qoi_enc.cpp
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#include <emscripten/bind.h>
|
||||||
|
#include <emscripten/val.h>
|
||||||
|
|
||||||
|
#define QOI_IMPLEMENTATION
|
||||||
|
#include "qoi.h"
|
||||||
|
|
||||||
|
using namespace emscripten;
|
||||||
|
|
||||||
|
struct QoiOptions {};
|
||||||
|
|
||||||
|
thread_local const val Uint8Array = val::global("Uint8Array");
|
||||||
|
|
||||||
|
val encode(std::string buffer, int width, int height, QoiOptions options) {
|
||||||
|
int compressedSizeInBytes;
|
||||||
|
qoi_desc desc;
|
||||||
|
desc.width = width;
|
||||||
|
desc.height = height;
|
||||||
|
desc.channels = 4;
|
||||||
|
desc.colorspace = QOI_SRGB;
|
||||||
|
|
||||||
|
uint8_t* encodedData = (uint8_t*)qoi_encode(buffer.c_str(), &desc, &compressedSizeInBytes);
|
||||||
|
if (encodedData == NULL)
|
||||||
|
return val::null();
|
||||||
|
|
||||||
|
auto js_result =
|
||||||
|
Uint8Array.new_(typed_memory_view(compressedSizeInBytes, (const uint8_t*)encodedData));
|
||||||
|
free(encodedData);
|
||||||
|
|
||||||
|
return js_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_BINDINGS(my_module) {
|
||||||
|
value_object<QoiOptions>("QoiOptions");
|
||||||
|
|
||||||
|
function("encode", &encode);
|
||||||
|
}
|
||||||
14
codecs/qoi/enc/qoi_enc.d.ts
vendored
Normal file
14
codecs/qoi/enc/qoi_enc.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
export interface EncodeOptions {}
|
||||||
|
|
||||||
|
export interface QoiModule extends EmscriptenWasm.Module {
|
||||||
|
encode(
|
||||||
|
data: BufferSource,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
options: EncodeOptions,
|
||||||
|
): Uint8Array;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var moduleFactory: EmscriptenWasm.ModuleFactory<QoiModule>;
|
||||||
|
|
||||||
|
export default moduleFactory;
|
||||||
16
codecs/qoi/enc/qoi_enc.js
generated
Normal file
16
codecs/qoi/enc/qoi_enc.js
generated
Normal file
File diff suppressed because one or more lines are too long
BIN
codecs/qoi/enc/qoi_enc.wasm
Normal file
BIN
codecs/qoi/enc/qoi_enc.wasm
Normal file
Binary file not shown.
7
codecs/qoi/package.json
Normal file
7
codecs/qoi/package.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "qoi",
|
||||||
|
"scripts": {
|
||||||
|
"build": "../build-cpp.sh"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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.9.1/wasm-pack-v0.9.1-x86_64-unknown-linux-musl.tar.gz | tar -xzf - --strip 1
|
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
|
||||||
|
|
||||||
FROM $RUST_IMG AS rust
|
FROM $RUST_IMG AS rust
|
||||||
ARG RUST_IMG
|
ARG RUST_IMG
|
||||||
|
|||||||
@@ -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 as pathUtils, isAbsolute } from 'path';
|
import { posix, isAbsolute, resolve } from 'path';
|
||||||
|
|
||||||
export default function resolveDirs(paths) {
|
export default function resolveDirs(paths) {
|
||||||
const pathBaseDir = paths.map((path) => [
|
const pathBaseDir = paths.map((path) => [
|
||||||
pathUtils.basename(path),
|
posix.basename(path),
|
||||||
pathUtils.dirname(path),
|
posix.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 pathUtils.resolve(resolveResult.id);
|
return resolve(resolveResult.id);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ 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) => {
|
||||||
|
|||||||
262
package-lock.json
generated
262
package-lock.json
generated
@@ -8,13 +8,11 @@
|
|||||||
"name": "squoosh",
|
"name": "squoosh",
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"license": "apache-2.0",
|
"license": "apache-2.0",
|
||||||
"dependencies": {
|
|
||||||
"wasm-feature-detect": "^1.2.11"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@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",
|
||||||
@@ -46,6 +44,7 @@
|
|||||||
"rollup-plugin-terser": "^7.0.2",
|
"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"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -151,6 +150,70 @@
|
|||||||
"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",
|
||||||
@@ -247,6 +310,39 @@
|
|||||||
"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",
|
||||||
@@ -406,6 +502,19 @@
|
|||||||
"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",
|
||||||
@@ -762,10 +871,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/buffer-from": {
|
"node_modules/buffer-from": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
|
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/builtin-modules": {
|
"node_modules/builtin-modules": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
@@ -7886,6 +7996,13 @@
|
|||||||
"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",
|
||||||
@@ -7896,10 +8013,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/source-map-support": {
|
"node_modules/source-map-support": {
|
||||||
"version": "0.5.19",
|
"version": "0.5.21",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
||||||
"integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
|
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
||||||
"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"
|
||||||
@@ -8410,14 +8528,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/terser": {
|
"node_modules/terser": {
|
||||||
"version": "5.3.1",
|
"version": "5.31.4",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.31.4.tgz",
|
||||||
"integrity": "sha512-yD80f4hdwCWTH5mojzxe1q8bN1oJbsK/vfJGLcPZM/fl+/jItIVNKhFIHqqR71OipFWMLgj3Kc+GIp6CeIqfnA==",
|
"integrity": "sha512-3OU03GgblDgu0g+sdnsVzhBPxnjV+WJuMmocN1qBBZDQ3ia7jZQSAkePeKbPlYAejGXUTYe1CmSaUeV51mvaIw==",
|
||||||
"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": "~0.6.1",
|
"source-map-support": "~0.5.20"
|
||||||
"source-map-support": "~0.5.12"
|
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"terser": "bin/terser"
|
"terser": "bin/terser"
|
||||||
@@ -8561,7 +8681,8 @@
|
|||||||
"node_modules/wasm-feature-detect": {
|
"node_modules/wasm-feature-detect": {
|
||||||
"version": "1.2.11",
|
"version": "1.2.11",
|
||||||
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.2.11.tgz",
|
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.2.11.tgz",
|
||||||
"integrity": "sha512-HUqwaodrQGaZgz1lZaNioIkog9tkeEJjrM3eq4aUL04whXOVDRc/o2EGb/8kV0QX411iAYWEqq7fMBmJ6dKS6w=="
|
"integrity": "sha512-HUqwaodrQGaZgz1lZaNioIkog9tkeEJjrM3eq4aUL04whXOVDRc/o2EGb/8kV0QX411iAYWEqq7fMBmJ6dKS6w==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
@@ -8757,6 +8878,55 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@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",
|
||||||
@@ -8842,6 +9012,28 @@
|
|||||||
"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",
|
||||||
@@ -8987,6 +9179,12 @@
|
|||||||
"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",
|
||||||
@@ -9275,9 +9473,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"buffer-from": {
|
"buffer-from": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
|
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"builtin-modules": {
|
"builtin-modules": {
|
||||||
@@ -15196,6 +15394,12 @@
|
|||||||
"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",
|
||||||
@@ -15203,9 +15407,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"source-map-support": {
|
"source-map-support": {
|
||||||
"version": "0.5.19",
|
"version": "0.5.21",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
||||||
"integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
|
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"buffer-from": "^1.0.0",
|
"buffer-from": "^1.0.0",
|
||||||
@@ -15626,14 +15830,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"terser": {
|
"terser": {
|
||||||
"version": "5.3.1",
|
"version": "5.31.4",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.31.4.tgz",
|
||||||
"integrity": "sha512-yD80f4hdwCWTH5mojzxe1q8bN1oJbsK/vfJGLcPZM/fl+/jItIVNKhFIHqqR71OipFWMLgj3Kc+GIp6CeIqfnA==",
|
"integrity": "sha512-3OU03GgblDgu0g+sdnsVzhBPxnjV+WJuMmocN1qBBZDQ3ia7jZQSAkePeKbPlYAejGXUTYe1CmSaUeV51mvaIw==",
|
||||||
"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": "~0.6.1",
|
"source-map-support": "~0.5.20"
|
||||||
"source-map-support": "~0.5.12"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": {
|
"commander": {
|
||||||
@@ -15757,7 +15962,8 @@
|
|||||||
"wasm-feature-detect": {
|
"wasm-feature-detect": {
|
||||||
"version": "1.2.11",
|
"version": "1.2.11",
|
||||||
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.2.11.tgz",
|
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.2.11.tgz",
|
||||||
"integrity": "sha512-HUqwaodrQGaZgz1lZaNioIkog9tkeEJjrM3eq4aUL04whXOVDRc/o2EGb/8kV0QX411iAYWEqq7fMBmJ6dKS6w=="
|
"integrity": "sha512-HUqwaodrQGaZgz1lZaNioIkog9tkeEJjrM3eq4aUL04whXOVDRc/o2EGb/8kV0QX411iAYWEqq7fMBmJ6dKS6w==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"which": {
|
"which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"@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",
|
||||||
@@ -43,11 +44,10 @@
|
|||||||
"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",
|
||||||
"which": "^2.0.2",
|
"wasm-feature-detect": "^1.2.11",
|
||||||
"wasm-feature-detect": "^1.2.11"
|
"which": "^2.0.2"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.{js,css,json,md,ts,tsx}": "prettier --write",
|
"*.{js,css,json,md,ts,tsx}": "prettier --write",
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -2,6 +2,26 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: relative;
|
position: relative;
|
||||||
--size: 17px;
|
--size: 17px;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 200%;
|
||||||
|
height: 200%;
|
||||||
|
background-color: var(--main-theme-color);
|
||||||
|
border-radius: 999px;
|
||||||
|
opacity: 0.25;
|
||||||
|
|
||||||
|
transform: translate(-50%, -50%) scale(0);
|
||||||
|
transition-property: transform;
|
||||||
|
transition-duration: 250ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-within::before {
|
||||||
|
transform: translate(-50%, -50%) scale(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.real-checkbox {
|
.real-checkbox {
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ range-input::before {
|
|||||||
height: 12px;
|
height: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
range-input:focus-within .thumb {
|
||||||
|
outline: white solid 2px;
|
||||||
|
}
|
||||||
|
|
||||||
.thumb-wrapper {
|
.thumb-wrapper {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 6px;
|
left: 6px;
|
||||||
|
|||||||
@@ -11,6 +11,10 @@
|
|||||||
padding: 3px calc(var(--thumb-size) / 2 + 3px);
|
padding: 3px calc(var(--thumb-size) / 2 + 3px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.checkbox:focus-within .track {
|
||||||
|
outline: white solid 2px;
|
||||||
|
}
|
||||||
|
|
||||||
.thumb {
|
.thumb {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: var(--thumb-size);
|
width: var(--thumb-size);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import Toggle from './Toggle';
|
|||||||
import Select from './Select';
|
import Select from './Select';
|
||||||
import { Options as QuantOptionsComponent } from 'features/processors/quantize/client';
|
import { Options as QuantOptionsComponent } from 'features/processors/quantize/client';
|
||||||
import { Options as ResizeOptionsComponent } from 'features/processors/resize/client';
|
import { Options as ResizeOptionsComponent } from 'features/processors/resize/client';
|
||||||
import { SwapIcon } from 'client/lazy-app/icons';
|
import { ImportIcon, SaveIcon, SwapIcon } from 'client/lazy-app/icons';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
index: 0 | 1;
|
index: 0 | 1;
|
||||||
@@ -29,10 +29,14 @@ interface Props {
|
|||||||
onEncoderOptionsChange(index: 0 | 1, newOptions: EncoderOptions): void;
|
onEncoderOptionsChange(index: 0 | 1, newOptions: EncoderOptions): void;
|
||||||
onProcessorOptionsChange(index: 0 | 1, newOptions: ProcessorState): void;
|
onProcessorOptionsChange(index: 0 | 1, newOptions: ProcessorState): void;
|
||||||
onCopyToOtherSideClick(index: 0 | 1): void;
|
onCopyToOtherSideClick(index: 0 | 1): void;
|
||||||
|
onSaveSideSettingsClick(index: 0 | 1): void;
|
||||||
|
onImportSideSettingsClick(index: 0 | 1): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
supportedEncoderMap?: PartialButNotUndefined<typeof encoderMap>;
|
supportedEncoderMap?: PartialButNotUndefined<typeof encoderMap>;
|
||||||
|
leftSideSettings?: string | null;
|
||||||
|
rightSideSettings?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
type PartialButNotUndefined<T> = {
|
type PartialButNotUndefined<T> = {
|
||||||
@@ -60,6 +64,8 @@ const supportedEncoderMapP: Promise<PartialButNotUndefined<typeof encoderMap>> =
|
|||||||
export default class Options extends Component<Props, State> {
|
export default class Options extends Component<Props, State> {
|
||||||
state: State = {
|
state: State = {
|
||||||
supportedEncoderMap: undefined,
|
supportedEncoderMap: undefined,
|
||||||
|
leftSideSettings: localStorage.getItem('leftSideSettings'),
|
||||||
|
rightSideSettings: localStorage.getItem('rightSideSettings'),
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -69,6 +75,29 @@ export default class Options extends Component<Props, State> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private setLeftSideSettings = () => {
|
||||||
|
this.setState({
|
||||||
|
leftSideSettings: localStorage.getItem('leftSideSettings'),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private setRightSideSettings = () => {
|
||||||
|
this.setState({
|
||||||
|
rightSideSettings: localStorage.getItem('rightSideSettings'),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount(): void {
|
||||||
|
// Changing the state when side setting is stored in localstorage
|
||||||
|
window.addEventListener('leftSideSettings', this.setLeftSideSettings);
|
||||||
|
window.addEventListener('rightSideSettings', this.setRightSideSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount(): void {
|
||||||
|
window.removeEventListener('leftSideSettings', this.setLeftSideSettings);
|
||||||
|
window.removeEventListener('removeSideSettings', this.setRightSideSettings);
|
||||||
|
}
|
||||||
|
|
||||||
private onEncoderTypeChange = (event: Event) => {
|
private onEncoderTypeChange = (event: Event) => {
|
||||||
const el = event.currentTarget as HTMLSelectElement;
|
const el = event.currentTarget as HTMLSelectElement;
|
||||||
|
|
||||||
@@ -110,6 +139,14 @@ export default class Options extends Component<Props, State> {
|
|||||||
this.props.onCopyToOtherSideClick(this.props.index);
|
this.props.onCopyToOtherSideClick(this.props.index);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private onSaveSideSettingClick = () => {
|
||||||
|
this.props.onSaveSideSettingsClick(this.props.index);
|
||||||
|
};
|
||||||
|
|
||||||
|
private onImportSideSettingsClick = () => {
|
||||||
|
this.props.onImportSideSettingsClick(this.props.index);
|
||||||
|
};
|
||||||
|
|
||||||
render(
|
render(
|
||||||
{ source, encoderState, processorState }: Props,
|
{ source, encoderState, processorState }: Props,
|
||||||
{ supportedEncoderMap }: State,
|
{ supportedEncoderMap }: State,
|
||||||
@@ -139,6 +176,36 @@ export default class Options extends Component<Props, State> {
|
|||||||
>
|
>
|
||||||
<SwapIcon />
|
<SwapIcon />
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
class={style.saveButton}
|
||||||
|
title="Save side settings"
|
||||||
|
onClick={this.onSaveSideSettingClick}
|
||||||
|
>
|
||||||
|
<SaveIcon />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class={
|
||||||
|
style.importButton +
|
||||||
|
' ' +
|
||||||
|
(!this.state.leftSideSettings && this.props.index === 0
|
||||||
|
? style.buttonOpacity
|
||||||
|
: '') +
|
||||||
|
' ' +
|
||||||
|
(!this.state.rightSideSettings && this.props.index === 1
|
||||||
|
? style.buttonOpacity
|
||||||
|
: '')
|
||||||
|
}
|
||||||
|
title="Import saved side settings"
|
||||||
|
onClick={this.onImportSideSettingsClick}
|
||||||
|
disabled={
|
||||||
|
// Disabled if this side's settings haven't been saved
|
||||||
|
(!this.state.leftSideSettings &&
|
||||||
|
this.props.index === 0) ||
|
||||||
|
(!this.state.rightSideSettings && this.props.index === 1)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ImportIcon />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</h3>
|
</h3>
|
||||||
<label class={style.sectionEnabler}>
|
<label class={style.sectionEnabler}>
|
||||||
@@ -190,7 +257,9 @@ export default class Options extends Component<Props, State> {
|
|||||||
onChange={this.onEncoderTypeChange}
|
onChange={this.onEncoderTypeChange}
|
||||||
large
|
large
|
||||||
>
|
>
|
||||||
<option value="identity">Original Image</option>
|
<option value="identity">{`Original Image ${
|
||||||
|
this.props.source ? `(${this.props.source.file.name})` : ''
|
||||||
|
}`}</option>
|
||||||
{Object.entries(supportedEncoderMap).map(([type, encoder]) => (
|
{Object.entries(supportedEncoderMap).map(([type, encoder]) => (
|
||||||
<option value={type}>{encoder.meta.label}</option>
|
<option value={type}>{encoder.meta.label}</option>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -53,6 +53,16 @@
|
|||||||
composes: option-toggle;
|
composes: option-toggle;
|
||||||
grid-template-columns: auto 1fr;
|
grid-template-columns: auto 1fr;
|
||||||
gap: 1em;
|
gap: 1em;
|
||||||
|
|
||||||
|
border-top: 1px solid #fff4;
|
||||||
|
|
||||||
|
transition-property: background-color;
|
||||||
|
transition-duration: 250ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-reveal:focus-within,
|
||||||
|
.option-reveal:hover {
|
||||||
|
background-color: #fff2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.option-one-cell {
|
.option-one-cell {
|
||||||
@@ -73,11 +83,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.text-field {
|
.text-field {
|
||||||
background: var(--white);
|
background-color: var(--black);
|
||||||
color: var(--black);
|
color: var(--white);
|
||||||
font: inherit;
|
font: inherit;
|
||||||
border: none;
|
border: none;
|
||||||
padding: 6px 0 6px 10px;
|
padding: 6px 6px 6px 10px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -112,7 +122,37 @@
|
|||||||
.copy-over-button {
|
.copy-over-button {
|
||||||
composes: title-button;
|
composes: title-button;
|
||||||
|
|
||||||
|
/* Make the filled arrow point towards the other options element */
|
||||||
|
transform: rotate(var(--rotate-copyoverbutton-angle));
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
fill: var(--header-text-color);
|
fill: var(--header-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: var(--header-text-color) solid 2px;
|
||||||
|
outline-offset: 0.25em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-button,
|
||||||
|
.import-button {
|
||||||
|
composes: title-button;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
stroke: var(--header-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: var(--header-text-color) solid 2px;
|
||||||
|
outline-offset: 0.25em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-opacity {
|
||||||
|
pointer-events: none;
|
||||||
|
cursor: not-allowed;
|
||||||
|
svg {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,6 +111,9 @@ async function decodeImage(
|
|||||||
if (mimeType === 'image/webp2') {
|
if (mimeType === 'image/webp2') {
|
||||||
return await workerBridge.wp2Decode(signal, blob);
|
return await workerBridge.wp2Decode(signal, blob);
|
||||||
}
|
}
|
||||||
|
if (mimeType === 'image/qoi') {
|
||||||
|
return await workerBridge.qoiDecode(signal, blob);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Otherwise fall through and try built-in decoding for a laugh.
|
// Otherwise fall through and try built-in decoding for a laugh.
|
||||||
return await builtinDecode(signal, blob);
|
return await builtinDecode(signal, blob);
|
||||||
@@ -281,15 +284,26 @@ export default class Compress extends Component<Props, State> {
|
|||||||
source: undefined,
|
source: undefined,
|
||||||
loading: false,
|
loading: false,
|
||||||
preprocessorState: defaultPreprocessorState,
|
preprocessorState: defaultPreprocessorState,
|
||||||
|
// Tasking catched side settings if available otherwise taking default settings
|
||||||
sides: [
|
sides: [
|
||||||
{
|
localStorage.getItem('leftSideSettings')
|
||||||
|
? {
|
||||||
|
...JSON.parse(localStorage.getItem('leftSideSettings') as string),
|
||||||
|
loading: false,
|
||||||
|
}
|
||||||
|
: {
|
||||||
latestSettings: {
|
latestSettings: {
|
||||||
processorState: defaultProcessorState,
|
processorState: defaultProcessorState,
|
||||||
encoderState: undefined,
|
encoderState: undefined,
|
||||||
},
|
},
|
||||||
loading: false,
|
loading: false,
|
||||||
},
|
},
|
||||||
{
|
localStorage.getItem('rightSideSettings')
|
||||||
|
? {
|
||||||
|
...JSON.parse(localStorage.getItem('rightSideSettings') as string),
|
||||||
|
loading: false,
|
||||||
|
}
|
||||||
|
: {
|
||||||
latestSettings: {
|
latestSettings: {
|
||||||
processorState: defaultProcessorState,
|
processorState: defaultProcessorState,
|
||||||
encoderState: {
|
encoderState: {
|
||||||
@@ -428,6 +442,99 @@ export default class Compress extends Component<Props, State> {
|
|||||||
sides: cleanSet(this.state.sides, otherIndex, oldSettings),
|
sides: cleanSet(this.state.sides, otherIndex, oldSettings),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* This function saves encodedSettings and latestSettings of
|
||||||
|
* particular side in browser local storage
|
||||||
|
* @param index : (0|1)
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
private onSaveSideSettingsClick = async (index: 0 | 1) => {
|
||||||
|
if (index === 0) {
|
||||||
|
const leftSideSettings = JSON.stringify({
|
||||||
|
encodedSettings: this.state.sides[index].encodedSettings,
|
||||||
|
latestSettings: this.state.sides[index].latestSettings,
|
||||||
|
});
|
||||||
|
localStorage.setItem('leftSideSettings', leftSideSettings);
|
||||||
|
// Firing an event when we save side settings in localstorage
|
||||||
|
window.dispatchEvent(new CustomEvent('leftSideSettings'));
|
||||||
|
await this.props.showSnack('Left side settings saved', {
|
||||||
|
timeout: 1500,
|
||||||
|
actions: ['dismiss'],
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index === 1) {
|
||||||
|
const rightSideSettings = JSON.stringify({
|
||||||
|
encodedSettings: this.state.sides[index].encodedSettings,
|
||||||
|
latestSettings: this.state.sides[index].latestSettings,
|
||||||
|
});
|
||||||
|
localStorage.setItem('rightSideSettings', rightSideSettings);
|
||||||
|
// Firing an event when we save side settings in localstorage
|
||||||
|
window.dispatchEvent(new CustomEvent('rightSideSettings'));
|
||||||
|
await this.props.showSnack('Right side settings saved', {
|
||||||
|
timeout: 1500,
|
||||||
|
actions: ['dismiss'],
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function sets the side state with catched localstorage
|
||||||
|
* value as per side index provided
|
||||||
|
* @param index : (0|1)
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
private onImportSideSettingsClick = async (index: 0 | 1) => {
|
||||||
|
const leftSideSettingsString = localStorage.getItem('leftSideSettings');
|
||||||
|
const rightSideSettingsString = localStorage.getItem('rightSideSettings');
|
||||||
|
|
||||||
|
if (index === 0 && leftSideSettingsString) {
|
||||||
|
const oldLeftSideSettings = this.state.sides[index];
|
||||||
|
const newLeftSideSettings = {
|
||||||
|
...this.state.sides[index],
|
||||||
|
...JSON.parse(leftSideSettingsString),
|
||||||
|
};
|
||||||
|
this.setState({
|
||||||
|
sides: cleanSet(this.state.sides, index, newLeftSideSettings),
|
||||||
|
});
|
||||||
|
const result = await this.props.showSnack('Left side settings imported', {
|
||||||
|
timeout: 3000,
|
||||||
|
actions: ['undo', 'dismiss'],
|
||||||
|
});
|
||||||
|
if (result === 'undo') {
|
||||||
|
this.setState({
|
||||||
|
sides: cleanSet(this.state.sides, index, oldLeftSideSettings),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index === 1 && rightSideSettingsString) {
|
||||||
|
const oldRightSideSettings = this.state.sides[index];
|
||||||
|
const newRightSideSettings = {
|
||||||
|
...this.state.sides[index],
|
||||||
|
...JSON.parse(rightSideSettingsString),
|
||||||
|
};
|
||||||
|
this.setState({
|
||||||
|
sides: cleanSet(this.state.sides, index, newRightSideSettings),
|
||||||
|
});
|
||||||
|
const result = await this.props.showSnack(
|
||||||
|
'Right side settings imported',
|
||||||
|
{
|
||||||
|
timeout: 3000,
|
||||||
|
actions: ['undo', 'dismiss'],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (result === 'undo') {
|
||||||
|
this.setState({
|
||||||
|
sides: cleanSet(this.state.sides, index, oldRightSideSettings),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private onPreprocessorChange = async (
|
private onPreprocessorChange = async (
|
||||||
preprocessorState: PreprocessorState,
|
preprocessorState: PreprocessorState,
|
||||||
@@ -829,6 +936,8 @@ export default class Compress extends Component<Props, State> {
|
|||||||
onEncoderOptionsChange={this.onEncoderOptionsChange}
|
onEncoderOptionsChange={this.onEncoderOptionsChange}
|
||||||
onProcessorOptionsChange={this.onProcessorOptionsChange}
|
onProcessorOptionsChange={this.onProcessorOptionsChange}
|
||||||
onCopyToOtherSideClick={this.onCopyToOtherClick}
|
onCopyToOtherSideClick={this.onCopyToOtherClick}
|
||||||
|
onSaveSideSettingsClick={this.onSaveSideSettingsClick}
|
||||||
|
onImportSideSettingsClick={this.onImportSideSettingsClick}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -842,7 +951,7 @@ export default class Compress extends Component<Props, State> {
|
|||||||
typeLabel={
|
typeLabel={
|
||||||
side.latestSettings.encoderState
|
side.latestSettings.encoderState
|
||||||
? encoderMap[side.latestSettings.encoderState.type].meta.label
|
? encoderMap[side.latestSettings.encoderState.type].meta.label
|
||||||
: 'Original Image'
|
: `${side.file ? `${side.file.name}` : 'Original Image'}`
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -45,9 +45,11 @@
|
|||||||
--hot-theme-color: var(--hot-pink);
|
--hot-theme-color: var(--hot-pink);
|
||||||
--header-text-color: var(--white);
|
--header-text-color: var(--white);
|
||||||
--scroller-radius: var(--options-radius) var(--options-radius) 0 0;
|
--scroller-radius: var(--options-radius) var(--options-radius) 0 0;
|
||||||
|
--rotate-copyoverbutton-angle: 90deg; /* To point down */
|
||||||
|
|
||||||
@media (min-width: 600px) {
|
@media (min-width: 600px) {
|
||||||
--scroller-radius: 0 var(--options-radius) var(--options-radius) 0;
|
--scroller-radius: 0 var(--options-radius) var(--options-radius) 0;
|
||||||
|
--rotate-copyoverbutton-angle: 0deg; /* To point right (no change) */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,9 +58,11 @@
|
|||||||
--hot-theme-color: var(--deep-blue);
|
--hot-theme-color: var(--deep-blue);
|
||||||
--header-text-color: var(--dark-text);
|
--header-text-color: var(--dark-text);
|
||||||
--scroller-radius: var(--options-radius) var(--options-radius) 0 0;
|
--scroller-radius: var(--options-radius) var(--options-radius) 0 0;
|
||||||
|
--rotate-copyoverbutton-angle: -90deg; /* To point up */
|
||||||
|
|
||||||
@media (min-width: 600px) {
|
@media (min-width: 600px) {
|
||||||
--scroller-radius: var(--options-radius) 0 0 var(--options-radius);
|
--scroller-radius: var(--options-radius) 0 0 var(--options-radius);
|
||||||
|
--rotate-copyoverbutton-angle: 180deg; /* To point left */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +113,13 @@
|
|||||||
|
|
||||||
& > svg {
|
& > svg {
|
||||||
width: 47px;
|
width: 47px;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus .back-blob {
|
||||||
|
stroke: var(--deep-blue);
|
||||||
|
stroke-width: 5px;
|
||||||
|
animation: strokePulse 500ms ease forwards;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 600px) {
|
@media (min-width: 600px) {
|
||||||
@@ -120,6 +131,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes strokePulse {
|
||||||
|
from {
|
||||||
|
stroke-width: 8px;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
stroke-width: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.back-blob {
|
.back-blob {
|
||||||
fill: var(--hot-pink);
|
fill: var(--hot-pink);
|
||||||
opacity: 0.77;
|
opacity: 0.77;
|
||||||
|
|||||||
@@ -97,3 +97,31 @@ export const SwapIcon = () => (
|
|||||||
<path d="M5.5 3.6v6.8L2.1 7l3.4-3.4M7 0L0 7l7 7V0zm4 0v14l7-7-7-7z" />
|
<path d="M5.5 3.6v6.8L2.1 7l3.4-3.4M7 0L0 7l7 7V0zm4 0v14l7-7-7-7z" />
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const SaveIcon = () => (
|
||||||
|
<svg viewBox="0 0 24 24">
|
||||||
|
<g
|
||||||
|
fill="none"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
>
|
||||||
|
<path d="M12.501 20.93c-.866.25-1.914-.166-2.176-1.247a1.724 1.724 0 0 0-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 0 0-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 0 0 1.066-2.573c-.94-1.543.826-3.31 2.37-2.37c1 .608 2.296.07 2.572-1.065c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.074.26 1.49 1.296 1.252 2.158M19 22v-6m3 3l-3-3l-3 3" />
|
||||||
|
<path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0-6 0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const ImportIcon = () => (
|
||||||
|
<svg viewBox="0 0 24 24">
|
||||||
|
<g
|
||||||
|
fill="none"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
>
|
||||||
|
<path d="M12.52 20.924c-.87.262-1.93-.152-2.195-1.241a1.724 1.724 0 0 0-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 0 0-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 0 0 1.066-2.573c-.94-1.543.826-3.31 2.37-2.37c1 .608 2.296.07 2.572-1.065c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.088.264 1.502 1.323 1.242 2.192M19 16v6m3-3l-3 3l-3-3" />
|
||||||
|
<path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0-6 0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ const magicNumberMapInput = [
|
|||||||
[/^\x00\x00\x00 ftypavif\x00\x00\x00\x00/, 'image/avif'],
|
[/^\x00\x00\x00 ftypavif\x00\x00\x00\x00/, 'image/avif'],
|
||||||
[/^\xff\x0a/, 'image/jxl'],
|
[/^\xff\x0a/, 'image/jxl'],
|
||||||
[/^\x00\x00\x00\x0cJXL \x0d\x0a\x87\x0a/, 'image/jxl'],
|
[/^\x00\x00\x00\x0cJXL \x0d\x0a\x87\x0a/, 'image/jxl'],
|
||||||
|
[/^qoif/, 'image/qoi'],
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export type ImageMimeTypes = typeof magicNumberMapInput[number][1];
|
export type ImageMimeTypes = typeof magicNumberMapInput[number][1];
|
||||||
|
|||||||
19
src/features/decoders/qoi/worker/qoiDecode.ts
Normal file
19
src/features/decoders/qoi/worker/qoiDecode.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import qoiDecoder, { QOIModule } from 'codecs/qoi/dec/qoi_dec';
|
||||||
|
import { initEmscriptenModule, blobToArrayBuffer } from 'features/worker-utils';
|
||||||
|
|
||||||
|
let emscriptenModule: Promise<QOIModule>;
|
||||||
|
|
||||||
|
export default async function decode(blob: Blob): Promise<ImageData> {
|
||||||
|
if (!emscriptenModule) {
|
||||||
|
emscriptenModule = initEmscriptenModule(qoiDecoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [module, data] = await Promise.all([
|
||||||
|
emscriptenModule,
|
||||||
|
blobToArrayBuffer(blob),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const result = module.decode(data);
|
||||||
|
if (!result) throw new Error('Decoding error');
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { EncodeOptions, defaultOptions, AVIFTune } from '../shared/meta';
|
import { EncodeOptions, AVIFTune, defaultOptions } 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,12 +36,20 @@ 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;
|
/**
|
||||||
const maxSpeed = 10;
|
* AVIF quality ranges from 0 (worst) to 100 (lossless).
|
||||||
|
* 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(
|
||||||
@@ -55,34 +63,28 @@ export class Options extends Component<Props, State> {
|
|||||||
const { options } = props;
|
const { options } = props;
|
||||||
|
|
||||||
const lossless =
|
const lossless =
|
||||||
options.cqLevel === 0 &&
|
options.quality === MAX_QUALITY &&
|
||||||
options.cqAlphaLevel <= 0 &&
|
(options.qualityAlpha == -1 || options.qualityAlpha == MAX_QUALITY) &&
|
||||||
options.subsample == 3;
|
options.subsample == 3;
|
||||||
|
|
||||||
const separateAlpha = options.cqAlphaLevel !== -1;
|
const separateAlpha = options.qualityAlpha !== -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: maxQuant - cqLevel,
|
quality: lossless ? defaultOptions.quality : options.quality,
|
||||||
separateAlpha,
|
separateAlpha,
|
||||||
alphaQuality:
|
alphaQuality: separateAlpha ? options.qualityAlpha : options.quality,
|
||||||
maxQuant -
|
subsample: options.subsample,
|
||||||
(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: maxSpeed - options.speed,
|
effort: MAX_EFFORT - 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,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,20 +122,21 @@ export class Options extends Component<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const newOptions: EncodeOptions = {
|
const newOptions: EncodeOptions = {
|
||||||
cqLevel: optionState.lossless ? 0 : maxQuant - optionState.quality,
|
quality: optionState.lossless ? MAX_QUALITY : optionState.quality,
|
||||||
cqAlphaLevel:
|
qualityAlpha:
|
||||||
optionState.lossless || !optionState.separateAlpha
|
optionState.lossless || !optionState.separateAlpha
|
||||||
? -1
|
? -1 // Set qualityAlpha to quality
|
||||||
: maxQuant - optionState.alphaQuality,
|
: 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: maxSpeed - optionState.effort,
|
speed: MAX_EFFORT - 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.
|
||||||
@@ -167,6 +170,7 @@ export class Options extends Component<Props, State> {
|
|||||||
sharpness,
|
sharpness,
|
||||||
denoiseLevel,
|
denoiseLevel,
|
||||||
tune,
|
tune,
|
||||||
|
enableSharpYUV,
|
||||||
}: State,
|
}: State,
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
@@ -183,7 +187,7 @@ export class Options extends Component<Props, State> {
|
|||||||
<div class={style.optionOneCell}>
|
<div class={style.optionOneCell}>
|
||||||
<Range
|
<Range
|
||||||
min="0"
|
min="0"
|
||||||
max="63"
|
max={MAX_QUALITY - 1} // MAX_QUALITY would mean lossless
|
||||||
value={quality}
|
value={quality}
|
||||||
onInput={this._inputChange('quality', 'number')}
|
onInput={this._inputChange('quality', 'number')}
|
||||||
>
|
>
|
||||||
@@ -211,11 +215,26 @@ export class Options extends Component<Props, State> {
|
|||||||
value={subsample}
|
value={subsample}
|
||||||
onChange={this._inputChange('subsample', 'number')}
|
onChange={this._inputChange('subsample', 'number')}
|
||||||
>
|
>
|
||||||
<option value="1">Half</option>
|
<option value="0">4:0:0</option>
|
||||||
{/*<option value="2">4:2:2</option>*/}
|
<option value="1">4:2:0</option>
|
||||||
<option value="3">Off</option>
|
<option value="2">4:2:2</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
|
||||||
@@ -228,7 +247,7 @@ export class Options extends Component<Props, State> {
|
|||||||
<div class={style.optionOneCell}>
|
<div class={style.optionOneCell}>
|
||||||
<Range
|
<Range
|
||||||
min="0"
|
min="0"
|
||||||
max="63"
|
max={MAX_QUALITY - 1} // MAX_QUALITY would mean lossless
|
||||||
value={alphaQuality}
|
value={alphaQuality}
|
||||||
onInput={this._inputChange(
|
onInput={this._inputChange(
|
||||||
'alphaQuality',
|
'alphaQuality',
|
||||||
@@ -307,7 +326,7 @@ export class Options extends Component<Props, State> {
|
|||||||
<div class={style.optionOneCell}>
|
<div class={style.optionOneCell}>
|
||||||
<Range
|
<Range
|
||||||
min="0"
|
min="0"
|
||||||
max="10"
|
max={MAX_EFFORT}
|
||||||
value={effort}
|
value={effort}
|
||||||
onInput={this._inputChange('effort', 'number')}
|
onInput={this._inputChange('effort', 'number')}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -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 = {
|
||||||
cqLevel: 33,
|
quality: 50,
|
||||||
cqAlphaLevel: -1,
|
qualityAlpha: -1,
|
||||||
denoiseLevel: 0,
|
denoiseLevel: 0,
|
||||||
tileColsLog2: 0,
|
tileColsLog2: 0,
|
||||||
tileRowsLog2: 0,
|
tileRowsLog2: 0,
|
||||||
@@ -28,4 +28,5 @@ export const defaultOptions: EncodeOptions = {
|
|||||||
chromaDeltaQ: false,
|
chromaDeltaQ: false,
|
||||||
sharpness: 0,
|
sharpness: 0,
|
||||||
tune: AVIFTune.auto,
|
tune: AVIFTune.auto,
|
||||||
|
enableSharpYUV: false,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import { canvasEncode } from 'client/lazy-app/util/canvas';
|
import { inputFieldChecked } from 'client/lazy-app/util';
|
||||||
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';
|
||||||
@@ -18,9 +13,7 @@ export async function encode(
|
|||||||
imageData: ImageData,
|
imageData: ImageData,
|
||||||
options: EncodeOptions,
|
options: EncodeOptions,
|
||||||
) {
|
) {
|
||||||
const pngBlob = await abortable(signal, canvasEncode(imageData, 'image/png'));
|
return workerBridge.oxipngEncode(signal, imageData, options);
|
||||||
const pngBuffer = await abortable(signal, blobToArrayBuffer(pngBlob));
|
|
||||||
return workerBridge.oxipngEncode(signal, pngBuffer, options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -56,7 +49,7 @@ export class Options extends Component<Props, {}> {
|
|||||||
<Range
|
<Range
|
||||||
name="level"
|
name="level"
|
||||||
min="0"
|
min="0"
|
||||||
max="3"
|
max="6"
|
||||||
step="1"
|
step="1"
|
||||||
value={options.level}
|
value={options.level}
|
||||||
onInput={this.onChange}
|
onInput={this.onChange}
|
||||||
|
|||||||
@@ -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: ArrayBuffer,
|
data: ImageData,
|
||||||
options: EncodeOptions,
|
options: EncodeOptions,
|
||||||
): Promise<ArrayBuffer> {
|
): Promise<ArrayBuffer> {
|
||||||
if (!wasmReady) {
|
if (!wasmReady) {
|
||||||
@@ -45,6 +45,11 @@ export default async function encode(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const optimise = await wasmReady;
|
const optimise = await wasmReady;
|
||||||
return optimise(new Uint8Array(data), options.level, options.interlace)
|
return optimise(
|
||||||
.buffer;
|
data.data,
|
||||||
|
data.width,
|
||||||
|
data.height,
|
||||||
|
options.level,
|
||||||
|
options.interlace,
|
||||||
|
).buffer;
|
||||||
}
|
}
|
||||||
|
|||||||
11
src/features/encoders/qoi/client/index.tsx
Normal file
11
src/features/encoders/qoi/client/index.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { EncodeOptions } from '../shared/meta';
|
||||||
|
import type WorkerBridge from 'client/lazy-app/worker-bridge';
|
||||||
|
|
||||||
|
export function encode(
|
||||||
|
signal: AbortSignal,
|
||||||
|
workerBridge: WorkerBridge,
|
||||||
|
imageData: ImageData,
|
||||||
|
options: EncodeOptions,
|
||||||
|
) {
|
||||||
|
return workerBridge.qoiEncode(signal, imageData, options);
|
||||||
|
}
|
||||||
13
src/features/encoders/qoi/client/missing-types.d.ts
vendored
Normal file
13
src/features/encoders/qoi/client/missing-types.d.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/// <reference path="../../../../../missing-types.d.ts" />
|
||||||
19
src/features/encoders/qoi/shared/meta.ts
Normal file
19
src/features/encoders/qoi/shared/meta.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* 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 { EncodeOptions } from 'codecs/qoi/enc/qoi_enc';
|
||||||
|
export { EncodeOptions };
|
||||||
|
|
||||||
|
export const label = 'QOI';
|
||||||
|
export const mimeType = 'image/qoi';
|
||||||
|
export const extension = 'qoi';
|
||||||
|
export const defaultOptions: EncodeOptions = {};
|
||||||
13
src/features/encoders/qoi/shared/missing-types.d.ts
vendored
Normal file
13
src/features/encoders/qoi/shared/missing-types.d.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/// <reference path="../../../../../missing-types.d.ts" />
|
||||||
13
src/features/encoders/qoi/worker/missing-types.d.ts
vendored
Normal file
13
src/features/encoders/qoi/worker/missing-types.d.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/// <reference path="../../../../../missing-types.d.ts" />
|
||||||
35
src/features/encoders/qoi/worker/qoiEncode.ts
Normal file
35
src/features/encoders/qoi/worker/qoiEncode.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* 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 qoiEncoder, { QoiModule } from 'codecs/qoi/enc/qoi_enc';
|
||||||
|
import type { EncodeOptions } from '../shared/meta';
|
||||||
|
import { initEmscriptenModule } from 'features/worker-utils';
|
||||||
|
|
||||||
|
let emscriptenModule: Promise<QoiModule>;
|
||||||
|
|
||||||
|
async function init() {
|
||||||
|
return initEmscriptenModule(qoiEncoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function encode(
|
||||||
|
data: ImageData,
|
||||||
|
options: EncodeOptions,
|
||||||
|
): Promise<ArrayBuffer> {
|
||||||
|
if (!emscriptenModule) {
|
||||||
|
emscriptenModule = init();
|
||||||
|
}
|
||||||
|
|
||||||
|
const module = await emscriptenModule;
|
||||||
|
const resultView = module.encode(data.data, data.width, data.height, options);
|
||||||
|
// wasm can’t run on SharedArrayBuffers, so we hard-cast to ArrayBuffer.
|
||||||
|
return resultView.buffer as ArrayBuffer;
|
||||||
|
}
|
||||||
@@ -62,7 +62,7 @@ snack-bar {
|
|||||||
position: relative;
|
position: relative;
|
||||||
flex: 0 1 auto;
|
flex: 0 1 auto;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
height: 36px;
|
height: 100%;
|
||||||
margin: auto 8px auto -8px;
|
margin: auto 8px auto -8px;
|
||||||
min-width: 5em;
|
min-width: 5em;
|
||||||
background: none;
|
background: none;
|
||||||
@@ -78,6 +78,7 @@ snack-bar {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: background-color 200ms ease;
|
transition: background-color 200ms ease;
|
||||||
outline: none;
|
outline: none;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
.button:hover {
|
.button:hover {
|
||||||
background-color: rgba(0, 0, 0, 0.15);
|
background-color: rgba(0, 0, 0, 0.15);
|
||||||
|
|||||||
@@ -24,28 +24,28 @@ import SlideOnScroll from './SlideOnScroll';
|
|||||||
const demos = [
|
const demos = [
|
||||||
{
|
{
|
||||||
description: 'Large photo',
|
description: 'Large photo',
|
||||||
size: '2.8mb',
|
size: '2.8MB',
|
||||||
filename: 'photo.jpg',
|
filename: 'photo.jpg',
|
||||||
url: largePhoto,
|
url: largePhoto,
|
||||||
iconUrl: largePhotoIcon,
|
iconUrl: largePhotoIcon,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: 'Artwork',
|
description: 'Artwork',
|
||||||
size: '2.9mb',
|
size: '2.9MB',
|
||||||
filename: 'art.jpg',
|
filename: 'art.jpg',
|
||||||
url: artwork,
|
url: artwork,
|
||||||
iconUrl: artworkIcon,
|
iconUrl: artworkIcon,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: 'Device screen',
|
description: 'Device screen',
|
||||||
size: '1.6mb',
|
size: '1.6MB',
|
||||||
filename: 'pixel3.png',
|
filename: 'pixel3.png',
|
||||||
url: deviceScreen,
|
url: deviceScreen,
|
||||||
iconUrl: deviceScreenIcon,
|
iconUrl: deviceScreenIcon,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: 'SVG icon',
|
description: 'SVG icon',
|
||||||
size: '13k',
|
size: '13KB',
|
||||||
filename: 'squoosh.svg',
|
filename: 'squoosh.svg',
|
||||||
url: logo,
|
url: logo,
|
||||||
iconUrl: logoIcon,
|
iconUrl: logoIcon,
|
||||||
@@ -319,7 +319,7 @@ export default class Intro extends Component<Props, State> {
|
|||||||
class="unbutton"
|
class="unbutton"
|
||||||
onClick={(event) => this.onDemoClick(i, event)}
|
onClick={(event) => this.onDemoClick(i, event)}
|
||||||
>
|
>
|
||||||
<div>
|
<div class={style.demoContainer}>
|
||||||
<div class={style.demoIconContainer}>
|
<div class={style.demoIconContainer}>
|
||||||
<img
|
<img
|
||||||
class={style.demoIcon}
|
class={style.demoIcon}
|
||||||
|
|||||||
@@ -321,6 +321,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.demo-container {
|
||||||
|
transition: scale 400ms ease-in-out;
|
||||||
|
&:hover {
|
||||||
|
scale: 1.05;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.demo-size {
|
.demo-size {
|
||||||
background: var(--dim-blue);
|
background: var(--dim-blue);
|
||||||
border-radius: 1000px;
|
border-radius: 1000px;
|
||||||
|
|||||||
@@ -18,3 +18,14 @@ 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ import favicon from 'url:static-build/assets/favicon.ico';
|
|||||||
import ogImage from 'url:static-build/assets/icon-large-maskable.png';
|
import ogImage from 'url:static-build/assets/icon-large-maskable.png';
|
||||||
import { escapeStyleScriptContent, siteOrigin } from 'static-build/utils';
|
import { escapeStyleScriptContent, siteOrigin } from 'static-build/utils';
|
||||||
import Intro from 'shared/prerendered-app/Intro';
|
import Intro from 'shared/prerendered-app/Intro';
|
||||||
|
import snackbarCss from 'css:../../../shared/custom-els/snack-bar/styles.css';
|
||||||
|
import * as snackbarStyle from '../../../shared/custom-els/snack-bar/styles.css';
|
||||||
|
|
||||||
interface Props {}
|
interface Props {}
|
||||||
|
|
||||||
@@ -73,6 +75,29 @@ const Index: FunctionalComponent<Props> = () => (
|
|||||||
<body>
|
<body>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<Intro />
|
<Intro />
|
||||||
|
<noscript>
|
||||||
|
<style
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: escapeStyleScriptContent(snackbarCss),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<snack-bar>
|
||||||
|
<div
|
||||||
|
class={snackbarStyle.snackbar}
|
||||||
|
aria-live="assertive"
|
||||||
|
aria-atomic="true"
|
||||||
|
aria-hidden="false"
|
||||||
|
>
|
||||||
|
<div class={snackbarStyle.text}>
|
||||||
|
Initialization error: This site requires JavaScript, which is
|
||||||
|
disabled in your browser.
|
||||||
|
</div>
|
||||||
|
<a class={snackbarStyle.button} href="/">
|
||||||
|
reload
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</snack-bar>
|
||||||
|
</noscript>
|
||||||
</div>
|
</div>
|
||||||
<script
|
<script
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
|
|||||||
Reference in New Issue
Block a user