Coverage Report

Created: 2025-06-16 07:00

/src/libjxl/lib/jxl/image_metadata.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
2
//
3
// Use of this source code is governed by a BSD-style
4
// license that can be found in the LICENSE file.
5
6
#include "lib/jxl/image_metadata.h"
7
8
#include <algorithm>
9
#include <cstddef>
10
#include <cstdint>
11
#include <vector>
12
13
#include "lib/jxl/base/common.h"
14
#include "lib/jxl/base/compiler_specific.h"
15
#include "lib/jxl/base/matrix_ops.h"
16
#include "lib/jxl/base/status.h"
17
#include "lib/jxl/cms/opsin_params.h"
18
#include "lib/jxl/dec_bit_reader.h"
19
#include "lib/jxl/field_encodings.h"
20
#include "lib/jxl/fields.h"
21
#include "lib/jxl/frame_header.h"
22
#include "lib/jxl/quantizer.h"
23
24
namespace jxl {
25
317k
BitDepth::BitDepth() { Bundle::Init(this); }
26
363k
Status BitDepth::VisitFields(Visitor* JXL_RESTRICT visitor) {
27
363k
  JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &floating_point_sample));
28
  // The same fields (bits_per_sample and exponent_bits_per_sample) are read
29
  // in a different way depending on floating_point_sample's value. It's still
30
  // default-initialized correctly so using visitor->Conditional is not
31
  // required.
32
363k
  if (!floating_point_sample) {
33
362k
    JXL_QUIET_RETURN_IF_ERROR(visitor->U32(
34
362k
        Val(8), Val(10), Val(12), BitsOffset(6, 1), 8, &bits_per_sample));
35
362k
    exponent_bits_per_sample = 0;
36
362k
  } else {
37
890
    JXL_QUIET_RETURN_IF_ERROR(visitor->U32(
38
890
        Val(32), Val(16), Val(24), BitsOffset(6, 1), 32, &bits_per_sample));
39
    // The encoded value is exponent_bits_per_sample - 1, encoded in 3 bits
40
    // so the value can be in range [1, 8].
41
886
    const uint32_t offset = 1;
42
886
    exponent_bits_per_sample -= offset;
43
886
    JXL_QUIET_RETURN_IF_ERROR(
44
886
        visitor->Bits(4, 8 - offset, &exponent_bits_per_sample));
45
868
    exponent_bits_per_sample += offset;
46
868
  }
47
48
  // Error-checking for floating point ranges.
49
363k
  if (floating_point_sample) {
50
868
    if (exponent_bits_per_sample < 2 || exponent_bits_per_sample > 8) {
51
30
      return JXL_FAILURE("Invalid exponent_bits_per_sample: %u",
52
30
                         exponent_bits_per_sample);
53
30
    }
54
838
    int mantissa_bits =
55
838
        static_cast<int>(bits_per_sample) - exponent_bits_per_sample - 1;
56
838
    if (mantissa_bits < 2 || mantissa_bits > 23) {
57
28
      return JXL_FAILURE("Invalid bits_per_sample: %u", bits_per_sample);
58
28
    }
59
362k
  } else {
60
362k
    if (bits_per_sample > 31) {
61
12
      return JXL_FAILURE("Invalid bits_per_sample: %u", bits_per_sample);
62
12
    }
63
362k
  }
64
363k
  return true;
65
363k
}
66
67
#if JXL_DEBUG_V_LEVEL >= 1
68
std::string BitDepth::DebugString() const {
69
  std::ostringstream os;
70
  os << (floating_point_sample ? "F" : "U");
71
  os << bits_per_sample;
72
  if (floating_point_sample) os << "." << exponent_bits_per_sample;
73
  return os.str();
74
}
75
#endif
76
77
29.7k
CustomTransformData::CustomTransformData() { Bundle::Init(this); }
78
69.2k
Status CustomTransformData::VisitFields(Visitor* JXL_RESTRICT visitor) {
79
69.2k
  if (visitor->AllDefault(*this, &all_default)) {
80
    // Overwrite all serialized fields, but not any nonserialized_*.
81
16.6k
    visitor->SetDefault(this);
82
16.6k
    return true;
83
16.6k
  }
84
52.6k
  if (visitor->Conditional(nonserialized_xyb_encoded)) {
85
50.5k
    JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&opsin_inverse_matrix));
86
50.5k
  }
