Coverage Report

Created: 2026-05-16 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibGfx/ImageFormats/JPEGXLLoader.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2023, Lucas Chollet <lucas.chollet@serenityos.org>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#include <AK/BitStream.h>
8
#include <AK/ConstrainedStream.h>
9
#include <AK/Debug.h>
10
#include <AK/Endian.h>
11
#include <AK/Enumerate.h>
12
#include <AK/FixedArray.h>
13
#include <AK/String.h>
14
#include <LibCompress/Brotli.h>
15
#include <LibGfx/ImageFormats/ExifOrientedBitmap.h>
16
#include <LibGfx/ImageFormats/ISOBMFF/JPEGXLBoxes.h>
17
#include <LibGfx/ImageFormats/ISOBMFF/Reader.h>
18
#include <LibGfx/ImageFormats/JPEGXL/Channel.h>
19
#include <LibGfx/ImageFormats/JPEGXL/Common.h>
20
#include <LibGfx/ImageFormats/JPEGXL/DCTNaturalOrder.h>
21
#include <LibGfx/ImageFormats/JPEGXL/EntropyDecoder.h>
22
#include <LibGfx/ImageFormats/JPEGXL/ModularTransforms.h>
23
#include <LibGfx/ImageFormats/JPEGXL/SelfCorrectingPredictor.h>
24
#include <LibGfx/ImageFormats/JPEGXLLoader.h>
25
#include <LibGfx/Matrix3x3.h>
26
27
namespace Gfx::JPEGXL {
28
29
// This is not specified
30
static ErrorOr<void> read_non_aligned(LittleEndianInputBitStream& stream, Bytes bytes)
31
0
{
32
0
    for (u8& byte : bytes)
33
0
        byte = TRY(stream.read_bits(8));
34
0
    return {};
35
0
}
36
37
static ErrorOr<String> read_string(LittleEndianInputBitStream& stream)
38
0
{
39
0
    auto const name_length = U32(0, TRY(stream.read_bits(4)), 16 + TRY(stream.read_bits(5)), 48 + TRY(stream.read_bits(10)));
40
0
    auto string_buffer = TRY(FixedArray<u8>::create(name_length));
41
0
    TRY(read_non_aligned(stream, string_buffer));
42
0
    return String::from_utf8(StringView { string_buffer });
43
0
}
44
45
/// D.2 - Image dimensions
46
struct SizeHeader {
47
    u32 height {};
48
    u32 width {};
49
};
50
51
static u32 aspect_ratio(u32 height, u32 ratio)
52
0
{
53
0
    if (ratio == 1)
54
0
        return height;
55
0
    if (ratio == 2)
56
0
        return height * 12 / 10;
57
0
    if (ratio == 3)
58
0
        return height * 4 / 3;
59
0
    if (ratio == 4)
60
0
        return height * 3 / 2;
61
0
    if (ratio == 5)
62
0
        return height * 16 / 9;
63
0
    if (ratio == 6)
64
0
        return height * 5 / 4;
65
0
    if (ratio == 7)
66
0
        return height * 2 / 1;
67
0
    VERIFY_NOT_REACHED();
68
0
}
69
70
static ErrorOr<SizeHeader> read_size_header(LittleEndianInputBitStream& stream)
71
0
{
72
0
    SizeHeader size {};
73
0
    auto const div8 = TRY(stream.read_bit());
74
75
0
    if (div8) {
76
0
        auto const h_div8 = 1 + TRY(stream.read_bits(5));
77
0
        size.height = 8 * h_div8;
78
0
    } else {
79
0
        size.height = U32(
80
0
            1 + TRY(stream.read_bits(9)),
81
0
            1 + TRY(stream.read_bits(13)),
82
0
            1 + TRY(stream.read_bits(18)),
83
0
            1 + TRY(stream.read_bits(30)));
84
0
    }
85
86
0
    auto const ratio = TRY(stream.read_bits(3));
87
88
0
    if (ratio == 0) {
89
0
        if (div8) {
90
0
            auto const w_div8 = 1 + TRY(stream.read_bits(5));
91
0
            size.width = 8 * w_div8;
92
0
        } else {
93
0
            size.width = U32(
94
0
                1 + TRY(stream.read_bits(9)),
95
0
                1 + TRY(stream.read_bits(13)),
96
0
                1 + TRY(stream.read_bits(18)),
97
0
                1 + TRY(stream.read_bits(30)));
98
0
        }
99
0
    } else {
100
0
        size.width = aspect_ratio(size.height, ratio);
101
0
    }
102
103
0
    return size;
104
0
}
105
///
106
107
/// D.3.5 - BitDepth
108
struct BitDepth {
109
    u32 bits_per_sample { 8 };
110
    u8 exp_bits {};
111
};
112
113
static ErrorOr<BitDepth> read_bit_depth(LittleEndianInputBitStream& stream)
114
0
{
115
0
    BitDepth bit_depth;
116
0
    bool const float_sample = TRY(stream.read_bit());
117
118
0
    if (float_sample) {
119
0
        bit_depth.bits_per_sample = U32(32, 16, 24, 1 + TRY(stream.read_bits(6)));
120
0
        bit_depth.exp_bits = 1 + TRY(stream.read_bits(4));
121
0
    } else {
122
0
        bit_depth.bits_per_sample = U32(8, 10, 12, 1 + TRY(stream.read_bits(6)));
123
0
    }
124
125
0
    return bit_depth;
126
0
}
127
///
128
129
/// E.2 - ColourEncoding
130
struct ColourEncoding {
131
    enum class ColourSpace {
132
        kRGB = 0,
133
        kGrey = 1,
134
        kXYB = 2,
135
        kUnknown = 3,
136
    };
137
138
    enum class WhitePoint {
139
        kD65 = 1,
140
        kCustom = 2,
141
        kE = 10,
142
        kDCI = 11,
143
    };
144
145
    enum class Primaries {
146
        kSRGB = 1,
147
        kCustom = 2,
148
        k2100 = 3,
149
        kP3 = 11,
150
    };
151
152
    enum class RenderingIntent {
153
        kPerceptual = 0,
154
        kRelative = 1,
155
        kSaturation = 2,
156
        kAbsolute = 3,
157
    };
158
159
    struct Customxy {
160
        u32 ux {};
161
        u32 uy {};
162
    };
163
164
    enum class TransferFunction {
165
        k709 = 1,
166
        kUnknown = 2,
167
        kLinear = 8,
168
        kSRGB = 13,
169
        kPQ = 16,
170
        kDCI = 17,
171
        kHLG = 18,
172
    };
173
174
    struct CustomTransferFunction {
175
        bool have_gamma { false };
176
        u32 gamma {};
177
        TransferFunction transfer_function { TransferFunction::kSRGB };
178
    };
179
180
    bool want_icc = false;
181
    ColourSpace colour_space { ColourSpace::kRGB };
182
    WhitePoint white_point { WhitePoint::kD65 };
183
    Primaries primaries { Primaries::kSRGB };
184
185
    Customxy white {};
186
    Customxy red {};
187
    Customxy green {};
188
    Customxy blue {};
189
190
    CustomTransferFunction tf {};
191
192
    RenderingIntent rendering_intent { RenderingIntent::kRelative };
193
};
194
195
[[maybe_unused]] static ErrorOr<ColourEncoding::Customxy> read_custom_xy(LittleEndianInputBitStream& stream)
196
0
{
197
0
    ColourEncoding::Customxy custom_xy;
198
199
0
    auto const read_custom = [&stream]() -> ErrorOr<u32> {
200
0
        return U32(
201
0
            TRY(stream.read_bits(19)),
202
0
            524288 + TRY(stream.read_bits(19)),
203
0
            1048576 + TRY(stream.read_bits(20)),
204
0
            2097152 + TRY(stream.read_bits(21)));
205
0
    };
206
207
0
    custom_xy.ux = TRY(read_custom());
208
0
    custom_xy.uy = TRY(read_custom());
209
210
0
    return custom_xy;
211
0
}
212
213
static ErrorOr<ColourEncoding::CustomTransferFunction> read_custom_transfer_function(LittleEndianInputBitStream& stream)
214
0
{
215
0
    ColourEncoding::CustomTransferFunction custom_transfer_function;
216
217
0
    custom_transfer_function.have_gamma = TRY(stream.read_bit());
218
219
0
    if (custom_transfer_function.have_gamma)
220
0
        custom_transfer_function.gamma = TRY(stream.read_bits(24));
221
0
    else
222
0
        custom_transfer_function.transfer_function = TRY(read_enum<ColourEncoding::TransferFunction>(stream));
223
224
0
    return custom_transfer_function;
225
0
}
226
227
static ErrorOr<ColourEncoding> read_colour_encoding(LittleEndianInputBitStream& stream)
228
0
{
229
0
    ColourEncoding colour_encoding;
230
0
    bool const all_default = TRY(stream.read_bit());
231
232
0
    if (!all_default) {
233
0
        colour_encoding.want_icc = TRY(stream.read_bit());
234
0
        colour_encoding.colour_space = TRY(read_enum<ColourEncoding::ColourSpace>(stream));
235
236
0
        auto const use_desc = !all_default && !colour_encoding.want_icc;
237
0
        auto const not_xyb = colour_encoding.colour_space != ColourEncoding::ColourSpace::kXYB;
238
239
0
        if (use_desc && not_xyb)
240
0
            colour_encoding.white_point = TRY(read_enum<ColourEncoding::WhitePoint>(stream));
241
242
0
        if (colour_encoding.white_point == ColourEncoding::WhitePoint::kCustom)
243
0
            colour_encoding.white = TRY(read_custom_xy(stream));
244
245
0
        auto const has_primaries = use_desc && not_xyb && colour_encoding.colour_space != ColourEncoding::ColourSpace::kGrey;
246
247
0
        if (has_primaries)
248
0
            colour_encoding.primaries = TRY(read_enum<ColourEncoding::Primaries>(stream));
249
250
0
        if (colour_encoding.primaries == ColourEncoding::Primaries::kCustom) {
251
0
            colour_encoding.red = TRY(read_custom_xy(stream));
252
0
            colour_encoding.green = TRY(read_custom_xy(stream));
253
0
            colour_encoding.blue = TRY(read_custom_xy(stream));
254
0
        }
255
256
0
        if (use_desc) {
257
0
            colour_encoding.tf = TRY(read_custom_transfer_function(stream));
258
0
            colour_encoding.rendering_intent = TRY(read_enum<ColourEncoding::RenderingIntent>(stream));
259
0
        }
260
0
    }
261
262
0
    return colour_encoding;
263
0
}
264
///
265
266
/// B.3 - Extensions
267
struct Extensions {
268
    u64 extensions {};
269
};
270
271
static ErrorOr<Extensions> read_extensions(LittleEndianInputBitStream& stream)
272
0
{
273
0
    Extensions extensions;
274
0
    extensions.extensions = TRY(U64(stream));
275
276
0
    if (extensions.extensions != 0)
277
0
        TODO();
278
279
0
    return extensions;
280
0
}
281
///
282
283
/// K.2 - Non-separable upsampling
284
Array s_d_up2 {
285
    -0.01716200, -0.03452303, -0.04022174, -0.02921014, -0.00624645,
286
    0.14111091, 0.28896755, 0.00278718, -0.01610267, 0.56661550,
287
    0.03777607, -0.01986694, -0.03144731, -0.01185068, -0.00213539
288
};
289
290
Array s_d_up4 = {
291
    -0.02419067, -0.03491987, -0.03693351, -0.03094285, -0.00529785,
292
    -0.01663432, -0.03556863, -0.03888905, -0.03516850, -0.00989469,
293
    0.23651958, 0.33392945, -0.01073543, -0.01313181, -0.03556694,
294
    0.13048175, 0.40103025, 0.03951150, -0.02077584, 0.46914198,
295
    -0.00209270, -0.01484589, -0.04064806, 0.18942530, 0.56279892,
296
    0.06674400, -0.02335494, -0.03551682, -0.00754830, -0.02267919,
297
    -0.02363578, 0.00315804, -0.03399098, -0.01359519, -0.00091653,
298
    -0.00335467, -0.01163294, -0.01610294, -0.00974088, -0.00191622,
299
    -0.01095446, -0.03198464, -0.04455121, -0.02799790, -0.00645912,
300
    0.06390599, 0.22963888, 0.00630981, -0.01897349, 0.67537268,
301
    0.08483369, -0.02534994, -0.02205197, -0.01667999, -0.00384443
302
};
303
304
Array s_d_up8 {
305
    -0.02928613, -0.03706353, -0.03783812, -0.03324558, -0.00447632, -0.02519406, -0.03752601, -0.03901508, -0.03663285, -0.00646649,
306
    -0.02066407, -0.03838633, -0.04002101, -0.03900035, -0.00901973, -0.01626393, -0.03954148, -0.04046620, -0.03979621, -0.01224485,
307
    0.29895328, 0.35757708, -0.02447552, -0.01081748, -0.04314594, 0.23903219, 0.41119301, -0.00573046, -0.01450239, -0.04246845,
308
    0.17567618, 0.45220643, 0.02287757, -0.01936783, -0.03583255, 0.11572472, 0.47416733, 0.06284440, -0.02685066, 0.42720050,
309
    -0.02248939, -0.01155273, -0.04562755, 0.28689496, 0.49093869, -0.00007891, -0.01545926, -0.04562659, 0.21238920, 0.53980934,
310
    0.03369474, -0.02070211, -0.03866988, 0.14229550, 0.56593398, 0.08045181, -0.02888298, -0.03680918, -0.00542229, -0.02920477,
311
    -0.02788574, -0.02118180, -0.03942402, -0.00775547, -0.02433614, -0.03193943, -0.02030828, -0.04044014, -0.01074016, -0.01930822,
312
    -0.03620399, -0.01974125, -0.03919545, -0.01456093, -0.00045072, -0.00360110, -0.01020207, -0.01231907, -0.00638988, -0.00071592,
313
    -0.00279122, -0.00957115, -0.01288327, -0.00730937, -0.00107783, -0.00210156, -0.00890705, -0.01317668, -0.00813895, -0.00153491,
314
    -0.02128481, -0.04173044, -0.04831487, -0.03293190, -0.00525260, -0.01720322, -0.04052736, -0.05045706, -0.03607317, -0.00738030,
315
    -0.01341764, -0.03965629, -0.05151616, -0.03814886, -0.01005819, 0.18968273, 0.33063684, -0.01300105, -0.01372950, -0.04017465,
316
    0.13727832, 0.36402234, 0.01027890, -0.01832107, -0.03365072, 0.08734506, 0.38194295, 0.04338228, -0.02525993, 0.56408126,
317
    0.00458352, -0.01648227, -0.04887868, 0.24585519, 0.62026135, 0.04314807, -0.02213737, -0.04158014, 0.16637289, 0.65027023,
318
    0.09621636, -0.03101388, -0.04082742, -0.00904519, -0.02790922, -0.02117818, 0.00798662, -0.03995711, -0.01243427, -0.02231705,
319
    -0.02946266, 0.00992055, -0.03600283, -0.01684920, -0.00111684, -0.00411204, -0.01297130, -0.01723725, -0.01022545, -0.00165306,
320
    -0.00313110, -0.01218016, -0.01763266, -0.01125620, -0.00231663, -0.01374149, -0.03797620, -0.05142937, -0.03117307, -0.00581914,
321
    -0.01064003, -0.03608089, -0.05272168, -0.03375670, -0.00795586, 0.09628104, 0.27129991, -0.00353779, -0.01734151, -0.03153981,
322
    0.05686230, 0.28500998, 0.02230594, -0.02374955, 0.68214326, 0.05018048, -0.02320852, -0.04383616, 0.18459474, 0.71517975,
323
    0.10805613, -0.03263677, -0.03637639, -0.01394373, -0.02511203, -0.01728636, 0.05407331, -0.02867568, -0.01893131, -0.00240854,
324
    -0.00446511, -0.01636187, -0.02377053, -0.01522848, -0.00333334, -0.00819975, -0.02964169, -0.04499287, -0.02745350, -0.00612408,
325
    0.02727416, 0.19446600, 0.00159832, -0.02232473, 0.74982506, 0.11452620, -0.03348048, -0.01605681, -0.02070339, -0.00458223
326
};
327
///
328
329
/// D.3 - Image metadata
330
331
struct PreviewHeader {
332
};
333
334
struct AnimationHeader {
335
};
336
337
struct ExtraChannelInfo {
338
    enum class ExtraChannelType {
339
        kAlpha = 0,
340
        kDepth = 1,
341
        kSpotColour = 2,
342
        kSelectionMask = 3,
343
        kBlack = 4,
344
        kCFA = 5,
345
        kThermal = 6,
346
        kNonOptional = 15,
347
        kOptional = 16,
348
    };
349
350
    bool d_alpha { true };
351
    ExtraChannelType type { ExtraChannelType::kAlpha };
352
    BitDepth bit_depth {};
353
    u32 dim_shift {};
354
    String name;
355
    bool alpha_associated { false };
356
};
357
358
static ErrorOr<ExtraChannelInfo> read_extra_channel_info(LittleEndianInputBitStream& stream)
359
0
{
360
0
    ExtraChannelInfo extra_channel_info;
361
362
0
    extra_channel_info.d_alpha = TRY(stream.read_bit());
363
364
0
    if (!extra_channel_info.d_alpha) {
365
0
        extra_channel_info.type = TRY(read_enum<ExtraChannelInfo::ExtraChannelType>(stream));
366
0
        extra_channel_info.bit_depth = TRY(read_bit_depth(stream));
367
0
        extra_channel_info.dim_shift = U32(0, 3, 4, 1 + TRY(stream.read_bits(3)));
368
0
        extra_channel_info.name = TRY(read_string(stream));
369
370
0
        if (extra_channel_info.type == ExtraChannelInfo::ExtraChannelType::kAlpha)
371
0
            extra_channel_info.alpha_associated = TRY(stream.read_bit());
372
0
    }
373
374
0
    if (extra_channel_info.type == ExtraChannelInfo::ExtraChannelType::kSpotColour) {
375
0
        return Error::from_string_literal("JPEGXLLoader: Read extra channel info for SpotColour");
376
0
    }
377
378
0
    if (extra_channel_info.type == ExtraChannelInfo::ExtraChannelType::kCFA) {
379
0
        return Error::from_string_literal("JPEGXLLoader: Read extra channel info for CFA");
380
0
    }
381
382
0
    return extra_channel_info;
383
0
}
384
385
struct ToneMapping {
386
    f32 intensity_target { 255 };
387
    f32 min_nits { 0 };
388
    bool relative_to_max_display { false };
389
    f32 linear_below { 0 };
390
};
391
392
static ErrorOr<ToneMapping> read_tone_mapping(LittleEndianInputBitStream& stream)
393
0
{
394
0
    ToneMapping tone_mapping;
395
0
    bool const all_default = TRY(stream.read_bit());
396
397
0
    if (!all_default) {
398
0
        tone_mapping.intensity_target = TRY(F16(stream));
399
0
        tone_mapping.min_nits = TRY(F16(stream));
400
0
        tone_mapping.relative_to_max_display = TRY(stream.read_bit());
401
0
        tone_mapping.linear_below = TRY(F16(stream));
402
0
    }
403
404
0
    return tone_mapping;
405
0
}
406
407
// L.2.1 - OpsinInverseMatrix
408
struct OpsinInverseMatrix {
409
    f32 inv_mat00 = 11.031566901960783;
410
    f32 inv_mat01 = -9.866943921568629;
411
    f32 inv_mat02 = -0.16462299647058826;
412
    f32 inv_mat10 = -3.254147380392157;
413
    f32 inv_mat11 = 4.418770392156863;
414
    f32 inv_mat12 = -0.16462299647058826;
415
    f32 inv_mat20 = -3.6588512862745097;
416
    f32 inv_mat21 = 2.7129230470588235;
417
    f32 inv_mat22 = 1.9459282392156863;
418
    f32 opsin_bias0 = -0.0037930732552754493;
419
    f32 opsin_bias1 = -0.0037930732552754493;
420
    f32 opsin_bias2 = -0.0037930732552754493;
421
    f32 quant_bias0 = 1 - 0.05465007330715401;
422
    f32 quant_bias1 = 1 - 0.07005449891748593;
423
    f32 quant_bias2 = 1 - 0.049935103337343655;
424
    f32 quant_bias_numerator = 0.145;
425
};
426
427
static ErrorOr<OpsinInverseMatrix> read_opsin_inverse_matrix(LittleEndianInputBitStream& stream)
428
0
{
429
0
    OpsinInverseMatrix matrix;
430
431
0
    bool all_default = TRY(stream.read_bit());
432
433
0
    if (!all_default) {
434
0
        matrix.inv_mat00 = TRY(F16(stream));
435
0
        matrix.inv_mat01 = TRY(F16(stream));
436
0
        matrix.inv_mat02 = TRY(F16(stream));
437
0
        matrix.inv_mat10 = TRY(F16(stream));
438
0
        matrix.inv_mat11 = TRY(F16(stream));
439
0
        matrix.inv_mat12 = TRY(F16(stream));
440
0
        matrix.inv_mat20 = TRY(F16(stream));
441
0
        matrix.inv_mat21 = TRY(F16(stream));
442
0
        matrix.inv_mat22 = TRY(F16(stream));
443
0
        matrix.opsin_bias0 = TRY(F16(stream));
444
0
        matrix.opsin_bias1 = TRY(F16(stream));
445
0
        matrix.opsin_bias2 = TRY(F16(stream));
446
0
        matrix.quant_bias0 = TRY(F16(stream));
447
0
        matrix.quant_bias1 = TRY(F16(stream));
448
0
        matrix.quant_bias2 = TRY(F16(stream));
449
0
        matrix.quant_bias_numerator = TRY(F16(stream));
450
0
    }
451
452
0
    return matrix;
453
0
}
454
455
struct ImageMetadata {
456
    u8 orientation { 1 };
457
    Optional<SizeHeader> intrinsic_size;
458
    Optional<PreviewHeader> preview;
459
    Optional<AnimationHeader> animation;
460
    BitDepth bit_depth;
461
    bool modular_16bit_buffers { true };
462
    u16 num_extra_channels {};
463
    Vector<ExtraChannelInfo, 4> ec_info;
464
    bool xyb_encoded { true };
465
    ColourEncoding colour_encoding;
466
    ToneMapping tone_mapping;
467
    Extensions extensions;
468
    bool default_m;
469
    OpsinInverseMatrix opsin_inverse_matrix;
470
    u8 cw_mask { 0 };
471
472
    Array<double, 15> up2_weight = s_d_up2;
473
    Array<double, 55> up4_weight = s_d_up4;
474
    Array<double, 210> up8_weight = s_d_up8;
475
476
    u16 number_of_color_channels() const
477
0
    {
478
0
        if (!xyb_encoded && colour_encoding.colour_space == ColourEncoding::ColourSpace::kGrey)
479
0
            return 1;
480
0
        return 3;
481
0
    }
482
483
    u16 number_of_channels() const
484
0
    {
485
0
        return number_of_color_channels() + num_extra_channels;
486
0
    }
487
488
    Optional<u16> black_channel() const
489
0
    {
490
0
        return first_extra_channel_matching([](auto& info) { return info.type == ExtraChannelInfo::ExtraChannelType::kBlack; });
491
0
    }
492
493
    Optional<u16> alpha_channel() const
494
0
    {
495
0
        return first_extra_channel_matching([](auto& info) { return info.type == ExtraChannelInfo::ExtraChannelType::kAlpha; });
496
0
    }
497
498
private:
499
    Optional<u16> first_extra_channel_matching(auto&& condition) const
500
0
    {
501
0
        for (u16 i = 0; i < ec_info.size(); ++i) {
502
0
            if (condition(ec_info[i]))
503
0
                return i + number_of_color_channels();
504
0
        }
505
0
        return OptionalNone {};
506
0
    }
Unexecuted instantiation: AK::Optional<unsigned short> Gfx::JPEGXL::ImageMetadata::first_extra_channel_matching<Gfx::JPEGXL::ImageMetadata::black_channel() const::{lambda(auto:1&)#1}>(Gfx::JPEGXL::ImageMetadata::black_channel() const::{lambda(auto:1&)#1}&&) const
Unexecuted instantiation: AK::Optional<unsigned short> Gfx::JPEGXL::ImageMetadata::first_extra_channel_matching<Gfx::JPEGXL::ImageMetadata::alpha_channel() const::{lambda(auto:1&)#1}>(Gfx::JPEGXL::ImageMetadata::alpha_channel() const::{lambda(auto:1&)#1}&&) const
507
};
508
509
static ErrorOr<void> ensure_metadata_correctness(ImageMetadata const& metadata)
510
0
{
511
    // "This includes CMYK colour spaces; in that case, the RGB components are interpreted as
512
    // CMY where 0 means full ink, want_icc is true (see Table E.1), and there is an extra channel
513
    // of type kBlack (see Table D.9)."
514
0
    bool should_be_cmyk = any_of(metadata.ec_info, [](auto& info) { return info.type == ExtraChannelInfo::ExtraChannelType::kBlack; });
515
0
    if (should_be_cmyk && !metadata.colour_encoding.want_icc)
516
0
        return Error::from_string_literal("JPEGXLLoader: Seemingly CMYK image doesn't have an ICC profile");
517
518
0
    return {};
519
0
}
520
521
static ErrorOr<ImageMetadata> read_metadata_header(LittleEndianInputBitStream& stream)
522
0
{
523
0
    ImageMetadata metadata;
524
0
    bool const all_default = TRY(stream.read_bit());
525
526
0
    if (!all_default) {
527
0
        bool const extra_fields = TRY(stream.read_bit());
528
529
0
        if (extra_fields) {
530
0
            metadata.orientation = 1 + TRY(stream.read_bits(3));
531
532
0
            bool const have_intr_size = TRY(stream.read_bit());
533
0
            if (have_intr_size)
534
0
                metadata.intrinsic_size = TRY(read_size_header(stream));
535
536
0
            bool const have_preview = TRY(stream.read_bit());
537
0
            if (have_preview)
538
0
                TODO();
539
540
0
            bool const have_animation = TRY(stream.read_bit());
541
0
            if (have_animation)
542
0
                TODO();
543
0
        }
544
545
0
        metadata.bit_depth = TRY(read_bit_depth(stream));
546
0
        metadata.modular_16bit_buffers = TRY(stream.read_bit());
547
0
        metadata.num_extra_channels = U32(0, 1, 2 + TRY(stream.read_bits(4)), 1 + TRY(stream.read_bits(12)));
548
549
0
        for (u16 i {}; i < metadata.num_extra_channels; ++i)
550
0
            metadata.ec_info.append(TRY(read_extra_channel_info(stream)));
551
552
0
        metadata.xyb_encoded = TRY(stream.read_bit());
553
554
0
        metadata.colour_encoding = TRY(read_colour_encoding(stream));
555
556
0
        if (extra_fields)
557
0
            metadata.tone_mapping = TRY(read_tone_mapping(stream));
558
559
0
        metadata.extensions = TRY(read_extensions(stream));
560
0
    }
561
562
0
    metadata.default_m = TRY(stream.read_bit());
563
564
0
    if (!metadata.default_m && metadata.xyb_encoded)
565
0
        metadata.opsin_inverse_matrix = TRY(read_opsin_inverse_matrix(stream));
566
567
0
    if (!metadata.default_m)
568
0
        metadata.cw_mask = TRY(stream.read_bits(3));
569
570
0
    if (metadata.cw_mask != 0)
571
0
        TODO();
572
573
0
    TRY(ensure_metadata_correctness(metadata));
574
575
0
    return metadata;
576
0
}
577
///
578
579
/// Table F.7 — BlendingInfo bundle
580
struct BlendingInfo {
581
    enum class SimpleBlendMode : u8 {
582
        kReplace = 0,
583
        kAdd = 1,
584
        kBlend = 2,
585
        kMulAdd = 3,
586
        kMul = 4,
587
    };
588
589
    // This is a superset of `BlendingInfo::SimpleBlendMode` and defined in `Table K.1 — PatchBlendMode.
590
    // It is only used for patches, but having it here allows us to share some code.
591
    enum class BlendMode : u8 {
592
        kNone = 0,
593
        kReplace = 1,
594
        kAdd = 2,
595
        kMul = 3,
596
        kBlendAbove = 4,
597
        kBlendBelow = 5,
598
        kMulAddAbove = 6,
599
        kMulAddBelow = 7,
600
    };
601
602
    static BlendMode to_general_blend_mode(SimpleBlendMode simple)
603
0
    {
604
0
        switch (simple) {
605
0
        case SimpleBlendMode::kReplace:
606
0
            return BlendMode::kReplace;
607
0
        case SimpleBlendMode::kAdd:
608
0
            return BlendMode::kAdd;
609
0
        case SimpleBlendMode::kBlend:
610
0
            return BlendMode::kBlendAbove;
611
0
        case SimpleBlendMode::kMulAdd:
612
0
            return BlendMode::kMulAddAbove;
613
0
        case SimpleBlendMode::kMul:
614
0
            return BlendMode::kMul;
615
0
        }
616
0
        VERIFY_NOT_REACHED();
617
0
    }
618
619
    BlendMode mode {};
620
    u8 alpha_channel {};
621
    bool clamp { false };
622
    u8 source {};
623
};
624
625
static ErrorOr<BlendingInfo> read_blending_info(LittleEndianInputBitStream& stream, ImageMetadata const& metadata, bool full_frame)
626
0
{
627
0
    BlendingInfo blending_info;
628
629
0
    auto simple = static_cast<BlendingInfo::SimpleBlendMode>(U32(0, 1, 2, 3 + TRY(stream.read_bits(2))));
630
0
    blending_info.mode = BlendingInfo::to_general_blend_mode(simple);
631
632
0
    bool const extra = metadata.num_extra_channels > 0;
633
634
0
    if (extra) {
635
0
        auto const blend_or_mul_add = blending_info.mode == BlendingInfo::BlendMode::kBlendAbove
636
0
            || blending_info.mode == BlendingInfo::BlendMode::kMulAddAbove;
637
638
0
        if (blend_or_mul_add)
639
0
            blending_info.alpha_channel = U32(0, 1, 2, 3 + TRY(stream.read_bits(3)));
640
641
0
        if (blend_or_mul_add || blending_info.mode == BlendingInfo::BlendMode::kMul)
642
0
            blending_info.clamp = TRY(stream.read_bit());
643
0
    }
644
645
0
    if (blending_info.mode != BlendingInfo::BlendMode::kReplace
646
0
        || !full_frame) {
647
0
        blending_info.source = TRY(stream.read_bits(2));
648
0
    }
649
650
0
    return blending_info;
651
0
}
652
///
653
654
// From FrameHeader, but used in RestorationFilter
655
enum class Encoding {
656
    kVarDCT = 0,
657
    kModular = 1,
658
};
659
660
/// J.1 - General
661
struct RestorationFilter {
662
    bool gab { true };
663
    bool gab_custom { false };
664
    f32 gab_x_weight1 { 0.115169525 };
665
    f32 gab_x_weight2 { 0.061248592 };
666
    f32 gab_y_weight1 { 0.115169525 };
667
    f32 gab_y_weight2 { 0.061248592 };
668
    f32 gab_b_weight1 { 0.115169525 };
669
    f32 gab_b_weight2 { 0.061248592 };
670
671
    u8 epf_iters { 2 };
672
673
    bool epf_sharp_custom { false };
674
    Array<f32, 8> epf_sharp_lut { 0, 1. / 7, 2. / 7, 3. / 7, 4. / 7, 5. / 7, 6. / 7, 1 };
675
676
    bool epf_weight_custom { false };
677
    Array<f32, 3> epf_channel_scale { 40.0, 5.0, 3.5 };
678
679
    bool epf_sigma_custom { false };
680
    f32 epf_quant_mul { 0.46 };
681
    f32 epf_pass0_sigma_scale { 0.9 };
682
    f32 epf_pass2_sigma_scale { 6.5 };
683
    f32 epf_border_sad_mul { 2. / 3 };
684
    f32 epf_sigma_for_modular { 1.0 };
685
686
    Extensions extensions;
687
};
688
689
static ErrorOr<RestorationFilter> read_restoration_filter(LittleEndianInputBitStream& stream, Encoding encoding)
690
0
{
691
0
    RestorationFilter restoration_filter;
692
693
0
    auto const all_defaults = TRY(stream.read_bit());
694
695
0
    if (!all_defaults) {
696
0
        restoration_filter.gab = TRY(stream.read_bit());
697
698
0
        if (restoration_filter.gab) {
699
0
            restoration_filter.gab_custom = TRY(stream.read_bit());
700
0
            if (restoration_filter.gab_custom) {
701
0
                restoration_filter.gab_x_weight1 = TRY(F16(stream));
702
0
                restoration_filter.gab_x_weight2 = TRY(F16(stream));
703
0
                restoration_filter.gab_y_weight1 = TRY(F16(stream));
704
0
                restoration_filter.gab_y_weight2 = TRY(F16(stream));
705
0
                restoration_filter.gab_b_weight1 = TRY(F16(stream));
706
0
                restoration_filter.gab_b_weight2 = TRY(F16(stream));
707
0
            }
708
0
        }
709
710
0
        restoration_filter.epf_iters = TRY(stream.read_bits(2));
711
0
        if (restoration_filter.epf_iters != 0) {
712
0
            if (encoding == Encoding::kVarDCT) {
713
0
                restoration_filter.epf_sharp_custom = TRY(stream.read_bit());
714
0
                if (restoration_filter.epf_sharp_custom)
715
0
                    return Error::from_string_literal("JPEGXLLoader: Implement custom restoration filters");
716
0
            }
717
0
            restoration_filter.epf_weight_custom = TRY(stream.read_bit());
718
0
            if (restoration_filter.epf_sharp_custom)
719
0
                return Error::from_string_literal("JPEGXLLoader: Implement custom restoration filters");
720
721
0
            restoration_filter.epf_sigma_custom = TRY(stream.read_bit());
722
0
            if (restoration_filter.epf_sharp_custom)
723
0
                return Error::from_string_literal("JPEGXLLoader: Implement custom restoration filters");
724
725
0
            if (encoding == Encoding::kModular)
726
0
                restoration_filter.epf_sigma_for_modular = TRY(F16(stream));
727
0
        }
728
729
0
        restoration_filter.extensions = TRY(read_extensions(stream));
730
0
    }
731
732
0
    return restoration_filter;
733
0
}
734
///
735
736
/// Table F.6 — Passes bundle
737
struct Passes {
738
    u8 num_passes { 1 };
739
};
740
741
static ErrorOr<Passes> read_passes(LittleEndianInputBitStream& stream)
742
0
{
743
0
    Passes passes;
744
745
0
    passes.num_passes = U32(1, 2, 3, 4 + TRY(stream.read_bits(3)));
746
747
0
    if (passes.num_passes != 1) {
748
0
        TODO();
749
0
    }
750
751
0
    return passes;
752
0
}
753
///
754
755
/// F.2 - FrameHeader
756
struct FrameHeader {
757
    enum class FrameType {
758
        kRegularFrame = 0,
759
        kLFFrame = 1,
760
        kReferenceOnly = 2,
761
        kSkipProgressive = 3,
762
    };
763
764
    enum class Flags {
765
        None = 0,
766
        kNoise = 1,
767
        kPatches = 1 << 1,
768
        kSplines = 1 << 4,
769
        kUseLfFrame = 1 << 5,
770
        kSkipAdaptiveLFSmoothing = 1 << 7,
771
    };
772
773
    FrameType frame_type { FrameType::kRegularFrame };
774
    Encoding encoding { Encoding::kVarDCT };
775
    Flags flags { Flags::None };
776
777
    bool do_YCbCr { false };
778
779
    Array<u8, 3> jpeg_upsampling {};
780
    u8 upsampling {};
781
    FixedArray<u8> ec_upsampling {};
782
783
    u8 group_size_shift { 1 };
784
0
    u16 group_dim() const { return 128 << group_size_shift; }
785
    u8 x_qm_scale { 3 };
786
    u8 b_qm_scale { 2 };
787
    Passes passes {};
788
789
    u8 lf_level {};
790
    bool have_crop { false };
791
    i32 x0 {};
792
    i32 y0 {};
793
    u32 width {};
794
    u32 height {};
795
796
    BlendingInfo blending_info {};
797
    FixedArray<BlendingInfo> ec_blending_info {};
798
799
    u32 duration {};
800
801
    bool is_last { true };
802
    u8 save_as_reference {};
803
    bool save_before_ct {};
804
805
    String name {};
806
    RestorationFilter restoration_filter {};
807
    Extensions extensions {};
808
};
809
810
static int operator&(FrameHeader::Flags first, FrameHeader::Flags second)
811
0
{
812
0
    return static_cast<int>(first) & static_cast<int>(second);
813
0
}
814
815
static ErrorOr<FrameHeader> read_frame_header(LittleEndianInputBitStream& stream,
816
    SizeHeader size_header,
817
    ImageMetadata const& metadata)
818
0
{
819
0
    FrameHeader frame_header;
820
0
    bool const all_default = TRY(stream.read_bit());
821
822
0
    if (!all_default) {
823
0
        frame_header.frame_type = static_cast<FrameHeader::FrameType>(TRY(stream.read_bits(2)));
824
0
        frame_header.encoding = static_cast<Encoding>(TRY(stream.read_bits(1)));
825
826
0
        frame_header.flags = static_cast<FrameHeader::Flags>(TRY(U64(stream)));
827
828
0
        if (!metadata.xyb_encoded)
829
0
            frame_header.do_YCbCr = TRY(stream.read_bit());
830
831
0
        if (!(frame_header.flags & FrameHeader::Flags::kUseLfFrame)) {
832
0
            if (frame_header.do_YCbCr) {
833
0
                frame_header.jpeg_upsampling[0] = TRY(stream.read_bits(2));
834
0
                frame_header.jpeg_upsampling[1] = TRY(stream.read_bits(2));
835
0
                frame_header.jpeg_upsampling[2] = TRY(stream.read_bits(2));
836
0
            }
837
838
0
            frame_header.upsampling = U32(1, 2, 4, 8);
839
840
0
            frame_header.ec_upsampling = TRY(FixedArray<u8>::create(metadata.num_extra_channels));
841
0
            for (u16 i {}; i < metadata.num_extra_channels; ++i)
842
0
                frame_header.ec_upsampling[i] = U32(1, 2, 4, 8);
843
0
        }
844
845
0
        if (frame_header.encoding == Encoding::kModular)
846
0
            frame_header.group_size_shift = TRY(stream.read_bits(2));
847
848
        // Set x_qm_scale default value
849
0
        frame_header.x_qm_scale = metadata.xyb_encoded && frame_header.encoding == Encoding::kVarDCT ? 3 : 2;
850
851
0
        if (metadata.xyb_encoded && frame_header.encoding == Encoding::kVarDCT) {
852
0
            frame_header.x_qm_scale = TRY(stream.read_bits(3));
853
0
            frame_header.b_qm_scale = TRY(stream.read_bits(3));
854
0
        }
855
856
0
        if (frame_header.frame_type != FrameHeader::FrameType::kReferenceOnly)
857
0
            frame_header.passes = TRY(read_passes(stream));
858
859
0
        if (frame_header.frame_type == FrameHeader::FrameType::kLFFrame)
860
0
            frame_header.lf_level = 1 + TRY(stream.read_bits(2));
861
862
0
        if (frame_header.frame_type != FrameHeader::FrameType::kLFFrame)
863
0
            frame_header.have_crop = TRY(stream.read_bit());
864
865
0
        if (frame_header.have_crop) {
866
0
            auto const read_crop_dimension = [&]() -> ErrorOr<u32> {
867
0
                return U32(TRY(stream.read_bits(8)), 256 + TRY(stream.read_bits(11)), 2304 + TRY(stream.read_bits(14)), 18688 + TRY(stream.read_bits(30)));
868
0
            };
869
870
0
            if (frame_header.frame_type != FrameHeader::FrameType::kReferenceOnly) {
871
0
                frame_header.x0 = unpack_signed(TRY(read_crop_dimension()));
872
0
                frame_header.y0 = unpack_signed(TRY(read_crop_dimension()));
873
0
            }
874
875
0
            frame_header.width = TRY(read_crop_dimension());
876
0
            frame_header.height = TRY(read_crop_dimension());
877
0
        }
878
879
0
        bool const normal_frame = frame_header.frame_type == FrameHeader::FrameType::kRegularFrame
880
0
            || frame_header.frame_type == FrameHeader::FrameType::kSkipProgressive;
881
882
        // Let full_frame be true if and only if have_crop is false or if the frame area given
883
        // by width and height and offsets x0 and y0 completely covers the image area.
884
0
        bool const cover_image_area = frame_header.x0 <= 0 && frame_header.y0 <= 0
885
0
            && (frame_header.width + frame_header.x0 >= size_header.width)
886
0
            && (frame_header.height + frame_header.y0 == size_header.height);
887
0
        bool const full_frame = !frame_header.have_crop || cover_image_area;
888
889
        // Set default value for is_last
890
0
        frame_header.is_last = frame_header.frame_type == FrameHeader::FrameType::kRegularFrame;
891
892
0
        if (normal_frame) {
893
0
            frame_header.blending_info = TRY(read_blending_info(stream, metadata, full_frame));
894
895
0
            frame_header.ec_blending_info = TRY(FixedArray<BlendingInfo>::create(metadata.num_extra_channels));
896
0
            for (u16 i {}; i < metadata.num_extra_channels; ++i)
897
0
                frame_header.ec_blending_info[i] = TRY(read_blending_info(stream, metadata, full_frame));
898
899
0
            if (metadata.animation.has_value())
900
0
                TODO();
901
902
0
            frame_header.is_last = TRY(stream.read_bit());
903
0
        }
904
905
0
        if (frame_header.frame_type != FrameHeader::FrameType::kLFFrame && !frame_header.is_last)
906
0
            frame_header.save_as_reference = TRY(stream.read_bits(2));
907
908
0
        auto const resets_canvas = full_frame && frame_header.blending_info.mode == BlendingInfo::BlendMode::kReplace;
909
0
        auto const can_reference = !frame_header.is_last && (frame_header.duration == 0 || frame_header.save_as_reference != 0) && frame_header.frame_type != FrameHeader::FrameType::kLFFrame;
910
911
0
        frame_header.save_before_ct = !normal_frame;
912
0
        if (frame_header.frame_type == FrameHeader::FrameType::kReferenceOnly || (resets_canvas && can_reference))
913
0
            frame_header.save_before_ct = TRY(stream.read_bit());
914
915
0
        frame_header.name = TRY(read_string(stream));
916
917
0
        frame_header.restoration_filter = TRY(read_restoration_filter(stream, frame_header.encoding));
918
919
0
        frame_header.extensions = TRY(read_extensions(stream));
920
0
    }
921
922
0
    return frame_header;
923
0
}
924
///
925
926
/// F.3  TOC
927
struct TOC {
928
    FixedArray<u32> entries;
929
    FixedArray<u32> group_offsets;
930
};
931
932
static u64 num_toc_entries(FrameHeader const& frame_header, u64 num_groups, u64 num_lf_groups)
933
0
{
934
    // F.3.1 - General
935
0
    if (num_groups == 1 && frame_header.passes.num_passes == 1)
936
0
        return 1;
937
938
0
    return 1 + num_lf_groups + 1 + num_groups * frame_header.passes.num_passes;
939
0
}
940
941
// F.3.2 - Decoding permutations
942
static ErrorOr<Vector<u32>> decode_permutations(LittleEndianInputBitStream& stream, EntropyDecoder& decoder, u32 size, u32 skip)
943
0
{
944
    // "Let GetContext(x) denote min(7, ceil(log2(x + 1)))."
945
0
    auto get_context = [](u32 x) -> u32 {
946
0
        return min(7, ceil(log2(x + 1)));
947
0
    };
948
949
    // "The decoder first decodes an integer end, as specified in C.3.3,
950
    // using DecodeHybridVarLenUint(GetContext(size))."
951
0
    auto end = TRY(decoder.decode_hybrid_uint(stream, get_context(size)));
952
953
    // "The value end is at most size − skip."
954
0
    if (end > size - skip)
955
0
        return Error::from_string_literal("JPEGXLLoader: Invalid value for end when decoding permutations");
956
957
    // "Then a sequence lehmer of size elements is produced as follows. It is zero-initialized."
958
0
    auto lehmer = TRY(FixedArray<u32>::create(size));
959
960
    // "For each index i in range [skip, skip + end), the value lehmer[i] is set to
961
    // DecodeHybridVarLenUint(GetContext(i > skip ? lehmer[i − 1] : 0));"
962
0
    for (u32 i = skip; i < skip + end; ++i) {
963
0
        lehmer[i] = TRY(decoder.decode_hybrid_uint(stream, get_context(i > skip ? lehmer[i - 1] : 0)));
964
        // "this value is strictly less than size − i."
965
0
        if (lehmer[i] >= size - i)
966
0
            return Error::from_string_literal("JPEGXLLoader: Decoded permutation is invalid");
967
0
    }
968
969
    // "The decoder then maintains a sequence of elements temp, initially containing
970
    // the numbers [0, size) in increasing order,"
971
0
    Vector<u32> temp;
972
0
    TRY(temp.try_ensure_capacity(size));
973
0
    for (u32 i = 0; i < size; ++i)
974
0
        temp.append(i);
975
976
    // "and a sequence of elements permutation, initially empty."
977
0
    Vector<u32> permutation;
978
0
    TRY(permutation.try_ensure_capacity(size));
979
980
    // "Then, for each integer i in the range [0, size), the decoder appends to
981
    // permutation element temp[lehmer[i]], then removes it from temp, leaving the
982
    // relative order of other elements unchanged."
983
0
    for (u32 i = 0; i < size; ++i) {
984
0
        permutation.append(temp[lehmer[i]]);
985
0
        temp.remove(lehmer[i]);
986
0
    }
987
988
    // " Finally, permutation is the decoded permutation."
989
0
    return permutation;
990
0
}
991
992
static ErrorOr<TOC> read_toc(LittleEndianInputBitStream& stream, FrameHeader const& frame_header, u64 num_groups, u64 num_lf_groups)
993
0
{
994
0
    TOC toc;
995
996
0
    bool const permuted_toc = TRY(stream.read_bit());
997
998
0
    if (permuted_toc) {
999
        // Read permutations
1000
0
        TODO();
1001
0
    }
1002
1003
    // F.3.3 - Decoding TOC
1004
0
    stream.align_to_byte_boundary();
1005
1006
0
    auto const toc_entries = num_toc_entries(frame_header, num_groups, num_lf_groups);
1007
1008
0
    toc.entries = TRY(FixedArray<u32>::create(toc_entries));
1009
0
    toc.group_offsets = TRY(FixedArray<u32>::create(toc_entries));
1010
1011
0
    for (u32 i {}; i < toc_entries; ++i) {
1012
0
        auto const new_entry = U32(
1013
0
            TRY(stream.read_bits(10)),
1014
0
            1024 + TRY(stream.read_bits(14)),
1015
0
            17408 + TRY(stream.read_bits(22)),
1016
0
            4211712 + TRY(stream.read_bits(30)));
1017
1018
0
        toc.entries[i] = new_entry;
1019
1020
        // The decoder then computes an array group_offsets, which has 0 as its first element
1021
        // and subsequent group_offsets[i] are the sum of all TOC entries [0, i).
1022
0
        toc.group_offsets[i] = i == 0 ? 0 : toc.group_offsets[i - 1] + toc.entries[i - 1];
1023
0
    }
1024
1025
0
    if (permuted_toc)
1026
0
        TODO();
1027
1028
0
    stream.align_to_byte_boundary();
1029
1030
0
    return toc;
1031
0
}
1032
///
1033
1034
/// G.1.2 - LF channel dequantization weights
1035
struct LfChannelDequantization {
1036
    f32 m_x_lf_unscaled { 1. / (32 * 128) };
1037
    f32 m_y_lf_unscaled { 1. / (4 * 128) };
1038
    f32 m_b_lf_unscaled { 1. / (2 * 128) };
1039
};
1040
1041
static ErrorOr<LfChannelDequantization> read_lf_channel_dequantization(LittleEndianInputBitStream& stream)
1042
0
{
1043
0
    LfChannelDequantization lf_channel_dequantization;
1044
1045
0
    auto const all_default = TRY(stream.read_bit());
1046
1047
0
    if (!all_default) {
1048
0
        lf_channel_dequantization.m_x_lf_unscaled = TRY(F16(stream)) / 128;
1049
0
        lf_channel_dequantization.m_y_lf_unscaled = TRY(F16(stream)) / 128;
1050
0
        lf_channel_dequantization.m_b_lf_unscaled = TRY(F16(stream)) / 128;
1051
0
    }
1052
1053
0
    return lf_channel_dequantization;
1054
0
}
1055
///
1056
1057
/// H.4.2 - MA tree decoding
1058
class MATree {
1059
public:
1060
    struct LeafNode {
1061
        u32 ctx {};
1062
        u8 predictor {};
1063
        i32 offset {};
1064
        u32 multiplier {};
1065
    };
1066
1067
    static ErrorOr<MATree> decode(LittleEndianInputBitStream& stream, Optional<EntropyDecoder>& decoder)
1068
0
    {
1069
        // G.1.3 - GlobalModular
1070
0
        MATree tree;
1071
1072
        // 1 / 2 Read the 6 pre-clustered distributions
1073
0
        auto const num_distrib = 6;
1074
0
        VERIFY(!decoder.has_value());
1075
0
        decoder = TRY(EntropyDecoder::create(stream, num_distrib));
1076
1077
        // 2 / 2 Decode the tree
1078
1079
0
        u64 ctx_id = 0;
1080
0
        u64 nodes_left = 1;
1081
0
        tree.m_tree.clear();
1082
1083
0
        while (nodes_left > 0) {
1084
0
            nodes_left--;
1085
1086
0
            i32 const property = TRY(decoder->decode_hybrid_uint(stream, 1)) - 1;
1087
1088
0
            if (property >= 0) {
1089
0
                DecisionNode decision_node;
1090
0
                decision_node.property = property;
1091
0
                decision_node.value = unpack_signed(TRY(decoder->decode_hybrid_uint(stream, 0)));
1092
0
                decision_node.left_child = tree.m_tree.size() + nodes_left + 1;
1093
0
                decision_node.right_child = tree.m_tree.size() + nodes_left + 2;
1094
0
                tree.m_tree.empend(decision_node);
1095
0
                nodes_left += 2;
1096
0
            } else {
1097
0
                LeafNode leaf_node;
1098
0
                leaf_node.ctx = ctx_id++;
1099
0
                leaf_node.predictor = TRY(decoder->decode_hybrid_uint(stream, 2));
1100
0
                leaf_node.offset = unpack_signed(TRY(decoder->decode_hybrid_uint(stream, 3)));
1101
0
                auto const mul_log = TRY(decoder->decode_hybrid_uint(stream, 4));
1102
0
                auto const mul_bits = TRY(decoder->decode_hybrid_uint(stream, 5));
1103
0
                leaf_node.multiplier = (mul_bits + 1) << mul_log;
1104
0
                tree.m_tree.empend(leaf_node);
1105
0
            }
1106
0
        }
1107
0
        TRY(decoder->ensure_end_state());
1108
1109
        // Finally, the decoder reads (tree.size() + 1) / 2 pre-clustered distributions D as specified in C.1.
1110
1111
0
        auto const num_pre_clustered_distributions = (tree.m_tree.size() + 1) / 2;
1112
0
        decoder = TRY(EntropyDecoder::create(stream, num_pre_clustered_distributions));
1113
1114
0
        tree.save_self_correction_usage();
1115
1116
0
        return tree;
1117
0
    }
1118
1119
    LeafNode get_leaf(Span<i32> properties) const
1120
0
    {
1121
        // To find the MA leaf node, the MA tree is traversed, starting at the root node tree[0]
1122
        // and for each decision node d, testing if property[d.property] > d.value, proceeding to
1123
        // the node tree[d.left_child] if the test evaluates to true and to the node tree[d.right_child]
1124
        // otherwise, until a leaf node is reached.
1125
1126
0
        DecisionNode node { m_tree[0].get<DecisionNode>() };
1127
0
        while (true) {
1128
0
            auto const next_node = [this, &properties, &node]() {
1129
                // Note: The behavior when trying to access a non-existing property is taken from jxl-oxide
1130
0
                if (node.property < properties.size() && properties[node.property] > node.value)
1131
0
                    return m_tree[node.left_child];
1132
0
                return m_tree[node.right_child];
1133
0
            }();
1134
1135
0
            if (next_node.has<LeafNode>())
1136
0
                return next_node.get<LeafNode>();
1137
0
            node = next_node.get<DecisionNode>();
1138
0
        }
1139
0
    }
1140
1141
    bool use_self_correcting_predictor() const
1142
0
    {
1143
0
        return m_use_self_correcting_predictor;
1144
0
    }
1145
1146
private:
1147
    void save_self_correction_usage()
1148
0
    {
1149
0
        for (auto const& node : m_tree) {
1150
            // We are looking for usage of the Self Correction predictor, so this includes both the
1151
            // 'max_error' property and the 'Self-correcting' predictor, They are given as index 15
1152
            // in Table H.4 — Property definitions and index 6 in Table H.3 — Modular predictors respectively.
1153
0
            auto const use_max_error = node.has<DecisionNode>() && node.get<DecisionNode>().property == 15;
1154
0
            auto const use_self_correcting = node.has<LeafNode>() && node.get<LeafNode>().predictor == 6;
1155
0
            if (use_max_error || use_self_correcting) {
1156
0
                m_use_self_correcting_predictor = true;
1157
0
                return;
1158
0
            }
1159
0
        }
1160
1161
0
        m_use_self_correcting_predictor = false;
1162
0
    }
1163
1164
    struct DecisionNode {
1165
        u64 property {};
1166
        i64 value {};
1167
        u64 left_child {};
1168
        u64 right_child {};
1169
    };
1170
1171
    Vector<Variant<DecisionNode, LeafNode>> m_tree;
1172
1173
    bool m_use_self_correcting_predictor { true };
1174
};
1175
///
1176
1177
/// Local abstractions to store the decoded image
1178
class BlendedImage {
1179
public:
1180
    ErrorOr<void> blend_into(BlendedImage& image, BlendingInfo::BlendMode mode) const
1181
0
    {
1182
0
        if (to_underlying(mode) > 2)
1183
0
            return Error::from_string_literal("JPEGXLLoder: Unsupported blend mode");
1184
1185
0
        auto input_rect = active_rectangle();
1186
0
        auto output_rect = image.active_rectangle();
1187
1188
0
        if (input_rect.size() != output_rect.size())
1189
0
            return Error::from_string_literal("JPEGXLLoder: Unable to blend image with a different size");
1190
1191
0
        for (u32 i = 0; i < channels().size(); ++i) {
1192
0
            auto const& input_channel = channels()[i];
1193
0
            auto& output_channel = image.channels()[i];
1194
1195
0
            if (mode == BlendingInfo::BlendMode::kNone)
1196
0
                blend_channel<BlendingInfo::BlendMode::kNone>(input_channel, input_rect, output_channel, output_rect);
1197
0
            else if (mode == BlendingInfo::BlendMode::kReplace)
1198
0
                blend_channel<BlendingInfo::BlendMode::kReplace>(input_channel, input_rect, output_channel, output_rect);
1199
0
            else if (mode == BlendingInfo::BlendMode::kAdd)
1200
0
                blend_channel<BlendingInfo::BlendMode::kAdd>(input_channel, input_rect, output_channel, output_rect);
1201
0
        }
1202
1203
0
        return {};
1204
0
    }
1205
1206
protected:
1207
0
    virtual ~BlendedImage() = default;
1208
1209
    virtual Vector<Channel>& channels() = 0;
1210
    virtual Vector<Channel> const& channels() const = 0;
1211
    virtual IntRect active_rectangle() const = 0;
1212
0
    IntSize size() const { return active_rectangle().size(); }
1213
1214
private:
1215
    template<BlendingInfo::BlendMode blend_mode>
1216
    void blend_channel(Channel const& input_channel, IntRect input_rect,
1217
        Channel& output_channel, IntRect output_rect) const
1218
0
    {
1219
0
        for (u32 y = 0; y < static_cast<u32>(input_rect.height()); ++y) {
1220
0
            for (u32 x = 0; x < static_cast<u32>(input_rect.width()); ++x) {
1221
0
                auto const old_sample = output_channel.get(x + output_rect.x(), y + output_rect.y());
1222
0
                auto const new_sample = input_channel.get(x + input_rect.x(), y + input_rect.y());
1223
1224
0
                auto const sample = [&]() {
1225
                    // Table F.8 — BlendMode (BlendingInfo.mode)
1226
                    if constexpr (blend_mode == BlendingInfo::BlendMode::kNone)
1227
0
                        return old_sample;
1228
                    if constexpr (blend_mode == BlendingInfo::BlendMode::kReplace)
1229
0
                        return new_sample;
1230
                    if constexpr (blend_mode == BlendingInfo::BlendMode::kAdd)
1231
0
                        return old_sample + new_sample;
1232
0
                }();
Unexecuted instantiation: Gfx::JPEGXL::BlendedImage::blend_channel<(Gfx::JPEGXL::BlendingInfo::BlendMode)0>(Gfx::JPEGXL::Detail::Channel<int> const&, Gfx::Rect<int>, Gfx::JPEGXL::Detail::Channel<int>&, Gfx::Rect<int>) const::{lambda()#1}::operator()() const
Unexecuted instantiation: Gfx::JPEGXL::BlendedImage::blend_channel<(Gfx::JPEGXL::BlendingInfo::BlendMode)1>(Gfx::JPEGXL::Detail::Channel<int> const&, Gfx::Rect<int>, Gfx::JPEGXL::Detail::Channel<int>&, Gfx::Rect<int>) const::{lambda()#1}::operator()() const
Unexecuted instantiation: Gfx::JPEGXL::BlendedImage::blend_channel<(Gfx::JPEGXL::BlendingInfo::BlendMode)2>(Gfx::JPEGXL::Detail::Channel<int> const&, Gfx::Rect<int>, Gfx::JPEGXL::Detail::Channel<int>&, Gfx::Rect<int>) const::{lambda()#1}::operator()() const
1233
0
                output_channel.set(x + output_rect.x(), y + output_rect.y(), sample);
1234
0
            }
1235
0
        }
1236
0
    }
Unexecuted instantiation: void Gfx::JPEGXL::BlendedImage::blend_channel<(Gfx::JPEGXL::BlendingInfo::BlendMode)0>(Gfx::JPEGXL::Detail::Channel<int> const&, Gfx::Rect<int>, Gfx::JPEGXL::Detail::Channel<int>&, Gfx::Rect<int>) const
Unexecuted instantiation: void Gfx::JPEGXL::BlendedImage::blend_channel<(Gfx::JPEGXL::BlendingInfo::BlendMode)1>(Gfx::JPEGXL::Detail::Channel<int> const&, Gfx::Rect<int>, Gfx::JPEGXL::Detail::Channel<int>&, Gfx::Rect<int>) const
Unexecuted instantiation: void Gfx::JPEGXL::BlendedImage::blend_channel<(Gfx::JPEGXL::BlendingInfo::BlendMode)2>(Gfx::JPEGXL::Detail::Channel<int> const&, Gfx::Rect<int>, Gfx::JPEGXL::Detail::Channel<int>&, Gfx::Rect<int>) const
1237
};
1238
1239
class ImageView : public BlendedImage {
1240
public:
1241
    ImageView(Vector<Channel>& channels, IntRect active_rect)
1242
0
        : m_channels_view(channels)
1243
0
        , m_active_rect(active_rect)
1244
0
    {
1245
0
    }
1246
1247
private:
1248
    virtual Vector<Channel> const& channels() const override
1249
0
    {
1250
0
        return m_channels_view;
1251
0
    }
1252
1253
    virtual Vector<Channel>& channels() override
1254
0
    {
1255
0
        return m_channels_view;
1256
0
    }
1257
1258
    virtual IntRect active_rectangle() const override
1259
0
    {
1260
0
        return m_active_rect;
1261
0
    }
1262
1263
    Vector<Channel>& m_channels_view;
1264
    IntRect m_active_rect;
1265
};
1266
1267
class Image : public BlendedImage {
1268
public:
1269
    static ErrorOr<Image> create(IntSize size, ImageMetadata const& metadata)
1270
0
    {
1271
0
        Image image {};
1272
1273
0
        for (u16 i = 0; i < metadata.number_of_channels(); ++i) {
1274
0
            if (i < metadata.number_of_color_channels()) {
1275
0
                TRY(image.m_channels.try_append(TRY(Channel::create(ChannelInfo::from_size(size)))));
1276
0
            } else {
1277
0
                auto const dim_shift = metadata.ec_info[i - metadata.number_of_color_channels()].dim_shift;
1278
0
                TRY(image.m_channels.try_append(TRY(Channel::create(
1279
0
                    {
1280
0
                        .width = static_cast<u32>(size.width() >> dim_shift),
1281
0
                        .height = static_cast<u32>(size.height() >> dim_shift),
1282
0
                    }))));
1283
0
            }
1284
0
        }
1285
1286
0
        return image;
1287
0
    }
1288
1289
    static ErrorOr<Image> adopt_channels(Vector<Channel>&& channels)
1290
0
    {
1291
0
        if (channels.size() > 1) {
1292
0
            if (any_of(channels, [&](auto const& channel) {
1293
0
                    return channel.width() != channels[0].width() || channel.height() != channels[0].height();
1294
0
                })) {
1295
0
                return Error::from_string_literal("JPEGXLLoader: One of the Global Modular channel has a different size");
1296
0
            }
1297
0
        }
1298
0
        return Image { move(channels) };
1299
0
    }
1300
1301
    ErrorOr<ImageView> get_subimage(IntRect rectangle)
1302
0
    {
1303
0
        if (rectangle.right() > size().width()
1304
0
            || rectangle.bottom() > size().height())
1305
0
            return Error::from_string_literal("JPEGXLLoader: Can't create subimage from out-of-bounds rectangle");
1306
1307
0
        return ImageView { m_channels, rectangle };
1308
0
    }
1309
1310
    ErrorOr<NonnullRefPtr<CMYKBitmap>> to_cmyk_bitmap(ImageMetadata const& metadata) const
1311
0
    {
1312
0
        auto const width = m_channels[0].width();
1313
0
        auto const height = m_channels[0].height();
1314
1315
0
        if (metadata.bit_depth.bits_per_sample != 8)
1316
0
            return Error::from_string_literal("JPEGXLLoader: Unsupported bit-depth for CMYK image");
1317
1318
0
        auto const orientation = static_cast<TIFF::Orientation>(metadata.orientation);
1319
0
        auto oriented_bitmap = TRY(ExifOrientedCMYKBitmap::create(orientation, { width, height }));
1320
1321
0
        auto const black_channel = *metadata.black_channel();
1322
1323
0
        for (u32 y {}; y < height; ++y) {
1324
0
            for (u32 x {}; x < width; ++x) {
1325
0
                CMYK const color = CMYK(
1326
0
                    255 - clamp(m_channels[0].get(x, y), 0, 255),
1327
0
                    255 - clamp(m_channels[1].get(x, y), 0, 255),
1328
0
                    255 - clamp(m_channels[2].get(x, y), 0, 255),
1329
0
                    255 - clamp(m_channels[black_channel].get(x, y), 0, 255));
1330
0
                oriented_bitmap.set_pixel(x, y, color);
1331
0
            }
1332
0
        }
1333
1334
0
        return oriented_bitmap.bitmap();
1335
0
    }
1336
1337
    ErrorOr<NonnullRefPtr<Bitmap>> to_bitmap(ImageMetadata const& metadata) const
1338
0
    {
1339
0
        auto const width = m_channels[0].width();
1340
0
        auto const height = m_channels[0].height();
1341
1342
0
        auto const orientation = static_cast<TIFF::Orientation>(metadata.orientation);
1343
0
        auto oriented_bitmap = TRY(ExifOrientedBitmap::create(orientation, { width, height }, BitmapFormat::BGRA8888));
1344
1345
0
        auto const alpha_channel = metadata.alpha_channel();
1346
1347
0
        auto const bits_per_sample = metadata.bit_depth.bits_per_sample;
1348
0
        VERIFY(bits_per_sample >= 8);
1349
0
        for (u32 y {}; y < height; ++y) {
1350
0
            for (u32 x {}; x < width; ++x) {
1351
0
                auto const to_u8 = [&, bits_per_sample](i32 sample) -> u8 {
1352
                    // FIXME: Don't truncate the result to 8 bits
1353
0
                    static constexpr auto maximum_supported_bit_depth = 8;
1354
0
                    if (bits_per_sample > maximum_supported_bit_depth)
1355
0
                        sample >>= (bits_per_sample - maximum_supported_bit_depth);
1356
1357
0
                    return clamp(sample + .5, 0, (1 << maximum_supported_bit_depth) - 1);
1358
0
                };
1359
1360
0
                auto const color = [&]() -> Color {
1361
0
                    if (metadata.number_of_color_channels() == 1) {
1362
0
                        auto gray = to_u8(m_channels[0].get(x, y));
1363
0
                        return { gray, gray, gray };
1364
0
                    }
1365
1366
0
                    if (!alpha_channel.has_value()) {
1367
0
                        return { to_u8(m_channels[0].get(x, y)),
1368
0
                            to_u8(m_channels[1].get(x, y)),
1369
0
                            to_u8(m_channels[2].get(x, y)) };
1370
0
                    }
1371
1372
0
                    return {
1373
0
                        to_u8(m_channels[0].get(x, y)),
1374
0
                        to_u8(m_channels[1].get(x, y)),
1375
0
                        to_u8(m_channels[2].get(x, y)),
1376
0
                        to_u8(m_channels[*alpha_channel].get(x, y)),
1377
0
                    };
1378
0
                }();
1379
0
                oriented_bitmap.set_pixel(x, y, color.value());
1380
0
            }
1381
0
        }
1382
1383
0
        return oriented_bitmap.bitmap();
1384
0
    }
1385
1386
    virtual Vector<Channel> const& channels() const override
1387
0
    {
1388
0
        return m_channels;
1389
0
    }
1390
1391
    virtual Vector<Channel>& channels() override
1392
0
    {
1393
0
        return m_channels;
1394
0
    }
1395
1396
    IntRect rect() const
1397
0
    {
1398
0
        return active_rectangle();
1399
0
    }
1400
1401
private:
1402
0
    Image() = default;
1403
1404
    Image(Vector<Channel>&& channels)
1405
0
        : m_channels(move(channels))
1406
0
    {
1407
0
    }
1408
1409
    IntRect active_rectangle() const override
1410
0
    {
1411
0
        return IntRect(0, 0, m_channels[0].width(), m_channels[0].height());
1412
0
    }
1413
1414
    Vector<Channel> m_channels;
1415
};
1416
///
1417
1418
/// H.2 - Image decoding
1419
1420
static ErrorOr<void> add_default_squeeze_params(TransformInfo& tr, Span<ChannelInfo> channels, u32 nb_meta_channels)
1421
0
{
1422
    // H.6.2.1  Parameters - "The default parameters (the case when sp.size() == 0) are specified by the following code:"
1423
1424
0
    auto first = nb_meta_channels;
1425
0
    auto count = channels.size() - first;
1426
0
    auto w = channels[first].width;
1427
0
    auto h = channels[first].height;
1428
0
    SqueezeParams param;
1429
0
    if (count > 2 && channels[first + 1].width == w && channels[first + 1].height == h) {
1430
0
        param.begin_c = first + 1;
1431
0
        param.num_c = 2;
1432
0
        param.in_place = false;
1433
0
        param.horizontal = true;
1434
0
        tr.sp.append(param);
1435
0
        param.horizontal = false;
1436
0
        tr.sp.append(param);
1437
0
    }
1438
0
    param.begin_c = first;
1439
0
    param.num_c = count;
1440
0
    param.in_place = true;
1441
0
    if (h >= w && h > 8) {
1442
0
        param.horizontal = false;
1443
0
        tr.sp.append(param);
1444
0
        h = (h + 1) / 2;
1445
0
    }
1446
0
    while (w > 8 || h > 8) {
1447
0
        if (w > 8) {
1448
0
            param.horizontal = true;
1449
0
            tr.sp.append(param);
1450
0
            w = (w + 1) / 2;
1451
0
        }
1452
0
        if (h > 8) {
1453
0
            param.horizontal = false;
1454
0
            tr.sp.append(param);
1455
0
            h = (h + 1) / 2;
1456
0
        }
1457
0
    }
1458
0
    return {};
1459
0
}
1460
1461
struct ModularData {
1462
    bool use_global_tree {};
1463
    WPHeader wp_params {};
1464
    Vector<TransformInfo> transform {};
1465
1466
    // Initially, nb_meta_channels is set to zero, but transformations can modify this value.
1467
    u32 nb_meta_channels {};
1468
1469
    Vector<Channel> channels {};
1470
1471
    ErrorOr<void> create_channels(Span<ChannelInfo> frame_size)
1472
0
    {
1473
0
        Vector<ChannelInfo> channel_infos {};
1474
0
        TRY(channel_infos.try_extend(frame_size));
1475
1476
0
        for (auto& tr : transform) {
1477
0
            if (tr.tr == TransformInfo::TransformId::kPalette) {
1478
                // Let end_c = begin_c + num_c − 1. When updating the channel list as described in H.2, channels begin_c to end_c,
1479
                // which all have the same dimensions, are replaced with two new channels:
1480
                //  - one meta-channel, inserted at the beginning of the channel list and has dimensions width = nb_colours and height = num_c and hshift = vshift = −1.
1481
                //    This channel represents the colours or deltas of the palette.
1482
                //  - one channel (at the same position in the channel list as the original channels, same dimensions) which contains palette indices.
1483
1484
0
                auto original_dimensions = channel_infos[tr.begin_c];
1485
0
                channel_infos.remove(tr.begin_c, tr.num_c);
1486
0
                TRY(channel_infos.try_insert(tr.begin_c, original_dimensions));
1487
0
                TRY(channel_infos.try_prepend({ .width = tr.nb_colours, .height = tr.num_c, .hshift = -1, .vshift = -1 }));
1488
1489
0
                if (tr.begin_c < nb_meta_channels)
1490
0
                    nb_meta_channels += 2 - tr.begin_c;
1491
0
                else
1492
0
                    nb_meta_channels += 1;
1493
0
            } else if (tr.tr == TransformInfo::TransformId::kSqueeze) {
1494
0
                if (tr.sp.is_empty())
1495
0
                    TRY(add_default_squeeze_params(tr, channel_infos, nb_meta_channels));
1496
1497
                // "Let begin = sp[i].begin_c and end = begin + sp[i].num_c − 1.
1498
                // The channel list is modified as specified by the following code:"
1499
0
                for (u32 i = 0; i < tr.sp.size(); i++) {
1500
0
                    auto begin = tr.sp[i].begin_c;
1501
0
                    auto end = begin + tr.sp[i].num_c - 1;
1502
0
                    auto r = tr.sp[i].in_place ? end + 1 : channel_infos.size();
1503
0
                    if (begin < nb_meta_channels) {
1504
                        /* sp[i].in_place is true */
1505
                        /* end < nb_meta_channels */
1506
0
                        if (!tr.sp[i].in_place || end >= nb_meta_channels)
1507
0
                            return Error::from_string_literal("JPEGXLLoader: Invalid values in the squeeze transform");
1508
0
                        nb_meta_channels += tr.sp[i].num_c;
1509
0
                    }
1510
0
                    for (u32 c = begin; c <= end; c++) {
1511
0
                        auto w = channel_infos[c].width;
1512
0
                        auto h = channel_infos[c].height;
1513
                        /* w > 0 and h > 0 */
1514
0
                        if (w == 0 || h == 0)
1515
0
                            return Error::from_string_literal("JPEGXLLoader: Can't apply the squeeze transform on a channel with a null dimension");
1516
1517
0
                        ChannelInfo residu;
1518
0
                        if (tr.sp[i].horizontal) {
1519
0
                            channel_infos[c].width = (w + 1) / 2;
1520
0
                            if (channel_infos[c].hshift >= 0)
1521
0
                                channel_infos[c].hshift++;
1522
0
                            residu = channel_infos[c];
1523
0
                            residu.width = w / 2;
1524
0
                        } else {
1525
0
                            channel_infos[c].height = (h + 1) / 2;
1526
0
                            if (channel_infos[c].vshift >= 0)
1527
0
                                channel_infos[c].vshift++;
1528
0
                            residu = channel_infos[c];
1529
0
                            residu.height = h / 2;
1530
0
                        }
1531
                        /* Insert residu into channel at index r + c − begin */
1532
0
                        TRY(channel_infos.try_insert(r + c - begin, residu));
1533
0
                    }
1534
0
                }
1535
0
            }
1536
0
        }
1537
1538
0
        TRY(channels.try_ensure_capacity(channel_infos.size()));
1539
0
        for (u32 i = 0; i < channel_infos.size(); ++i)
1540
0
            channels.append(TRY(Channel::create(channel_infos[i])));
1541
1542
0
        return {};
1543
0
    }
1544
};
1545
1546
static constexpr u32 nb_base_predictors = 16;
1547
1548
static void get_properties(FixedArray<i32>& properties, Span<Channel> channels, u16 i, u32 x, u32 y, i32 max_error)
1549
0
{
1550
    // Table H.4 - Property definitions
1551
0
    properties[0] = i;
1552
0
    properties[2] = y;
1553
0
    properties[3] = x;
1554
1555
0
    i32 const W = x > 0 ? channels[i].get(x - 1, y) : (y > 0 ? channels[i].get(x, y - 1) : 0);
1556
0
    i32 const N = y > 0 ? channels[i].get(x, y - 1) : W;
1557
0
    i32 const NW = x > 0 && y > 0 ? channels[i].get(x - 1, y - 1) : W;
1558
0
    i32 const NE = x + 1 < channels[i].width() && y > 0 ? channels[i].get(x + 1, y - 1) : N;
1559
0
    i32 const NN = y > 1 ? channels[i].get(x, y - 2) : N;
1560
0
    i32 const WW = x > 1 ? channels[i].get(x - 2, y) : W;
1561
1562
0
    properties[4] = abs(N);
1563
0
    properties[5] = abs(W);
1564
0
    properties[6] = N;
1565
0
    properties[7] = W;
1566
1567
    // x > 0 ? W - /* (the value of property 9 at position (x - 1, y)) */ : W
1568
0
    if (x > 0) {
1569
0
        auto const x_1 = x - 1;
1570
0
        i32 const W_x_1 = x_1 > 0 ? channels[i].get(x_1 - 1, y) : (y > 0 ? channels[i].get(x_1, y - 1) : 0);
1571
0
        i32 const N_x_1 = y > 0 ? channels[i].get(x_1, y - 1) : W_x_1;
1572
0
        i32 const NW_x_1 = x_1 > 0 && y > 0 ? channels[i].get(x_1 - 1, y - 1) : W_x_1;
1573
0
        properties[8] = W - (W_x_1 + N_x_1 - NW_x_1);
1574
0
    } else {
1575
0
        properties[8] = W;
1576
0
    }
1577
1578
0
    properties[9] = W + N - NW;
1579
0
    properties[10] = W - NW;
1580
0
    properties[11] = NW - N;
1581
0
    properties[12] = N - NE;
1582
0
    properties[13] = N - NN;
1583
0
    properties[14] = W - WW;
1584
1585
0
    properties[15] = max_error;
1586
1587
0
    for (i16 j = i - 1; j >= 0; j--) {
1588
0
        if (channels[j].width() != channels[i].width())
1589
0
            continue;
1590
0
        if (channels[j].height() != channels[i].height())
1591
0
            continue;
1592
0
        if (channels[j].hshift() != channels[i].hshift())
1593
0
            continue;
1594
0
        if (channels[j].vshift() != channels[i].vshift())
1595
0
            continue;
1596
0
        auto rC = channels[j].get(x, y);
1597
0
        auto rW = (x > 0 ? channels[j].get(x - 1, y) : 0);
1598
0
        auto rN = (y > 0 ? channels[j].get(x, y - 1) : rW);
1599
0
        auto rNW = (x > 0 && y > 0 ? channels[j].get(x - 1, y - 1) : rW);
1600
0
        auto rG = clamp(rW + rN - rNW, min(rW, rN), max(rW, rN));
1601
0
        properties[nb_base_predictors + (i - 1 - j) * 4 + 0] = abs(rC);
1602
0
        properties[nb_base_predictors + (i - 1 - j) * 4 + 1] = rC;
1603
0
        properties[nb_base_predictors + (i - 1 - j) * 4 + 2] = abs(rC - rG);
1604
0
        properties[nb_base_predictors + (i - 1 - j) * 4 + 3] = rC - rG;
1605
0
    }
1606
0
}
1607
1608
struct ModularOptions {
1609
    Span<ChannelInfo> channels_info;
1610
    Optional<EntropyDecoder>& decoder;
1611
    MATree const& global_tree;
1612
    u32 group_dim {};
1613
    u32 stream_index {};
1614
1615
    enum class ApplyTransformations : u8 {
1616
        No,
1617
        Yes,
1618
    };
1619
1620
    ApplyTransformations apply_transformations { ApplyTransformations::Yes };
1621
    u32 bit_depth {};
1622
};
1623
1624
static ErrorOr<ModularData> read_modular_bitstream(LittleEndianInputBitStream& stream,
1625
    ModularOptions&& options)
1626
0
{
1627
0
    auto [channels_info,
1628
0
        decoder,
1629
0
        global_tree,
1630
0
        group_dim,
1631
0
        stream_index,
1632
0
        should_apply_transformation,
1633
0
        bit_depth]
1634
0
        = options;
1635
1636
0
    ModularData modular_data;
1637
1638
0
    modular_data.use_global_tree = TRY(stream.read_bit());
1639
0
    modular_data.wp_params = TRY(read_self_correcting_predictor(stream));
1640
0
    auto const nb_transforms = U32(0, 1, 2 + TRY(stream.read_bits(4)), 18 + TRY(stream.read_bits(8)));
1641
1642
0
    TRY(modular_data.transform.try_resize(nb_transforms));
1643
0
    for (u32 i {}; i < nb_transforms; ++i)
1644
0
        modular_data.transform[i] = TRY(read_transform_info(stream));
1645
1646
0
    TRY(modular_data.create_channels(channels_info));
1647
1648
    // "However, the decoder only decodes the first nb_meta_channels channels and any further channels
1649
    // that have a width and height that are both at most group_dim. At that point, it stops decoding."
1650
0
    u32 first_non_decoded_index = NumericLimits<u32>::max();
1651
0
    auto will_be_decoded = [&](u32 index, Channel const& channel) {
1652
0
        if (channel.width() == 0 || channel.height() == 0)
1653
0
            return false;
1654
0
        if (index < modular_data.nb_meta_channels)
1655
0
            return true;
1656
0
        if (index >= first_non_decoded_index)
1657
0
            return false;
1658
0
        if (channel.width() <= group_dim && channel.height() <= group_dim)
1659
0
            return true;
1660
0
        first_non_decoded_index = index;
1661
0
        return false;
1662
0
    };
1663
1664
    if constexpr (JPEGXL_DEBUG) {
1665
        dbgln("Decoding modular sub-stream ({} tree, {} transforms, stream_index={}):",
1666
            modular_data.use_global_tree ? "global"sv : "local"sv,
1667
            nb_transforms,
1668
            stream_index);
1669
1670
        for (auto const& tr : modular_data.transform) {
1671
            switch (tr.tr) {
1672
            case TransformInfo::TransformId::kRCT:
1673
                dbgln("* RCT: begin_c={} - rct_type={}", tr.begin_c, tr.rct_type);
1674
                break;
1675
            case TransformInfo::TransformId::kPalette:
1676
                dbgln("* Palette: begin_c={} - num_c={} - nb_colours={} - nb_deltas={} - d_pred={}",
1677
                    tr.begin_c, tr.num_c, tr.nb_colours, tr.nb_deltas, tr.d_pred);
1678
                break;
1679
            case TransformInfo::TransformId::kSqueeze:
1680
                dbgln("* Squeeze: num_sp={}", tr.sp.size());
1681
                break;
1682
            }
1683
        }
1684
        for (auto const& [i, channel] : enumerate(modular_data.channels))
1685
            dbgln("- Channel {}: {}x{}{}", i, channel.width(), channel.height(), will_be_decoded(i, channel) ? ""sv : " - skipped"sv);
1686
    }
1687
1688
0
    Optional<MATree> local_tree;
1689
0
    if (!modular_data.use_global_tree)
1690
0
        TODO();
1691
1692
    // where the dist_multiplier from C.3.3 is set to the largest channel width amongst all channels
1693
    // that are to be decoded.
1694
0
    auto const dist_multiplier = [&]() {
1695
0
        u32 dist_multiplier {};
1696
0
        for (auto [i, channel] : enumerate(modular_data.channels)) {
1697
0
            if (will_be_decoded(i, channel) && channel.width() > dist_multiplier)
1698
0
                dist_multiplier = channel.width();
1699
0
        }
1700
0
        return dist_multiplier;
1701
0
    }();
1702
0
    decoder->set_dist_multiplier(dist_multiplier);
1703
1704
    // The decoder then starts an entropy-coded stream (C.1) and decodes the data for each channel
1705
    // (in ascending order of index) as specified in H.3, skipping any channels having width or height
1706
    // zero. Finally, the inverse transformations are applied (from last to first) as described in H.6.
1707
1708
0
    auto properties = TRY(FixedArray<i32>::create(nb_base_predictors + modular_data.channels.size() * 4));
1709
0
    properties[1] = stream_index;
1710
1711
0
    auto const& tree = local_tree.has_value() ? *local_tree : global_tree;
1712
0
    for (auto [i, channel] : enumerate(modular_data.channels)) {
1713
0
        if (!will_be_decoded(i, channel))
1714
0
            continue;
1715
1716
0
        auto self_correcting_data = TRY(SelfCorrectingData::create(modular_data.wp_params, channel.width()));
1717
1718
0
        for (u32 y {}; y < channel.height(); y++) {
1719
0
            for (u32 x {}; x < channel.width(); x++) {
1720
0
                auto const neighborhood = retrieve_neighborhood(channel, x, y);
1721
1722
0
                SelfCorrectingData::Predictions self_prediction {};
1723
0
                if (tree.use_self_correcting_predictor())
1724
0
                    self_prediction = self_correcting_data.compute_predictions(neighborhood, x);
1725
1726
0
                get_properties(properties, modular_data.channels, i, x, y, self_prediction.max_error);
1727
0
                auto const leaf_node = tree.get_leaf(properties);
1728
0
                auto diff = unpack_signed(TRY(decoder->decode_hybrid_uint(stream, leaf_node.ctx)));
1729
0
                diff = (diff * leaf_node.multiplier) + leaf_node.offset;
1730
0
                auto const total = diff + prediction(neighborhood, self_prediction.prediction, leaf_node.predictor);
1731
1732
0
                if (tree.use_self_correcting_predictor())
1733
0
                    self_correcting_data.compute_errors(x, total);
1734
0
                channel.set(x, y, total);
1735
0
            }
1736
1737
0
            self_correcting_data.register_next_row();
1738
0
        }
1739
1740
0
        channel.set_decoded(true);
1741
0
    }
1742
0
    TRY(decoder->ensure_end_state());
1743
1744
0
    if (should_apply_transformation == ModularOptions::ApplyTransformations::Yes) {
1745
0
        for (auto const& tr : modular_data.transform.in_reverse())
1746
0
            TRY(apply_transformation(modular_data.channels, tr, bit_depth, modular_data.wp_params));
1747
0
    }
1748
1749
0
    return modular_data;
1750
0
}
1751
///
1752
1753
/// G.1.2 - LF channel dequantization weights
1754
struct GlobalModular {
1755
    Optional<EntropyDecoder> decoder;
1756
    MATree ma_tree;
1757
    ModularData modular_data;
1758
};
1759
1760
static ErrorOr<GlobalModular> read_global_modular(LittleEndianInputBitStream& stream,
1761
    IntSize frame_size,
1762
    FrameHeader const& frame_header,
1763
    ImageMetadata const& metadata)
1764
0
{
1765
0
    GlobalModular global_modular;
1766
1767
0
    auto const decode_ma_tree = TRY(stream.read_bit());
1768
1769
0
    if (decode_ma_tree)
1770
0
        global_modular.ma_tree = TRY(MATree::decode(stream, global_modular.decoder));
1771
1772
    // The decoder then decodes a modular sub-bitstream (Annex H), where
1773
    // the number of channels is computed as follows:
1774
1775
0
    auto num_channels = metadata.num_extra_channels;
1776
0
    if (frame_header.encoding == Encoding::kModular) {
1777
0
        if (!frame_header.do_YCbCr && !metadata.xyb_encoded
1778
0
            && metadata.colour_encoding.colour_space == ColourEncoding::ColourSpace::kGrey) {
1779
0
            num_channels += 1;
1780
0
        } else {
1781
0
            num_channels += 3;
1782
0
        }
1783
0
    }
1784
1785
0
    auto channels = TRY(FixedArray<ChannelInfo>::create(num_channels));
1786
0
    channels.fill_with(ChannelInfo::from_size(frame_size));
1787
1788
0
    if (channels.is_empty())
1789
0
        return global_modular;
1790
1791
    // "No inverse transforms are applied yet."
1792
0
    global_modular.modular_data = TRY(read_modular_bitstream(stream,
1793
0
        {
1794
0
            .channels_info = channels,
1795
0
            .decoder = global_modular.decoder,
1796
0
            .global_tree = global_modular.ma_tree,
1797
0
            .group_dim = frame_header.group_dim(),
1798
0
            .stream_index = 0,
1799
0
            .apply_transformations = ModularOptions::ApplyTransformations::No,
1800
0
            .bit_depth = metadata.bit_depth.bits_per_sample,
1801
0
        }));
1802
1803
0
    return global_modular;
1804
0
}
1805
///
1806
1807
/// K.3.1  Patches decoding
1808
struct Patch {
1809
    u32 width {};
1810
    u32 height {};
1811
1812
    u32 ref {};
1813
1814
    u32 x0 {};
1815
    u32 y0 {};
1816
1817
    u32 count {};
1818
1819
    // x[] and y[] in the spec
1820
    FixedArray<IntPoint> positions;
1821
1822
    // "blending: arrays of count blend mode information structures, which consists of arrays of mode, alpha_channel and clamp"
1823
    FixedArray<FixedArray<BlendingInfo>> blending;
1824
};
1825
1826
static ErrorOr<Patch> read_patch(LittleEndianInputBitStream& stream, EntropyDecoder& decoder, u32 num_extra_channels)
1827
0
{
1828
0
    Patch patch;
1829
0
    patch.ref = TRY(decoder.decode_hybrid_uint(stream, 1));
1830
0
    patch.x0 = TRY(decoder.decode_hybrid_uint(stream, 3));
1831
0
    patch.y0 = TRY(decoder.decode_hybrid_uint(stream, 3));
1832
0
    patch.width = TRY(decoder.decode_hybrid_uint(stream, 2)) + 1;
1833
0
    patch.height = TRY(decoder.decode_hybrid_uint(stream, 2)) + 1;
1834
0
    patch.count = TRY(decoder.decode_hybrid_uint(stream, 7)) + 1;
1835
1836
0
    patch.positions = TRY(FixedArray<IntPoint>::create(patch.count));
1837
0
    patch.blending = TRY(FixedArray<FixedArray<BlendingInfo>>::create(patch.count));
1838
0
    for (auto& array : patch.blending)
1839
0
        array = TRY(FixedArray<BlendingInfo>::create(num_extra_channels + 1));
1840
1841
0
    for (u32 j = 0; j < patch.count; j++) {
1842
0
        if (j == 0) {
1843
0
            auto position = IntPoint {
1844
0
                TRY(decoder.decode_hybrid_uint(stream, 4)),
1845
0
                TRY(decoder.decode_hybrid_uint(stream, 4)),
1846
0
            };
1847
0
            patch.positions[j] = position;
1848
0
        } else {
1849
0
            auto position = IntPoint {
1850
0
                unpack_signed(TRY(decoder.decode_hybrid_uint(stream, 6))) + patch.positions[j - 1].x(),
1851
0
                unpack_signed(TRY(decoder.decode_hybrid_uint(stream, 6))) + patch.positions[j - 1].y(),
1852
0
            };
1853
0
            patch.positions[j] = position;
1854
0
        }
1855
1856
        // FIXME: Bail out if this condition is not respected
1857
        /* the width x height rectangle with top-left coordinates (x, y)
1858
           is fully contained within the frame */
1859
1860
0
        for (u32 k = 0; k < num_extra_channels + 1; k++) {
1861
0
            u8 mode = TRY(decoder.decode_hybrid_uint(stream, 5));
1862
1863
            /* mode < 8 */
1864
0
            if (mode >= 8)
1865
0
                return Error::from_string_literal("JPEGXLLoader: Invalid mode when reading patches");
1866
0
            patch.blending[j][k].mode = static_cast<BlendingInfo::BlendMode>(mode);
1867
            // FIXME: The condition is supposed to be "/* there is more than 1 alpha channel */"
1868
            //        rather than num_extra_channels > 1
1869
0
            if (mode > 3 && num_extra_channels > 1) {
1870
0
                patch.blending[j][k].alpha_channel = TRY(decoder.decode_hybrid_uint(stream, 8));
1871
                // FIXME: Ensure that condition
1872
                /* this is a valid index of an extra channel */
1873
0
            }
1874
0
            if (mode > 2)
1875
0
                patch.blending[j][k].clamp = TRY(decoder.decode_hybrid_uint(stream, 9));
1876
0
        }
1877
0
    }
1878
1879
0
    return patch;
1880
0
}
1881
1882
static ErrorOr<FixedArray<Patch>> read_patches(LittleEndianInputBitStream& stream, u32 num_extra_channels)
1883
0
{
1884
0
    auto decoder = TRY(EntropyDecoder::create(stream, 10));
1885
0
    u32 const num_patches = TRY(decoder.decode_hybrid_uint(stream, 0));
1886
1887
0
    auto patches = TRY(FixedArray<Patch>::create(num_patches));
1888
0
    for (auto& patch : patches)
1889
0
        patch = TRY(read_patch(stream, decoder, num_extra_channels));
1890
1891
0
    TRY(decoder.ensure_end_state());
1892
0
    return patches;
1893
0
}
1894
///
1895
1896
/// I.2.1 - Quantizer
1897
struct Quantizer {
1898
    u32 global_scale {};
1899
    u32 quant_lf {};
1900
};
1901
1902
static ErrorOr<Quantizer> read_quantizer(LittleEndianInputBitStream& stream)
1903
0
{
1904
0
    Quantizer quantizer;
1905
0
    quantizer.global_scale = U32(1 + TRY(stream.read_bits(11)), 2049 + TRY(stream.read_bits(11)), 4097 + TRY(stream.read_bits(12)), 8193 + TRY(stream.read_bits(16)));
1906
0
    quantizer.quant_lf = U32(16, 1 + TRY(stream.read_bits(5)), 1 + TRY(stream.read_bits(8)), 1 + TRY(stream.read_bits(16)));
1907
1908
0
    return quantizer;
1909
0
}
1910
///
1911
1912
/// I.2.2 - HF block context decoding
1913
struct HFBlockContext {
1914
    Vector<u32> block_ctx_map {};
1915
    Vector<u32> qf_thresholds {};
1916
    Array<Vector<i32>, 3> lf_thresholds {};
1917
};
1918
1919
static ErrorOr<HFBlockContext> read_hf_block_context(LittleEndianInputBitStream& stream)
1920
0
{
1921
0
    HFBlockContext hf_block_context;
1922
1923
0
    if (TRY(stream.read_bit())) {
1924
0
        hf_block_context.block_ctx_map = { 0, 1, 2, 2, 3, 3, 4, 5, 6, 6, 6, 6, 6,
1925
0
            7, 8, 9, 9, 10, 11, 12, 13, 14, 14, 14, 14, 14,
1926
0
            7, 8, 9, 9, 10, 11, 12, 13, 14, 14, 14, 14, 14 };
1927
0
    } else {
1928
0
        Array<u8, 3> nb_lf_thr {};
1929
1930
0
        for (u8 i = 0; i < 3; i++) {
1931
0
            nb_lf_thr[i] = TRY(stream.read_bits(4));
1932
0
            for (u8 j = 0; j < nb_lf_thr[i]; j++) {
1933
0
                i32 t = unpack_signed(U32(TRY(stream.read_bits(4)), 16 + TRY(stream.read_bits(8)), 272 + TRY(stream.read_bits(16)), 65808 + TRY(stream.read_bits(32))));
1934
0
                TRY(hf_block_context.lf_thresholds[i].try_append(t));
1935
0
            }
1936
0
        }
1937
1938
0
        u8 nb_qf_thr = TRY(stream.read_bits(4));
1939
0
        for (u8 i = 0; i < nb_qf_thr; i++) {
1940
0
            u32 t = 1 + U32(TRY(stream.read_bits(2)), 4 + TRY(stream.read_bits(3)), 12 + TRY(stream.read_bits(5)), 44 + TRY(stream.read_bits(8)));
1941
0
            TRY(hf_block_context.qf_thresholds.try_append(t));
1942
0
        }
1943
1944
0
        u32 bsize = 39 * (nb_qf_thr + 1) * (nb_lf_thr[0] + 1) * (nb_lf_thr[1] + 1) * (nb_lf_thr[2] + 1);
1945
1946
0
        if (bsize > 39 * 64)
1947
0
            return Error::from_string_literal("JPEGXLLoader: Invalid bsize in read HF Block Context");
1948
1949
        /* num_dist = bsize <= 39 * 64 and the resulting num_clusters <= 16 */
1950
0
        auto [clusters, num_clusters] = TRY(read_pre_clustered_distributions(stream, bsize));
1951
0
        hf_block_context.block_ctx_map = move(clusters);
1952
0
        if (num_clusters > 16)
1953
0
            return Error::from_string_literal("JPEGXLLoader: Invalid num_clusters in HF Block Context");
1954
0
    }
1955
1956
0
    return hf_block_context;
1957
0
}
1958
///
1959
1960
/// I.2.3 - LF channel correlation factors
1961
struct LfChannelCorrelation {
1962
    u32 colour_factor { 84 };
1963
    f32 base_correlation_x { 0.0 };
1964
    f32 base_correlation_b { 1.0 };
1965
    u8 x_factor_lf { 128 };
1966
    u8 b_factor_lf { 128 };
1967
};
1968
1969
static ErrorOr<LfChannelCorrelation> read_lf_channel_correlation(LittleEndianInputBitStream& stream)
1970
0
{
1971
0
    LfChannelCorrelation lf_channel_correlation;
1972
1973
0
    bool all_default = TRY(stream.read_bit());
1974
0
    if (!all_default) {
1975
0
        lf_channel_correlation.colour_factor = U32(84, 256, 2 + TRY(stream.read_bits(8)), 258 + TRY(stream.read_bits(16)));
1976
0
        lf_channel_correlation.base_correlation_x = TRY(F16(stream));
1977
0
        lf_channel_correlation.base_correlation_b = TRY(F16(stream));
1978
0
        lf_channel_correlation.x_factor_lf = TRY(F16(stream));
1979
0
        lf_channel_correlation.b_factor_lf = TRY(F16(stream));
1980
0
    }
1981
1982
0
    return lf_channel_correlation;
1983
0
}
1984
///
1985
1986
/// G.1 - LfGlobal
1987
struct LfGlobal {
1988
    FixedArray<Patch> patches;
1989
    LfChannelDequantization lf_dequant;
1990
    Quantizer quantizer;
1991
    HFBlockContext hf_block_ctx;
1992
    LfChannelCorrelation lf_chan_corr;
1993
    GlobalModular gmodular;
1994
};
1995
1996
static ErrorOr<LfGlobal> read_lf_global(LittleEndianInputBitStream& stream,
1997
    IntSize frame_size,
1998
    FrameHeader const& frame_header,
1999
    ImageMetadata const& metadata)
2000
0
{
2001
0
    LfGlobal lf_global;
2002
2003
0
    if (frame_header.flags != FrameHeader::Flags::None) {
2004
0
        if (frame_header.flags & FrameHeader::Flags::kPatches) {
2005
0
            lf_global.patches = TRY(read_patches(stream, metadata.num_extra_channels));
2006
0
        }
2007
0
        if (frame_header.flags & FrameHeader::Flags::kSplines) {
2008
0
            return Error::from_string_literal("JPEGXLLoader: Implement Splines");
2009
0
        }
2010
0
        if (frame_header.flags & FrameHeader::Flags::kNoise) {
2011
0
            return Error::from_string_literal("JPEGXLLoader: Implement Noise");
2012
0
        }
2013
0
    }
2014
2015
0
    lf_global.lf_dequant = TRY(read_lf_channel_dequantization(stream));
2016
2017
0
    if (frame_header.encoding == Encoding::kVarDCT) {
2018
0
        lf_global.quantizer = TRY(read_quantizer(stream));
2019
0
        lf_global.hf_block_ctx = TRY(read_hf_block_context(stream));
2020
0
        lf_global.lf_chan_corr = TRY(read_lf_channel_correlation(stream));
2021
0
    }
2022
2023
0
    lf_global.gmodular = TRY(read_global_modular(stream, frame_size, frame_header, metadata));
2024
2025
0
    return lf_global;
2026
0
}
2027
///
2028
2029
/// Helpers to decode groups for the GlobalModular
2030
static IntRect rect_for_group(ChannelInfo const& info, u32 group_dim, u32 group_index)
2031
0
{
2032
0
    u32 horizontal_group_dim = group_dim >> info.hshift;
2033
0
    u32 vertical_group_dim = group_dim >> info.vshift;
2034
2035
0
    IntRect rect(0, 0, horizontal_group_dim, vertical_group_dim);
2036
2037
0
    auto nb_groups_per_row = (info.width + horizontal_group_dim - 1) / horizontal_group_dim;
2038
0
    auto group_x = group_index % nb_groups_per_row;
2039
0
    rect.set_x(group_x * horizontal_group_dim);
2040
0
    if (group_x == nb_groups_per_row - 1 && info.width % horizontal_group_dim != 0) {
2041
0
        rect.set_width(info.width % horizontal_group_dim);
2042
0
    }
2043
2044
0
    auto nb_groups_per_column = (info.height + vertical_group_dim - 1) / vertical_group_dim;
2045
0
    auto group_y = group_index / nb_groups_per_row;
2046
0
    rect.set_y(group_y * vertical_group_dim);
2047
0
    if (group_y == nb_groups_per_column - 1 && info.height % vertical_group_dim != 0) {
2048
0
        rect.set_height(info.height % vertical_group_dim);
2049
0
    }
2050
2051
0
    return rect;
2052
0
}
2053
2054
struct GroupOptions {
2055
    GlobalModular& global_modular;
2056
    FrameHeader const& frame_header;
2057
    u32 group_index {};
2058
    u32 stream_index {};
2059
    u32 bit_depth {};
2060
    u32 group_dim {};
2061
};
2062
2063
template<CallableAs<bool, Channel const&> F1, CallableAs<void, ChannelInfo const&> F2>
2064
static ErrorOr<void> read_group_data(
2065
    LittleEndianInputBitStream& stream,
2066
    GroupOptions&& options,
2067
    F1&& match_decode_conditions,
2068
    F2&& debug_print)
2069
0
{
2070
0
    auto& [global_modular, frame_header, group_index, stream_index, bit_depth, group_dim] = options;
2071
2072
0
    Vector<ChannelInfo> channels_info;
2073
0
    Vector<Channel&> original_channels;
2074
0
    auto& channels = global_modular.modular_data.channels;
2075
0
    for (auto& channel : channels) {
2076
0
        if (!match_decode_conditions(channel))
2077
0
            continue;
2078
2079
0
        auto rect_size = rect_for_group(channel.info(), group_dim, group_index).size();
2080
0
        TRY(channels_info.try_append({
2081
0
            .width = static_cast<u32>(rect_size.width()),
2082
0
            .height = static_cast<u32>(rect_size.height()),
2083
0
            .hshift = channel.hshift(),
2084
0
            .vshift = channel.vshift(),
2085
0
        }));
2086
0
        TRY(original_channels.try_append(channel));
2087
0
    }
2088
0
    if (channels_info.is_empty())
2089
0
        return {};
2090
2091
    if constexpr (JPEGXL_DEBUG)
2092
        debug_print(original_channels[0].info());
2093
2094
0
    auto decoded = TRY(read_modular_bitstream(stream,
2095
0
        {
2096
0
            .channels_info = channels_info,
2097
0
            .decoder = global_modular.decoder,
2098
0
            .global_tree = global_modular.ma_tree,
2099
0
            .group_dim = group_dim,
2100
0
            .stream_index = stream_index,
2101
0
            .apply_transformations = ModularOptions::ApplyTransformations::Yes,
2102
0
            .bit_depth = bit_depth,
2103
0
        }));
2104
2105
    // The decoded modular group data is then copied into the partially decoded GlobalModular image in the corresponding positions.
2106
0
    for (u32 i = 0; i < original_channels.size(); ++i) {
2107
0
        auto destination = rect_for_group(original_channels[i].info(), group_dim, group_index);
2108
0
        original_channels[i].copy_from(destination, decoded.channels[i]);
2109
0
    }
2110
2111
0
    return {};
2112
0
}
Unexecuted instantiation: JPEGXLLoader.cpp:_ZN3Gfx6JPEGXLL15read_group_dataITkN2AK8Concepts10CallableAsIbRKNS0_6Detail7ChannelIiEEEEZNS0_L13read_lf_groupERNS2_26LittleEndianInputBitStreamEONS0_14LFGroupOptionsEONS0_20LFGroupVarDCTOptionsEE3$_0TkNS4_IvRKNS0_11ChannelInfoEEEZNS0_L13read_lf_groupESB_SD_SF_E3$_1EENS2_7ErrorOrIvNS2_5ErrorEEESB_ONS0_12GroupOptionsEOT_OT0_
Unexecuted instantiation: JPEGXLLoader.cpp:_ZN3Gfx6JPEGXLL15read_group_dataITkN2AK8Concepts10CallableAsIbRKNS0_6Detail7ChannelIiEEEEZNS0_L23read_modular_group_dataERNS2_26LittleEndianInputBitStreamERNS0_16PassGroupOptionsERKNS0_23PassGroupModularOptionsEE3$_0TkNS4_IvRKNS0_11ChannelInfoEEEZNS0_L23read_modular_group_dataESB_SD_SG_E3$_1EENS2_7ErrorOrIvNS2_5ErrorEEESB_ONS0_12GroupOptionsEOT_OT0_
2113
///
2114
2115
/// G.2 - LfGroup
2116
static constexpr i32 DCT_UNINITIALIZED = -2;
2117
static constexpr i32 DCT_COVERED = -1;
2118
2119
struct VarDCTLfGroup {
2120
    Channel x_from_y;
2121
    Channel b_from_y;
2122
    // dct_select hold DCT information in the top-left corner of every varblock.
2123
    // -1 means occupied by a varblock but non top-left.
2124
    // -2 is the default value, which shouldn't be found after proper initialization.
2125
    Channel dct_select;
2126
    Channel hf_mul;
2127
    Channel sharpness;
2128
};
2129
2130
struct LFGroupOptions {
2131
    GlobalModular& global_modular;
2132
    FrameHeader const& frame_header;
2133
    u32 group_index {};
2134
    u32 stream_index {};
2135
    u32 bit_depth {};
2136
};
2137
2138
// G.2.2 - LF coefficients
2139
static ErrorOr<void> read_lf_coefficients(LittleEndianInputBitStream&, FrameHeader const& frame_header)
2140
0
{
2141
    // "If the kUseLfFrame flag in frame_header is set, this subclause is skipped"
2142
0
    if (frame_header.flags & FrameHeader::Flags::kUseLfFrame)
2143
0
        return {};
2144
2145
0
    return Error::from_string_literal("JPEGXLLoader: Implement reading LF coefficients");
2146
0
}
2147
2148
// I.1 - Transform types
2149
enum class TransformType : u8 {
2150
    DCT8x8 = 0,
2151
    Hornuss = 1,
2152
    DCT2x2 = 2,
2153
    DCT4x4 = 3,
2154
    DCT16x16 = 4,
2155
    DCT32x32 = 5,
2156
    DCT16x8 = 6,
2157
    DCT8x16 = 7,
2158
    DCT32x8 = 8,
2159
    DCT8x32 = 9,
2160
    DCT32x16 = 10,
2161
    DCT16x32 = 11,
2162
    DCT4x8 = 12,
2163
    DCT8x4 = 13,
2164
    AFV0 = 14,
2165
    AFV1 = 15,
2166
    AFV2 = 16,
2167
    AFV3 = 17,
2168
    DCT64x64 = 18,
2169
    DCT64x32 = 19,
2170
    DCT32x64 = 20,
2171
    DCT128x128 = 21,
2172
    DCT128x64 = 22,
2173
    DCT64x128 = 23,
2174
    DCT256x256 = 24,
2175
    DCT256x128 = 25,
2176
    DCT128x256 = 26,
2177
};
2178
2179
// NOTE: In the spec, DCT matrices use "matrices order" so DCT16x8 is actually
2180
//       16 rows and 8 columns. This function return the size in "image order"
2181
//       with columns first and rows in second.
2182
static Size<u32> dct_select_to_dct_size(TransformType t)
2183
0
{
2184
0
    switch (t) {
2185
0
    case TransformType::DCT8x8:
2186
0
    case TransformType::Hornuss:
2187
0
    case TransformType::DCT2x2:
2188
0
    case TransformType::DCT4x4:
2189
0
        return { 1, 1 };
2190
0
    case TransformType::DCT16x16:
2191
0
        return { 2, 2 };
2192
0
    case TransformType::DCT32x32:
2193
0
        return { 4, 4 };
2194
0
    case TransformType::DCT16x8:
2195
0
        return { 1, 2 };
2196
0
    case TransformType::DCT8x16:
2197
0
        return { 2, 1 };
2198
0
    case TransformType::DCT32x8:
2199
0
        return { 1, 4 };
2200
0
    case TransformType::DCT8x32:
2201
0
        return { 4, 1 };
2202
0
    case TransformType::DCT32x16:
2203
0
        return { 2, 4 };
2204
0
    case TransformType::DCT16x32:
2205
0
        return { 4, 2 };
2206
0
    case TransformType::DCT4x8:
2207
0
    case TransformType::DCT8x4:
2208
0
        return { 1, 1 };
2209
0
    case TransformType::AFV0:
2210
0
    case TransformType::AFV1:
2211
0
    case TransformType::AFV2:
2212
0
    case TransformType::AFV3:
2213
0
        return { 1, 1 };
2214
0
    case TransformType::DCT64x64:
2215
0
        return { 8, 8 };
2216
0
    case TransformType::DCT64x32:
2217
0
        return { 4, 8 };
2218
0
    case TransformType::DCT32x64:
2219
0
        return { 8, 4 };
2220
0
    case TransformType::DCT128x128:
2221
0
        return { 16, 16 };
2222
0
    case TransformType::DCT128x64:
2223
0
        return { 8, 16 };
2224
0
    case TransformType::DCT64x128:
2225
0
        return { 16, 8 };
2226
0
    case TransformType::DCT256x256:
2227
0
        return { 32, 32 };
2228
0
    case TransformType::DCT256x128:
2229
0
        return { 16, 32 };
2230
0
    case TransformType::DCT128x256:
2231
0
        return { 32, 16 };
2232
0
    default:
2233
0
        VERIFY_NOT_REACHED();
2234
0
    }
2235
0
}
2236
2237
static Size<u32> dct_select_to_image_size(TransformType t)
2238
0
{
2239
0
    return dct_select_to_dct_size(t).scaled(8);
2240
0
}
2241
2242
// Table I.7 — Order ID for DctSelect values
2243
static u8 dct_select_to_order_id(TransformType t)
2244
0
{
2245
0
    switch (t) {
2246
0
    case TransformType::DCT8x8:
2247
0
        return 0;
2248
0
    case TransformType::Hornuss:
2249
0
    case TransformType::DCT2x2:
2250
0
    case TransformType::DCT4x4:
2251
0
    case TransformType::DCT4x8:
2252
0
    case TransformType::DCT8x4:
2253
0
    case TransformType::AFV0:
2254
0
    case TransformType::AFV1:
2255
0
    case TransformType::AFV2:
2256
0
    case TransformType::AFV3:
2257
0
        return 1;
2258
0
    case TransformType::DCT16x16:
2259
0
        return 2;
2260
0
    case TransformType::DCT32x32:
2261
0
        return 3;
2262
0
    case TransformType::DCT16x8:
2263
0
    case TransformType::DCT8x16:
2264
0
        return 4;
2265
0
    case TransformType::DCT32x8:
2266
0
    case TransformType::DCT8x32:
2267
0
        return 5;
2268
0
    case TransformType::DCT32x16:
2269
0
    case TransformType::DCT16x32:
2270
0
        return 6;
2271
0
    case TransformType::DCT64x64:
2272
0
        return 7;
2273
0
    case TransformType::DCT64x32:
2274
0
    case TransformType::DCT32x64:
2275
0
        return 8;
2276
0
    case TransformType::DCT128x128:
2277
0
        return 9;
2278
0
    case TransformType::DCT128x64:
2279
0
    case TransformType::DCT64x128:
2280
0
        return 10;
2281
0
    case TransformType::DCT256x256:
2282
0
        return 11;
2283
0
    case TransformType::DCT256x128:
2284
0
    case TransformType::DCT128x256:
2285
0
        return 12;
2286
0
    default:
2287
0
        VERIFY_NOT_REACHED();
2288
0
    }
2289
0
}
2290
2291
struct LFGroupVarDCTOptions {
2292
    Vector<Optional<VarDCTLfGroup>>& group_data;
2293
    IntSize frame_size;
2294
    u32 num_lf_group {};
2295
};
2296
2297
// G.2.4 - HF metadata
2298
static ErrorOr<void> read_hf_metadata(LittleEndianInputBitStream& stream,
2299
    LFGroupOptions& options,
2300
    LFGroupVarDCTOptions const& var_dct_options,
2301
    u32 lf_group_dim)
2302
0
{
2303
2304
0
    auto group_size = rect_for_group(ChannelInfo::from_size(var_dct_options.frame_size), lf_group_dim, options.group_index).size();
2305
2306
    // "The decoder reads nb_blocks = 1 + u(ceil(log2(ceil(width / 8) * ceil(height / 8))))."
2307
0
    u32 nb_blocks = 1 + TRY(stream.read_bits(ceil(log2(ceil_div(group_size.width(), 8) * ceil_div(group_size.height(), 8)))));
2308
2309
    // "Then, the decoder reads a Modular sub-bitstream as described in Annex H, for an image with four channels."
2310
0
    Vector<ChannelInfo> channels_info;
2311
0
    TRY(channels_info.try_ensure_capacity(4));
2312
    // "the first two channels have ceil(height / 64) rows and ceil(width / 64) columns"
2313
0
    auto color_correlation_channels_size = IntSize { ceil_div(group_size.width(), 64), ceil_div(group_size.height(), 64) };
2314
0
    channels_info.unchecked_append(ChannelInfo::from_size(color_correlation_channels_size));
2315
0
    channels_info.unchecked_append(ChannelInfo::from_size(color_correlation_channels_size));
2316
    // "the third channel has two rows and nb_blocks columns"
2317
0
    channels_info.unchecked_append(ChannelInfo::from_size(IntSize(nb_blocks, 2)));
2318
    // "and the fourth channel has ceil(height / 8) rows and ceil(width / 8) columns"
2319
0
    channels_info.unchecked_append(ChannelInfo::from_size({ ceil_div(group_size.width(), 8), ceil_div(group_size.height(), 8) }));
2320
2321
    // "The stream index is defined as follows:
2322
    //  - for ModularLfGroup: 1 + num_lf_groups + LF group index;
2323
    //  - for HFMetadata: 1 + 2 * num_lf_groups + LF group index;"
2324
    // We pass ModularLfGroup's stream index in LFGroupOptions, so we
2325
    // just need to add `num_lf_groups` here.
2326
0
    auto stream_index = options.stream_index + var_dct_options.num_lf_group;
2327
2328
0
    auto decoded_channels = TRY(read_modular_bitstream(stream,
2329
0
                                    {
2330
0
                                        .channels_info = channels_info,
2331
0
                                        .decoder = options.global_modular.decoder,
2332
0
                                        .global_tree = options.global_modular.ma_tree,
2333
0
                                        .group_dim = lf_group_dim,
2334
0
                                        .stream_index = stream_index,
2335
0
                                        .apply_transformations = ModularOptions::ApplyTransformations::Yes,
2336
0
                                        .bit_depth = options.bit_depth,
2337
0
                                    }))
2338
0
                                .channels;
2339
2340
    // "The DctSelect and HfMul fields are derived from the first and second rows of BlockInfo.
2341
    // These two fields have ceil(height / 8) rows and ceil(width / 8) columns."
2342
0
    auto derived_size = IntSize(ceil_div(group_size.width(), 8), ceil_div(group_size.height(), 8));
2343
0
    auto dct_select = TRY(Channel::create(ChannelInfo::from_size(derived_size)));
2344
0
    auto hf_mul = TRY(Channel::create(ChannelInfo::from_size(derived_size)));
2345
2346
0
    dct_select.fill(DCT_UNINITIALIZED);
2347
2348
0
    i32 x = 0;
2349
0
    i32 y = 0;
2350
0
    auto update_next_valid_position = [&]() {
2351
        // "This position is the earliest block in raster order that is not already covered by
2352
        // other varblocks. The positioned varblock is completely contained in the current LF
2353
        // group, does not cross group boundaries, and also does not overlap with
2354
        // already-positioned varblocks."
2355
2356
        // FIXME: There has to be a smarter way of doing this.
2357
0
        while (dct_select.get(x, y) != DCT_UNINITIALIZED) {
2358
0
            if (x == derived_size.width() - 1) {
2359
0
                x = 0;
2360
0
                y += 1;
2361
0
                continue;
2362
0
            }
2363
0
            ++x;
2364
0
        }
2365
0
    };
2366
2367
    // "They are reconstructed by iterating over the columns of BlockInfo to obtain a varblock
2368
    // transform type type (the sample at the first row) and a quantization multiplier mul (the
2369
    // sample at the second row)."
2370
0
    auto const& block_info = decoded_channels[2];
2371
0
    for (u32 column = 0; column < nb_blocks; ++column) {
2372
0
        auto type = block_info.get(column, 0);
2373
0
        if (type > 26)
2374
0
            return Error::from_string_literal("JPEGXLLoader: Invalid DctSelect value");
2375
2376
0
        auto mul = block_info.get(column, 1);
2377
2378
        // "The type is a DctSelect sample and is stored at the coordinates of the top-left
2379
        // 8 × 8 rectangle of the varblock."
2380
0
        dct_select.set(x, y, type);
2381
        // "The HfMul sample is stored at the same position and gets the value 1 + mul."
2382
0
        hf_mul.set(x, y, 1 + mul);
2383
2384
        // We fill the whole surface of the varblock as a way to check that
2385
        // varblocks don't overlap.
2386
0
        auto dct_size = dct_select_to_dct_size(static_cast<TransformType>(type));
2387
0
        for (u8 y_offset = 0; y_offset < dct_size.height(); ++y_offset) {
2388
0
            for (u8 x_offset = 0; x_offset < dct_size.width(); ++x_offset) {
2389
0
                if (y_offset == 0 && x_offset == 0)
2390
0
                    continue;
2391
0
                if (dct_select.get(x + x_offset, y + y_offset) != DCT_UNINITIALIZED)
2392
0
                    return Error::from_string_literal("JPEGXLLoader: Invalid varblocks pattern");
2393
0
                dct_select.set(x + x_offset, y + y_offset, DCT_COVERED);
2394
0
            }
2395
0
        }
2396
0
        if (column != nb_blocks - 1)
2397
0
            update_next_valid_position();
2398
0
    }
2399
2400
    // FIXME: Ensure that dct_select contains no DCT_UNINITIALIZED.
2401
2402
0
    var_dct_options.group_data[options.group_index] = VarDCTLfGroup {
2403
0
        .x_from_y = move(decoded_channels[0]),
2404
0
        .b_from_y = move(decoded_channels[1]),
2405
0
        .dct_select = move(dct_select),
2406
0
        .hf_mul = move(hf_mul),
2407
0
        .sharpness = move(decoded_channels[2]),
2408
0
    };
2409
0
    return {};
2410
0
}
2411
2412
static ErrorOr<void> read_lf_group(LittleEndianInputBitStream& stream,
2413
    LFGroupOptions&& options,
2414
    LFGroupVarDCTOptions&& var_dct_options)
2415
0
{
2416
0
    auto const& [global_modular, frame_header, group_index, stream_index, bit_depth] = options;
2417
2418
0
    if (options.frame_header.encoding == Encoding::kVarDCT) {
2419
0
        if (var_dct_options.group_data.is_empty())
2420
0
            TRY(var_dct_options.group_data.try_resize(var_dct_options.num_lf_group));
2421
0
    }
2422
2423
    // LF coefficients
2424
0
    if (frame_header.encoding == Encoding::kVarDCT)
2425
0
        TRY(read_lf_coefficients(stream, frame_header));
2426
2427
    // ModularLfGroup
2428
0
    u32 lf_group_dim = frame_header.group_dim() * 8;
2429
2430
0
    auto match_decoding_conditions = [](Channel const& channel) {
2431
0
        if (channel.decoded())
2432
0
            return false;
2433
0
        if (channel.hshift() < 3 || channel.vshift() < 3)
2434
0
            return false;
2435
0
        return true;
2436
0
    };
2437
0
    TRY(read_group_data(
2438
0
        stream,
2439
0
        GroupOptions {
2440
0
            .global_modular = global_modular,
2441
0
            .frame_header = frame_header,
2442
0
            .group_index = group_index,
2443
0
            .stream_index = stream_index,
2444
0
            .bit_depth = bit_depth,
2445
0
            .group_dim = lf_group_dim },
2446
0
        move(match_decoding_conditions),
2447
0
        [&](auto const& first_channel) { dbgln("Decoding LFGroup {} for rectangle {}", group_index, rect_for_group(first_channel, lf_group_dim, group_index)); }));
2448
2449
    // HF metadata
2450
0
    if (options.frame_header.encoding == Encoding::kVarDCT)
2451
0
        TRY(read_hf_metadata(stream, options, var_dct_options, lf_group_dim));
2452
2453
0
    return {};
2454
0
}
2455
///
2456
2457
/// G.3 - HfGlobal
2458
struct HfGlobalPassMetadata {
2459
    // I.3.1 - HF coefficient order
2460
    // 13 Order ID and 3 color component.
2461
    // These spans refer to either the static, default values or
2462
    // a Vector of backing_data.
2463
    DCTOrderDescription order;
2464
    Vector<Vector<Point<u32>>> backing_data;
2465
2466
    // I.3.3 - HF coefficient histograms
2467
    u32 nb_block_ctx {};
2468
    EntropyDecoder decoder;
2469
};
2470
2471
struct HfGlobal {
2472
    // Dequantization matrices.
2473
    u32 num_hf_presets {};
2474
    FixedArray<HfGlobalPassMetadata> hf_passes;
2475
};
2476
2477
// I.2.4 - Dequantization matrices
2478
static ErrorOr<void> read_quantization_matrices(LittleEndianInputBitStream& stream)
2479
0
{
2480
    // "First, the decoder reads a Bool(). If this is true, all matrices have their default encoding."
2481
0
    bool is_default = TRY(stream.read_bit());
2482
2483
0
    if (!is_default)
2484
0
        return Error::from_string_literal("JPEGXLLoader: Implement reading quantization matrices");
2485
2486
0
    return {};
2487
0
}
2488
2489
// I.3 - HfPass
2490
static ErrorOr<void> read_hf_passes(LittleEndianInputBitStream& stream, LfGlobal const& lf_global, HfGlobal& hf_global)
2491
0
{
2492
    // I.3.1 - HF coefficient order
2493
2494
    // "The decoder first reads used_orders as U32(0x5F, 0x13, 0x00, u(13))."
2495
0
    u32 used_orders = U32(0x5F, 0x13, 0x00, TRY(stream.read_bits(13)));
2496
2497
    // "If used_orders != 0, it reads 8 pre-clustered distributions as specified in C.1."
2498
0
    Optional<EntropyDecoder> decoder;
2499
0
    if (used_orders != 0)
2500
0
        decoder = TRY(EntropyDecoder::create(stream, 8));
2501
2502
    // "It then reads HF coefficient orders order[p][b][c] as specified by the code below,
2503
    // where p is the index of the current pass, b is an Order ID (see Table I.7), c is a
2504
    // component index, and natural_coeff_order[b] is the natural coefficient order for Order
2505
    // ID b, as specified in I.3.2."
2506
0
    auto const& natural_coeff_order = *TRY(DCTNaturalOrder::the());
2507
0
    for (auto& pass_data : hf_global.hf_passes) {
2508
0
        for (u8 b = 0; b < 13; b++) {
2509
0
            for (u8 c = 0; c < 3; c++) {
2510
0
                if ((used_orders & (1 << b)) != 0) {
2511
                    // "DecodePermutation(b) is defined as follows. The decoder reads a permutation
2512
                    // nat_ord_perm from a single stream (shared during the above loop) as specified
2513
                    // in F.3.2, where size is the number of coefficients covered by transforms with
2514
                    // Order ID b (so size == natural_coeff_order[b].size()) and skip = size / 64.
2515
0
                    auto size = natural_coeff_order[b][c].size();
2516
0
                    auto nat_ord_perm = TRY(decode_permutations(stream, *decoder, size, size / 64));
2517
2518
0
                    Vector<Point<u32>> local_order;
2519
0
                    TRY(local_order.try_resize(size));
2520
0
                    pass_data.order[b][c] = local_order.span();
2521
0
                    TRY(pass_data.backing_data.try_append(move(local_order)));
2522
2523
0
                    for (u32 i = 0; i < nat_ord_perm.size(); ++i)
2524
0
                        pass_data.order[b][c][i] = natural_coeff_order[b][c][nat_ord_perm[i]];
2525
0
                } else {
2526
0
                    pass_data.order[b][c] = natural_coeff_order[b][c];
2527
0
                }
2528
0
            }
2529
0
        }
2530
2531
        // I.3.3 - HF coefficient histograms
2532
        // "Let nb_block_ctx be equal to max(block_ctx_map) + 1."
2533
0
        auto max = lf_global.hf_block_ctx.block_ctx_map[0];
2534
0
        for (auto v : lf_global.hf_block_ctx.block_ctx_map) {
2535
0
            if (v > max)
2536
0
                max = v;
2537
0
        }
2538
0
        pass_data.nb_block_ctx = max + 1;
2539
2540
        // "The decoder reads a histogram with 495 * num_hf_presets * nb_block_ctx
2541
        // pre-clustered distributions D from the codestream as specified in C.1."
2542
0
        auto distributions = 495 * hf_global.num_hf_presets * pass_data.nb_block_ctx;
2543
0
        pass_data.decoder = TRY(EntropyDecoder::create(stream, distributions));
2544
0
    }
2545
2546
0
    if (decoder.has_value())
2547
0
        TRY(decoder->ensure_end_state());
2548
2549
0
    return {};
2550
0
}
2551
2552
static ErrorOr<HfGlobal> read_hf_global(LittleEndianInputBitStream& stream, LfGlobal const& lf_global, u32 num_groups, u32 num_passes)
2553
0
{
2554
0
    HfGlobal hf_global;
2555
2556
0
    TRY(read_quantization_matrices(stream));
2557
2558
    // I.2.6 - Number of HF decoding presets
2559
    // "The decoder reads num_hf_presets as u(ceil(log2(num_groups))) + 1."
2560
0
    hf_global.num_hf_presets = TRY(stream.read_bits(ceil(log2(num_groups)))) + 1;
2561
2562
0
    hf_global.hf_passes = TRY(FixedArray<HfGlobalPassMetadata>::create(num_passes));
2563
0
    TRY(read_hf_passes(stream, lf_global, hf_global));
2564
2565
0
    return hf_global;
2566
0
}
2567
///
2568
2569
/// G.3.2 - PassGroup
2570
struct PassGroupOptions {
2571
    GlobalModular& global_modular;
2572
    FrameHeader const& frame_header;
2573
    u32 group_index;
2574
    u32 pass_index;
2575
    u32 stream_index;
2576
};
2577
2578
struct PassGroupModularOptions {
2579
    u32 bit_depth {};
2580
};
2581
2582
// G.4.2 - Modular group data
2583
static ErrorOr<void> read_modular_group_data(LittleEndianInputBitStream& stream,
2584
    PassGroupOptions& options,
2585
    PassGroupModularOptions const& modular_options)
2586
0
{
2587
0
    auto& [global_modular, frame_header, group_index, pass_index, stream_index] = options;
2588
2589
0
    i8 max_shift = 3;
2590
0
    i8 min_shift = 0;
2591
2592
0
    if (pass_index != 0)
2593
0
        return Error::from_string_literal("JPEGXLLoader: Subsequent passes are not supported yet");
2594
2595
    // for every remaining channel in the partially decoded GlobalModular image (i.e. it is not a meta-channel,
2596
    // the channel dimensions exceed group_dim × group_dim, and hshift < 3 or vshift < 3, and the channel has
2597
    // not been already decoded in a previous pass)
2598
0
    auto match_decoding_conditions = [&](auto const& channel) {
2599
0
        if (channel.decoded())
2600
0
            return false;
2601
0
        auto channel_min_shift = min(channel.hshift(), channel.vshift());
2602
0
        if (channel_min_shift < min_shift || channel_min_shift >= max_shift)
2603
0
            return false;
2604
0
        return true;
2605
0
    };
2606
2607
0
    TRY(read_group_data(stream,
2608
0
        {
2609
0
            .global_modular = global_modular,
2610
0
            .frame_header = frame_header,
2611
0
            .group_index = group_index,
2612
0
            .stream_index = stream_index,
2613
0
            .bit_depth = modular_options.bit_depth,
2614
0
            .group_dim = frame_header.group_dim(),
2615
0
        },
2616
0
        move(match_decoding_conditions),
2617
0
        [&](auto const& first_channel) { dbgln_if(JPEGXL_DEBUG, "Decoding pass {} for rectangle {}", options.pass_index, rect_for_group(first_channel, frame_header.group_dim(), group_index)); }));
2618
2619
0
    return {};
2620
0
}
2621
2622
struct PassGroupVarDCTOptions {
2623
    LfGlobal const& lf_global;
2624
    Vector<Optional<VarDCTLfGroup>> const& lf_groups;
2625
    HfGlobal& hf_global;
2626
};
2627
2628
static constexpr Array CoeffFreqContext = to_array<u8>({ 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
2629
    15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
2630
    23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26,
2631
    27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30 });
2632
2633
static constexpr Array CoeffNumNonzeroContext = to_array<u8>({ 0, 0, 31, 62, 62, 93, 93, 93, 93, 123, 123, 123, 123,
2634
    152, 152, 152, 152, 152, 152, 152, 152, 180, 180, 180, 180, 180,
2635
    180, 180, 180, 180, 180, 180, 180, 206, 206, 206, 206, 206, 206,
2636
    206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206,
2637
    206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206 });
2638
2639
// I.4 - Decoding of quantized HF coefficients
2640
static ErrorOr<void> read_hf_coefficients(LittleEndianInputBitStream& stream,
2641
    PassGroupOptions const& options,
2642
    PassGroupVarDCTOptions&& var_dct_options)
2643
0
{
2644
0
    auto& hf_global = var_dct_options.hf_global;
2645
0
    auto& hf_pass = hf_global.hf_passes[options.pass_index];
2646
0
    auto const& hf_group = *var_dct_options.lf_groups[options.group_index];
2647
2648
0
    auto nb_block_ctx = hf_pass.nb_block_ctx;
2649
2650
0
    auto hfp = TRY(stream.read_bits(ceil(log2(hf_global.num_hf_presets))));
2651
0
    u32 clusters_size = 495 * nb_block_ctx;
2652
0
    u32 offset = clusters_size * hfp;
2653
2654
0
    Optional<ScopeGuard<Function<void()>>> restore_histogram;
2655
0
    TRY(hf_pass.decoder.temporarily_restrict_histogram(restore_histogram, offset, clusters_size));
2656
0
    auto& decoder = hf_pass.decoder;
2657
2658
    // "After selecting the histogram and coefficient order, the decoder reads symbols
2659
    // from an entropy-coded stream, as specified in C.3.3."
2660
2661
    // "The decoder proceeds by decoding varblocks in raster order;"
2662
0
    auto const& varblock_description = hf_group.dct_select;
2663
0
    auto const& order = hf_pass.order;
2664
2665
0
    Array<Channel, 3> non_zeros_channels = {
2666
0
        TRY(Channel::create(varblock_description.info())),
2667
0
        TRY(Channel::create(varblock_description.info())),
2668
0
        TRY(Channel::create(varblock_description.info()))
2669
0
    };
2670
2671
    // "If the kUseLfFrame flag in frame_header is set [...] the quantized LF coefficients LfQuant are all set to −∞, that is,
2672
    // regardless of lf_thresholds, the value of lf_idx at the end of the function BlockContext() (I.4) is always equal to zero."
2673
0
    Array<i32, 3> qdc;
2674
0
    qdc.fill(NumericLimits<i32>::min());
2675
2676
0
    for (u32 y = 0; y < varblock_description.height(); ++y) {
2677
0
        for (u32 x = 0; x < varblock_description.width(); ++x) {
2678
0
            auto dct_type = varblock_description.get(x, y);
2679
0
            if (dct_type == DCT_UNINITIALIZED || dct_type == DCT_COVERED)
2680
0
                continue;
2681
            // "For each varblock of size W × H,"
2682
0
            auto transform_type = static_cast<TransformType>(dct_type);
2683
0
            auto varblock_size = dct_select_to_image_size(transform_type);
2684
0
            auto W = varblock_size.width();
2685
0
            auto H = varblock_size.height();
2686
            // "covering num_blocks = (W / 8) * (H / 8) blocks,"
2687
0
            u32 num_blocks = (W / 8) * (H / 8);
2688
2689
            // "s is the Order ID (see Table I.7) of the DctSelect value"
2690
0
            auto s = dct_select_to_order_id(transform_type);
2691
            // "qf is the HfMul value for the current varblock"
2692
0
            u32 qf = hf_group.hf_mul.get(x, y);
2693
2694
            // FIXME: Implement this for in-frame LF coefficients.
2695
            // "qdc[3] are the quantized LF values of LfQuant (G.2.2) corresponding to
2696
            // (the top-left 8×8 block within) the current varblock (taking into account jpeg_upsampling if needed)."
2697
2698
            // "The lists of thresholds qf_thresholds and lf_thresholds[3], and block_ctx_map are as decoded in LfGlobal"
2699
0
            auto const& qf_thresholds = var_dct_options.lf_global.hf_block_ctx.qf_thresholds;
2700
0
            auto const& lf_thresholds = var_dct_options.lf_global.hf_block_ctx.lf_thresholds;
2701
0
            auto const& block_ctx_map = var_dct_options.lf_global.hf_block_ctx.block_ctx_map;
2702
2703
            // "for each varblock it reads channels Y, X, then B;"
2704
            // "where c is the current channel (with 0=X, 1=Y, 2=B)" - from the second paragraph of I.4
2705
0
            for (u8 c : { 1, 0, 2 }) {
2706
0
                auto BlockContext = [&]() -> u32 {
2707
0
                    u32 idx = (c < 2 ? c ^ 1 : 2) * 13 + s;
2708
0
                    idx *= (qf_thresholds.size() + 1);
2709
0
                    for (auto t : qf_thresholds)
2710
0
                        if (qf > t)
2711
0
                            idx++;
2712
0
                    for (u8 i = 0; i < 3; i++)
2713
0
                        idx *= (lf_thresholds[i].size() + 1);
2714
0
                    u32 lf_idx = 0;
2715
0
                    for (auto t : lf_thresholds[0])
2716
0
                        if (qdc[0] > t)
2717
0
                            lf_idx++;
2718
0
                    lf_idx *= (lf_thresholds[2].size() + 1);
2719
0
                    for (auto t : lf_thresholds[2])
2720
0
                        if (qdc[2] > t)
2721
0
                            lf_idx++;
2722
0
                    lf_idx *= (lf_thresholds[1].size() + 1);
2723
0
                    for (auto t : lf_thresholds[1])
2724
0
                        if (qdc[1] > t)
2725
0
                            lf_idx++;
2726
0
                    return block_ctx_map[idx + lf_idx];
2727
0
                };
2728
2729
0
                auto NonZerosContext = [&](u32 predicted) -> u32 {
2730
0
                    if (predicted > 64)
2731
0
                        predicted = 64;
2732
0
                    if (predicted < 8)
2733
0
                        return BlockContext() + nb_block_ctx * predicted;
2734
0
                    return BlockContext() + nb_block_ctx * (4 + predicted / 2);
2735
0
                };
2736
2737
0
                auto NonZeros = [&](u32 x, u32 y) -> i32& {
2738
0
                    return non_zeros_channels[c].get(x, y);
2739
0
                };
2740
2741
0
                auto PredictedNonZeros = [&](u32 x, u32 y) -> u32 {
2742
0
                    if (x == 0 and y == 0)
2743
0
                        return 32;
2744
0
                    if (x == 0)
2745
0
                        return NonZeros(x, y - 1);
2746
0
                    if (y == 0)
2747
0
                        return NonZeros(x - 1, y);
2748
0
                    return (NonZeros(x, y - 1) + NonZeros(x - 1, y) + 1) >> 1;
2749
0
                };
2750
2751
                // "the decoder reads an integer non_zeros using
2752
                // DecodeHybridVarLenUint(NonZerosContext(PredictedNonZeros(x, y)) + offset)."
2753
0
                u32 context = NonZerosContext(PredictedNonZeros(x, y));
2754
0
                auto non_zeros = TRY(decoder.decode_hybrid_uint(stream, context));
2755
2756
                // The decoder then sets the NonZeros(x, y) value for each block in the
2757
                // current varblock as follows: for each i in [0, W / 8) and j in [0, H / 8),
2758
                // NonZeros(x + i, y + j) is set to (non_zeros + num_blocks − 1) Idiv num_blocks.
2759
0
                for (u32 j = 0; j < H / 8; ++j) {
2760
0
                    for (u32 i = 0; i < W / 8; ++i)
2761
0
                        NonZeros(x + i, y + j) = (non_zeros + num_blocks - 1) / num_blocks;
2762
0
                }
2763
2764
                // "If non_zeros reaches 0, the decoder stops decoding further coefficients for the current block."
2765
0
                if (non_zeros == 0)
2766
0
                    continue;
2767
2768
0
                auto CoefficientContext = [&](u32 k, u32 non_zeros, u32 num_blocks, u32 prev) -> u32 {
2769
0
                    non_zeros = (non_zeros + num_blocks - 1) / num_blocks;
2770
0
                    k = k / num_blocks;
2771
0
                    return (CoeffNumNonzeroContext[non_zeros] + CoeffFreqContext[k]) * 2 + prev + BlockContext() * 458 + 37 * nb_block_ctx;
2772
0
                };
2773
2774
                // "Let size = W * H."
2775
0
                auto size = W * H;
2776
                // "For k in the range [num_blocks, size)"
2777
0
                u32 last_ucoeff {};
2778
0
                for (u32 k = num_blocks; k < size; ++k) {
2779
                    // "the decoder reads an integer ucoeff from the codestream, using
2780
                    // DecodeHybridVarLenUint(CoefficientContext(k, non_zeros, num_blocks, size, prev) + offset),
2781
                    // where prev is computed as specified in the following code:"
2782
0
                    auto prev = [&]() -> u32 {
2783
0
                        if (k == num_blocks) {
2784
0
                            if (non_zeros > size / 16)
2785
0
                                return 0;
2786
0
                            else
2787
0
                                return 1;
2788
0
                        } else {
2789
0
                            if (last_ucoeff == 0)
2790
0
                                return 0;
2791
0
                            else
2792
0
                                return 1;
2793
0
                        }
2794
0
                    }();
2795
2796
0
                    auto ucoeff = TRY(decoder.decode_hybrid_uint(stream, CoefficientContext(k, non_zeros, num_blocks, prev) + offset));
2797
0
                    last_ucoeff = ucoeff;
2798
2799
                    // "The decoder then sets the quantized HF coefficient in the position corresponding to index
2800
                    // order[p][s][c][k] to UnpackSigned(ucoeff), where p is the index of the current pass and s
2801
                    // and c are the Order ID and current channel index as above."
2802
0
                    auto destination = order[s][c][k];
2803
                    // FIXME: Actually do something with the decoded data.
2804
0
                    (void)destination;
2805
2806
                    // "If ucoeff != 0, the decoder decreases non_zeros by 1."
2807
0
                    if (ucoeff != 0)
2808
0
                        non_zeros -= 1;
2809
                    // "If non_zeros reaches 0, the decoder stops decoding further coefficients for the current block."
2810
0
                    if (non_zeros == 0)
2811
0
                        break;
2812
0
                }
2813
0
            }
2814
0
        }
2815
0
    }
2816
2817
0
    TRY(decoder.ensure_end_state());
2818
2819
0
    return {};
2820
0
}
2821
2822
// G.4.1 - General
2823
static ErrorOr<void> read_pass_group(LittleEndianInputBitStream& stream,
2824
    PassGroupOptions&& options,
2825
    PassGroupModularOptions&& modular_options,
2826
    PassGroupVarDCTOptions&& var_dct_options)
2827
0
{
2828
0
    if (options.frame_header.encoding == Encoding::kVarDCT)
2829
0
        TRY(read_hf_coefficients(stream, options, move(var_dct_options)));
2830
2831
0
    TRY(read_modular_group_data(stream, options, modular_options));
2832
2833
0
    return {};
2834
0
}
2835
///
2836
2837
/// Table F.1 — Frame bundle
2838
struct Frame {
2839
    FrameHeader frame_header;
2840
    TOC toc;
2841
    LfGlobal lf_global;
2842
    Vector<Optional<VarDCTLfGroup>> lf_groups;
2843
    HfGlobal hf_global;
2844
2845
    u64 width {};
2846
    u64 height {};
2847
2848
    u32 num_groups {};
2849
    u32 num_lf_groups {};
2850
2851
    Optional<Image> image {};
2852
};
2853
2854
class AutoDepletingConstrainedStream : public ConstrainedStream {
2855
public:
2856
    AutoDepletingConstrainedStream(MaybeOwned<Stream> stream, u64 limit)
2857
0
        : ConstrainedStream(move(stream), limit)
2858
0
    {
2859
0
    }
2860
2861
    ~AutoDepletingConstrainedStream()
2862
0
    {
2863
0
        dbgln_if(JPEGXL_DEBUG, "Discarding {} remaining bytes", remaining());
2864
0
        if (discard(remaining()).is_error())
2865
0
            dbgln("JPEGXLLoader: Corrupted stream, reached EOF");
2866
0
    }
2867
};
2868
2869
static ErrorOr<Frame> read_frame(LittleEndianInputBitStream& stream,
2870
    SizeHeader const& size_header,
2871
    ImageMetadata const& metadata)
2872
0
{
2873
    // F.1 - General
2874
    // Each Frame is byte-aligned by invoking ZeroPadToByte() (B.2.7)
2875
0
    stream.align_to_byte_boundary();
2876
2877
0
    Frame frame;
2878
2879
0
    frame.frame_header = TRY(read_frame_header(stream, size_header, metadata));
2880
2881
0
    if (!frame.frame_header.have_crop) {
2882
0
        frame.width = size_header.width;
2883
0
        frame.height = size_header.height;
2884
0
    } else {
2885
0
        frame.width = frame.frame_header.width;
2886
0
        frame.height = frame.frame_header.height;
2887
0
    }
2888
2889
0
    if (frame.frame_header.upsampling > 1) {
2890
0
        frame.width = ceil_div(frame.width, frame.frame_header.upsampling);
2891
0
        frame.height = ceil_div(frame.height, frame.frame_header.upsampling);
2892
0
    }
2893
2894
    // "If lf_level > 0 (which is also a field in frame_header), then
2895
    // width = ceil(width / (1 << (3 * lf_level))) and height = ceil(height / (1 << (3 * lf_level)))."
2896
0
    if (frame.frame_header.lf_level > 0) {
2897
0
        frame.width = ceil_div(frame.width, 1u << (3 * frame.frame_header.lf_level));
2898
0
        frame.height = ceil_div(frame.height, 1u << (3 * frame.frame_header.lf_level));
2899
0
    }
2900
2901
0
    dbgln_if(JPEGXL_DEBUG, "Frame{}: {}x{} {} - {} - flags({}){}"sv,
2902
0
        frame.frame_header.name.is_empty() ? ""sv : MUST(String::formatted(" \"{}\"", frame.frame_header.name)),
2903
0
        frame.width, frame.height,
2904
0
        frame.frame_header.encoding,
2905
0
        frame.frame_header.frame_type,
2906
0
        to_underlying(frame.frame_header.flags),
2907
0
        frame.frame_header.is_last ? " - is_last"sv : ""sv);
2908
2909
0
    auto const group_dim = frame.frame_header.group_dim();
2910
0
    auto const frame_width = static_cast<double>(frame.width);
2911
0
    auto const frame_height = static_cast<double>(frame.height);
2912
0
    frame.num_groups = ceil(frame_width / group_dim) * ceil(frame_height / group_dim);
2913
0
    frame.num_lf_groups = ceil(frame_width / (group_dim * 8)) * ceil(frame_height / (group_dim * 8));
2914
2915
0
    frame.toc = TRY(read_toc(stream, frame.frame_header, frame.num_groups, frame.num_lf_groups));
2916
2917
    if constexpr (JPEGXL_DEBUG) {
2918
        dbgln("TOC: index |  size | offset");
2919
        for (u32 i {}; i < frame.toc.entries.size(); ++i)
2920
            dbgln("     {:5} | {:5} | {:6}", i, frame.toc.entries[i], frame.toc.group_offsets[i]);
2921
    }
2922
2923
0
    auto bits_per_sample = metadata.bit_depth.bits_per_sample;
2924
0
    IntSize frame_size { frame.width, frame.height };
2925
2926
0
    auto get_stream_for_section = [&](LittleEndianInputBitStream& stream, u32 section_index) -> ErrorOr<MaybeOwned<LittleEndianInputBitStream>> {
2927
        // "If num_groups == 1 and num_passes == 1, then there is a single TOC entry and a single section
2928
        // containing all frame data structures."
2929
0
        if (frame.num_groups == 1 && frame.frame_header.passes.num_passes == 1)
2930
0
            return MaybeOwned(stream);
2931
0
        auto section_size = frame.toc.entries[section_index];
2932
0
        if (stream.align_to_byte_boundary() != 0)
2933
0
            return Error::from_string_literal("JPEGXLLoader: Padding bits between sections must all be zeros");
2934
0
        auto constrained_stream = make<AutoDepletingConstrainedStream>(MaybeOwned<Stream>(stream), section_size);
2935
0
        return TRY(try_make<LittleEndianInputBitStream>(move(constrained_stream)));
2936
0
    };
2937
2938
0
    {
2939
0
        auto lf_stream = TRY(get_stream_for_section(stream, 0));
2940
0
        frame.lf_global = TRY(read_lf_global(*lf_stream, frame_size, frame.frame_header, metadata));
2941
0
    }
2942
2943
0
    for (u32 i {}; i < frame.num_lf_groups; ++i) {
2944
0
        auto lf_stream = TRY(get_stream_for_section(stream, 1 + i));
2945
        // From H.4.1, "The stream index is defined as follows: [...] for ModularLfGroup: 1 + num_lf_groups + LF group index;"
2946
0
        TRY(read_lf_group(*lf_stream,
2947
0
            {
2948
0
                .global_modular = frame.lf_global.gmodular,
2949
0
                .frame_header = frame.frame_header,
2950
0
                .group_index = i,
2951
0
                .stream_index = 1 + frame.num_lf_groups + i,
2952
0
                .bit_depth = bits_per_sample,
2953
0
            },
2954
0
            {
2955
0
                .group_data = frame.lf_groups,
2956
0
                .frame_size = frame_size,
2957
0
                .num_lf_group = frame.num_lf_groups,
2958
0
            }));
2959
0
    }
2960
2961
0
    {
2962
0
        auto hf_global_stream = TRY(get_stream_for_section(stream, 1 + frame.num_lf_groups));
2963
0
        if (frame.frame_header.encoding == Encoding::kVarDCT)
2964
0
            frame.hf_global = TRY(read_hf_global(stream, frame.lf_global, frame.num_groups, frame.frame_header.passes.num_passes));
2965
0
    }
2966
2967
0
    for (u32 pass_index {}; pass_index < frame.frame_header.passes.num_passes; ++pass_index) {
2968
0
        for (u32 group_index {}; group_index < frame.num_groups; ++group_index) {
2969
0
            auto toc_section_number = 2 + frame.num_lf_groups + pass_index * frame.num_groups + group_index;
2970
0
            auto pass_stream = TRY(get_stream_for_section(stream, toc_section_number));
2971
2972
            // From H.4.1, ModularGroup: 1 + 3 * num_lf_groups + 17 + num_groups * pass index + group index
2973
0
            u32 stream_index = 1 + 3 * frame.num_lf_groups + 17 + frame.num_groups * pass_index + group_index;
2974
0
            TRY(read_pass_group(*pass_stream,
2975
0
                {
2976
0
                    .global_modular = frame.lf_global.gmodular,
2977
0
                    .frame_header = frame.frame_header,
2978
0
                    .group_index = group_index,
2979
0
                    .pass_index = pass_index,
2980
0
                    .stream_index = stream_index,
2981
0
                },
2982
0
                { .bit_depth = bits_per_sample },
2983
0
                {
2984
0
                    .lf_global = frame.lf_global,
2985
0
                    .lf_groups = frame.lf_groups,
2986
0
                    .hf_global = frame.hf_global,
2987
0
                }));
2988
0
        }
2989
0
    }
2990
2991
    // G.4.2 - Modular group data
2992
    // When all modular groups are decoded, the inverse transforms are applied to
2993
    // the at that point fully decoded GlobalModular image, as specified in H.6.
2994
0
    auto& channels = frame.lf_global.gmodular.modular_data.channels;
2995
0
    auto const& transform_infos = frame.lf_global.gmodular.modular_data.transform;
2996
0
    for (auto const& transformation : transform_infos.in_reverse())
2997
0
        TRY(apply_transformation(channels, transformation, bits_per_sample, frame.lf_global.gmodular.modular_data.wp_params));
2998
2999
0
    if (frame.frame_header.encoding == Encoding::kVarDCT) {
3000
0
        channels.prepend(TRY(Channel::create(ChannelInfo::from_size(frame_size))));
3001
0
        channels.prepend(TRY(Channel::create(ChannelInfo::from_size(frame_size))));
3002
0
        channels.prepend(TRY(Channel::create(ChannelInfo::from_size(frame_size))));
3003
0
    }
3004
3005
0
    frame.image = TRY(Image::adopt_channels(move(channels)));
3006
3007
0
    return frame;
3008
0
}
3009
///
3010
3011
/// J - Restoration filters
3012
3013
// J.3  Gabor-like transform
3014
using GaborWeights = Array<float, 2>;
3015
3016
static FloatMatrix3x3 construct_gabor_like_filter(GaborWeights weights)
3017
0
{
3018
0
    FloatMatrix3x3 filter {};
3019
3020
    // "the unnormalized weight for the center is 1"
3021
0
    filter(1, 1) = 1;
3022
3023
    // "its four neighbours (top, bottom, left, right) are restoration_filter.gab_C_weight1"
3024
0
    filter(0, 1) = weights[0];
3025
0
    filter(1, 0) = weights[0];
3026
0
    filter(1, 2) = weights[0];
3027
0
    filter(2, 1) = weights[0];
3028
3029
    // "and the four corners (top-left, top-right, bottom-left, bottom-right) are restoration_filter.gab_C_weight2."
3030
0
    filter(0, 0) = weights[1];
3031
0
    filter(0, 2) = weights[1];
3032
0
    filter(2, 0) = weights[1];
3033
0
    filter(2, 2) = weights[1];
3034
3035
    // These weights are rescaled uniformly before convolution, such that the nine kernel weights sum to 1.
3036
0
    return filter / filter.element_sum();
3037
0
}
3038
3039
static FloatMatrix3x3 extract_matrix_from_channel(FloatChannel const& channel, u32 x, u32 y)
3040
0
{
3041
0
    FloatMatrix3x3 m;
3042
0
    auto x_minus_1 = x == 0 ? mirror_1d(x, channel.width()) : x - 1;
3043
0
    auto x_plus_1 = x == channel.width() - 1 ? mirror_1d(x, channel.width()) : x + 1;
3044
3045
0
    auto y_minus_1 = y == 0 ? mirror_1d(y, channel.height()) : y - 1;
3046
0
    auto y_plus_1 = y == channel.height() - 1 ? mirror_1d(y, channel.height()) : y + 1;
3047
3048
0
    m(0, 0) = channel.get(x_minus_1, y_minus_1);
3049
0
    m(0, 1) = channel.get(x, y_minus_1);
3050
0
    m(0, 2) = channel.get(x_plus_1, y_minus_1);
3051
0
    m(1, 0) = channel.get(x_minus_1, y);
3052
0
    m(1, 1) = channel.get(x, y);
3053
0
    m(1, 2) = channel.get(x_plus_1, y);
3054
0
    m(2, 0) = channel.get(x_minus_1, y_plus_1);
3055
0
    m(2, 1) = channel.get(x, y_plus_1);
3056
0
    m(2, 2) = channel.get(x_plus_1, y_plus_1);
3057
3058
0
    return m;
3059
0
}
3060
3061
static ErrorOr<void> apply_gabor_like_on_channel(FloatChannel& channel, GaborWeights weights)
3062
0
{
3063
0
    auto filter = construct_gabor_like_filter(weights);
3064
0
    auto out = TRY(channel.copy());
3065
0
    for (u32 y = 0; y < channel.height(); ++y) {
3066
0
        for (u32 x = 0; x < channel.width(); ++x) {
3067
0
            auto source = extract_matrix_from_channel(channel, x, y);
3068
0
            auto result = source.hadamard_product(filter).element_sum();
3069
0
            out.set(x, y, result);
3070
0
        }
3071
0
    }
3072
0
    channel = move(out);
3073
0
    return {};
3074
0
}
3075
3076
static ErrorOr<void> apply_gabor_like_filter(RestorationFilter const& restoration_filter, Span<FloatChannel> channels)
3077
0
{
3078
0
    VERIFY(channels.size() == 3);
3079
3080
0
    Array<GaborWeights, 3> weights {
3081
0
        GaborWeights { restoration_filter.gab_x_weight1, restoration_filter.gab_x_weight2 },
3082
0
        GaborWeights { restoration_filter.gab_y_weight1, restoration_filter.gab_y_weight2 },
3083
0
        GaborWeights { restoration_filter.gab_b_weight1, restoration_filter.gab_b_weight2 },
3084
0
    };
3085
0
    for (auto [i, channel] : enumerate(channels))
3086
0
        TRY(apply_gabor_like_on_channel(channel, weights[i]));
3087
0
    return {};
3088
0
}
3089
3090
// J.4 - Edge-preserving filter
3091
3092
// J.4.2 - Distances
3093
static f32 DistanceStep0and1(RestorationFilter const& rf, Span<FloatChannel const> input, u32 x, u32 y, i8 cx, i8 cy)
3094
0
{
3095
0
    f32 dist = 0;
3096
0
    auto coords = to_array<IntPoint>({ { 0, 0 }, { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } });
3097
0
    for (u8 c = 0; c < 3; c++) {
3098
0
        for (auto coord : coords) {
3099
0
            auto ix = coord.x();
3100
0
            auto iy = coord.y();
3101
0
            dist += abs(input[c].get_mirrored(x + ix, y + iy) - input[c].get_mirrored(x + cx + ix, y + cy + iy)) * rf.epf_channel_scale[c];
3102
0
        }
3103
0
    }
3104
0
    return dist;
3105
0
}
3106
3107
static f32 DistanceStep2(RestorationFilter const& rf, Span<FloatChannel const> input, u32 x, u32 y, i8 cx, i8 cy)
3108
0
{
3109
0
    f32 dist = 0;
3110
0
    for (u8 c = 0; c < 3; c++) {
3111
0
        dist += abs(input[c].get_mirrored(x, y) - input[c].get_mirrored(x + cx, y + cy)) * rf.epf_channel_scale[c];
3112
0
    }
3113
0
    return dist;
3114
0
}
3115
3116
// J.4.3 - Weights
3117
static f32 Weight(RestorationFilter const& rf, f32 step, f32 distance, f32 sigma, u32 x, u32 y)
3118
0
{
3119
    // "step = /* 0 if first step, 1 if second step, 2 if third step */;"
3120
0
    Array<f32, 3> step_multiplier = { 1.65f * rf.epf_pass0_sigma_scale, 1.65f * 1, 1.65f * rf.epf_pass2_sigma_scale };
3121
0
    f32 position_multiplier {};
3122
    // "either coordinate of the reference sample is 0 or 7 UMod 8."
3123
0
    if (x % 8 == 0 || x % 8 == 7 || y % 8 == 0 || y % 8 == 7)
3124
0
        position_multiplier = rf.epf_border_sad_mul;
3125
0
    else
3126
0
        position_multiplier = 1;
3127
0
    f32 inv_sigma = step_multiplier[step] * 4 * (1 - sqrt(0.5f)) / sigma;
3128
0
    f32 scaled_distance = position_multiplier * distance;
3129
0
    f32 v = 1 - scaled_distance * inv_sigma;
3130
0
    if (v <= 0)
3131
0
        return 0;
3132
0
    return v;
3133
0
}
3134
3135
// J.4.4 - Weighted average
3136
static void apply_epf_step_on_pixel(RestorationFilter const& rf, Span<FloatChannel const> input, Span<FloatChannel> output, u32 step, f32 sigma, u32 x, u32 y)
3137
0
{
3138
0
    auto kernel_coords = [&]() {
3139
0
        if (step == 0) {
3140
0
            static constexpr Array points = to_array<IntPoint>({ { 0, 0 }, { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 },
3141
0
                { 1, -1 }, { 1, 1 }, { -1, 1 }, { -1, -1 }, { -2, 0 },
3142
0
                { 2, 0 }, { 0, 2 }, { 0, -2 } });
3143
0
            return points.span();
3144
0
        }
3145
0
        static constexpr Array points = to_array<IntPoint>({ { 0, 0 }, { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } });
3146
0
        return points.span();
3147
0
    }();
3148
3149
0
    f32 sum_weights = 0;
3150
0
    Array<f32, 3> sum_channels = { 0, 0, 0 };
3151
0
    for (auto coord : kernel_coords) {
3152
0
        auto ix = coord.x();
3153
0
        auto iy = coord.y();
3154
0
        f32 distance {};
3155
0
        if (step == 0 || step == 1) {
3156
0
            distance = DistanceStep0and1(rf, input, x, y, ix, iy);
3157
0
        } else {
3158
0
            distance = DistanceStep2(rf, input, x, y, ix, iy);
3159
0
        }
3160
0
        f32 weight = Weight(rf, step, distance, sigma, x, y);
3161
0
        sum_weights += weight;
3162
0
        for (u8 c = 0; c < 3; c++) {
3163
0
            sum_channels[c] += input[c].get_mirrored(x + ix, y + iy) * weight;
3164
0
        }
3165
0
    }
3166
0
    for (u8 c = 0; c < 3; c++) {
3167
0
        output[c].set(x, y, sum_channels[c] / sum_weights);
3168
0
    }
3169
0
}
3170
3171
// J.4.1 - General
3172
static void apply_epf_step(RestorationFilter const& rf, Span<FloatChannel const> input, Span<FloatChannel> output, u32 step, f32 sigma)
3173
0
{
3174
0
    for (u64 y = 0; y < input[0].height(); ++y) {
3175
0
        for (u64 x = 0; x < input[0].width(); ++x)
3176
0
            apply_epf_step_on_pixel(rf, input, output, step, sigma, x, y);
3177
0
    }
3178
0
}
3179
3180
static ErrorOr<void> apply_epf_filter(FrameHeader const& frame_header, Span<FloatChannel> channels)
3181
0
{
3182
    // "sigma is then computed as specified by the following code if the frame encoding is kVarDCT, else it is set to rf.epf_sigma_for_modular."
3183
0
    if (frame_header.encoding == Encoding::kVarDCT)
3184
0
        return Error::from_string_literal("FIXME: Compute epf's sigma for VarDCT frames.");
3185
0
    f32 sigma = frame_header.restoration_filter.epf_sigma_for_modular;
3186
3187
    // "The output of each step is used as an input for the following step."
3188
0
    Vector<FloatChannel> next_input;
3189
0
    for (u8 i = 0; i < channels.size(); ++i)
3190
0
        TRY(next_input.try_append(TRY(channels[i].copy())));
3191
3192
    // "The first step is only done if rf.epf_iters == 3."
3193
0
    if (frame_header.restoration_filter.epf_iters == 3) {
3194
0
        apply_epf_step(frame_header.restoration_filter, next_input, channels, 0, sigma);
3195
0
        next_input.clear();
3196
0
        for (u8 i = 0; i < channels.size(); ++i)
3197
0
            TRY(next_input.try_append(TRY(channels[i].copy())));
3198
0
    }
3199
3200
    // "The second step is always done (if rf.epf_iters > 0)."
3201
0
    if (frame_header.restoration_filter.epf_iters > 0) {
3202
0
        apply_epf_step(frame_header.restoration_filter, next_input, channels, 1, sigma);
3203
0
        next_input.clear();
3204
0
        for (u8 i = 0; i < channels.size(); ++i)
3205
0
            TRY(next_input.try_append(TRY(channels[i].copy())));
3206
0
    }
3207
3208
    // "The third step is only done if rf.epf_iters >= 2."
3209
0
    if (frame_header.restoration_filter.epf_iters >= 2)
3210
0
        apply_epf_step(frame_header.restoration_filter, next_input, channels, 2, sigma);
3211
3212
0
    return {};
3213
0
}
3214
3215
struct SplitChannels {
3216
    Vector<FloatChannel> color_channels {};
3217
    Vector<Channel> extra_channels {};
3218
};
3219
3220
template<typename T2, typename T1>
3221
static ErrorOr<Vector<Detail::Channel<T2>>> convert_channels(Span<Detail::Channel<T1>> const& channels, u8 bits_per_sample)
3222
0
{
3223
0
    Vector<Detail::Channel<T2>> new_channels;
3224
0
    TRY(new_channels.try_ensure_capacity(channels.size()));
3225
0
    for (u32 i = 0; i < channels.size(); ++i)
3226
0
        new_channels.append(TRY(channels[i].template as<T2>(bits_per_sample)));
3227
0
    return new_channels;
3228
0
}
Unexecuted instantiation: JPEGXLLoader.cpp:AK::ErrorOr<AK::Vector<Gfx::JPEGXL::Detail::Channel<float>, 0ul>, AK::Error> Gfx::JPEGXL::convert_channels<float, int>(AK::Span<Gfx::JPEGXL::Detail::Channel<int> > const&, unsigned char)
Unexecuted instantiation: JPEGXLLoader.cpp:AK::ErrorOr<AK::Vector<Gfx::JPEGXL::Detail::Channel<int>, 0ul>, AK::Error> Gfx::JPEGXL::convert_channels<int, float>(AK::Span<Gfx::JPEGXL::Detail::Channel<float> > const&, unsigned char)
3229
3230
static ErrorOr<SplitChannels> extract_color_channels(ImageMetadata const& metadata, Image& image)
3231
0
{
3232
0
    auto all_channels = move(image.channels());
3233
0
    auto f32_color_channels = TRY(convert_channels<f32>(all_channels.span().trim(metadata.number_of_color_channels()), metadata.bit_depth.bits_per_sample));
3234
0
    all_channels.remove(0, metadata.number_of_color_channels());
3235
0
    return SplitChannels { move(f32_color_channels), move(all_channels) };
3236
0
}
3237
3238
static ErrorOr<void> ensure_enough_color_channels(Vector<FloatChannel>& channels)
3239
0
{
3240
0
    if (channels.size() == 3)
3241
0
        return {};
3242
0
    VERIFY(channels.size() == 1);
3243
0
    TRY(channels.try_append(TRY(channels[0].copy())));
3244
0
    TRY(channels.try_append(TRY(channels[0].copy())));
3245
0
    return {};
3246
0
}
3247
3248
// J.1 - General
3249
static ErrorOr<void> apply_restoration_filters(Frame& frame, ImageMetadata const& metadata)
3250
0
{
3251
0
    auto const& frame_header = frame.frame_header;
3252
3253
0
    if (frame_header.restoration_filter.gab || frame_header.restoration_filter.epf_iters != 0) {
3254
        if constexpr (JPEGXL_DEBUG) {
3255
            dbgln("Restoration filters:");
3256
            dbgln(" * Gab: {}", frame_header.restoration_filter.gab);
3257
            dbgln(" * EPF: {}", frame_header.restoration_filter.epf_iters);
3258
        }
3259
3260
        // FIXME: Clarify where we should actually do the i32 -> f32 convertion.
3261
0
        auto channels = TRY(extract_color_channels(metadata, *frame.image));
3262
0
        TRY(ensure_enough_color_channels(channels.color_channels));
3263
3264
0
        if (frame_header.restoration_filter.gab)
3265
0
            TRY(apply_gabor_like_filter(frame.frame_header.restoration_filter, channels.color_channels));
3266
0
        if (frame_header.restoration_filter.epf_iters != 0)
3267
0
            TRY(apply_epf_filter(frame_header, channels.color_channels));
3268
3269
        // Remove unwanted color channels if the image is greyscale.
3270
0
        if (metadata.number_of_color_channels() == 1)
3271
0
            channels.color_channels.remove(1, 2);
3272
0
        auto i32_channels = TRY(convert_channels<i32>(channels.color_channels.span(), metadata.bit_depth.bits_per_sample));
3273
0
        TRY(i32_channels.try_extend(move(channels.extra_channels)));
3274
0
        frame.image = TRY(Image::adopt_channels(move(i32_channels)));
3275
0
    }
3276
3277
0
    return {};
3278
0
}
3279
///
3280
3281
/// K - Image features
3282
static ErrorOr<void> apply_upsampling(Frame& frame, ImageMetadata const& metadata)
3283
0
{
3284
0
    Optional<u32> ec_max;
3285
0
    for (auto upsampling : frame.frame_header.ec_upsampling) {
3286
0
        if (!ec_max.has_value() || upsampling > *ec_max)
3287
0
            ec_max = upsampling;
3288
0
    }
3289
3290
0
    if (frame.frame_header.upsampling > 1 || ec_max.value_or(0) > 1) {
3291
0
        if (ec_max.value_or(0) > 2)
3292
0
            TODO();
3293
3294
0
        auto const k = frame.frame_header.upsampling;
3295
3296
0
        auto weight = [k, &metadata](u8 index) -> double {
3297
0
            if (k == 2)
3298
0
                return metadata.up2_weight[index];
3299
0
            if (k == 4)
3300
0
                return metadata.up4_weight[index];
3301
0
            return metadata.up8_weight[index];
3302
0
        };
3303
3304
        // FIXME: Use ec_upsampling for extra-channels
3305
0
        for (auto& channel : frame.image->channels()) {
3306
0
            auto upsampled = TRY(Channel::create({ .width = k * channel.width(), .height = k * channel.height() }));
3307
3308
            // Loop over the original image
3309
0
            for (u32 y {}; y < channel.height(); y++) {
3310
0
                for (u32 x {}; x < channel.width(); x++) {
3311
3312
                    // Loop over the upsampling factor
3313
0
                    for (u8 kx {}; kx < k; ++kx) {
3314
0
                        for (u8 ky {}; ky < k; ++ky) {
3315
0
                            double sum {};
3316
                            // Loop over the W window
3317
0
                            double W_min = NumericLimits<double>::max();
3318
0
                            double W_max = -NumericLimits<double>::max();
3319
0
                            for (u8 ix {}; ix < 5; ++ix) {
3320
0
                                for (u8 iy {}; iy < 5; ++iy) {
3321
0
                                    auto const j = (ky < k / 2) ? (iy + 5 * ky) : ((4 - iy) + 5 * (k - 1 - ky));
3322
0
                                    auto const i = (kx < k / 2) ? (ix + 5 * kx) : ((4 - ix) + 5 * (k - 1 - kx));
3323
0
                                    auto const minimum = min(i, j);
3324
0
                                    auto const maximum = max(i, j);
3325
0
                                    auto const index = 5 * k * minimum / 2 - minimum * (minimum - 1) / 2 + maximum - minimum;
3326
3327
0
                                    auto const origin_sample = channel.get_mirrored(x + ix - 2, y + iy - 2);
3328
3329
0
                                    W_min = min(W_min, origin_sample);
3330
0
                                    W_max = max(W_max, origin_sample);
3331
3332
0
                                    sum += origin_sample * weight(index);
3333
0
                                }
3334
0
                            }
3335
3336
                            // The resulting sample is clamped to the range [a, b] where a and b are
3337
                            // the minimum and maximum of the samples in W.
3338
0
                            sum = clamp(sum, W_min, W_max);
3339
3340
0
                            upsampled.set(x * k + kx, y * k + ky, sum);
3341
0
                        }
3342
0
                    }
3343
0
                }
3344
0
            }
3345
0
            channel = move(upsampled);
3346
0
        }
3347
0
    }
3348
3349
0
    return {};
3350
0
}
3351
3352
/// K.3.2  Patches rendering
3353
static ErrorOr<void> apply_patches(Span<Frame> previous_frames, Frame& frame)
3354
0
{
3355
0
    auto& destination_image = frame.image;
3356
0
    for (auto const& [i, patch] : enumerate(frame.lf_global.patches)) {
3357
0
        if (patch.ref > previous_frames.size())
3358
0
            return Error::from_string_literal("JPEGXLLoader: Unable to find the requested reference frame");
3359
3360
0
        auto& source_image = previous_frames[patch.ref].image;
3361
0
        auto source_rect = IntRect({ patch.x0, patch.y0 }, { patch.width, patch.height });
3362
0
        auto source_patch = TRY(source_image->get_subimage(source_rect));
3363
3364
0
        for (u32 j = 0; j < patch.count; ++j) {
3365
0
            auto destination = IntRect(patch.positions[j], { patch.width, patch.height });
3366
0
            auto destination_patch = TRY(destination_image->get_subimage(destination));
3367
            // FIXME: "iterates over the three colour channels if c == 0 and refers to the extra channel with index c−1 otherwise"
3368
0
            TRY(source_patch.blend_into(destination_patch, patch.blending[j][0].mode));
3369
0
        }
3370
0
    }
3371
3372
0
    return {};
3373
0
}
3374
3375
static ErrorOr<void> apply_image_features(Span<Frame> previous_frames, Frame& frame, ImageMetadata const& metadata)
3376
0
{
3377
0
    TRY(apply_upsampling(frame, metadata));
3378
3379
0
    auto flags = frame.frame_header.flags;
3380
0
    if (flags & FrameHeader::Flags::kPatches) {
3381
0
        TRY(apply_patches(previous_frames, frame));
3382
0
    } else if (flags != FrameHeader::Flags::None) {
3383
0
        dbgln("JPEGXLLoader: Unsupported image features");
3384
0
    }
3385
0
    return {};
3386
0
}
3387
///
3388
3389
/// L.2 - XYB + L.3 - YCbCr
3390
template<typename F>
3391
static void for_each_pixel_of_color_channels(Image& image, F color_conversion)
3392
0
{
3393
0
    auto& channels = image.channels();
3394
0
    VERIFY(channels.size() >= 3);
3395
3396
0
    VERIFY(channels[0].width() == channels[1].width() && channels[1].width() == channels[2].width());
3397
0
    VERIFY(channels[0].height() == channels[1].height() && channels[1].height() == channels[2].height());
3398
3399
0
    for (u32 y = 0; y < channels[0].height(); ++y) {
3400
0
        for (u32 x = 0; x < channels[0].width(); ++x) {
3401
0
            color_conversion(channels[0].get(x, y), channels[1].get(x, y), channels[2].get(x, y));
3402
0
        }
3403
0
    }
3404
0
}
Unexecuted instantiation: JPEGXLLoader.cpp:void Gfx::JPEGXL::for_each_pixel_of_color_channels<Gfx::JPEGXL::ycbcr_to_rgb(Gfx::JPEGXL::Image&, unsigned char)::$_0>(Gfx::JPEGXL::Image&, Gfx::JPEGXL::ycbcr_to_rgb(Gfx::JPEGXL::Image&, unsigned char)::$_0)
Unexecuted instantiation: JPEGXLLoader.cpp:void Gfx::JPEGXL::for_each_pixel_of_color_channels<Gfx::JPEGXL::xyb_to_rgb(Gfx::JPEGXL::Frame&, Gfx::JPEGXL::ImageMetadata const&)::$_0>(Gfx::JPEGXL::Image&, Gfx::JPEGXL::xyb_to_rgb(Gfx::JPEGXL::Frame&, Gfx::JPEGXL::ImageMetadata const&)::$_0)
3405
3406
static void ycbcr_to_rgb(Image& image, u8 bits_per_sample)
3407
0
{
3408
0
    auto const half_range_offset = (1 << bits_per_sample) / 2;
3409
0
    auto color_conversion = [half_range_offset](i32& c1, i32& c2, i32& c3) {
3410
0
        auto const cb = c1;
3411
0
        auto const luma = c2;
3412
0
        auto const cr = c3;
3413
3414
0
        c1 = luma + half_range_offset + 1.402 * cr;
3415
0
        c2 = luma + half_range_offset - 0.344136 * cb - 0.714136 * cr;
3416
0
        c3 = luma + half_range_offset + 1.772 * cb;
3417
0
    };
3418
3419
0
    for_each_pixel_of_color_channels(image, move(color_conversion));
3420
0
}
3421
3422
// L.2.2  Inverse XYB transform
3423
static void xyb_to_rgb(Frame& frame, ImageMetadata const& metadata)
3424
0
{
3425
    // "X, Y, B samples are converted to an RGB colour encoding as specified in this subclause,
3426
    // in which oim denotes metadata.opsin_inverse_matrix."
3427
0
    auto const& oim = metadata.opsin_inverse_matrix;
3428
0
    f32 to_int = (1 << metadata.bit_depth.bits_per_sample) - 1;
3429
0
    auto linear_to_srgb = [](f32 c) {
3430
0
        return c >= 0.0031308f ? 1.055f * pow(c, 0.4166666f) - 0.055f : 12.92f * c;
3431
0
    };
3432
0
    auto color_conversion = [&](i32& c1, i32& c2, i32& c3) {
3433
0
        f32 const y_ = c1;
3434
0
        f32 const x_ = c2;
3435
0
        f32 const b_ = c3;
3436
3437
0
        f32 y {}, x {}, b {};
3438
0
        if (frame.frame_header.encoding == Encoding::kModular) {
3439
0
            y = y_ * frame.lf_global.lf_dequant.m_y_lf_unscaled;
3440
0
            x = x_ * frame.lf_global.lf_dequant.m_x_lf_unscaled;
3441
0
            b = (b_ + y_) * frame.lf_global.lf_dequant.m_b_lf_unscaled;
3442
0
        } else {
3443
0
            y = y_;
3444
0
            x = x_;
3445
0
            b = b_;
3446
0
        }
3447
3448
0
        f32 Lgamma = y + x;
3449
0
        f32 Mgamma = y - x;
3450
0
        f32 Sgamma = b;
3451
0
        f32 itscale = 255 / metadata.tone_mapping.intensity_target;
3452
0
        f32 Lmix = (powf(Lgamma - cbrt(oim.opsin_bias0), 3) + oim.opsin_bias0) * itscale;
3453
0
        f32 Mmix = (powf(Mgamma - cbrt(oim.opsin_bias1), 3) + oim.opsin_bias1) * itscale;
3454
0
        f32 Smix = (powf(Sgamma - cbrt(oim.opsin_bias2), 3) + oim.opsin_bias2) * itscale;
3455
0
        f32 R = oim.inv_mat00 * Lmix + oim.inv_mat01 * Mmix + oim.inv_mat02 * Smix;
3456
0
        f32 G = oim.inv_mat10 * Lmix + oim.inv_mat11 * Mmix + oim.inv_mat12 * Smix;
3457
0
        f32 B = oim.inv_mat20 * Lmix + oim.inv_mat21 * Mmix + oim.inv_mat22 * Smix;
3458
3459
        // "The resulting RGB samples correspond to sRGB primaries and a D65 white point, and the transfer function is linear."
3460
        // We assume sRGB everywhere, so let's apply the transfer function here.
3461
0
        R = linear_to_srgb(R);
3462
0
        G = linear_to_srgb(G);
3463
0
        B = linear_to_srgb(B);
3464
3465
0
        c1 = round_to<i32>(R * to_int);
3466
0
        c2 = round_to<i32>(G * to_int);
3467
0
        c3 = round_to<i32>(B * to_int);
3468
0
    };
3469
3470
0
    for_each_pixel_of_color_channels(*frame.image, move(color_conversion));
3471
0
}
3472
3473
static void apply_colour_transformation(Frame& frame, ImageMetadata const& metadata)
3474
0
{
3475
0
    if (frame.frame_header.do_YCbCr)
3476
0
        ycbcr_to_rgb(*frame.image, metadata.bit_depth.bits_per_sample);
3477
3478
0
    if (metadata.xyb_encoded) {
3479
0
        xyb_to_rgb(frame, metadata);
3480
0
    } else {
3481
        // FIXME: Do a proper color transformation with metadata.colour_encoding
3482
0
    }
3483
0
}
3484
///
3485
3486
/// L.4 - Extra channel rendering
3487
static ErrorOr<void> render_extra_channels(Image&, ImageMetadata const& metadata)
3488
0
{
3489
0
    for (u16 i = metadata.number_of_color_channels(); i < metadata.number_of_channels(); ++i) {
3490
0
        auto const ec_index = i - metadata.number_of_color_channels();
3491
0
        if (metadata.ec_info[ec_index].dim_shift != 0)
3492
0
            TODO();
3493
0
    }
3494
3495
0
    return {};
3496
0
}
3497
///
3498
3499
class LoadingContext {
3500
public:
3501
    LoadingContext(NonnullOwnPtr<Stream> stream)
3502
0
        : m_stream(move(stream))
3503
0
    {
3504
0
    }
3505
3506
    ErrorOr<void> decode_image_header()
3507
0
    {
3508
0
        constexpr auto JPEGXL_SIGNATURE = 0xFF0A;
3509
3510
0
        auto const signature = TRY(m_stream.read_value<BigEndian<u16>>());
3511
0
        if (signature != JPEGXL_SIGNATURE)
3512
0
            return Error::from_string_literal("Unrecognized signature");
3513
3514
0
        m_header = TRY(read_size_header(m_stream));
3515
0
        m_metadata = TRY(read_metadata_header(m_stream));
3516
3517
0
        dbgln_if(JPEGXL_DEBUG, "Decoding a JPEG XL image with size {}x{} and {} channels, bit-depth={}{}.",
3518
0
            m_header.width, m_header.height, m_metadata.number_of_channels(), m_metadata.bit_depth.bits_per_sample,
3519
0
            m_metadata.colour_encoding.want_icc ? ", icc_profile"sv : ""sv);
3520
3521
0
        m_state = State::HeaderDecoded;
3522
3523
0
        return {};
3524
0
    }
3525
3526
    ErrorOr<void> decode_icc()
3527
0
    {
3528
0
        if (m_metadata.colour_encoding.want_icc && m_icc_profile.size() == 0)
3529
0
            m_icc_profile = TRY(read_icc(m_stream));
3530
0
        m_state = State::ICCProfileDecoded;
3531
0
        return {};
3532
0
    }
3533
3534
    ErrorOr<void> decode_frame()
3535
0
    {
3536
0
        auto frame = TRY(read_frame(m_stream, m_header, m_metadata));
3537
0
        auto const& frame_header = frame.frame_header;
3538
3539
0
        TRY(apply_restoration_filters(frame, m_metadata));
3540
3541
0
        TRY(apply_image_features(m_frames, frame, m_metadata));
3542
3543
        // "If lf_level != 0, the samples of the frame (before any colour transform is applied)
3544
        // are recorded as LFFrame[lf_level−1] and may be referenced by subsequent frames."
3545
0
        if (frame.frame_header.lf_level != 0) {
3546
0
            m_lf_frames[frame.frame_header.lf_level - 1] = move(frame);
3547
0
            return {};
3548
0
        }
3549
3550
0
        if (!frame_header.save_before_ct) {
3551
0
            apply_colour_transformation(frame, m_metadata);
3552
0
        }
3553
3554
0
        TRY(render_extra_channels(*frame.image, m_metadata));
3555
3556
0
        m_frames.append(move(frame));
3557
3558
0
        return {};
3559
0
    }
3560
3561
    ErrorOr<void> decode()
3562
0
    {
3563
0
        auto result = [this]() -> ErrorOr<void> {
3564
            // A.1 - Codestream structure
3565
3566
            // The header is already decoded in JPEGXLImageDecoderPlugin::create()
3567
3568
0
            TRY(decode_icc());
3569
3570
0
            if (m_metadata.preview.has_value())
3571
0
                TODO();
3572
3573
0
            while (m_frames.is_empty() || !m_frames.last().frame_header.is_last)
3574
0
                TRY(decode_frame());
3575
3576
0
            TRY(render_frame());
3577
3578
0
            return {};
3579
0
        }();
3580
3581
0
        m_state = result.is_error() ? State::Error : State::FrameDecoded;
3582
3583
0
        return result;
3584
0
    }
3585
3586
    enum class State {
3587
        NotDecoded = 0,
3588
        Error,
3589
        HeaderDecoded,
3590
        ICCProfileDecoded,
3591
        FrameDecoded,
3592
    };
3593
3594
    State state() const
3595
0
    {
3596
0
        return m_state;
3597
0
    }
3598
3599
    IntSize size() const
3600
0
    {
3601
0
        return { m_header.width, m_header.height };
3602
0
    }
3603
3604
    RefPtr<Bitmap> bitmap() const
3605
0
    {
3606
0
        return m_bitmap;
3607
0
    }
3608
3609
    RefPtr<CMYKBitmap> cmyk_bitmap() const
3610
0
    {
3611
0
        return m_cmyk_bitmap;
3612
0
    }
3613
3614
    ByteBuffer const& icc_profile() const
3615
0
    {
3616
0
        return m_icc_profile;
3617
0
    }
3618
3619
    bool is_cmyk() const
3620
0
    {
3621
0
        return any_of(m_metadata.ec_info, [](auto& info) { return info.type == ExtraChannelInfo::ExtraChannelType::kBlack; });
3622
0
    }
3623
3624
private:
3625
    ErrorOr<void> render_frame()
3626
0
    {
3627
0
        auto final_image = TRY(Image::create({ m_header.width, m_header.height }, m_metadata));
3628
3629
0
        for (auto& frame : m_frames) {
3630
0
            if (frame.frame_header.frame_type != FrameHeader::FrameType::kRegularFrame)
3631
0
                continue;
3632
3633
0
            auto blending_mode = frame.frame_header.blending_info.mode;
3634
3635
            // "If x0 or y0 is negative, or the frame extends beyond the right or bottom
3636
            // edge of the image, only the intersection of the frame with the image is
3637
            // updated and contributes to the decoded image."
3638
0
            IntRect frame_rect = frame.image->rect();
3639
0
            auto image_rect = IntRect::intersection(frame_rect.translated(IntPoint { frame.frame_header.x0, frame.frame_header.y0 }), final_image.rect());
3640
0
            frame_rect.set_x(-min(frame.frame_header.x0, 0));
3641
0
            frame_rect.set_y(-min(frame.frame_header.y0, 0));
3642
0
            frame_rect.set_size(image_rect.size());
3643
3644
0
            auto frame_out = TRY(frame.image->get_subimage(frame_rect));
3645
0
            auto image_out = TRY(final_image.get_subimage(image_rect));
3646
0
            TRY(frame_out.blend_into(image_out, blending_mode));
3647
0
        }
3648
3649
0
        if (is_cmyk())
3650
0
            m_cmyk_bitmap = TRY(final_image.to_cmyk_bitmap(m_metadata));
3651
0
        else
3652
0
            m_bitmap = TRY(final_image.to_bitmap(m_metadata));
3653
0
        return {};
3654
0
    }
3655
3656
    State m_state { State::NotDecoded };
3657
3658
    LittleEndianInputBitStream m_stream;
3659
    RefPtr<Gfx::Bitmap> m_bitmap;
3660
    RefPtr<Gfx::CMYKBitmap> m_cmyk_bitmap;
3661
3662
    Vector<Frame> m_frames;
3663
    Array<Optional<Frame>, 4> m_lf_frames;
3664
3665
    SizeHeader m_header;
3666
    ImageMetadata m_metadata;
3667
3668
    ByteBuffer m_icc_profile;
3669
};
3670
3671
}
3672
3673
namespace Gfx {
3674
3675
JPEGXLImageDecoderPlugin::JPEGXLImageDecoderPlugin(Optional<Vector<u8>>&& jxlc_content, NonnullOwnPtr<FixedMemoryStream> stream)
3676
0
    : m_context(make<JPEGXL::LoadingContext>(move(stream)))
3677
0
    , m_jxlc_content(move(jxlc_content))
3678
0
{
3679
0
}
3680
3681
0
JPEGXLImageDecoderPlugin::~JPEGXLImageDecoderPlugin() = default;
3682
3683
IntSize JPEGXLImageDecoderPlugin::size()
3684
0
{
3685
0
    return m_context->size();
3686
0
}
3687
3688
static bool is_raw_codestream(ReadonlyBytes data)
3689
0
{
3690
0
    return data.starts_with(to_array<u8>({ 0xFF, 0x0A }));
3691
0
}
3692
3693
bool JPEGXLImageDecoderPlugin::sniff(ReadonlyBytes data)
3694
0
{
3695
    // 18181-2: 9.1  JPEG XL Signature box (JXL␣)
3696
0
    static constexpr Array signature = to_array<u8>({
3697
        // clang-format off
3698
0
        0x00, 0x00, 0x00, 0x0C,
3699
0
        0x4A, 0x58, 0x4C, 0x20,
3700
0
        0x0D, 0x0A, 0x87, 0x0A,
3701
        // clang-format on
3702
0
    });
3703
0
    bool is_container = data.starts_with(signature);
3704
0
    return is_raw_codestream(data) || is_container;
3705
0
}
3706
3707
static ErrorOr<Vector<u8>> extract_codestream_from_container(NonnullOwnPtr<FixedMemoryStream> input)
3708
0
{
3709
0
    auto box_reader = TRY(ISOBMFF::Reader::create(move(input)));
3710
0
    auto box_list = TRY(box_reader.read_entire_file());
3711
3712
0
    size_t jxlc_box_count = 0;
3713
0
    size_t jxlp_box_count = 0;
3714
0
    for (auto& box : box_list) {
3715
0
        if (box->box_type() == ISOBMFF::BoxType::JPEGXLCodestreamBox)
3716
0
            jxlc_box_count++;
3717
0
        else if (box->box_type() == ISOBMFF::BoxType::JPEGXLPartialCodestreamBox)
3718
0
            jxlp_box_count++;
3719
0
    }
3720
3721
    // "A JPEG XL file shall contain either exactly one JPEG XL codestream box, or one or more JPEG XL partial
3722
    //  codestream boxes, but not both."
3723
0
    if (jxlc_box_count == 0 && jxlp_box_count == 0)
3724
0
        return Error::from_string_literal("JPEGXLLoader: No jxlc box and no jxlp boxes found");
3725
0
    if (jxlc_box_count > 1)
3726
0
        return Error::from_string_literal("JPEGXLLoader: Multiple jxlc boxes found");
3727
0
    if (jxlp_box_count > 0 && jxlc_box_count > 0)
3728
0
        return Error::from_string_literal("JPEGXLLoader: Both jxlc box and jxlp boxes found");
3729
3730
0
    if (jxlc_box_count > 0) {
3731
0
        auto& box = *box_list.find_if([](auto& box) { return box->box_type() == ISOBMFF::BoxType::JPEGXLCodestreamBox; });
3732
0
        auto& codestream_box = static_cast<ISOBMFF::JPEGXLCodestreamBox&>(*box);
3733
0
        return move(codestream_box.codestream);
3734
0
    }
3735
3736
    // "The index modulo 2^31 shall be 0 for the first partial
3737
    //  codestream box, and incremented by 1 for each next partial codestream box. The index shall be lower
3738
    //  than 2^31, except for the last partial codestream box, which shall have an index of at least 2^31. The boxes
3739
    //  shall appear in the file in order of increasing index. The full concatenation of all partial codestream
3740
    //  boxes in this order shall form exactly one complete and valid JPEG XL codestream."
3741
    // FIXME: Try to prevent the extra copy, maybe with a non-contiguous steam class.
3742
0
    VERIFY(jxlp_box_count > 0);
3743
0
    size_t next_part_index = 0;
3744
0
    Vector<u8> codestream;
3745
0
    for (auto& box : box_list) {
3746
0
        if (box->box_type() != ISOBMFF::BoxType::JPEGXLPartialCodestreamBox)
3747
0
            continue;
3748
0
        auto& partial_box = static_cast<ISOBMFF::JPEGXLPartialCodestreamBox&>(*box);
3749
3750
0
        if (partial_box.index() != next_part_index)
3751
0
            return Error::from_string_literal("JPEGXLLoader: Partial box indices not sequential");
3752
0
        ++next_part_index;
3753
3754
0
        bool is_last_box = next_part_index == jxlp_box_count;
3755
0
        if (partial_box.is_last() != is_last_box)
3756
0
            return Error::from_string_literal("JPEGXLLoader: Invalid is_last bit on partial box");
3757
3758
0
        TRY(codestream.try_extend(partial_box.codestream));
3759
0
    }
3760
0
    return codestream;
3761
0
}
3762
3763
ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> JPEGXLImageDecoderPlugin::create(ReadonlyBytes data)
3764
0
{
3765
0
    auto stream = TRY(try_make<FixedMemoryStream>(data));
3766
0
    Optional<Vector<u8>> jxlc_content;
3767
0
    if (!is_raw_codestream(data)) {
3768
0
        jxlc_content = TRY(extract_codestream_from_container(move(stream)));
3769
0
        stream = TRY(try_make<FixedMemoryStream>(jxlc_content->span()));
3770
0
    }
3771
0
    auto plugin = TRY(adopt_nonnull_own_or_enomem(new (nothrow) JPEGXLImageDecoderPlugin(move(jxlc_content), move(stream))));
3772
0
    TRY(plugin->m_context->decode_image_header());
3773
0
    return plugin;
3774
0
}
3775
3776
bool JPEGXLImageDecoderPlugin::is_animated()
3777
0
{
3778
0
    return false;
3779
0
}
3780
3781
size_t JPEGXLImageDecoderPlugin::loop_count()
3782
0
{
3783
0
    return 0;
3784
0
}
3785
3786
size_t JPEGXLImageDecoderPlugin::frame_count()
3787
0
{
3788
0
    return 1;
3789
0
}
3790
3791
size_t JPEGXLImageDecoderPlugin::first_animated_frame_index()
3792
0
{
3793
0
    return 0;
3794
0
}
3795
3796
ErrorOr<ImageFrameDescriptor> JPEGXLImageDecoderPlugin::frame(size_t index, Optional<IntSize>)
3797
0
{
3798
0
    if (index > 0)
3799
0
        return Error::from_string_literal("JPEGXLImageDecoderPlugin: Invalid frame index");
3800
3801
0
    if (m_context->state() == JPEGXL::LoadingContext::State::Error)
3802
0
        return Error::from_string_literal("JPEGXLImageDecoderPlugin: Decoding failed");
3803
3804
0
    if (m_context->state() < JPEGXL::LoadingContext::State::FrameDecoded)
3805
0
        TRY(m_context->decode());
3806
3807
0
    if (m_context->cmyk_bitmap() && !m_context->bitmap())
3808
0
        return ImageFrameDescriptor { TRY(m_context->cmyk_bitmap()->to_low_quality_rgb()), 0 };
3809
3810
0
    return ImageFrameDescriptor { m_context->bitmap(), 0 };
3811
0
}
3812
3813
ErrorOr<NonnullRefPtr<CMYKBitmap>> JPEGXLImageDecoderPlugin::cmyk_frame()
3814
0
{
3815
0
    if (m_context->state() == JPEGXL::LoadingContext::State::Error)
3816
0
        return Error::from_string_literal("JPEGXLImageDecoderPlugin: Decoding failed");
3817
3818
0
    if (m_context->state() < JPEGXL::LoadingContext::State::FrameDecoded)
3819
0
        TRY(m_context->decode());
3820
3821
0
    VERIFY(m_context->cmyk_bitmap() && !m_context->bitmap());
3822
0
    return *m_context->cmyk_bitmap();
3823
0
}
3824
3825
NaturalFrameFormat JPEGXLImageDecoderPlugin::natural_frame_format() const
3826
0
{
3827
0
    return m_context->is_cmyk() ? NaturalFrameFormat::CMYK : NaturalFrameFormat::RGB;
3828
0
}
3829
3830
ErrorOr<Optional<ReadonlyBytes>> JPEGXLImageDecoderPlugin::icc_data()
3831
0
{
3832
0
    if (m_context->state() < JPEGXL::LoadingContext::State::ICCProfileDecoded)
3833
0
        TRY(m_context->decode_icc());
3834
0
    if (m_context->icc_profile().size() == 0)
3835
0
        return OptionalNone {};
3836
0
    return m_context->icc_profile();
3837
0
}
3838
3839
}
3840
3841
namespace AK {
3842
3843
template<>
3844
struct Formatter<Gfx::JPEGXL::Encoding> : Formatter<StringView> {
3845
    ErrorOr<void> format(FormatBuilder& builder, Gfx::JPEGXL::Encoding const& header)
3846
0
    {
3847
0
        auto string = "Unknown"sv;
3848
0
        switch (header) {
3849
0
        case Gfx::JPEGXL::Encoding::kVarDCT:
3850
0
            string = "VarDCT"sv;
3851
0
            break;
3852
0
        case Gfx::JPEGXL::Encoding::kModular:
3853
0
            string = "Modular"sv;
3854
0
            break;
3855
0
        default:
3856
0
            break;
3857
0
        }
3858
0
3859
0
        return Formatter<StringView>::format(builder, string);
3860
0
    }
3861
};
3862
3863
template<>
3864
struct Formatter<Gfx::JPEGXL::FrameHeader::FrameType> : Formatter<StringView> {
3865
    ErrorOr<void> format(FormatBuilder& builder, Gfx::JPEGXL::FrameHeader::FrameType const& header)
3866
0
    {
3867
0
        switch (header) {
3868
0
        case Gfx::JPEGXL::FrameHeader::FrameType::kRegularFrame:
3869
0
            return Formatter<StringView>::format(builder, "RegularFrame"sv);
3870
0
        case Gfx::JPEGXL::FrameHeader::FrameType::kLFFrame:
3871
0
            return Formatter<StringView>::format(builder, "LFFrame"sv);
3872
0
        case Gfx::JPEGXL::FrameHeader::FrameType::kReferenceOnly:
3873
0
            return Formatter<StringView>::format(builder, "ReferenceOnly"sv);
3874
0
        case Gfx::JPEGXL::FrameHeader::FrameType::kSkipProgressive:
3875
0
            return Formatter<StringView>::format(builder, "SkipProgressive"sv);
3876
0
        }
3877
0
        VERIFY_NOT_REACHED();
3878
0
    }
3879
};
3880
3881
}