Coverage Report

Created: 2025-06-16 07:00

/src/libjxl/lib/jxl/image_metadata.h
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
// Main codestream header bundles, the metadata that applies to all frames.
7
// Enums must align with the C API definitions in codestream_header.h.
8
9
#ifndef LIB_JXL_IMAGE_METADATA_H_
10
#define LIB_JXL_IMAGE_METADATA_H_
11
12
#include <jxl/codestream_header.h>
13
14
#include <cstddef>
15
#include <cstdint>
16
#include <string>
17
#include <vector>
18
19
#include "lib/jxl/base/compiler_specific.h"
20
#include "lib/jxl/base/matrix_ops.h"
21
#include "lib/jxl/base/status.h"
22
#include "lib/jxl/color_encoding_internal.h"
23
#include "lib/jxl/dec_bit_reader.h"
24
#include "lib/jxl/field_encodings.h"
25
#include "lib/jxl/fields.h"
26
#include "lib/jxl/headers.h"
27
28
namespace jxl {
29
30
struct AuxOut;
31
enum class LayerType : uint8_t;
32
33
// EXIF orientation of the image. This field overrides any field present in
34
// actual EXIF metadata. The value tells which transformation the decoder must
35
// apply after decoding to display the image with the correct orientation.
36
enum class Orientation : uint32_t {
37
  // Values 1..8 match the EXIF definitions.
38
  kIdentity = JXL_ORIENT_IDENTITY,
39
  kFlipHorizontal = JXL_ORIENT_FLIP_HORIZONTAL,
40
  kRotate180 = JXL_ORIENT_ROTATE_180,
41
  kFlipVertical = JXL_ORIENT_FLIP_VERTICAL,
42
  kTranspose = JXL_ORIENT_TRANSPOSE,
43
  kRotate90 = JXL_ORIENT_ROTATE_90_CW,
44
  kAntiTranspose = JXL_ORIENT_ANTI_TRANSPOSE,
45
  kRotate270 = JXL_ORIENT_ROTATE_90_CCW,
46
};
47
// Don't need an EnumBits because Orientation is not read via Enum().
48
49
enum class ExtraChannel : uint32_t {
50
  // First two enumerators (most common) are cheaper to encode
51
  kAlpha = JXL_CHANNEL_ALPHA,
52
  kDepth = JXL_CHANNEL_DEPTH,
53
54
  kSpotColor = JXL_CHANNEL_SPOT_COLOR,
55
  kSelectionMask = JXL_CHANNEL_SELECTION_MASK,
56
  kBlack = JXL_CHANNEL_BLACK,  // for CMYK
57
  kCFA = JXL_CHANNEL_CFA,      // Bayer channel
58
  kThermal = JXL_CHANNEL_THERMAL,
59
  kReserved0 = JXL_CHANNEL_RESERVED0,
60
  kReserved1 = JXL_CHANNEL_RESERVED1,
61
  kReserved2 = JXL_CHANNEL_RESERVED2,
62
  kReserved3 = JXL_CHANNEL_RESERVED3,
63
  kReserved4 = JXL_CHANNEL_RESERVED4,
64
  kReserved5 = JXL_CHANNEL_RESERVED5,
65
  kReserved6 = JXL_CHANNEL_RESERVED6,
66
  kReserved7 = JXL_CHANNEL_RESERVED7,
67
  // disambiguated via name string, raise warning if unsupported
68
  kUnknown = JXL_CHANNEL_UNKNOWN,
69
  // like kUnknown but can silently be ignored
70
  kOptional = JXL_CHANNEL_OPTIONAL
71
};
72
50
static inline const char* EnumName(ExtraChannel /*unused*/) {
73
50
  return "ExtraChannel";
74
50
}
Unexecuted instantiation: encode.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_fields.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_ans.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_lz77.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_fast_lossless.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_frame.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_modular.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_patch_dictionary.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_dot_dictionary.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_detect_dots.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_debug_image.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_quant_weights.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_xyb.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_image_bundle.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_external_image.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_heuristics.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_adaptive_quantization.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_butteraugli_comparator.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_cache.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_group.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_progressive_split.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_chroma_from_luma.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_ac_strategy.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_entropy_coder.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_jpeg_data.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: enc_encoding.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: compressed_dc.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: dec_cache.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: blending.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: dec_external_image.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: dec_frame.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: dec_group.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: dec_modular.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: dec_noise.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: dec_patch_dictionary.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: dec_xyb.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: decode.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: epf.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: frame_header.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: image_bundle.cc:jxl::EnumName(jxl::ExtraChannel)
image_metadata.cc:jxl::EnumName(jxl::ExtraChannel)
Line
Count
Source
72
50
static inline const char* EnumName(ExtraChannel /*unused*/) {
73
50
  return "ExtraChannel";
74
50
}
Unexecuted instantiation: luminance.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: passes_state.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: quant_weights.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: render_pipeline.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: low_memory_render_pipeline.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: simple_render_pipeline.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: stage_blending.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: render_pipeline_stage.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: stage_chroma_upsampling.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: stage_cms.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: stage_epf.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: stage_from_linear.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: stage_gaborish.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: stage_noise.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: stage_patches.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: stage_splines.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: stage_spot.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: stage_to_linear.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: stage_tone_mapping.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: stage_upsampling.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: stage_write.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: stage_xyb.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: stage_ycbcr.cc:jxl::EnumName(jxl::ExtraChannel)
Unexecuted instantiation: decode_to_jpeg.cc:jxl::EnumName(jxl::ExtraChannel)
75
295k
static inline constexpr uint64_t EnumBits(ExtraChannel /*unused*/) {
76
295k
  using EC = ExtraChannel;
77
295k
  return MakeBit(EC::kAlpha) | MakeBit(EC::kDepth) | MakeBit(EC::kSpotColor) |
78
295k
         MakeBit(EC::kSelectionMask) | MakeBit(EC::kBlack) | MakeBit(EC::kCFA) |
79
295k
         MakeBit(EC::kThermal) | MakeBit(EC::kUnknown) | MakeBit(EC::kOptional);
80
295k
}
Unexecuted instantiation: encode.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_fields.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_ans.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_lz77.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_fast_lossless.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_frame.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_modular.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_patch_dictionary.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_dot_dictionary.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_detect_dots.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_debug_image.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_quant_weights.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_xyb.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_image_bundle.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_external_image.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_heuristics.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_adaptive_quantization.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_butteraugli_comparator.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_cache.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_group.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_progressive_split.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_chroma_from_luma.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_ac_strategy.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_entropy_coder.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_jpeg_data.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: enc_encoding.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: compressed_dc.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: dec_cache.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: blending.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: dec_external_image.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: dec_frame.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: dec_group.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: dec_modular.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: dec_noise.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: dec_patch_dictionary.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: dec_xyb.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: decode.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: epf.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: frame_header.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: image_bundle.cc:jxl::EnumBits(jxl::ExtraChannel)
image_metadata.cc:jxl::EnumBits(jxl::ExtraChannel)
Line
Count
Source
75
295k
static inline constexpr uint64_t EnumBits(ExtraChannel /*unused*/) {
76
295k
  using EC = ExtraChannel;
77
295k
  return MakeBit(EC::kAlpha) | MakeBit(EC::kDepth) | MakeBit(EC::kSpotColor) |
78
295k
         MakeBit(EC::kSelectionMask) | MakeBit(EC::kBlack) | MakeBit(EC::kCFA) |
79
295k
         MakeBit(EC::kThermal) | MakeBit(EC::kUnknown) | MakeBit(EC::kOptional);
80
295k
}
Unexecuted instantiation: luminance.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: passes_state.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: quant_weights.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: render_pipeline.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: low_memory_render_pipeline.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: simple_render_pipeline.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: stage_blending.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: render_pipeline_stage.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: stage_chroma_upsampling.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: stage_cms.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: stage_epf.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: stage_from_linear.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: stage_gaborish.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: stage_noise.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: stage_patches.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: stage_splines.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: stage_spot.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: stage_to_linear.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: stage_tone_mapping.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: stage_upsampling.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: stage_write.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: stage_xyb.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: stage_ycbcr.cc:jxl::EnumBits(jxl::ExtraChannel)
Unexecuted instantiation: decode_to_jpeg.cc:jxl::EnumBits(jxl::ExtraChannel)
81
82
// Used in ImageMetadata and ExtraChannelInfo.
83
struct BitDepth : public Fields {
84
  BitDepth();
85
  JXL_FIELDS_NAME(BitDepth)
86
87
  Status VisitFields(Visitor* JXL_RESTRICT visitor) override;
88
89
  std::string DebugString() const;
90
91
  // Whether the original (uncompressed) samples are floating point or
92
  // unsigned integer.
93
  bool floating_point_sample;
94
95
  // Bit depth of the original (uncompressed) image samples. Must be in the
96
  // range [1, 32].
97
  uint32_t bits_per_sample;
98
99
  // Floating point exponent bits of the original (uncompressed) image samples,
100
  // only used if floating_point_sample is true.
101
  // If used, the samples are floating point with:
102
  // - 1 sign bit
103
  // - exponent_bits_per_sample exponent bits
104
  // - (bits_per_sample - exponent_bits_per_sample - 1) mantissa bits
105
  // If used, exponent_bits_per_sample must be in the range
106
  // [2, 8] and amount of mantissa bits must be in the range [2, 23].
107
  // NOTE: exponent_bits_per_sample is 8 for single precision binary32
108
  // point, 5 for half precision binary16, 7 for fp24.
109
  uint32_t exponent_bits_per_sample;
110
};
111
112
// Describes one extra channel.
113
struct ExtraChannelInfo : public Fields {
114
  ExtraChannelInfo();
115
  JXL_FIELDS_NAME(ExtraChannelInfo)
116
117
  Status VisitFields(Visitor* JXL_RESTRICT visitor) override;
118
119
  std::string DebugString() const;
120
121
  mutable bool all_default;
122
123
  ExtraChannel type;
124
  BitDepth bit_depth;
125
  uint32_t dim_shift;  // downsampled by 2^dim_shift on each axis
126
127
  std::string name;  // UTF-8
128
129
  // Conditional:
130
  bool alpha_associated;  // i.e. premultiplied
131
  float spot_color[4];    // spot color in linear RGBA
132
  uint32_t cfa_channel;
133
};
134
135
struct OpsinInverseMatrix : public Fields {
136
  OpsinInverseMatrix();
137
  JXL_FIELDS_NAME(OpsinInverseMatrix)
138
139
  Status VisitFields(Visitor* JXL_RESTRICT visitor) override;
140
141
  mutable bool all_default;
142
143
  Matrix3x3 inverse_matrix;
144
  float opsin_biases[3];
145
  float quant_biases[4];
146
};
147
148
// Information useful for mapping HDR images to lower dynamic range displays.
149
struct ToneMapping : public Fields {
150
  ToneMapping();
151
  JXL_FIELDS_NAME(ToneMapping)
152
153
  Status VisitFields(Visitor* JXL_RESTRICT visitor) override;
154
155
  mutable bool all_default;
156
157
  // Upper bound on the intensity level present in the image. For unsigned
158
  // integer pixel encodings, this is the brightness of the largest
159
  // representable value. The image does not necessarily contain a pixel
160
  // actually this bright. An encoder is allowed to set 255 for SDR images
161
  // without computing a histogram.
162
  float intensity_target;  // [nits]
163
164
  // Lower bound on the intensity level present in the image. This may be
165
  // loose, i.e. lower than the actual darkest pixel. When tone mapping, a
166
  // decoder will map [min_nits, intensity_target] to the display range.
167
  float min_nits;
168
169
  bool relative_to_max_display;  // see below
170
  // The tone mapping will leave unchanged (linear mapping) any pixels whose
171
  // brightness is strictly below this. The interpretation depends on
172
  // relative_to_max_display. If true, this is a ratio [0, 1] of the maximum
173
  // display brightness [nits], otherwise an absolute brightness [nits].
174
  float linear_below;
175
};
176
177
// Contains weights to customize some transforms - in particular, XYB and
178
// upsampling.
179
struct CustomTransformData : public Fields {
180
  CustomTransformData();
181
  JXL_FIELDS_NAME(CustomTransformData)
182
183
  Status VisitFields(Visitor* JXL_RESTRICT visitor) override;
184
185
  // Must be set before calling VisitFields. Must equal xyb_encoded of
186
  // ImageMetadata, should be set by ImageMetadata during VisitFields.
187
  bool nonserialized_xyb_encoded = false;
188
189
  mutable bool all_default;
190
191
  OpsinInverseMatrix opsin_inverse_matrix;
192
193
  uint32_t custom_weights_mask;
194
  float upsampling2_weights[15];
195
  float upsampling4_weights[55];
196
  float upsampling8_weights[210];
197
};
198
199
// Properties of the original image bundle. This enables Encode(Decode()) to
200
// re-create an equivalent image without user input.
201
struct ImageMetadata : public Fields {
202
  ImageMetadata();
203
  JXL_FIELDS_NAME(ImageMetadata)
204
205
  Status VisitFields(Visitor* JXL_RESTRICT visitor) override;
206
207
  // Returns bit depth of the JPEG XL compressed alpha channel, or 0 if no alpha
208
  // channel present. In the theoretical case that there are multiple alpha
209
  // channels, returns the bit depth of the first.
210
186
  uint32_t GetAlphaBits() const {
211
186
    const ExtraChannelInfo* alpha = Find(ExtraChannel::kAlpha);
212
186
    if (alpha == nullptr) return 0;
213
14
    JXL_DASSERT(alpha->bit_depth.bits_per_sample != 0);
214
14
    return alpha->bit_depth.bits_per_sample;
215
186
  }
216
217
  // Sets bit depth of alpha channel, adding extra channel if needed, or
218
  // removing all alpha channels if bits is 0.
219
  // Assumes integer alpha channel and not designed to support multiple
220
  // alpha channels (it's possible to use those features by manipulating
221
  // extra_channel_info directly).
222
  //
223
  // Callers must insert the actual channel image at the same index before any
224
  // further modifications to extra_channel_info.
225
  void SetAlphaBits(uint32_t bits, bool alpha_is_premultiplied = false);
226
227
186
  bool HasAlpha() const { return GetAlphaBits() != 0; }
228
229
  // Sets the original bit depth fields to indicate unsigned integer of the
230
  // given bit depth.
231
  // TODO(lode): move function to BitDepth
232
0
  void SetUintSamples(uint32_t bits) {
233
0
    bit_depth.bits_per_sample = bits;
234
0
    bit_depth.exponent_bits_per_sample = 0;
235
0
    bit_depth.floating_point_sample = false;
236
0
    // RCT / Squeeze may add one bit each, and this is about int16_t,
237
0
    // so uint13 should still be OK but limiting it to 12 seems safer.
238
0
    // TODO(jon): figure out a better way to set this header field.
239
0
    // (in particular, if modular mode is not used it doesn't matter,
240
0
    // and if transforms are restricted, up to 15-bit could be done)
241
0
    if (bits > 12) modular_16_bit_buffer_sufficient = false;
242
0
  }
243
  // Sets the original bit depth fields to indicate single precision floating
244
  // point.
245
  // TODO(lode): move function to BitDepth
246
0
  void SetFloat32Samples() {
247
0
    bit_depth.bits_per_sample = 32;
248
0
    bit_depth.exponent_bits_per_sample = 8;
249
0
    bit_depth.floating_point_sample = true;
250
0
    modular_16_bit_buffer_sufficient = false;
251
0
  }
252
253
0
  void SetFloat16Samples() {
254
0
    bit_depth.bits_per_sample = 16;
255
0
    bit_depth.exponent_bits_per_sample = 5;
256
0
    bit_depth.floating_point_sample = true;
257
0
    modular_16_bit_buffer_sufficient = false;
258
0
  }
259
260
217
  void SetIntensityTarget(float intensity_target) {
261
217
    tone_mapping.intensity_target = intensity_target;
262
217
  }
263
21.6k
  float IntensityTarget() const {
264
21.6k
    JXL_DASSERT(tone_mapping.intensity_target != 0.0f);
265
21.6k
    return tone_mapping.intensity_target;
266
21.6k
  }
267
268
  // Returns first ExtraChannelInfo of the given type, or nullptr if none.
269
38.3k
  const ExtraChannelInfo* Find(ExtraChannel type) const {
270
38.3k
    for (const ExtraChannelInfo& eci : extra_channel_info) {
271
8.57k
      if (eci.type == type) return &eci;
272
8.57k
    }
273
36.5k
    return nullptr;
274
38.3k
  }
275
276
  // Returns first ExtraChannelInfo of the given type, or nullptr if none.
277
0
  ExtraChannelInfo* Find(ExtraChannel type) {
278
0
    for (ExtraChannelInfo& eci : extra_channel_info) {
279
0
      if (eci.type == type) return &eci;
280
0
    }
281
0
    return nullptr;
282
0
  }
283
284
25.1k
  Orientation GetOrientation() const {
285
25.1k
    return static_cast<Orientation>(orientation);
286
25.1k
  }
287
288
  bool ExtraFieldsDefault() const;
289
290
  std::string DebugString() const;
291
292
  mutable bool all_default;
293
294
  BitDepth bit_depth;
295
  bool modular_16_bit_buffer_sufficient;  // otherwise 32 is.
296
297
  // Whether the colors values of the pixels of frames are encoded in the
298
  // codestream using the absolute XYB color space, or the using values that
299
  // follow the color space defined by the ColorEncoding or ICC profile. This
300
  // determines when or whether a CMS (Color Management System) is needed to get
301
  // the pixels in a desired color space. In one case, the pixels have one known
302
  // color space and a CMS is needed to convert them to the original image's
303
  // color space, in the other case the pixels have the color space of the
304
  // original image and a CMS is required if a different display space, or a
305
  // single known consistent color space for multiple decoded images, is
306
  // desired. In all cases, the color space of all frames from a single image is
307
  // the same, both VarDCT and modular frames.
308
  //
309
  // If true: then frames can be decoded to XYB (which can also be converted to
310
  // linear and non-linear sRGB with the built in conversion without CMS). The
311
  // attached ColorEncoding or ICC profile has no effect on the meaning of the
312
  // pixel's color values, but instead indicates what the color profile of the
313
  // original image was, and what color profile one should convert to when
314
  // decoding to integers to prevent clipping and precision loss. To do that
315
  // conversion requires a CMS.
316
  //
317
  // If false: then the color values of decoded frames are in the space defined
318
  // by the attached ColorEncoding or ICC profile. To instead get the pixels in
319
  // a chosen known color space, such as sRGB, requires a CMS, since the
320
  // attached ColorEncoding or ICC profile could be any arbitrary color space.
321
  // This mode is typically used for lossless images encoded as integers.
322
  // Frames can also use YCbCr encoding, some frames may and some may not, but
323
  // this is not a different color space but a certain encoding of the RGB
324
  // values.
325
  //
326
  // Note: if !xyb_encoded, but the attached color profile indicates XYB (which
327
  // can happen either if it's a ColorEncoding with color_space_ ==
328
  // ColorSpace::kXYB, or if it's an ICC Profile that has been crafted to
329
  // represent XYB), then the frames still may not use ColorEncoding kXYB, they
330
  // must still use kNone (or kYCbCr, which would mean applying the YCbCr
331
  // transform to the 3-channel XYB data), since with !xyb_encoded, the 3
332
  // channels are stored as-is, no matter what meaning the color profile assigns
333
  // to them. To use ColorSpace::kXYB, xyb_encoded must be true.
334
  //
335
  // This value is defined in image metadata because this is the global
336
  // codestream header. This value does not affect the image itself, so is not
337
  // image metadata per se, it only affects the encoding, and what color space
338
  // the decoder can receive the pixels in without needing a CMS.
339
  bool xyb_encoded;
340
341
  ColorEncoding color_encoding;
342
343
  // These values are initialized to defaults such that the 'extra_fields'
344
  // condition in VisitFields uses correctly initialized values.
345
  uint32_t orientation = 1;
346
  bool have_preview = false;
347
  bool have_animation = false;
348
  bool have_intrinsic_size = false;
349
350
  // If present, the stored image has the dimensions of the first SizeHeader,
351
  // but decoders are advised to resample or display per `intrinsic_size`.
352
  SizeHeader intrinsic_size;  // only if have_intrinsic_size
353
354
  ToneMapping tone_mapping;
355
356
  // When reading: deserialized. When writing: automatically set from vector.
357
  uint32_t num_extra_channels;
358
  std::vector<ExtraChannelInfo> extra_channel_info;
359
360
  // Only present if m.have_preview.
361
  PreviewHeader preview_size;
362
  // Only present if m.have_animation.
363
  AnimationHeader animation;
364
365
  uint64_t extensions;
366
367
  // Option to stop parsing after basic info, and treat as if the later
368
  // fields do not participate. Use to parse only basic image information
369
  // excluding the final larger or variable sized data.
370
  bool nonserialized_only_parse_basic_info = false;
371
};
372
373
Status ReadImageMetadata(BitReader* JXL_RESTRICT reader,
374
                         ImageMetadata* JXL_RESTRICT metadata);
375
376
Status WriteImageMetadata(const ImageMetadata& metadata,
377
                          BitWriter* JXL_RESTRICT writer, LayerType layer,
378
                          AuxOut* aux_out);
379
380
// All metadata applicable to the entire codestream (dimensions, extra channels,
381
// ...)
382
struct CodecMetadata {
383
  // TODO(lode): use the preview and animation fields too, in place of the
384
  // nonserialized_ ones in ImageMetadata.
385
  ImageMetadata m;
386
  // The size of the codestream: this is the nominal size applicable to all
387
  // frames, although some frames can have a different effective size through
388
  // crop, dc_level or representing a the preview.
389
  SizeHeader size;
390
  // Often default.
391
  CustomTransformData transform_data;
392
393
239k
  size_t xsize() const { return size.xsize(); }
394
239k
  size_t ysize() const { return size.ysize(); }
395
12.5k
  size_t oriented_xsize(bool keep_orientation) const {
396
12.5k
    if (static_cast<uint32_t>(m.GetOrientation()) > 4 && !keep_orientation) {
397
0
      return ysize();
398
12.5k
    } else {
399
12.5k
      return xsize();
400
12.5k
    }
401
12.5k
  }
402
0
  size_t oriented_preview_xsize(bool keep_orientation) const {
403
0
    if (static_cast<uint32_t>(m.GetOrientation()) > 4 && !keep_orientation) {
404
0
      return m.preview_size.ysize();
405
0
    } else {
406
0
      return m.preview_size.xsize();
407
0
    }
408
0
  }
409
12.5k
  size_t oriented_ysize(bool keep_orientation) const {
410
12.5k
    if (static_cast<uint32_t>(m.GetOrientation()) > 4 && !keep_orientation) {
411
0
      return xsize();
412
12.5k
    } else {
413
12.5k
      return ysize();
414
12.5k
    }
415
12.5k
  }
416
0
  size_t oriented_preview_ysize(bool keep_orientation) const {
417
0
    if (static_cast<uint32_t>(m.GetOrientation()) > 4 && !keep_orientation) {
418
0
      return m.preview_size.xsize();
419
0
    } else {
420
0
      return m.preview_size.ysize();
421
0
    }
422
0
  }
423
424
  std::string DebugString() const;
425
};
426
427
}  // namespace jxl
428
429
#endif  // LIB_JXL_IMAGE_METADATA_H_