87
52.4k
  JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(3, 0, &custom_weights_mask));
88
52.4k
  if (visitor->Conditional((custom_weights_mask & 0x1) != 0)) {
89
    // 4 5x5 kernels, but all of them can be obtained by symmetry from one,
90
    // which is symmetric along its main diagonal. The top-left kernel is
91
    // defined by
92
    //
93
    // 0  1  2  3  4
94
    // 1  5  6  7  8
95
    // 2  6  9 10 11
96
    // 3  7 10 12 13
97
    // 4  8 11 13 14
98
46.1k
    float constexpr kWeights2[15] = {
99
46.1k
        -0.01716200f, -0.03452303f, -0.04022174f, -0.02921014f, -0.00624645f,
100
46.1k
        0.14111091f,  0.28896755f,  0.00278718f,  -0.01610267f, 0.56661550f,
101
46.1k
        0.03777607f,  -0.01986694f, -0.03144731f, -0.01185068f, -0.00213539f};
102
736k
    for (size_t i = 0; i < 15; i++) {
103
690k
      JXL_QUIET_RETURN_IF_ERROR(
104
690k
          visitor->F16(kWeights2[i], &upsampling2_weights[i]));
105
690k
    }
106
46.1k
  }
107
52.3k
  if (visitor->Conditional((custom_weights_mask & 0x2) != 0)) {
108
    // 16 5x5 kernels, but all of them can be obtained by symmetry from
109
    // three, two of which are symmetric along their main diagonals. The top
110
    // left 4 kernels are defined by
111
    //
112
    // 0  1  2  3  4   5  6  7  8  9
113
    // 1 10 11 12 13  14 15 16 17 18
114
    // 2 11 19 20 21  22 23 24 25 26
115
    // 3 12 20 27 28  29 30 31 32 33
116
    // 4 13 21 28 34  35 36 37 38 39
117
    //
118
    // 5 14 22 29 35  40 41 42 43 44
119
    // 6 15 23 30 36  41 45 46 47 48
120
    // 7 16 24 31 37  42 46 49 50 51
121
    // 8 17 25 32 38  43 47 50 52 53
122
    // 9 18 26 33 39  44 48 51 53 54
123
46.2k
    constexpr float kWeights4[55] = {
124
46.2k
        -0.02419067f, -0.03491987f, -0.03693351f, -0.03094285f, -0.00529785f,
125
46.2k
        -0.01663432f, -0.03556863f, -0.03888905f, -0.03516850f, -0.00989469f,
126
46.2k
        0.23651958f,  0.33392945f,  -0.01073543f, -0.01313181f, -0.03556694f,
127
46.2k
        0.13048175f,  0.40103025f,  0.03951150f,  -0.02077584f, 0.46914198f,
128
46.2k
        -0.00209270f, -0.01484589f, -0.04064806f, 0.18942530f,  0.56279892f,
129
46.2k
        0.06674400f,  -0.02335494f, -0.03551682f, -0.00754830f, -0.02267919f,
130
46.2k
        -0.02363578f, 0.00315804f,  -0.03399098f, -0.01359519f, -0.00091653f,
131
46.2k
        -0.00335467f, -0.01163294f, -0.01610294f, -0.00974088f, -0.00191622f,
132
46.2k
        -0.01095446f, -0.03198464f, -0.04455121f, -0.02799790f, -0.00645912f,
133
46.2k
        0.06390599f,  0.22963888f,  0.00630981f,  -0.01897349f, 0.67537268f,
134
46.2k
        0.08483369f,  -0.02534994f, -0.02205197f, -0.01667999f, -0.00384443f};
135
2.58M
    for (size_t i = 0; i < 55; i++) {
136
2.54M
      JXL_QUIET_RETURN_IF_ERROR(
137
2.54M
          visitor->F16(kWeights4[i], &upsampling4_weights[i]));
138
2.54M
    }
139
46.2k
  }
