/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 |