Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot]
dabee063b8 Bump crossbeam-deque from 0.8.0 to 0.8.2 in /codecs/oxipng
Bumps [crossbeam-deque](https://github.com/crossbeam-rs/crossbeam) from 0.8.0 to 0.8.2.
- [Release notes](https://github.com/crossbeam-rs/crossbeam/releases)
- [Changelog](https://github.com/crossbeam-rs/crossbeam/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crossbeam-rs/crossbeam/compare/crossbeam-deque-0.8.0...crossbeam-deque-0.8.2)

---
updated-dependencies:
- dependency-name: crossbeam-deque
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-09 10:44:02 +00:00
78 changed files with 536 additions and 1278 deletions

2
.nvmrc
View File

@@ -1 +1 @@
20.16.0
14.15.1

View File

@@ -1,9 +1,9 @@
# using libavif from https://github.com/AOMediaCodec/libavif
LIBAVIF_URL = https://github.com/AOMediaCodec/libavif/archive/refs/tags/v1.0.1.tar.gz
LIBAVIF_PACKAGE = node_modules/libavif.tar.gz
# libavif and libaom versions are from
# https://docs.google.com/document/d/1wEEA5rRU7wT54k41u3qyZIZHDCJArIMzLuzsrLAwaK8/edit
CODEC_URL = https://github.com/AOMediaCodec/libavif/archive/1c39e772c2c0d687691dd4b589a12c323f5f767d.tar.gz
CODEC_PACKAGE = node_modules/libavif.tar.gz
# using libaom from https://aomedia.googlesource.com/aom
LIBAOM_URL = https://aomedia.googlesource.com/aom/+archive/v3.7.0.tar.gz
LIBAOM_URL = https://aomedia.googlesource.com/aom/+archive/v3.1.0.tar.gz
LIBAOM_PACKAGE = node_modules/libaom.tar.gz
export CODEC_DIR = node_modules/libavif
@@ -11,14 +11,7 @@ export BUILD_DIR = node_modules/build
export LIBAOM_DIR = node_modules/libaom
override CFLAGS += "-Wno-unused-macros"
# 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
export
OUT_ENC_JS = enc/avif_enc.js
OUT_NODE_ENC_JS = enc/avif_node_enc.js
@@ -35,11 +28,10 @@ HELPER_MAKEFLAGS := -f helper.Makefile
.PHONY: all clean
all: $(OUT_ENC_JS) $(OUT_DEC_JS) $(OUT_ENC_MT_JS)
all: $(OUT_ENC_JS) $(OUT_DEC_JS) $(OUT_ENC_MT_JS) $(OUT_NODE_ENC_JS) $(OUT_NODE_ENC_MT_JS) $(OUT_NODE_DEC_JS)
# ST-Encoding
$(OUT_ENC_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt $(LIBSHARPYUV_ST)
mkdir -p $(LIBWEBP_DIR)/build && cp $(LIBSHARPYUV_ST) $(LIBSHARPYUV)
$(OUT_NODE_ENC_JS) $(OUT_NODE_ENC_MT_JS): ENVIRONMENT=node
$(OUT_NODE_ENC_JS) $(OUT_ENC_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt
$(MAKE) \
$(HELPER_MAKEFLAGS) \
OUT_JS=$@ \
@@ -50,12 +42,9 @@ $(OUT_ENC_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLis
-DCONFIG_AV1_HIGHBITDEPTH=0 \
" \
ENVIRONMENT=$(ENVIRONMENT) \
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_DECODE=0 -DAVIF_LOCAL_LIBSHARPYUV=ON"
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_DECODE=0"
# 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)
$(OUT_ENC_MT_JS) $(OUT_NODE_ENC_MT_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt
$(MAKE) \
$(HELPER_MAKEFLAGS) \
OUT_JS=$@ \
@@ -65,11 +54,11 @@ $(OUT_ENC_MT_JS): $(OUT_ENC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMake
-DCONFIG_AV1_HIGHBITDEPTH=0 \
" \
ENVIRONMENT=$(ENVIRONMENT) \
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_DECODE=0 -DAVIF_LOCAL_LIBSHARPYUV=ON" \
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_DECODE=0" \
OUT_FLAGS="-pthread"
# Decoding
$(OUT_DEC_JS): $(OUT_DEC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt
$(OUT_NODE_DEC_JS): ENVIRONMENT=node
$(OUT_NODE_DEC_JS) $(OUT_DEC_JS): $(OUT_DEC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLists.txt
$(MAKE) \
$(HELPER_MAKEFLAGS) \
OUT_JS=$@ \
@@ -81,77 +70,22 @@ $(OUT_DEC_JS): $(OUT_DEC_CPP) $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_DIR)/CMakeLis
ENVIRONMENT=$(ENVIRONMENT) \
LIBAVIF_FLAGS="-DAVIF_CODEC_AOM_ENCODE=0"
# LIBAOM EXTRACTION SECTION
$(CODEC_PACKAGE):
mkdir -p $(@D)
curl -sL $(CODEC_URL) -o $@
# Download the libaom tarball
$(LIBAOM_PACKAGE):
mkdir -p $(@D)
curl -sL $(LIBAOM_URL) -o $@
# Extract libaom from the tarball
$(CODEC_DIR)/CMakeLists.txt: $(CODEC_PACKAGE)
mkdir -p $(@D)
tar xzm --strip 1 -C $(@D) -f $(CODEC_PACKAGE)
$(LIBAOM_DIR)/CMakeLists.txt: $(LIBAOM_PACKAGE)
mkdir -p $(@D)
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:
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_ENC_JS) clean
$(MAKE) $(HELPER_MAKEFLAGS) OUT_JS=$(OUT_ENC_MT_JS) clean

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

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

View File

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

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

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

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -10,11 +10,8 @@
# $(LIBAVIF_FLAGS)
# $(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))
# We're making libavif and libaom for every node_modules/[enc|dec]/
CODEC_BUILD_DIR := $(OUT_BUILD_DIR)/libavif
CODEC_OUT := $(CODEC_BUILD_DIR)/libavif.a
@@ -28,13 +25,6 @@ OUT_WORKER=$(OUT_JS:.js=.worker.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)
$(CXX) \
-I $(CODEC_DIR)/include \
@@ -42,7 +32,6 @@ $(OUT_JS): $(OUT_CPP) $(LIBAOM_OUT) $(CODEC_OUT)
$(LDFLAGS) \
$(OUT_FLAGS) \
--bind \
-s ERROR_ON_UNDEFINED_SYMBOLS=0 \
-s ENVIRONMENT=$(ENVIRONMENT) \
-s EXPORT_ES6=1 \
-o $@ \
@@ -50,7 +39,6 @@ $(OUT_JS): $(OUT_CPP) $(LIBAOM_OUT) $(CODEC_OUT)
$(CODEC_OUT): $(CODEC_DIR)/CMakeLists.txt $(LIBAOM_OUT)
emcmake cmake \
-DCMAKE_LIBRARY_PATH=$(LIBSHARPYUV_BUILD_DIR) \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=0 \
-DAVIF_CODEC_AOM=1 \

View File

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

409
codecs/oxipng/Cargo.lock generated
View File

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

View File

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

View File

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

View File

@@ -5,5 +5,5 @@ set -e
rm -rf pkg,{-parallel}
export CFLAGS="${CFLAGS} -DUNALIGNED_ACCESS_IS_FAST=1"
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,42 +0,0 @@
CODEC_URL = https://github.com/phoboslab/qoi/archive/8d35d93cdca85d2868246c2a8a80a1e2c16ba2a8.tar.gz
CODEC_DIR = node_modules/qoi
CODEC_BUILD_DIR:= $(CODEC_DIR)/build
ENVIRONMENT = worker
OUT_JS = enc/qoi_enc.js dec/qoi_dec.js
OUT_WASM := $(OUT_JS:.js=.wasm)
.PHONY: all clean
all: $(OUT_JS)
$(filter enc/%,$(OUT_JS)): enc/qoi_enc.o
$(filter dec/%,$(OUT_JS)): dec/qoi_dec.o
# ALL .js FILES
$(OUT_JS):
$(LD) \
$(LDFLAGS) \
--bind \
-s ENVIRONMENT=$(ENVIRONMENT) \
-s EXPORT_ES6=1 \
-o $@ \
$+
# ALL .o FILES
%.o: %.cpp $(CODEC_DIR)
$(CXX) -c \
$(CXXFLAGS) \
-I $(CODEC_DIR) \
-o $@ \
$<
# CREATE DIRECTORY
$(CODEC_DIR):
mkdir -p $(CODEC_DIR)
curl -sL $(CODEC_URL) | tar xz --strip 1 -C $(CODEC_DIR)
clean:
$(RM) $(OUT_JS) $(OUT_WASM)
$(MAKE) -C $(CODEC_DIR) clean

View File

@@ -1,30 +0,0 @@
#include <emscripten/bind.h>
#include <emscripten/val.h>
#define QOI_IMPLEMENTATION
#include "qoi.h"
using namespace emscripten;
thread_local const val Uint8ClampedArray = val::global("Uint8ClampedArray");
thread_local const val ImageData = val::global("ImageData");
val decode(std::string qoiimage) {
qoi_desc desc;
uint8_t* rgba = (uint8_t*)qoi_decode(qoiimage.c_str(), qoiimage.length(), &desc, 4);
// Resultant width and height stored in descriptor
int decodedWidth = desc.width;
int decodedHeight = desc.height;
val result = ImageData.new_(
Uint8ClampedArray.new_(typed_memory_view(4 * decodedWidth * decodedHeight, rgba)),
decodedWidth, decodedHeight);
free(rgba);
return result;
}
EMSCRIPTEN_BINDINGS(my_module) {
function("decode", &decode);
}

View File

@@ -1,7 +0,0 @@
export interface QOIModule extends EmscriptenWasm.Module {
decode(data: BufferSource): ImageData | null;
}
declare var moduleFactory: EmscriptenWasm.ModuleFactory<QOIModule>;
export default moduleFactory;

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -1,36 +0,0 @@
#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);
}

View File

@@ -1,14 +0,0 @@
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;

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -1,7 +0,0 @@
{
"name": "qoi",
"scripts": {
"build": "../build-cpp.sh"
}
}

View File

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

View File

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

View File

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

262
package-lock.json generated
View File

@@ -8,11 +8,13 @@
"name": "squoosh",
"version": "2.0.0",
"license": "apache-2.0",
"dependencies": {
"wasm-feature-detect": "^1.2.11"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^17.0.0",
"@rollup/plugin-node-resolve": "^11.1.0",
"@rollup/plugin-replace": "^2.3.4",
"@rollup/plugin-terser": "^0.4.4",
"@surma/rollup-plugin-off-main-thread": "^2.2.2",
"@types/dedent": "^0.7.0",
"@types/mime-types": "^2.1.1",
@@ -44,7 +46,6 @@
"rollup-plugin-terser": "^7.0.2",
"serve": "^11.3.2",
"typescript": "^4.4.4",
"wasm-feature-detect": "^1.2.11",
"which": "^2.0.2"
}
},
@@ -150,70 +151,6 @@
"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": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
@@ -310,39 +247,6 @@
"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": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
@@ -502,19 +406,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": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz",
@@ -871,11 +762,10 @@
}
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true,
"license": "MIT"
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true
},
"node_modules/builtin-modules": {
"version": "3.2.0",
@@ -7996,13 +7886,6 @@
"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": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -8013,11 +7896,10 @@
}
},
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"version": "0.5.19",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
"integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
"dev": true,
"license": "MIT",
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
@@ -8528,16 +8410,14 @@
}
},
"node_modules/terser": {
"version": "5.31.4",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.31.4.tgz",
"integrity": "sha512-3OU03GgblDgu0g+sdnsVzhBPxnjV+WJuMmocN1qBBZDQ3ia7jZQSAkePeKbPlYAejGXUTYe1CmSaUeV51mvaIw==",
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.3.1.tgz",
"integrity": "sha512-yD80f4hdwCWTH5mojzxe1q8bN1oJbsK/vfJGLcPZM/fl+/jItIVNKhFIHqqR71OipFWMLgj3Kc+GIp6CeIqfnA==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.8.2",
"commander": "^2.20.0",
"source-map-support": "~0.5.20"
"source-map": "~0.6.1",
"source-map-support": "~0.5.12"
},
"bin": {
"terser": "bin/terser"
@@ -8681,8 +8561,7 @@
"node_modules/wasm-feature-detect": {
"version": "1.2.11",
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.2.11.tgz",
"integrity": "sha512-HUqwaodrQGaZgz1lZaNioIkog9tkeEJjrM3eq4aUL04whXOVDRc/o2EGb/8kV0QX411iAYWEqq7fMBmJ6dKS6w==",
"dev": true
"integrity": "sha512-HUqwaodrQGaZgz1lZaNioIkog9tkeEJjrM3eq4aUL04whXOVDRc/o2EGb/8kV0QX411iAYWEqq7fMBmJ6dKS6w=="
},
"node_modules/which": {
"version": "2.0.2",
@@ -8878,55 +8757,6 @@
}
}
},
"@jridgewell/gen-mapping": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
"dev": true,
"requires": {
"@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.24"
}
},
"@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true
},
"@jridgewell/set-array": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"dev": true
},
"@jridgewell/source-map": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
"dev": true,
"requires": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25"
}
},
"@jridgewell/sourcemap-codec": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
"dev": true
},
"@jridgewell/trace-mapping": {
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"dev": true,
"requires": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"@nodelib/fs.scandir": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
@@ -9012,28 +8842,6 @@
"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": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
@@ -9179,12 +8987,6 @@
"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": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz",
@@ -9473,9 +9275,9 @@
}
},
"buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true
},
"builtin-modules": {
@@ -15394,12 +15196,6 @@
"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": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -15407,9 +15203,9 @@
"dev": true
},
"source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"version": "0.5.19",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
"integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
@@ -15830,15 +15626,14 @@
}
},
"terser": {
"version": "5.31.4",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.31.4.tgz",
"integrity": "sha512-3OU03GgblDgu0g+sdnsVzhBPxnjV+WJuMmocN1qBBZDQ3ia7jZQSAkePeKbPlYAejGXUTYe1CmSaUeV51mvaIw==",
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.3.1.tgz",
"integrity": "sha512-yD80f4hdwCWTH5mojzxe1q8bN1oJbsK/vfJGLcPZM/fl+/jItIVNKhFIHqqR71OipFWMLgj3Kc+GIp6CeIqfnA==",
"dev": true,
"requires": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.8.2",
"commander": "^2.20.0",
"source-map-support": "~0.5.20"
"source-map": "~0.6.1",
"source-map-support": "~0.5.12"
},
"dependencies": {
"commander": {
@@ -15962,8 +15757,7 @@
"wasm-feature-detect": {
"version": "1.2.11",
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.2.11.tgz",
"integrity": "sha512-HUqwaodrQGaZgz1lZaNioIkog9tkeEJjrM3eq4aUL04whXOVDRc/o2EGb/8kV0QX411iAYWEqq7fMBmJ6dKS6w==",
"dev": true
"integrity": "sha512-HUqwaodrQGaZgz1lZaNioIkog9tkeEJjrM3eq4aUL04whXOVDRc/o2EGb/8kV0QX411iAYWEqq7fMBmJ6dKS6w=="
},
"which": {
"version": "2.0.2",

View File

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

View File

@@ -15,7 +15,7 @@ import { promises as fsp } from 'fs';
import del from 'del';
import resolve from '@rollup/plugin-node-resolve';
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 replace from '@rollup/plugin-replace';
import { importMetaAssets } from '@web/rollup-plugin-import-meta-assets';

View File

@@ -2,26 +2,6 @@
display: inline-block;
position: relative;
--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 {

View File

@@ -47,10 +47,6 @@ range-input::before {
height: 12px;
}
range-input:focus-within .thumb {
outline: white solid 2px;
}
.thumb-wrapper {
position: absolute;
left: 6px;

View File

@@ -11,10 +11,6 @@
padding: 3px calc(var(--thumb-size) / 2 + 3px);
}
.checkbox:focus-within .track {
outline: white solid 2px;
}
.thumb {
position: relative;
width: var(--thumb-size);

View File

@@ -17,7 +17,7 @@ import Toggle from './Toggle';
import Select from './Select';
import { Options as QuantOptionsComponent } from 'features/processors/quantize/client';
import { Options as ResizeOptionsComponent } from 'features/processors/resize/client';
import { ImportIcon, SaveIcon, SwapIcon } from 'client/lazy-app/icons';
import { SwapIcon } from 'client/lazy-app/icons';
interface Props {
index: 0 | 1;
@@ -29,14 +29,10 @@ interface Props {
onEncoderOptionsChange(index: 0 | 1, newOptions: EncoderOptions): void;
onProcessorOptionsChange(index: 0 | 1, newOptions: ProcessorState): void;
onCopyToOtherSideClick(index: 0 | 1): void;
onSaveSideSettingsClick(index: 0 | 1): void;
onImportSideSettingsClick(index: 0 | 1): void;
}
interface State {
supportedEncoderMap?: PartialButNotUndefined<typeof encoderMap>;
leftSideSettings?: string | null;
rightSideSettings?: string | null;
}
type PartialButNotUndefined<T> = {
@@ -64,8 +60,6 @@ const supportedEncoderMapP: Promise<PartialButNotUndefined<typeof encoderMap>> =
export default class Options extends Component<Props, State> {
state: State = {
supportedEncoderMap: undefined,
leftSideSettings: localStorage.getItem('leftSideSettings'),
rightSideSettings: localStorage.getItem('rightSideSettings'),
};
constructor() {
@@ -75,29 +69,6 @@ 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) => {
const el = event.currentTarget as HTMLSelectElement;
@@ -139,14 +110,6 @@ export default class Options extends Component<Props, State> {
this.props.onCopyToOtherSideClick(this.props.index);
};
private onSaveSideSettingClick = () => {
this.props.onSaveSideSettingsClick(this.props.index);
};
private onImportSideSettingsClick = () => {
this.props.onImportSideSettingsClick(this.props.index);
};
render(
{ source, encoderState, processorState }: Props,
{ supportedEncoderMap }: State,
@@ -176,36 +139,6 @@ export default class Options extends Component<Props, State> {
>
<SwapIcon />
</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>
</h3>
<label class={style.sectionEnabler}>
@@ -257,9 +190,7 @@ export default class Options extends Component<Props, State> {
onChange={this.onEncoderTypeChange}
large
>
<option value="identity">{`Original Image ${
this.props.source ? `(${this.props.source.file.name})` : ''
}`}</option>
<option value="identity">Original Image</option>
{Object.entries(supportedEncoderMap).map(([type, encoder]) => (
<option value={type}>{encoder.meta.label}</option>
))}

View File

@@ -53,16 +53,6 @@
composes: option-toggle;
grid-template-columns: auto 1fr;
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 {
@@ -83,11 +73,11 @@
}
.text-field {
background-color: var(--black);
color: var(--white);
background: var(--white);
color: var(--black);
font: inherit;
border: none;
padding: 6px 6px 6px 10px;
padding: 6px 0 6px 10px;
width: 100%;
box-sizing: border-box;
border-radius: 4px;
@@ -122,37 +112,7 @@
.copy-over-button {
composes: title-button;
/* Make the filled arrow point towards the other options element */
transform: rotate(var(--rotate-copyoverbutton-angle));
svg {
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;
}
}

View File

@@ -111,9 +111,6 @@ async function decodeImage(
if (mimeType === 'image/webp2') {
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.
return await builtinDecode(signal, blob);
@@ -284,35 +281,24 @@ export default class Compress extends Component<Props, State> {
source: undefined,
loading: false,
preprocessorState: defaultPreprocessorState,
// Tasking catched side settings if available otherwise taking default settings
sides: [
localStorage.getItem('leftSideSettings')
? {
...JSON.parse(localStorage.getItem('leftSideSettings') as string),
loading: false,
}
: {
latestSettings: {
processorState: defaultProcessorState,
encoderState: undefined,
},
loading: false,
},
localStorage.getItem('rightSideSettings')
? {
...JSON.parse(localStorage.getItem('rightSideSettings') as string),
loading: false,
}
: {
latestSettings: {
processorState: defaultProcessorState,
encoderState: {
type: 'mozJPEG',
options: encoderMap.mozJPEG.meta.defaultOptions,
},
},
loading: false,
{
latestSettings: {
processorState: defaultProcessorState,
encoderState: undefined,
},
loading: false,
},
{
latestSettings: {
processorState: defaultProcessorState,
encoderState: {
type: 'mozJPEG',
options: encoderMap.mozJPEG.meta.defaultOptions,
},
},
loading: false,
},
],
mobileView: this.widthQuery.matches,
};
@@ -442,99 +428,6 @@ export default class Compress extends Component<Props, State> {
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 (
preprocessorState: PreprocessorState,
@@ -936,8 +829,6 @@ export default class Compress extends Component<Props, State> {
onEncoderOptionsChange={this.onEncoderOptionsChange}
onProcessorOptionsChange={this.onProcessorOptionsChange}
onCopyToOtherSideClick={this.onCopyToOtherClick}
onSaveSideSettingsClick={this.onSaveSideSettingsClick}
onImportSideSettingsClick={this.onImportSideSettingsClick}
/>
));
@@ -951,7 +842,7 @@ export default class Compress extends Component<Props, State> {
typeLabel={
side.latestSettings.encoderState
? encoderMap[side.latestSettings.encoderState.type].meta.label
: `${side.file ? `${side.file.name}` : 'Original Image'}`
: 'Original Image'
}
/>
));

View File

@@ -45,11 +45,9 @@
--hot-theme-color: var(--hot-pink);
--header-text-color: var(--white);
--scroller-radius: var(--options-radius) var(--options-radius) 0 0;
--rotate-copyoverbutton-angle: 90deg; /* To point down */
@media (min-width: 600px) {
--scroller-radius: 0 var(--options-radius) var(--options-radius) 0;
--rotate-copyoverbutton-angle: 0deg; /* To point right (no change) */
}
}
@@ -58,11 +56,9 @@
--hot-theme-color: var(--deep-blue);
--header-text-color: var(--dark-text);
--scroller-radius: var(--options-radius) var(--options-radius) 0 0;
--rotate-copyoverbutton-angle: -90deg; /* To point up */
@media (min-width: 600px) {
--scroller-radius: var(--options-radius) 0 0 var(--options-radius);
--rotate-copyoverbutton-angle: 180deg; /* To point left */
}
}
@@ -113,13 +109,6 @@
& > svg {
width: 47px;
overflow: visible;
}
&:focus .back-blob {
stroke: var(--deep-blue);
stroke-width: 5px;
animation: strokePulse 500ms ease forwards;
}
@media (min-width: 600px) {
@@ -131,15 +120,6 @@
}
}
@keyframes strokePulse {
from {
stroke-width: 8px;
}
to {
stroke-width: 5px;
}
}
.back-blob {
fill: var(--hot-pink);
opacity: 0.77;

View File

@@ -97,31 +97,3 @@ export const SwapIcon = () => (
<path d="M5.5 3.6v6.8L2.1 7l3.4-3.4M7 0L0 7l7 7V0zm4 0v14l7-7-7-7z" />
</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>
);

View File

@@ -103,7 +103,6 @@ const magicNumberMapInput = [
[/^\x00\x00\x00 ftypavif\x00\x00\x00\x00/, 'image/avif'],
[/^\xff\x0a/, 'image/jxl'],
[/^\x00\x00\x00\x0cJXL \x0d\x0a\x87\x0a/, 'image/jxl'],
[/^qoif/, 'image/qoi'],
] as const;
export type ImageMimeTypes = typeof magicNumberMapInput[number][1];

View File

@@ -1,19 +0,0 @@
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;
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,11 +0,0 @@
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);
}

View File

@@ -1,13 +0,0 @@
/**
* 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" />

View File

@@ -1,19 +0,0 @@
/**
* 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 = {};

View File

@@ -1,13 +0,0 @@
/**
* 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" />

View File

@@ -1,13 +0,0 @@
/**
* 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" />

View File

@@ -1,35 +0,0 @@
/**
* 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 cant run on SharedArrayBuffers, so we hard-cast to ArrayBuffer.
return resultView.buffer as ArrayBuffer;
}

View File

@@ -62,7 +62,7 @@ snack-bar {
position: relative;
flex: 0 1 auto;
padding: 8px;
height: 100%;
height: 36px;
margin: auto 8px auto -8px;
min-width: 5em;
background: none;
@@ -78,7 +78,6 @@ snack-bar {
overflow: hidden;
transition: background-color 200ms ease;
outline: none;
text-decoration: none;
}
.button:hover {
background-color: rgba(0, 0, 0, 0.15);

View File

@@ -24,28 +24,28 @@ import SlideOnScroll from './SlideOnScroll';
const demos = [
{
description: 'Large photo',
size: '2.8MB',
size: '2.8mb',
filename: 'photo.jpg',
url: largePhoto,
iconUrl: largePhotoIcon,
},
{
description: 'Artwork',
size: '2.9MB',
size: '2.9mb',
filename: 'art.jpg',
url: artwork,
iconUrl: artworkIcon,
},
{
description: 'Device screen',
size: '1.6MB',
size: '1.6mb',
filename: 'pixel3.png',
url: deviceScreen,
iconUrl: deviceScreenIcon,
},
{
description: 'SVG icon',
size: '13KB',
size: '13k',
filename: 'squoosh.svg',
url: logo,
iconUrl: logoIcon,
@@ -319,7 +319,7 @@ export default class Intro extends Component<Props, State> {
class="unbutton"
onClick={(event) => this.onDemoClick(i, event)}
>
<div class={style.demoContainer}>
<div>
<div class={style.demoIconContainer}>
<img
class={style.demoIcon}

View File

@@ -321,13 +321,6 @@
}
}
.demo-container {
transition: scale 400ms ease-in-out;
&:hover {
scale: 1.05;
}
}
.demo-size {
background: var(--dim-blue);
border-radius: 1000px;

View File

@@ -18,14 +18,3 @@ html {
/* Old stuff: */
--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);
}
}
}

View File

@@ -19,8 +19,6 @@ import favicon from 'url:static-build/assets/favicon.ico';
import ogImage from 'url:static-build/assets/icon-large-maskable.png';
import { escapeStyleScriptContent, siteOrigin } from 'static-build/utils';
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 {}
@@ -75,29 +73,6 @@ const Index: FunctionalComponent<Props> = () => (
<body>
<div id="app">
<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>
<script
dangerouslySetInnerHTML={{