140
52.2k
  if (visitor->Conditional((custom_weights_mask & 0x4) != 0)) {
141
    // typo:off
142
    // 64 5x5 kernels, all of them can be obtained by symmetry from
143
    // 10, 4 of which are symmetric along their main diagonals. The top
144
    // left 16 kernels are defined by
145
    //  0  1  2  3  4   5  6  7  8  9   a  b  c  d  e   f 10 11 12 13
146
    //  1 14 15 16 17  18 19 1a 1b 1c  1d 1e 1f 20 21  22 23 24 25 26
147
    //  2 15 27 28 29  2a 2b 2c 2d 2e  2f 30 31 32 33  34 35 36 37 38
148
    //  3 16 28 39 3a  3b 3c 3d 3e 3f  40 41 42 43 44  45 46 47 48 49
149
    //  4 17 29 3a 4a  4b 4c 4d 4e 4f  50 51 52 53 54  55 56 57 58 59
150
151
    //  5 18 2a 3b 4b  5a 5b 5c 5d 5e  5f 60 61 62 63  64 65 66 67 68
152
    //  6 19 2b 3c 4c  5b 69 6a 6b 6c  6d 6e 6f 70 71  72 73 74 75 76
153
    //  7 1a 2c 3d 4d  5c 6a 77 78 79  7a 7b 7c 7d 7e  7f 80 81 82 83
154
    //  8 1b 2d 3e 4e  5d 6b 78 84 85  86 87 88 89 8a  8b 8c 8d 8e 8f
155
    //  9 1c 2e 3f 4f  5e 6c 79 85 90  91 92 93 94 95  96 97 98 99 9a
156
157
    //  a 1d 2f 40 50  5f 6d 7a 86 91  9b 9c 9d 9e 9f  a0 a1 a2 a3 a4
158
    //  b 1e 30 41 51  60 6e 7b 87 92  9c a5 a6 a7 a8  a9 aa ab ac ad
159
    //  c 1f 31 42 52  61 6f 7c 88 93  9d a6 ae af b0  b1 b2 b3 b4 b5
160
    //  d 20 32 43 53  62 70 7d 89 94  9e a7 af b6 b7  b8 b9 ba bb bc
161
    //  e 21 33 44 54  63 71 7e 8a 95  9f a8 b0 b7 bd  be bf c0 c1 c2
162
163
    //  f 22 34 45 55  64 72 7f 8b 96  a0 a9 b1 b8 be  c3 c4 c5 c6 c7
164
    // 10 23 35 46 56  65 73 80 8c 97  a1 aa b2 b9 bf  c4 c8 c9 ca cb
165
    // 11 24 36 47 57  66 74 81 8d 98  a2 ab b3 ba c0  c5 c9 cc cd ce
166
    // 12 25 37 48 58  67 75 82 8e 99  a3 ac b4 bb c1  c6 ca cd cf d0
167
    // 13 26 38 49 59  68 76 83 8f 9a  a4 ad b5 bc c2  c7 cb ce d0 d1
168
    // typo:on
169
46.0k
    constexpr float kWeights8[210] = {
170
46.0k
        -0.02928613f, -0.03706353f, -0.03783812f, -0.03324558f, -0.00447632f,
171
46.0k
        -0.02519406f, -0.03752601f, -0.03901508f, -0.03663285f, -0.00646649f,
172
46.0k
        -0.02066407f, -0.03838633f, -0.04002101f, -0.03900035f, -0.00901973f,
173
46.0k
        -0.01626393f, -0.03954148f, -0.04046620f, -0.03979621f, -0.01224485f,
174
46.0k
        0.29895328f,  0.35757708f,  -0.02447552f, -0.01081748f, -0.04314594f,
175
46.0k
        0.23903219f,  0.41119301f,  -0.00573046f, -0.01450239f, -0.04246845f,
176
46.0k
        0.17567618f,  0.45220643f,  0.02287757f,  -0.01936783f, -0.03583255f,
177
46.0k
        0.11572472f,  0.47416733f,  0.06284440f,  -0.02685066f, 0.42720050f,
178
46.0k
        -0.02248939f, -0.01155273f, -0.04562755f, 0.28689496f,  0.49093869f,
179
46.0k
        -0.00007891f, -0.01545926f, -0.04562659f, 0.21238920f,  0.53980934f,
180
46.0k
        0.03369474f,  -0.02070211f, -0.03866988f, 0.14229550f,  0.56593398f,
181
46.0k
        0.08045181f,  -0.02888298f, -0.03680918f, -0.00542229f, -0.02920477f,
182
46.0k
        -0.02788574f, -0.02118180f, -0.03942402f, -0.00775547f, -0.02433614f,
183
46.0k
        -0.03193943f, -0.02030828f, -0.04044014f, -0.01074016f, -0.01930822f,
184
46.0k
        -0.03620399f, -0.01974125f, -0.03919545f, -0.01456093f, -0.00045072f,
185
46.0k
        -0.00360110f, -0.01020207f, -0.01231907f, -0.00638988f, -0.00071592f,
186
46.0k
        -0.00279122f, -0.00957115f, -0.01288327f, -0.00730937f, -0.00107783f,
187
46.0k
        -0.00210156f, -0.00890705f, -0.01317668f, -0.00813895f, -0.00153491f,
188
46.0k
        -0.02128481f, -0.04173044f, -0.04831487f, -0.03293190f, -0.00525260f,
189
46.0k
        -0.01720322f, -0.04052736f, -0.05045706f, -0.03607317f, -0.00738030f,
190
46.0k
        -0.01341764f, -0.03965629f, -0.05151616f, -0.03814886f, -0.01005819f,
191
46.0k
        0.18968273f,  0.33063684f,  -0.01300105f, -0.01372950f, -0.04017465f,
192
46.0k
        0.13727832f,  0.36402234f,  0.01027890f,  -0.01832107f, -0.03365072f,
193
46.0k
        0.08734506f,  0.38194295f,  0.04338228f,  -0.02525993f, 0.56408126f,
194
46.0k
        0.00458352f,  -0.01648227f, -0.04887868f, 0.24585519f,  0.62026135f,
195
46.0k
        0.04314807f,  -0.02213737f, -0.04158014f, 0.16637289f,  0.65027023f,
196
46.0k
        0.09621636f,  -0.03101388f, -0.04082742f, -0.00904519f, -0.02790922f,
197
46.0k
        -0.02117818f, 0.00798662f,  -0.03995711f, -0.01243427f, -0.02231705f,
198
46.0k
        -0.02946266f, 0.00992055f,  -0.03600283f, -0.01684920f, -0.00111684f,
199
46.0k
        -0.00411204f, -0.01297130f, -0.01723725f, -0.01022545f, -0.00165306f,
200
46.0k
        -0.00313110f, -0.01218016f, -0.01763266f, -0.01125620f, -0.00231663f,
201
46.0k
        -0.01374149f, -0.03797620f, -0.05142937f, -0.03117307f, -0.00581914f,
202
46.0k
        -0.01064003f, -0.03608089f, -0.05272168f, -0.03375670f, -0.00795586f,
203
46.0k
        0.09628104f,  0.27129991f,  -0.00353779f, -0.01734151f, -0.03153981f,
204
46.0k
        0.05686230f,  0.28500998f,  0.02230594f,  -0.02374955f, 0.68214326f,
205
46.0k
        0.05018048f,  -0.02320852f, -0.04383616f, 0.18459474f,  0.71517975f,
206
46.0k
        0.10805613f,  -0.03263677f, -0.03637639f, -0.01394373f, -0.02511203f,
207
46.0k
        -0.01728636f, 0.05407331f,  -0.02867568f, -0.01893131f, -0.00240854f,
208
46.0k
        -0.00446511f, -0.01636187f, -0.02377053f, -0.01522848f, -0.00333334f,
209
46.0k
        -0.00819975f, -0.02964169f, -0.04499287f, -0.02745350f, -0.00612408f,
210
46.0k
        0.02727416f,  0.19446600f,  0.00159832f,  -0.02232473f, 0.74982506f,
211
46.0k
        0.11452620f,  -0.03348048f, -0.01605681f, -0.02070339f, -0.00458223f};
212
9.69M
    for (size_t i = 0; i < 210; i++) {
213
9.65M
      JXL_QUIET_RETURN_IF_ERROR(
214
9.65M
          visitor->F16(kWeights8[i], &upsampling8_weights[i]));
215
9.65M
    }
216
46.0k
  }
