Skip to content

Commit 18b53e2

Browse files
JPEG XL: Add lossy Modular option (GoogleChromeLabs#1136)
* Improve .gitattributes * Add disabled checkbox style * Update Makefile * Update jxl_enc.cpp * add -O3 flag to skia compilation for optimization's sake * Bump libjxl revision to 9f544641ec83f6abd9da598bdd08178ee8a003e0 Change use of EncodeFile from `EncodeFile(cparams, &io, &passes_enc_state, &bytes, /*aux=*/nullptr, pool_ptr)` to `EncodeFile(cparams, &io, &passes_enc_state, &bytes, /*cms=*/nullptr, /*aux=*/jxl::GetJxlCms(), pool_ptr)` * JPEG XL: Add lossy Modular option Co-authored-by: CanadianBaconBoi <[email protected]> Co-authored-by: CanadianBaconBoi <[email protected]>
1 parent 66ec763 commit 18b53e2

21 files changed

+50
-16
lines changed

.gitattributes

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
/codecs/**/*.js linguist-generated=true
2-
/codecs/*/pkg*/*.d.ts linguist-generated=true
1+
/codecs/**/*.js linguist-generated -diff
2+
/codecs/*/pkg*/*.d.ts linguist-generated

codecs/jxl/Makefile

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
CODEC_URL = https://github.com/libjxl/libjxl.git
2-
CODEC_VERSION = v0.5
2+
CODEC_VERSION = 9f544641ec83f6abd9da598bdd08178ee8a003e0
33
CODEC_DIR = node_modules/jxl
44
CODEC_BUILD_ROOT := $(CODEC_DIR)/build
55
CODEC_MT_BUILD_DIR := $(CODEC_BUILD_ROOT)/mt
@@ -75,6 +75,9 @@ $(CODEC_MT_SIMD_BUILD_DIR)/Makefile: CXXFLAGS+=-msimd128
7575
-DCMAKE_CROSSCOMPILING_EMULATOR=node \
7676
-B $(@D) \
7777
$(<D)
78+
emcc -Wall -O3 -o $(CODEC_DIR)/third_party/skcms/skcms.cc.o -I$(CODEC_DIR)/third_party/skcms -c $(CODEC_DIR)/third_party/skcms/skcms.cc
79+
llvm-ar rc $(CODEC_BUILD_DIR)/third_party/libskcms.a $(CODEC_DIR)/third_party/skcms/skcms.cc.o
80+
rm $(CODEC_DIR)/third_party/skcms/skcms.cc.o
7881

7982
$(CODEC_DIR)/CMakeLists.txt:
8083
$(RM) -r $(@D)

codecs/jxl/dec/jxl_dec.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

codecs/jxl/dec/jxl_dec.wasm

56.9 KB
Binary file not shown.

codecs/jxl/dec/jxl_node_dec.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

codecs/jxl/dec/jxl_node_dec.wasm

56.9 KB
Binary file not shown.

codecs/jxl/enc/jxl_enc.cpp

+13-5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "lib/jxl/base/thread_pool_internal.h"
55
#include "lib/jxl/enc_external_image.h"
66
#include "lib/jxl/enc_file.h"
7+
#include "lib/jxl/enc_color_management.h"
78

89
using namespace emscripten;
910

@@ -17,6 +18,7 @@ struct JXLOptions {
1718
bool lossyPalette;
1819
size_t decodingSpeedTier;
1920
float photonNoiseIso;
21+
bool lossyModular;
2022
};
2123

2224
val encode(std::string image, int width, int height, JXLOptions options) {
@@ -50,11 +52,16 @@ val encode(std::string image, int width, int height, JXLOptions options) {
5052
float quality = options.quality;
5153

5254
// Quality settings roughly match libjpeg qualities.
53-
if (quality < 7 || quality == 100) {
55+
if (options.lossyModular || quality == 100) {
5456
cparams.modular_mode = true;
5557
// Internal modular quality to roughly match VarDCT size.
56-
cparams.quality_pair.first = cparams.quality_pair.second =
57-
std::min(35 + (quality - 7) * 3.0f, 100.0f);
58+
if (quality < 7) {
59+
cparams.quality_pair.first = cparams.quality_pair.second =
60+
std::min(35 + (quality - 7) * 3.0f, 100.0f);
61+
} else {
62+
cparams.quality_pair.first = cparams.quality_pair.second =
63+
std::min(35 + (quality - 7) * 65.f / 93.f, 100.0f);
64+
}
5865
} else {
5966
cparams.modular_mode = false;
6067
if (quality >= 30) {
@@ -91,14 +98,14 @@ val encode(std::string image, int width, int height, JXLOptions options) {
9198
jxl::Span<const uint8_t>(reinterpret_cast<const uint8_t*>(image.data()), image.size()), width,
9299
height, jxl::ColorEncoding::SRGB(/*is_gray=*/false), /*has_alpha=*/true,
93100
/*alpha_is_premultiplied=*/false, /*bits_per_sample=*/8, /*endiannes=*/JXL_LITTLE_ENDIAN,
94-
/*flipped_y=*/false, pool_ptr, main);
101+
/*flipped_y=*/false, pool_ptr, main, /*(only true if bits_per_sample==32) float_in=*/false);
95102

96103
if (!result) {
97104
return val::null();
98105
}
99106

100107
auto js_result = val::null();
101-
if (EncodeFile(cparams, &io, &passes_enc_state, &bytes, /*aux=*/nullptr, pool_ptr)) {
108+
if (EncodeFile(cparams, &io, &passes_enc_state, &bytes, jxl::GetJxlCms(), /*aux=*/nullptr, pool_ptr)) {
102109
js_result = Uint8Array.new_(typed_memory_view(bytes.size(), bytes.data()));
103110
}
104111

@@ -113,6 +120,7 @@ EMSCRIPTEN_BINDINGS(my_module) {
113120
.field("lossyPalette", &JXLOptions::lossyPalette)
114121
.field("decodingSpeedTier", &JXLOptions::decodingSpeedTier)
115122
.field("photonNoiseIso", &JXLOptions::photonNoiseIso)
123+
.field("lossyModular", &JXLOptions::lossyModular)
116124
.field("epf", &JXLOptions::epf);
117125

118126
function("encode", &encode);

codecs/jxl/enc/jxl_enc.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export interface EncodeOptions {
66
lossyPalette: boolean;
77
decodingSpeedTier: number;
88
photonNoiseIso: number;
9+
lossyModular: boolean;
910
}
1011

1112
export interface JXLModule extends EmscriptenWasm.Module {

codecs/jxl/enc/jxl_enc.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

codecs/jxl/enc/jxl_enc.wasm

73.2 KB
Binary file not shown.

codecs/jxl/enc/jxl_enc_mt.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

codecs/jxl/enc/jxl_enc_mt.wasm

73.3 KB
Binary file not shown.

codecs/jxl/enc/jxl_enc_mt_simd.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

codecs/jxl/enc/jxl_enc_mt_simd.wasm

233 KB
Binary file not shown.

codecs/jxl/enc/jxl_node_enc.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

codecs/jxl/enc/jxl_node_enc.wasm

73.2 KB
Binary file not shown.

libsquoosh/src/codecs.ts

+1
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@ export const codecs = {
419419
lossyPalette: false,
420420
decodingSpeedTier: 0,
421421
photonNoiseIso: 0,
422+
lossyModular: false,
422423
},
423424
autoOptimize: {
424425
option: 'quality',

src/client/lazy-app/Compress/Options/Checkbox/index.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ export default class Checkbox extends Component<Props, State> {
1111
return (
1212
<div class={style.checkbox}>
1313
{props.checked ? (
14-
<CheckedIcon class={`${style.icon} ${style.checked}`} />
14+
props.disabled ? (
15+
<CheckedIcon class={`${style.icon} ${style.disabled}`} />
16+
) : (
17+
<CheckedIcon class={`${style.icon} ${style.checked}`} />
18+
)
1519
) : (
1620
<UncheckedIcon class={style.icon} />
1721
)}

src/client/lazy-app/Compress/Options/Checkbox/style.css

+4
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,7 @@
2020
.checked {
2121
fill: var(--main-theme-color);
2222
}
23+
24+
.disabled {
25+
fill: var(--dark-gray);
26+
}

src/features/encoders/jxl/client/index.tsx

+13-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ interface State {
3030
autoEdgePreservingFilter: boolean;
3131
decodingSpeedTier: number;
3232
photonNoiseIso: number;
33+
alternativeLossy: boolean;
3334
}
3435

3536
export class Options extends Component<Props, State> {
@@ -55,6 +56,7 @@ export class Options extends Component<Props, State> {
5556
autoEdgePreservingFilter: options.epf === -1,
5657
decodingSpeedTier: options.decodingSpeedTier,
5758
photonNoiseIso: options.photonNoiseIso,
59+
alternativeLossy: options.lossyModular,
5860
};
5961
}
6062

@@ -96,6 +98,7 @@ export class Options extends Component<Props, State> {
9698
lossyPalette: optionState.lossless ? optionState.slightLoss : false,
9799
decodingSpeedTier: optionState.decodingSpeedTier,
98100
photonNoiseIso: optionState.photonNoiseIso,
101+
lossyModular: optionState.quality < 7 ? true : optionState.alternativeLossy,
99102
};
100103

101104
// Updating options, so we don't recalculate in getDerivedStateFromProps.
@@ -122,6 +125,7 @@ export class Options extends Component<Props, State> {
122125
autoEdgePreservingFilter,
123126
decodingSpeedTier,
124127
photonNoiseIso,
128+
alternativeLossy,
125129
}: State,
126130
) {
127131
// I'm rendering both lossy and lossless forms, as it becomes much easier when
@@ -162,6 +166,14 @@ export class Options extends Component<Props, State> {
162166
Quality:
163167
</Range>
164168
</div>
169+
<label class={style.optionToggle}>
170+
Alternative lossy mode
171+
<Checkbox
172+
checked={quality < 7 ? true : alternativeLossy}
173+
disabled={quality < 7}
174+
onChange={this._inputChange('alternativeLossy', 'boolean')}
175+
/>
176+
</label>
165177
<label class={style.optionToggle}>
166178
Auto edge filter
167179
<Checkbox
@@ -223,7 +235,7 @@ export class Options extends Component<Props, State> {
223235
</label>
224236
<div class={style.optionOneCell}>
225237
<Range
226-
min="3"
238+
min="1"
227239
max="9"
228240
value={effort}
229241
onInput={this._inputChange('effort', 'number')}

src/features/encoders/jxl/shared/meta.ts

+1
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,5 @@ export const defaultOptions: EncodeOptions = {
2525
lossyPalette: false,
2626
decodingSpeedTier: 0,
2727
photonNoiseIso: 0,
28+
lossyModular: false,
2829
};

0 commit comments

Comments
 (0)