217
52.1k
  return true;
218
52.2k
}
219
220
273k
ExtraChannelInfo::ExtraChannelInfo() { Bundle::Init(this); }
221
313k
Status ExtraChannelInfo::VisitFields(Visitor* JXL_RESTRICT visitor) {
222
313k
  if (visitor->AllDefault(*this, &all_default)) {
223
    // Overwrite all serialized fields, but not any nonserialized_*.
224
18.1k
    visitor->SetDefault(this);
225
18.1k
    return true;
226
18.1k
  }
227
228
  // General
229
295k
  JXL_QUIET_RETURN_IF_ERROR(visitor->Enum(ExtraChannel::kAlpha, &type));
230
231
295k
  JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&bit_depth));
232
233
294k
  JXL_QUIET_RETURN_IF_ERROR(
234
294k
      visitor->U32(Val(0), Val(3), Val(4), BitsOffset(3, 1), 0, &dim_shift));
235
294k
  if ((1U << dim_shift) > 8) {
236
14
    return JXL_FAILURE("dim_shift %u too large", dim_shift);
237
14
  }
238
239
294k
  JXL_QUIET_RETURN_IF_ERROR(VisitNameString(visitor, &name));
240
241
  // Conditional
242
294k
  if (visitor->Conditional(type == ExtraChannel::kAlpha)) {
243
293k
    JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &alpha_associated));
244
293k
  }
245
294k
  if (visitor->Conditional(type == ExtraChannel::kSpotColor)) {
246
1.16M
    for (float& c : spot_color) {
247
1.16M
      JXL_QUIET_RETURN_IF_ERROR(visitor->F16(0, &c));
248
1.16M
    }
249
291k
  }
250
294k
  if (visitor->Conditional(type == ExtraChannel::kCFA)) {
251
291k
    JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(1), Bits(2), BitsOffset(4, 3),
252
291k
                                           BitsOffset(8, 19), 1, &cfa_channel));
253
291k
  }
254
255
294k
  if (type == ExtraChannel::kUnknown ||
256
294k
      (static_cast<int>(ExtraChannel::kReserved0) <= static_cast<int>(type) &&
257
294k
       static_cast<int>(type) <= static_cast<int>(ExtraChannel::kReserved7))) {
258
4
    return JXL_FAILURE("Unknown extra channel (bits %u, shift %u, name '%s')\n",
259
4
                       bit_depth.bits_per_sample, dim_shift, name.c_str());
260
4
  }
261
294k
  return true;
262
294k
}
263
264
#if JXL_DEBUG_V_LEVEL >= 1
265
std::string ExtraChannelInfo::DebugString() const {
266
  std::ostringstream os;
267
  os << (type == ExtraChannel::kAlpha           ? "Alpha"
268
         : type == ExtraChannel::kDepth         ? "Depth"
269
         : type == ExtraChannel::kSpotColor     ? "Spot"
270
         : type == ExtraChannel::kSelectionMask ? "Mask"
271
         : type == ExtraChannel::kBlack         ? "Black"
272
         : type == ExtraChannel::kCFA           ? "CFA"
273
         : type == ExtraChannel::kThermal       ? "Thermal"
274
                                                : "Unknown");
275
  if (type == ExtraChannel::kAlpha && alpha_associated) os << "(premul)";
276
  os << " " << bit_depth.DebugString();
277
  os << " shift: " << dim_shift;
278
  return os.str();
279
}
280
#endif
281
282
44.0k
ImageMetadata::ImageMetadata() { Bundle::Init(this); }
283
83.9k
Status ImageMetadata::VisitFields(Visitor* JXL_RESTRICT visitor) {
284
83.9k
  if (visitor->AllDefault(*this, &all_default)) {
285
    // Overwrite all serialized fields, but not any nonserialized_*.
286
14.9k
    visitor->SetDefault(this);
287
14.9k
    return true;
288
14.9k
  }
289
290
  // Bundle::AllDefault does not allow usage when reading (it may abort the
291
  // program when a codestream has invalid values), but when reading we
292
  // overwrite the extra_fields value, so do not need to call AllDefault.
293
68.9k
  bool tone_mapping_default =
294
68.9k
      visitor->IsReading() ? false : Bundle::AllDefault(tone_mapping);
295
296
68.9k
  bool extra_fields = (orientation != 1 || have_preview || have_animation ||
297
68.9k
                       have_intrinsic_size || !tone_mapping_default);
298
68.9k
  JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &extra_fields));
299
68.9k
  if (visitor->Conditional(extra_fields)) {
300
59.8k
    orientation--;
301
59.8k
    JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(3, 0, &orientation));
302
59.8k
    orientation++;
303
    // (No need for bounds checking because we read exactly 3 bits)
304
305
59.8k
    JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &have_intrinsic_size));
306
59.8k
    if (visitor->Conditional(have_intrinsic_size)) {
307
59.0k
      JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&intrinsic_size));
308
59.0k
    }
309
59.8k
    JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &have_preview));
310
59.8k
    if (visitor->Conditional(have_preview)) {
311
59.1k
      JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&preview_size));
312
59.1k
    }
313
59.7k
    JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &have_animation));
314
59.7k
    if (visitor->Conditional(have_animation)) {
315
59.2k
      JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&animation));
316
59.2k
    }
317
59.7k
  } else {
318
9.13k
    orientation = 1;  // identity
319
9.13k
    have_intrinsic_size = false;
320
9.13k
    have_preview = false;
321
9.13k
    have_animation = false;
322
9.13k
  }
323
324
68.8k
  JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&bit_depth));
325
68.8k
  JXL_QUIET_RETURN_IF_ERROR(
326
68.8k
      visitor->Bool(true, &modular_16_bit_buffer_sufficient));
327
328
68.8k
  num_extra_channels = extra_channel_info.size();
329
68.8k
  JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(0), Val(1), BitsOffset(4, 2),
330
68.8k
                                         BitsOffset(12, 1), 0,
331
68.8k
                                         &num_extra_channels));
332
333
68.8k
  if (visitor->Conditional(num_extra_channels != 0)) {
334
62.4k
    if (visitor->IsReading()) {
335
3.69k
      extra_channel_info.resize(num_extra_channels);
336
3.69k
    }
337
62.4k
    for (ExtraChannelInfo& eci : extra_channel_info) {
338
21.5k
      JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&eci));
339
21.5k
    }
340
62.4k
  }
341
342
68.3k
  JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(true, &xyb_encoded));
343
68.3k
  JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&color_encoding));
344
68.1k
  if (visitor->Conditional(extra_fields)) {
345
59.6k
    JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&tone_mapping));
346
59.6k
  }
347
348
  // Treat as if only the fields up to extra channels exist.
349
68.1k
  if (visitor->IsReading() && nonserialized_only_parse_basic_info) {
350
0
    return true;
351
0
  }
352
353
68.1k
  JXL_QUIET_RETURN_IF_ERROR(visitor->BeginExtensions(&extensions));
354
  // Extensions: in chronological order of being added to the format.
355
67.7k
  return visitor->EndExtensions();
356
68.1k
}
357
358
29.7k
OpsinInverseMatrix::OpsinInverseMatrix() { Bundle::Init(this); }
359
53.6k
Status OpsinInverseMatrix::VisitFields(Visitor* JXL_RESTRICT visitor) {
360
53.6k
  if (visitor->AllDefault(*this, &all_default)) {
361
    // Overwrite all serialized fields, but not any nonserialized_*.
362
3.14k
    visitor->SetDefault(this);
363
3.14k
    return true;
364
3.14k
  }
365
50.5k
  const Matrix3x3& default_inverse =
366
50.5k
      jxl::cms::DefaultInverseOpsinAbsorbanceMatrix();
367
201k
  for (int j = 0; j < 3; ++j) {
368
605k
    for (int i = 0; i < 3; ++i) {
369
454k
      JXL_QUIET_RETURN_IF_ERROR(
370
454k
          visitor->F16(default_inverse[j][i], &inverse_matrix[j][i]));
371
454k
    }
372
151k
  }
373
201k
  for (int i = 0; i < 3; ++i) {
374
151k
    JXL_QUIET_RETURN_IF_ERROR(visitor->F16(
375
151k
        jxl::cms::kNegOpsinAbsorbanceBiasRGB[i], &opsin_biases[i]));
376
151k
  }
377
251k
  for (int i = 0; i < 4; ++i) {
378
201k
    JXL_QUIET_RETURN_IF_ERROR(
379
201k
        visitor->F16(kDefaultQuantBias[i], &quant_biases[i]));
380
201k
  }
381
50.3k
  return true;
382
50.3k
}
383
384
44.0k
ToneMapping::ToneMapping() { Bundle::Init(this); }
385
119k
Status ToneMapping::VisitFields(Visitor* JXL_RESTRICT visitor) {
386
119k
  if (visitor->AllDefault(*this, &all_default)) {
387
    // Overwrite all serialized fields, but not any nonserialized_*.
388
669
    visitor->SetDefault(this);
389
669
    return true;
390
669
  }
391
392
118k
  JXL_QUIET_RETURN_IF_ERROR(
393
118k
      visitor->F16(kDefaultIntensityTarget, &intensity_target));
394
118k
  if (intensity_target <= 0.f) {
395
14
    return JXL_FAILURE("invalid intensity target");
396
14
  }
397
398
118k
  JXL_QUIET_RETURN_IF_ERROR(visitor->F16(0.0f, &min_nits));
399
118k
  if (min_nits < 0.f || min_nits > intensity_target) {
400
8
    return JXL_FAILURE("invalid min %f vs max %f", min_nits, intensity_target);
401
8
  }
402
403
118k
  JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &relative_to_max_display));
404
405
118k
  JXL_QUIET_RETURN_IF_ERROR(visitor->F16(0.0f, &linear_below));
406
118k
  if (linear_below < 0 || (relative_to_max_display && linear_below > 1.0f)) {
407
8
    return JXL_FAILURE("invalid linear_below %f (%s)", linear_below,
408
8
                       relative_to_max_display ? "relative" : "absolute");
409
8
  }
410
411
118k
  return true;
412
118k
}
413
414
Status ReadImageMetadata(BitReader* JXL_RESTRICT reader,
415
0
                         ImageMetadata* JXL_RESTRICT metadata) {
416
0
  return Bundle::Read(reader, metadata);
417
0
}
418
419
0
void ImageMetadata::SetAlphaBits(uint32_t bits, bool alpha_is_premultiplied) {
420
0
  std::vector<ExtraChannelInfo>& eciv = extra_channel_info;
421
0
  ExtraChannelInfo* alpha = Find(ExtraChannel::kAlpha);
422
0
  if (bits == 0) {
423
0
    if (alpha != nullptr) {
424
      // Remove the alpha channel from the extra channel info. It's
425
      // theoretically possible that there are multiple, remove all in that
426
      // case. This ensure a next HasAlpha() will return false.
427
0
      const auto is_alpha = [](const ExtraChannelInfo& eci) {
428
0
        return eci.type == ExtraChannel::kAlpha;
429
0
      };
430
0
      eciv.erase(std::remove_if(eciv.begin(), eciv.end(), is_alpha),
431
0
                 eciv.end());
432
0
    }
433
0
  } else {
434
0
    if (alpha == nullptr) {
435
0
      ExtraChannelInfo info;
436
0
      info.type = ExtraChannel::kAlpha;
437
0
      info.bit_depth.bits_per_sample = bits;
438
0
      info.dim_shift = 0;
439
0
      info.alpha_associated = alpha_is_premultiplied;
440
      // Prepend rather than append: in case there already are other extra
441
      // channels, prefer alpha channel to be listed first.
442
0
      eciv.insert(eciv.begin(), info);
443
0
    } else {
444
      // Ignores potential extra alpha channels, only sets to first one.
445
0
      alpha->bit_depth.bits_per_sample = bits;
446
0
      alpha->bit_depth.floating_point_sample = false;
447
0
      alpha->bit_depth.exponent_bits_per_sample = 0;
448
0
      alpha->alpha_associated = alpha_is_premultiplied;
449
0
    }
450
0
  }
451
0
  num_extra_channels = extra_channel_info.size();
452
0
  if (bits > 12) modular_16_bit_buffer_sufficient = false;
453
0
}
454
455
#if JXL_DEBUG_V_LEVEL >= 1
456
std::string ImageMetadata::DebugString() const {
457
  std::ostringstream os;
458
  os << bit_depth.DebugString();
459
  if (modular_16_bit_buffer_sufficient) {
460
    os << " (modular 16)";
461
  }
462
  os << (xyb_encoded ? " xyb encoded" : " orig profile");
463
  os << " " << Description(color_encoding);
464
  if (num_extra_channels > 0) {
465
    os << " extra channels:";
466
    for (size_t i = 0; i < num_extra_channels; ++i) {
467
      os << " (" << extra_channel_info[i].DebugString() << ")";
468
      if (i + 1 < num_extra_channels) os << ",";
469
    }
470
  }
471
  if (have_preview) {
472
    os << " preview: " << preview_size.xsize() << "x" << preview_size.ysize();
473
  }
474
  if (orientation != 1) {
475
    os << " orientation: " << orientation;
476
  }
477
  return os.str();
478
}
479
480
std::string CodecMetadata::DebugString() const {
481
  std::ostringstream os;
482
  os << size.xsize() << "x" << size.ysize();
483
  os << " " << m.DebugString();
484
  return os.str();
485
}
486
#endif
487
488
}  // namespace jxl