Coverage Report

Created: 2024-05-21 06:24

/src/libjxl/lib/jxl/cms/jxl_cms_internal.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
#ifndef LIB_JXL_CMS_JXL_CMS_INTERNAL_H_
7
#define LIB_JXL_CMS_JXL_CMS_INTERNAL_H_
8
9
// ICC profiles and color space conversions.
10
11
#include <jxl/color_encoding.h>
12
13
#include <algorithm>
14
#include <cmath>
15
#include <cstddef>
16
#include <cstdint>
17
#include <cstring>
18
#include <string>
19
#include <vector>
20
21
#include "lib/jxl/base/common.h"
22
#include "lib/jxl/base/compiler_specific.h"
23
#include "lib/jxl/base/matrix_ops.h"
24
#include "lib/jxl/base/span.h"  // Bytes
25
#include "lib/jxl/base/status.h"
26
#include "lib/jxl/cms/opsin_params.h"
27
#include "lib/jxl/cms/tone_mapping.h"
28
#include "lib/jxl/cms/transfer_functions.h"
29
30
#ifndef JXL_ENABLE_3D_ICC_TONEMAPPING
31
#define JXL_ENABLE_3D_ICC_TONEMAPPING 1
32
#endif
33
34
namespace jxl {
35
36
enum class ExtraTF {
37
  kNone,
38
  kPQ,
39
  kHLG,
40
  kSRGB,
41
};
42
43
static Status PrimariesToXYZ(float rx, float ry, float gx, float gy, float bx,
44
8.72k
                             float by, float wx, float wy, Matrix3x3& matrix) {
45
8.72k
  bool ok = (wx >= 0) && (wx <= 1) && (wy > 0) && (wy <= 1);
46
8.72k
  if (!ok) {
47
0
    return JXL_FAILURE("Invalid white point");
48
0
  }
49
  // TODO(lode): also require rx, ry, gx, gy, bx, to be in range 0-1? ICC
50
  // profiles in theory forbid negative XYZ values, but in practice the ACES P0
51
  // color space uses a negative y for the blue primary.
52
8.72k
  Matrix3x3 primaries{{{rx, gx, bx},
53
8.72k
                       {ry, gy, by},
54
8.72k
                       {1.0f - rx - ry, 1.0f - gx - gy, 1.0f - bx - by}}};
55
8.72k
  Matrix3x3 primaries_inv;
56
8.72k
  primaries_inv = primaries;
57
8.72k
  JXL_RETURN_IF_ERROR(Inv3x3Matrix(primaries_inv));
58
59
8.72k
  Vector3 w{wx / wy, 1.0f, (1.0f - wx - wy) / wy};
60
  // 1 / tiny float can still overflow
61
8.72k
  JXL_RETURN_IF_ERROR(std::isfinite(w[0]) && std::isfinite(w[2]));
62
8.72k
  Vector3 xyz;
63
8.72k
  Mul3x3Vector(primaries_inv, w, xyz);
64
65
8.72k
  Matrix3x3 a{{{xyz[0], 0, 0}, {0, xyz[1], 0}, {0, 0, xyz[2]}}};
66
67
8.72k
  Mul3x3Matrix(primaries, a, matrix);
68
8.72k
  return true;
69
8.72k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::PrimariesToXYZ(float, float, float, float, float, float, float, float, std::__1::array<std::__1::array<float, 3ul>, 3ul>&)
color_encoding_internal.cc:jxl::PrimariesToXYZ(float, float, float, float, float, float, float, float, std::__1::array<std::__1::array<float, 3ul>, 3ul>&)
Line
Count
Source
44
8.72k
                             float by, float wx, float wy, Matrix3x3& matrix) {
45
8.72k
  bool ok = (wx >= 0) && (wx <= 1) && (wy > 0) && (wy <= 1);
46
8.72k
  if (!ok) {
47
0
    return JXL_FAILURE("Invalid white point");
48
0
  }
49
  // TODO(lode): also require rx, ry, gx, gy, bx, to be in range 0-1? ICC
50
  // profiles in theory forbid negative XYZ values, but in practice the ACES P0
51
  // color space uses a negative y for the blue primary.
52
8.72k
  Matrix3x3 primaries{{{rx, gx, bx},
53
8.72k
                       {ry, gy, by},
54
8.72k
                       {1.0f - rx - ry, 1.0f - gx - gy, 1.0f - bx - by}}};
55
8.72k
  Matrix3x3 primaries_inv;
56
8.72k
  primaries_inv = primaries;
57
8.72k
  JXL_RETURN_IF_ERROR(Inv3x3Matrix(primaries_inv));
58
59
8.72k
  Vector3 w{wx / wy, 1.0f, (1.0f - wx - wy) / wy};
60
  // 1 / tiny float can still overflow
61
8.72k
  JXL_RETURN_IF_ERROR(std::isfinite(w[0]) && std::isfinite(w[2]));
62
8.72k
  Vector3 xyz;
63
8.72k
  Mul3x3Vector(primaries_inv, w, xyz);
64
65
8.72k
  Matrix3x3 a{{{xyz[0], 0, 0}, {0, xyz[1], 0}, {0, 0, xyz[2]}}};
66
67
8.72k
  Mul3x3Matrix(primaries, a, matrix);
68
8.72k
  return true;
69
8.72k
}
Unexecuted instantiation: frame_header.cc:jxl::PrimariesToXYZ(float, float, float, float, float, float, float, float, std::__1::array<std::__1::array<float, 3ul>, 3ul>&)
Unexecuted instantiation: image_metadata.cc:jxl::PrimariesToXYZ(float, float, float, float, float, float, float, float, std::__1::array<std::__1::array<float, 3ul>, 3ul>&)
70
71
/* Chromatic adaptation matrices*/
72
constexpr Matrix3x3 kBradford{{{0.8951f, 0.2664f, -0.1614f},
73
                               {-0.7502f, 1.7135f, 0.0367f},
74
                               {0.0389f, -0.0685f, 1.0296f}}};
75
constexpr Matrix3x3 kBradfordInv{{{0.9869929f, -0.1470543f, 0.1599627f},
76
                                  {0.4323053f, 0.5183603f, 0.0492912f},
77
                                  {-0.0085287f, 0.0400428f, 0.9684867f}}};
78
79
// Adapts white point x, y to D50
80
11.6k
static Status AdaptToXYZD50(float wx, float wy, Matrix3x3& matrix) {
81
11.6k
  bool ok = (wx >= 0) && (wx <= 1) && (wy > 0) && (wy <= 1);
82
11.6k
  if (!ok) {
83
    // Out of range values can cause division through zero
84
    // further down with the bradford adaptation too.
85
7
    return JXL_FAILURE("Invalid white point");
86
7
  }
87
11.6k
  Vector3 w{wx / wy, 1.0f, (1.0f - wx - wy) / wy};
88
  // 1 / tiny float can still overflow
89
11.6k
  JXL_RETURN_IF_ERROR(std::isfinite(w[0]) && std::isfinite(w[2]));
90
11.6k
  Vector3 w50{0.96422f, 1.0f, 0.82521f};
91
92
11.6k
  Vector3 lms;
93
11.6k
  Vector3 lms50;
94
95
11.6k
  Mul3x3Vector(kBradford, w, lms);
96
11.6k
  Mul3x3Vector(kBradford, w50, lms50);
97
98
11.6k
  if (lms[0] == 0 || lms[1] == 0 || lms[2] == 0) {
99
3
    return JXL_FAILURE("Invalid white point");
100
3
  }
101
11.6k
  Matrix3x3 a{{{lms50[0] / lms[0], 0, 0},
102
11.6k
               {0, lms50[1] / lms[1], 0},
103
11.6k
               {0, 0, lms50[2] / lms[2]}}};
104
11.6k
  if (!std::isfinite(a[0][0]) || !std::isfinite(a[1][1]) ||
105
11.6k
      !std::isfinite(a[2][2])) {
106
0
    return JXL_FAILURE("Invalid white point");
107
0
  }
108
109
11.6k
  Matrix3x3 b;
110
11.6k
  Mul3x3Matrix(a, kBradford, b);
111
11.6k
  Mul3x3Matrix(kBradfordInv, b, matrix);
112
113
11.6k
  return true;
114
11.6k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::AdaptToXYZD50(float, float, std::__1::array<std::__1::array<float, 3ul>, 3ul>&)
color_encoding_internal.cc:jxl::AdaptToXYZD50(float, float, std::__1::array<std::__1::array<float, 3ul>, 3ul>&)
Line
Count
Source
80
11.6k
static Status AdaptToXYZD50(float wx, float wy, Matrix3x3& matrix) {
81
11.6k
  bool ok = (wx >= 0) && (wx <= 1) && (wy > 0) && (wy <= 1);
82
11.6k
  if (!ok) {
83
    // Out of range values can cause division through zero
84
    // further down with the bradford adaptation too.
85
7
    return JXL_FAILURE("Invalid white point");
86
7
  }
87
11.6k
  Vector3 w{wx / wy, 1.0f, (1.0f - wx - wy) / wy};
88
  // 1 / tiny float can still overflow
89
11.6k
  JXL_RETURN_IF_ERROR(std::isfinite(w[0]) && std::isfinite(w[2]));
90
11.6k
  Vector3 w50{0.96422f, 1.0f, 0.82521f};
91
92
11.6k
  Vector3 lms;
93
11.6k
  Vector3 lms50;
94
95
11.6k
  Mul3x3Vector(kBradford, w, lms);
96
11.6k
  Mul3x3Vector(kBradford, w50, lms50);
97
98
11.6k
  if (lms[0] == 0 || lms[1] == 0 || lms[2] == 0) {
99
3
    return JXL_FAILURE("Invalid white point");
100
3
  }
101
11.6k
  Matrix3x3 a{{{lms50[0] / lms[0], 0, 0},
102
11.6k
               {0, lms50[1] / lms[1], 0},
103
11.6k
               {0, 0, lms50[2] / lms[2]}}};
104
11.6k
  if (!std::isfinite(a[0][0]) || !std::isfinite(a[1][1]) ||
105
11.6k
      !std::isfinite(a[2][2])) {
106
0
    return JXL_FAILURE("Invalid white point");
107
0
  }
108
109
11.6k
  Matrix3x3 b;
110
11.6k
  Mul3x3Matrix(a, kBradford, b);
111
11.6k
  Mul3x3Matrix(kBradfordInv, b, matrix);
112
113
11.6k
  return true;
114
11.6k
}
Unexecuted instantiation: frame_header.cc:jxl::AdaptToXYZD50(float, float, std::__1::array<std::__1::array<float, 3ul>, 3ul>&)
Unexecuted instantiation: image_metadata.cc:jxl::AdaptToXYZD50(float, float, std::__1::array<std::__1::array<float, 3ul>, 3ul>&)
115
116
static Status PrimariesToXYZD50(float rx, float ry, float gx, float gy,
117
                                float bx, float by, float wx, float wy,
118
2.88k
                                Matrix3x3& matrix) {
119
2.88k
  Matrix3x3 toXYZ;
120
2.88k
  JXL_RETURN_IF_ERROR(PrimariesToXYZ(rx, ry, gx, gy, bx, by, wx, wy, toXYZ));
121
2.88k
  Matrix3x3 d50;
122
2.88k
  JXL_RETURN_IF_ERROR(AdaptToXYZD50(wx, wy, d50));
123
124
2.88k
  Mul3x3Matrix(d50, toXYZ, matrix);
125
2.88k
  return true;
126
2.88k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::PrimariesToXYZD50(float, float, float, float, float, float, float, float, std::__1::array<std::__1::array<float, 3ul>, 3ul>&)
color_encoding_internal.cc:jxl::PrimariesToXYZD50(float, float, float, float, float, float, float, float, std::__1::array<std::__1::array<float, 3ul>, 3ul>&)
Line
Count
Source
118
2.88k
                                Matrix3x3& matrix) {
119
2.88k
  Matrix3x3 toXYZ;
120
2.88k
  JXL_RETURN_IF_ERROR(PrimariesToXYZ(rx, ry, gx, gy, bx, by, wx, wy, toXYZ));
121
2.88k
  Matrix3x3 d50;
122
2.88k
  JXL_RETURN_IF_ERROR(AdaptToXYZD50(wx, wy, d50));
123
124
2.88k
  Mul3x3Matrix(d50, toXYZ, matrix);
125
2.88k
  return true;
126
2.88k
}
Unexecuted instantiation: frame_header.cc:jxl::PrimariesToXYZD50(float, float, float, float, float, float, float, float, std::__1::array<std::__1::array<float, 3ul>, 3ul>&)
Unexecuted instantiation: image_metadata.cc:jxl::PrimariesToXYZD50(float, float, float, float, float, float, float, float, std::__1::array<std::__1::array<float, 3ul>, 3ul>&)
127
128
static Status ToneMapPixel(const JxlColorEncoding& c, const float in[3],
129
5.83k
                           uint8_t pcslab_out[3]) {
130
5.83k
  Matrix3x3 primaries_XYZ;
131
5.83k
  JXL_RETURN_IF_ERROR(PrimariesToXYZ(
132
5.83k
      c.primaries_red_xy[0], c.primaries_red_xy[1], c.primaries_green_xy[0],
133
5.83k
      c.primaries_green_xy[1], c.primaries_blue_xy[0], c.primaries_blue_xy[1],
134
5.83k
      c.white_point_xy[0], c.white_point_xy[1], primaries_XYZ));
135
5.83k
  const Vector3 luminances = primaries_XYZ[1];
136
5.83k
  Color linear;
137
5.83k
  JxlTransferFunction tf = c.transfer_function;
138
5.83k
  if (tf == JXL_TRANSFER_FUNCTION_PQ) {
139
17.4k
    for (size_t i = 0; i < 3; ++i) {
140
13.1k
      linear[i] = TF_PQ_Base::DisplayFromEncoded(
141
13.1k
          /*display_intensity_target=*/10000.0, in[i]);
142
13.1k
    }
143
4.37k
  } else {
144
5.83k
    for (size_t i = 0; i < 3; ++i) {
145
4.37k
      linear[i] = TF_HLG_Base::DisplayFromEncoded(in[i]);
146
4.37k
    }
147
1.45k
  }
148
5.83k
  if (tf == JXL_TRANSFER_FUNCTION_PQ) {
149
4.37k
    Rec2408ToneMapperBase tone_mapper({0, 10000}, {0, 250}, luminances);
150
4.37k
    tone_mapper.ToneMap(linear);
151
4.37k
  } else {
152
1.45k
    HlgOOTF_Base ootf(/*source_luminance=*/300, /*target_luminance=*/80,
153
1.45k
                      luminances);
154
1.45k
    ootf.Apply(linear);
155
1.45k
  }
156
5.83k
  GamutMapScalar(linear, luminances,
157
5.83k
                 /*preserve_saturation=*/0.3f);
158
159
5.83k
  Matrix3x3 chad;
160
5.83k
  JXL_RETURN_IF_ERROR(
161
5.83k
      AdaptToXYZD50(c.white_point_xy[0], c.white_point_xy[1], chad));
162
5.83k
  Matrix3x3 to_xyzd50;
163
5.83k
  Mul3x3Matrix(chad, primaries_XYZ, to_xyzd50);
164
165
5.83k
  Vector3 xyz{0, 0, 0};
166
23.3k
  for (size_t xyz_c = 0; xyz_c < 3; ++xyz_c) {
167
69.9k
    for (size_t rgb_c = 0; rgb_c < 3; ++rgb_c) {
168
52.4k
      xyz[xyz_c] += linear[rgb_c] * to_xyzd50[xyz_c][rgb_c];
169
52.4k
    }
170
17.4k
  }
171
172
17.4k
  const auto lab_f = [](const float x) {
173
17.4k
    static constexpr float kDelta = 6. / 29;
174
17.4k
    return x <= kDelta * kDelta * kDelta
175
17.4k
               ? x * (1 / (3 * kDelta * kDelta)) + 4.f / 29
176
17.4k
               : std::cbrt(x);
177
17.4k
  };
178
5.83k
  static constexpr float kXn = 0.964212;
179
5.83k
  static constexpr float kYn = 1;
180
5.83k
  static constexpr float kZn = 0.825188;
181
182
5.83k
  const float f_x = lab_f(xyz[0] / kXn);
183
5.83k
  const float f_y = lab_f(xyz[1] / kYn);
184
5.83k
  const float f_z = lab_f(xyz[2] / kZn);
185
186
5.83k
  pcslab_out[0] = static_cast<uint8_t>(
187
5.83k
      std::lroundf(255.f * Clamp1(1.16f * f_y - .16f, 0.f, 1.f)));
188
5.83k
  pcslab_out[1] = static_cast<uint8_t>(
189
5.83k
      std::lroundf(128.f + Clamp1(500 * (f_x - f_y), -128.f, 127.f)));
190
5.83k
  pcslab_out[2] = static_cast<uint8_t>(
191
5.83k
      std::lroundf(128.f + Clamp1(200 * (f_y - f_z), -128.f, 127.f)));
192
193
5.83k
  return true;
194
5.83k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::ToneMapPixel(JxlColorEncoding const&, float const*, unsigned char*)
color_encoding_internal.cc:jxl::ToneMapPixel(JxlColorEncoding const&, float const*, unsigned char*)
Line
Count
Source
129
5.83k
                           uint8_t pcslab_out[3]) {
130
5.83k
  Matrix3x3 primaries_XYZ;
131
5.83k
  JXL_RETURN_IF_ERROR(PrimariesToXYZ(
132
5.83k
      c.primaries_red_xy[0], c.primaries_red_xy[1], c.primaries_green_xy[0],
133
5.83k
      c.primaries_green_xy[1], c.primaries_blue_xy[0], c.primaries_blue_xy[1],
134
5.83k
      c.white_point_xy[0], c.white_point_xy[1], primaries_XYZ));
135
5.83k
  const Vector3 luminances = primaries_XYZ[1];
136
5.83k
  Color linear;
137
5.83k
  JxlTransferFunction tf = c.transfer_function;
138
5.83k
  if (tf == JXL_TRANSFER_FUNCTION_PQ) {
139
17.4k
    for (size_t i = 0; i < 3; ++i) {
140
13.1k
      linear[i] = TF_PQ_Base::DisplayFromEncoded(
141
13.1k
          /*display_intensity_target=*/10000.0, in[i]);
142
13.1k
    }
143
4.37k
  } else {
144
5.83k
    for (size_t i = 0; i < 3; ++i) {
145
4.37k
      linear[i] = TF_HLG_Base::DisplayFromEncoded(in[i]);
146
4.37k
    }
147
1.45k
  }
148
5.83k
  if (tf == JXL_TRANSFER_FUNCTION_PQ) {
149
4.37k
    Rec2408ToneMapperBase tone_mapper({0, 10000}, {0, 250}, luminances);
150
4.37k
    tone_mapper.ToneMap(linear);
151
4.37k
  } else {
152
1.45k
    HlgOOTF_Base ootf(/*source_luminance=*/300, /*target_luminance=*/80,
153
1.45k
                      luminances);
154
1.45k
    ootf.Apply(linear);
155
1.45k
  }
156
5.83k
  GamutMapScalar(linear, luminances,
157
5.83k
                 /*preserve_saturation=*/0.3f);
158
159
5.83k
  Matrix3x3 chad;
160
5.83k
  JXL_RETURN_IF_ERROR(
161
5.83k
      AdaptToXYZD50(c.white_point_xy[0], c.white_point_xy[1], chad));
162
5.83k
  Matrix3x3 to_xyzd50;
163
5.83k
  Mul3x3Matrix(chad, primaries_XYZ, to_xyzd50);
164
165
5.83k
  Vector3 xyz{0, 0, 0};
166
23.3k
  for (size_t xyz_c = 0; xyz_c < 3; ++xyz_c) {
167
69.9k
    for (size_t rgb_c = 0; rgb_c < 3; ++rgb_c) {
168
52.4k
      xyz[xyz_c] += linear[rgb_c] * to_xyzd50[xyz_c][rgb_c];
169
52.4k
    }
170
17.4k
  }
171
172
5.83k
  const auto lab_f = [](const float x) {
173
5.83k
    static constexpr float kDelta = 6. / 29;
174
5.83k
    return x <= kDelta * kDelta * kDelta
175
5.83k
               ? x * (1 / (3 * kDelta * kDelta)) + 4.f / 29
176
5.83k
               : std::cbrt(x);
177
5.83k
  };
178
5.83k
  static constexpr float kXn = 0.964212;
179
5.83k
  static constexpr float kYn = 1;
180
5.83k
  static constexpr float kZn = 0.825188;
181
182
5.83k
  const float f_x = lab_f(xyz[0] / kXn);
183
5.83k
  const float f_y = lab_f(xyz[1] / kYn);
184
5.83k
  const float f_z = lab_f(xyz[2] / kZn);
185
186
5.83k
  pcslab_out[0] = static_cast<uint8_t>(
187
5.83k
      std::lroundf(255.f * Clamp1(1.16f * f_y - .16f, 0.f, 1.f)));
188
5.83k
  pcslab_out[1] = static_cast<uint8_t>(
189
5.83k
      std::lroundf(128.f + Clamp1(500 * (f_x - f_y), -128.f, 127.f)));
190
5.83k
  pcslab_out[2] = static_cast<uint8_t>(
191
5.83k
      std::lroundf(128.f + Clamp1(200 * (f_y - f_z), -128.f, 127.f)));
192
193
5.83k
  return true;
194
5.83k
}
Unexecuted instantiation: frame_header.cc:jxl::ToneMapPixel(JxlColorEncoding const&, float const*, unsigned char*)
Unexecuted instantiation: image_metadata.cc:jxl::ToneMapPixel(JxlColorEncoding const&, float const*, unsigned char*)
195
196
static std::vector<uint16_t> CreateTableCurve(uint32_t N, const ExtraTF tf,
197
19
                                              bool tone_map) {
198
  // The generated PQ curve will make room for highlights up to this luminance.
199
  // TODO(sboukortt): make this variable?
200
19
  static constexpr float kPQIntensityTarget = 10000;
201
202
19
  JXL_ASSERT(N <= 4096);  // ICC MFT2 only allows 4K entries
203
19
  JXL_ASSERT(tf == ExtraTF::kPQ || tf == ExtraTF::kHLG);
204
205
19
  static constexpr Vector3 kLuminances{1.f / 3, 1.f / 3, 1.f / 3};
206
19
  Rec2408ToneMapperBase tone_mapper({0, kPQIntensityTarget},
207
19
                                    {0, kDefaultIntensityTarget}, kLuminances);
208
  // No point using float - LCMS converts to 16-bit for A2B/MFT.
209
19
  std::vector<uint16_t> table(N);
210
1.23k
  for (uint32_t i = 0; i < N; ++i) {
211
1.21k
    const float x = static_cast<float>(i) / (N - 1);  // 1.0 at index N - 1.
212
1.21k
    const double dx = static_cast<double>(x);
213
    // LCMS requires EOTF (e.g. 2.4 exponent).
214
1.21k
    double y = (tf == ExtraTF::kHLG)
215
1.21k
                   ? TF_HLG_Base::DisplayFromEncoded(dx)
216
1.21k
                   : TF_PQ_Base::DisplayFromEncoded(kPQIntensityTarget, dx);
217
1.21k
    if (tone_map && tf == ExtraTF::kPQ &&
218
1.21k
        kPQIntensityTarget > kDefaultIntensityTarget) {
219
0
      float l = y * 10000 / kPQIntensityTarget;
220
0
      Color gray{l, l, l};
221
0
      tone_mapper.ToneMap(gray);
222
0
      y = gray[0];
223
0
    }
224
1.21k
    JXL_ASSERT(y >= 0.0);
225
    // Clamp to table range - necessary for HLG.
226
1.21k
    if (y > 1.0) y = 1.0;
227
    // 1.0 corresponds to table value 0xFFFF.
228
1.21k
    table[i] = static_cast<uint16_t>(roundf(y * 65535.0));
229
1.21k
  }
230
19
  return table;
231
19
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::CreateTableCurve(unsigned int, jxl::ExtraTF, bool)
color_encoding_internal.cc:jxl::CreateTableCurve(unsigned int, jxl::ExtraTF, bool)
Line
Count
Source
197
19
                                              bool tone_map) {
198
  // The generated PQ curve will make room for highlights up to this luminance.
199
  // TODO(sboukortt): make this variable?
200
19
  static constexpr float kPQIntensityTarget = 10000;
201
202
19
  JXL_ASSERT(N <= 4096);  // ICC MFT2 only allows 4K entries
203
19
  JXL_ASSERT(tf == ExtraTF::kPQ || tf == ExtraTF::kHLG);
204
205
19
  static constexpr Vector3 kLuminances{1.f / 3, 1.f / 3, 1.f / 3};
206
19
  Rec2408ToneMapperBase tone_mapper({0, kPQIntensityTarget},
207
19
                                    {0, kDefaultIntensityTarget}, kLuminances);
208
  // No point using float - LCMS converts to 16-bit for A2B/MFT.
209
19
  std::vector<uint16_t> table(N);
210
1.23k
  for (uint32_t i = 0; i < N; ++i) {
211
1.21k
    const float x = static_cast<float>(i) / (N - 1);  // 1.0 at index N - 1.
212
1.21k
    const double dx = static_cast<double>(x);
213
    // LCMS requires EOTF (e.g. 2.4 exponent).
214
1.21k
    double y = (tf == ExtraTF::kHLG)
215
1.21k
                   ? TF_HLG_Base::DisplayFromEncoded(dx)
216
1.21k
                   : TF_PQ_Base::DisplayFromEncoded(kPQIntensityTarget, dx);
217
1.21k
    if (tone_map && tf == ExtraTF::kPQ &&
218
1.21k
        kPQIntensityTarget > kDefaultIntensityTarget) {
219
0
      float l = y * 10000 / kPQIntensityTarget;
220
0
      Color gray{l, l, l};
221
0
      tone_mapper.ToneMap(gray);
222
0
      y = gray[0];
223
0
    }
224
1.21k
    JXL_ASSERT(y >= 0.0);
225
    // Clamp to table range - necessary for HLG.
226
1.21k
    if (y > 1.0) y = 1.0;
227
    // 1.0 corresponds to table value 0xFFFF.
228
1.21k
    table[i] = static_cast<uint16_t>(roundf(y * 65535.0));
229
1.21k
  }
230
19
  return table;
231
19
}
Unexecuted instantiation: frame_header.cc:jxl::CreateTableCurve(unsigned int, jxl::ExtraTF, bool)
Unexecuted instantiation: image_metadata.cc:jxl::CreateTableCurve(unsigned int, jxl::ExtraTF, bool)
232
233
26
static Status CIEXYZFromWhiteCIExy(double wx, double wy, Color& XYZ) {
234
  // Target Y = 1.
235
26
  if (std::abs(wy) < 1e-12) return JXL_FAILURE("Y value is too small");
236
25
  const float factor = 1 / wy;
237
25
  XYZ[0] = wx * factor;
238
25
  XYZ[1] = 1;
239
25
  XYZ[2] = (1 - wx - wy) * factor;
240
25
  return true;
241
26
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::CIEXYZFromWhiteCIExy(double, double, std::__1::array<float, 3ul>&)
color_encoding_internal.cc:jxl::CIEXYZFromWhiteCIExy(double, double, std::__1::array<float, 3ul>&)
Line
Count
Source
233
26
static Status CIEXYZFromWhiteCIExy(double wx, double wy, Color& XYZ) {
234
  // Target Y = 1.
235
26
  if (std::abs(wy) < 1e-12) return JXL_FAILURE("Y value is too small");
236
25
  const float factor = 1 / wy;
237
25
  XYZ[0] = wx * factor;
238
25
  XYZ[1] = 1;
239
25
  XYZ[2] = (1 - wx - wy) * factor;
240
25
  return true;
241
26
}
Unexecuted instantiation: frame_header.cc:jxl::CIEXYZFromWhiteCIExy(double, double, std::__1::array<float, 3ul>&)
Unexecuted instantiation: image_metadata.cc:jxl::CIEXYZFromWhiteCIExy(double, double, std::__1::array<float, 3ul>&)
242
243
namespace detail {
244
245
constexpr bool kEnable3DToneMapping = JXL_ENABLE_3D_ICC_TONEMAPPING;
246
247
5.85k
static bool CanToneMap(const JxlColorEncoding& encoding) {
248
  // If the color space cannot be represented by a CICP tag in the ICC profile
249
  // then the rest of the profile must unambiguously identify it; we have less
250
  // freedom to do use it for tone mapping.
251
5.85k
  JxlTransferFunction tf = encoding.transfer_function;
252
5.85k
  JxlPrimaries p = encoding.primaries;
253
5.85k
  JxlWhitePoint wp = encoding.white_point;
254
5.85k
  return encoding.color_space == JXL_COLOR_SPACE_RGB &&
255
5.85k
         (tf == JXL_TRANSFER_FUNCTION_PQ || tf == JXL_TRANSFER_FUNCTION_HLG) &&
256
5.85k
         ((p == JXL_PRIMARIES_P3 &&
257
60
           (wp == JXL_WHITE_POINT_D65 || wp == JXL_WHITE_POINT_DCI)) ||
258
60
          (p != JXL_PRIMARIES_CUSTOM && wp == JXL_WHITE_POINT_D65));
259
5.85k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::CanToneMap(JxlColorEncoding const&)
color_encoding_internal.cc:jxl::detail::CanToneMap(JxlColorEncoding const&)
Line
Count
Source
247
5.85k
static bool CanToneMap(const JxlColorEncoding& encoding) {
248
  // If the color space cannot be represented by a CICP tag in the ICC profile
249
  // then the rest of the profile must unambiguously identify it; we have less
250
  // freedom to do use it for tone mapping.
251
5.85k
  JxlTransferFunction tf = encoding.transfer_function;
252
5.85k
  JxlPrimaries p = encoding.primaries;
253
5.85k
  JxlWhitePoint wp = encoding.white_point;
254
5.85k
  return encoding.color_space == JXL_COLOR_SPACE_RGB &&
255
5.85k
         (tf == JXL_TRANSFER_FUNCTION_PQ || tf == JXL_TRANSFER_FUNCTION_HLG) &&
256
5.85k
         ((p == JXL_PRIMARIES_P3 &&
257
60
           (wp == JXL_WHITE_POINT_D65 || wp == JXL_WHITE_POINT_DCI)) ||
258
60
          (p != JXL_PRIMARIES_CUSTOM && wp == JXL_WHITE_POINT_D65));
259
5.85k
}
Unexecuted instantiation: frame_header.cc:jxl::detail::CanToneMap(JxlColorEncoding const&)
Unexecuted instantiation: image_metadata.cc:jxl::detail::CanToneMap(JxlColorEncoding const&)
260
261
static void ICCComputeMD5(const std::vector<uint8_t>& data, uint8_t sum[16])
262
2.90k
    JXL_NO_SANITIZE("unsigned-integer-overflow") {
263
2.90k
  std::vector<uint8_t> data64 = data;
264
2.90k
  data64.push_back(128);
265
  // Add bytes such that ((size + 8) & 63) == 0.
266
2.90k
  size_t extra = ((64 - ((data64.size() + 8) & 63)) & 63);
267
2.90k
  data64.resize(data64.size() + extra, 0);
268
26.1k
  for (uint64_t i = 0; i < 64; i += 8) {
269
23.2k
    data64.push_back(static_cast<uint64_t>(data.size() << 3u) >> i);
270
23.2k
  }
271
272
2.90k
  static const uint32_t sineparts[64] = {
273
2.90k
      0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,
274
2.90k
      0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
275
2.90k
      0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340,
276
2.90k
      0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
277
2.90k
      0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
278
2.90k
      0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
279
2.90k
      0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
280
2.90k
      0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
281
2.90k
      0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
282
2.90k
      0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
283
2.90k
      0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
284
2.90k
  };
285
2.90k
  static const uint32_t shift[64] = {
286
2.90k
      7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
287
2.90k
      5, 9,  14, 20, 5, 9,  14, 20, 5, 9,  14, 20, 5, 9,  14, 20,
288
2.90k
      4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
289
2.90k
      6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
290
2.90k
  };
291
292
2.90k
  uint32_t a0 = 0x67452301;
293
2.90k
  uint32_t b0 = 0xefcdab89;
294
2.90k
  uint32_t c0 = 0x98badcfe;
295
2.90k
  uint32_t d0 = 0x10325476;
296
297
29.5k
  for (size_t i = 0; i < data64.size(); i += 64) {
298
26.6k
    uint32_t a = a0;
299
26.6k
    uint32_t b = b0;
300
26.6k
    uint32_t c = c0;
301
26.6k
    uint32_t d = d0;
302
26.6k
    uint32_t f;
303
26.6k
    uint32_t g;
304
1.73M
    for (size_t j = 0; j < 64; j++) {
305
1.70M
      if (j < 16) {
306
426k
        f = (b & c) | ((~b) & d);
307
426k
        g = j;
308
1.27M
      } else if (j < 32) {
309
426k
        f = (d & b) | ((~d) & c);
310
426k
        g = (5 * j + 1) & 0xf;
311
852k
      } else if (j < 48) {
312
426k
        f = b ^ c ^ d;
313
426k
        g = (3 * j + 5) & 0xf;
314
426k
      } else {
315
426k
        f = c ^ (b | (~d));
316
426k
        g = (7 * j) & 0xf;
317
426k
      }
318
1.70M
      uint32_t dg0 = data64[i + g * 4 + 0];
319
1.70M
      uint32_t dg1 = data64[i + g * 4 + 1];
320
1.70M
      uint32_t dg2 = data64[i + g * 4 + 2];
321
1.70M
      uint32_t dg3 = data64[i + g * 4 + 3];
322
1.70M
      uint32_t u = dg0 | (dg1 << 8u) | (dg2 << 16u) | (dg3 << 24u);
323
1.70M
      f += a + sineparts[j] + u;
324
1.70M
      a = d;
325
1.70M
      d = c;
326
1.70M
      c = b;
327
1.70M
      b += (f << shift[j]) | (f >> (32u - shift[j]));
328
1.70M
    }
329
26.6k
    a0 += a;
330
26.6k
    b0 += b;
331
26.6k
    c0 += c;
332
26.6k
    d0 += d;
333
26.6k
  }
334
2.90k
  sum[0] = a0;
335
2.90k
  sum[1] = a0 >> 8u;
336
2.90k
  sum[2] = a0 >> 16u;
337
2.90k
  sum[3] = a0 >> 24u;
338
2.90k
  sum[4] = b0;
339
2.90k
  sum[5] = b0 >> 8u;
340
2.90k
  sum[6] = b0 >> 16u;
341
2.90k
  sum[7] = b0 >> 24u;
342
2.90k
  sum[8] = c0;
343
2.90k
  sum[9] = c0 >> 8u;
344
2.90k
  sum[10] = c0 >> 16u;
345
2.90k
  sum[11] = c0 >> 24u;
346
2.90k
  sum[12] = d0;
347
2.90k
  sum[13] = d0 >> 8u;
348
2.90k
  sum[14] = d0 >> 16u;
349
2.90k
  sum[15] = d0 >> 24u;
350
2.90k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::ICCComputeMD5(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const&, unsigned char*)
color_encoding_internal.cc:jxl::detail::ICCComputeMD5(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const&, unsigned char*)
Line
Count
Source
262
2.90k
    JXL_NO_SANITIZE("unsigned-integer-overflow") {
263
2.90k
  std::vector<uint8_t> data64 = data;
264
2.90k
  data64.push_back(128);
265
  // Add bytes such that ((size + 8) & 63) == 0.
266
2.90k
  size_t extra = ((64 - ((data64.size() + 8) & 63)) & 63);
267
2.90k
  data64.resize(data64.size() + extra, 0);
268
26.1k
  for (uint64_t i = 0; i < 64; i += 8) {
269
23.2k
    data64.push_back(static_cast<uint64_t>(data.size() << 3u) >> i);
270
23.2k
  }
271
272
2.90k
  static const uint32_t sineparts[64] = {
273
2.90k
      0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,
274
2.90k
      0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
275
2.90k
      0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340,
276
2.90k
      0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
277
2.90k
      0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
278
2.90k
      0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
279
2.90k
      0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
280
2.90k
      0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
281
2.90k
      0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
282
2.90k
      0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
283
2.90k
      0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
284
2.90k
  };
285
2.90k
  static const uint32_t shift[64] = {
286
2.90k
      7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
287
2.90k
      5, 9,  14, 20, 5, 9,  14, 20, 5, 9,  14, 20, 5, 9,  14, 20,
288
2.90k
      4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
289
2.90k
      6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
290
2.90k
  };
291
292
2.90k
  uint32_t a0 = 0x67452301;
293
2.90k
  uint32_t b0 = 0xefcdab89;
294
2.90k
  uint32_t c0 = 0x98badcfe;
295
2.90k
  uint32_t d0 = 0x10325476;
296
297
29.5k
  for (size_t i = 0; i < data64.size(); i += 64) {
298
26.6k
    uint32_t a = a0;
299
26.6k
    uint32_t b = b0;
300
26.6k
    uint32_t c = c0;
301
26.6k
    uint32_t d = d0;
302
26.6k
    uint32_t f;
303
26.6k
    uint32_t g;
304
1.73M
    for (size_t j = 0; j < 64; j++) {
305
1.70M
      if (j < 16) {
306
426k
        f = (b & c) | ((~b) & d);
307
426k
        g = j;
308
1.27M
      } else if (j < 32) {
309
426k
        f = (d & b) | ((~d) & c);
310
426k
        g = (5 * j + 1) & 0xf;
311
852k
      } else if (j < 48) {
312
426k
        f = b ^ c ^ d;
313
426k
        g = (3 * j + 5) & 0xf;
314
426k
      } else {
315
426k
        f = c ^ (b | (~d));
316
426k
        g = (7 * j) & 0xf;
317
426k
      }
318
1.70M
      uint32_t dg0 = data64[i + g * 4 + 0];
319
1.70M
      uint32_t dg1 = data64[i + g * 4 + 1];
320
1.70M
      uint32_t dg2 = data64[i + g * 4 + 2];
321
1.70M
      uint32_t dg3 = data64[i + g * 4 + 3];
322
1.70M
      uint32_t u = dg0 | (dg1 << 8u) | (dg2 << 16u) | (dg3 << 24u);
323
1.70M
      f += a + sineparts[j] + u;
324
1.70M
      a = d;
325
1.70M
      d = c;
326
1.70M
      c = b;
327
1.70M
      b += (f << shift[j]) | (f >> (32u - shift[j]));
328
1.70M
    }
329
26.6k
    a0 += a;
330
26.6k
    b0 += b;
331
26.6k
    c0 += c;
332
26.6k
    d0 += d;
333
26.6k
  }
334
2.90k
  sum[0] = a0;
335
2.90k
  sum[1] = a0 >> 8u;
336
2.90k
  sum[2] = a0 >> 16u;
337
2.90k
  sum[3] = a0 >> 24u;
338
2.90k
  sum[4] = b0;
339
2.90k
  sum[5] = b0 >> 8u;
340
2.90k
  sum[6] = b0 >> 16u;
341
2.90k
  sum[7] = b0 >> 24u;
342
2.90k
  sum[8] = c0;
343
2.90k
  sum[9] = c0 >> 8u;
344
2.90k
  sum[10] = c0 >> 16u;
345
2.90k
  sum[11] = c0 >> 24u;
346
2.90k
  sum[12] = d0;
347
2.90k
  sum[13] = d0 >> 8u;
348
2.90k
  sum[14] = d0 >> 16u;
349
2.90k
  sum[15] = d0 >> 24u;
350
2.90k
}
Unexecuted instantiation: frame_header.cc:jxl::detail::ICCComputeMD5(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const&, unsigned char*)
Unexecuted instantiation: image_metadata.cc:jxl::detail::ICCComputeMD5(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const&, unsigned char*)
351
352
2.90k
static Status CreateICCChadMatrix(double wx, double wy, Matrix3x3& result) {
353
2.90k
  Matrix3x3 m;
354
2.90k
  if (wy == 0) {  // WhitePoint can not be pitch-black.
355
1
    return JXL_FAILURE("Invalid WhitePoint");
356
1
  }
357
2.90k
  JXL_RETURN_IF_ERROR(AdaptToXYZD50(wx, wy, m));
358
2.89k
  result = m;
359
2.89k
  return true;
360
2.90k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::CreateICCChadMatrix(double, double, std::__1::array<std::__1::array<float, 3ul>, 3ul>&)
color_encoding_internal.cc:jxl::detail::CreateICCChadMatrix(double, double, std::__1::array<std::__1::array<float, 3ul>, 3ul>&)
Line
Count
Source
352
2.90k
static Status CreateICCChadMatrix(double wx, double wy, Matrix3x3& result) {
353
2.90k
  Matrix3x3 m;
354
2.90k
  if (wy == 0) {  // WhitePoint can not be pitch-black.
355
1
    return JXL_FAILURE("Invalid WhitePoint");
356
1
  }
357
2.90k
  JXL_RETURN_IF_ERROR(AdaptToXYZD50(wx, wy, m));
358
2.89k
  result = m;
359
2.89k
  return true;
360
2.90k
}
Unexecuted instantiation: frame_header.cc:jxl::detail::CreateICCChadMatrix(double, double, std::__1::array<std::__1::array<float, 3ul>, 3ul>&)
Unexecuted instantiation: image_metadata.cc:jxl::detail::CreateICCChadMatrix(double, double, std::__1::array<std::__1::array<float, 3ul>, 3ul>&)
361
362
// Creates RGB to XYZ matrix given RGB primaries and white point in xy.
363
static Status CreateICCRGBMatrix(double rx, double ry, double gx, double gy,
364
                                 double bx, double by, double wx, double wy,
365
2.88k
                                 Matrix3x3& result) {
366
2.88k
  Matrix3x3 m;
367
2.88k
  JXL_RETURN_IF_ERROR(PrimariesToXYZD50(rx, ry, gx, gy, bx, by, wx, wy, m));
368
2.88k
  result = m;
369
2.88k
  return true;
370
2.88k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::CreateICCRGBMatrix(double, double, double, double, double, double, double, double, std::__1::array<std::__1::array<float, 3ul>, 3ul>&)
color_encoding_internal.cc:jxl::detail::CreateICCRGBMatrix(double, double, double, double, double, double, double, double, std::__1::array<std::__1::array<float, 3ul>, 3ul>&)
Line
Count
Source
365
2.88k
                                 Matrix3x3& result) {
366
2.88k
  Matrix3x3 m;
367
2.88k
  JXL_RETURN_IF_ERROR(PrimariesToXYZD50(rx, ry, gx, gy, bx, by, wx, wy, m));
368
2.88k
  result = m;
369
2.88k
  return true;
370
2.88k
}
Unexecuted instantiation: frame_header.cc:jxl::detail::CreateICCRGBMatrix(double, double, double, double, double, double, double, double, std::__1::array<std::__1::array<float, 3ul>, 3ul>&)
Unexecuted instantiation: image_metadata.cc:jxl::detail::CreateICCRGBMatrix(double, double, double, double, double, double, double, double, std::__1::array<std::__1::array<float, 3ul>, 3ul>&)
371
372
static void WriteICCUint32(uint32_t value, size_t pos,
373
261k
                           std::vector<uint8_t>* icc) {
374
261k
  if (icc->size() < pos + 4) icc->resize(pos + 4);
375
261k
  (*icc)[pos + 0] = (value >> 24u) & 255;
376
261k
  (*icc)[pos + 1] = (value >> 16u) & 255;
377
261k
  (*icc)[pos + 2] = (value >> 8u) & 255;
378
261k
  (*icc)[pos + 3] = value & 255;
379
261k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::WriteICCUint32(unsigned int, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
color_encoding_internal.cc:jxl::detail::WriteICCUint32(unsigned int, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Line
Count
Source
373
261k
                           std::vector<uint8_t>* icc) {
374
261k
  if (icc->size() < pos + 4) icc->resize(pos + 4);
375
261k
  (*icc)[pos + 0] = (value >> 24u) & 255;
376
261k
  (*icc)[pos + 1] = (value >> 16u) & 255;
377
261k
  (*icc)[pos + 2] = (value >> 8u) & 255;
378
261k
  (*icc)[pos + 3] = value & 255;
379
261k
}
Unexecuted instantiation: frame_header.cc:jxl::detail::WriteICCUint32(unsigned int, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Unexecuted instantiation: image_metadata.cc:jxl::detail::WriteICCUint32(unsigned int, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
380
381
static void WriteICCUint16(uint16_t value, size_t pos,
382
24.7k
                           std::vector<uint8_t>* icc) {
383
24.7k
  if (icc->size() < pos + 2) icc->resize(pos + 2);
384
24.7k
  (*icc)[pos + 0] = (value >> 8u) & 255;
385
24.7k
  (*icc)[pos + 1] = value & 255;
386
24.7k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::WriteICCUint16(unsigned short, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
color_encoding_internal.cc:jxl::detail::WriteICCUint16(unsigned short, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Line
Count
Source
382
24.7k
                           std::vector<uint8_t>* icc) {
383
24.7k
  if (icc->size() < pos + 2) icc->resize(pos + 2);
384
24.7k
  (*icc)[pos + 0] = (value >> 8u) & 255;
385
24.7k
  (*icc)[pos + 1] = value & 255;
386
24.7k
}
Unexecuted instantiation: frame_header.cc:jxl::detail::WriteICCUint16(unsigned short, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Unexecuted instantiation: image_metadata.cc:jxl::detail::WriteICCUint16(unsigned short, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
387
388
static void WriteICCUint8(uint8_t value, size_t pos,
389
41.2k
                          std::vector<uint8_t>* icc) {
390
41.2k
  if (icc->size() < pos + 1) icc->resize(pos + 1);
391
41.2k
  (*icc)[pos] = value;
392
41.2k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::WriteICCUint8(unsigned char, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
color_encoding_internal.cc:jxl::detail::WriteICCUint8(unsigned char, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Line
Count
Source
389
41.2k
                          std::vector<uint8_t>* icc) {
390
41.2k
  if (icc->size() < pos + 1) icc->resize(pos + 1);
391
41.2k
  (*icc)[pos] = value;
392
41.2k
}
Unexecuted instantiation: frame_header.cc:jxl::detail::WriteICCUint8(unsigned char, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Unexecuted instantiation: image_metadata.cc:jxl::detail::WriteICCUint8(unsigned char, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
393
394
// Writes a 4-character tag
395
static void WriteICCTag(const char* value, size_t pos,
396
84.3k
                        std::vector<uint8_t>* icc) {
397
84.3k
  if (icc->size() < pos + 4) icc->resize(pos + 4);
398
84.3k
  memcpy(icc->data() + pos, value, 4);
399
84.3k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::WriteICCTag(char const*, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
color_encoding_internal.cc:jxl::detail::WriteICCTag(char const*, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Line
Count
Source
396
84.3k
                        std::vector<uint8_t>* icc) {
397
84.3k
  if (icc->size() < pos + 4) icc->resize(pos + 4);
398
84.3k
  memcpy(icc->data() + pos, value, 4);
399
84.3k
}
Unexecuted instantiation: frame_header.cc:jxl::detail::WriteICCTag(char const*, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Unexecuted instantiation: image_metadata.cc:jxl::detail::WriteICCTag(char const*, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
400
401
static Status WriteICCS15Fixed16(float value, size_t pos,
402
75.2k
                                 std::vector<uint8_t>* icc) {
403
  // "nextafterf" for 32768.0f towards zero are:
404
  // 32767.998046875, 32767.99609375, 32767.994140625
405
  // Even the first value works well,...
406
75.2k
  bool ok = (-32767.995f <= value) && (value <= 32767.995f);
407
75.2k
  if (!ok) return JXL_FAILURE("ICC value is out of range / NaN");
408
75.2k
  int32_t i = static_cast<int32_t>(std::lround(value * 65536.0f));
409
  // Use two's complement
410
75.2k
  uint32_t u = static_cast<uint32_t>(i);
411
75.2k
  WriteICCUint32(u, pos, icc);
412
75.2k
  return true;
413
75.2k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::WriteICCS15Fixed16(float, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
color_encoding_internal.cc:jxl::detail::WriteICCS15Fixed16(float, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Line
Count
Source
402
75.2k
                                 std::vector<uint8_t>* icc) {
403
  // "nextafterf" for 32768.0f towards zero are:
404
  // 32767.998046875, 32767.99609375, 32767.994140625
405
  // Even the first value works well,...
406
75.2k
  bool ok = (-32767.995f <= value) && (value <= 32767.995f);
407
75.2k
  if (!ok) return JXL_FAILURE("ICC value is out of range / NaN");
408
75.2k
  int32_t i = static_cast<int32_t>(std::lround(value * 65536.0f));
409
  // Use two's complement
410
75.2k
  uint32_t u = static_cast<uint32_t>(i);
411
75.2k
  WriteICCUint32(u, pos, icc);
412
75.2k
  return true;
413
75.2k
}
Unexecuted instantiation: frame_header.cc:jxl::detail::WriteICCS15Fixed16(float, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Unexecuted instantiation: image_metadata.cc:jxl::detail::WriteICCS15Fixed16(float, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
414
415
static Status CreateICCHeader(const JxlColorEncoding& c,
416
2.93k
                              std::vector<uint8_t>* header) {
417
  // TODO(lode): choose color management engine name, e.g. "skia" if
418
  // integrated in skia.
419
2.93k
  static const char* kCmm = "jxl ";
420
421
2.93k
  header->resize(128, 0);
422
423
2.93k
  WriteICCUint32(0, 0, header);  // size, correct value filled in at end
424
2.93k
  WriteICCTag(kCmm, 4, header);
425
2.93k
  WriteICCUint32(0x04400000u, 8, header);
426
2.93k
  const char* profile_type =
427
2.93k
      c.color_space == JXL_COLOR_SPACE_XYB ? "scnr" : "mntr";
428
2.93k
  WriteICCTag(profile_type, 12, header);
429
2.93k
  WriteICCTag(c.color_space == JXL_COLOR_SPACE_GRAY ? "GRAY" : "RGB ", 16,
430
2.93k
              header);
431
2.93k
  if (kEnable3DToneMapping && CanToneMap(c)) {
432
    // We are going to use a 3D LUT for tone mapping, which will be more compact
433
    // with an 8-bit LUT to CIELAB than with a 16-bit LUT to XYZ. 8-bit XYZ
434
    // would not be viable due to XYZ being linear, whereas it is fine with
435
    // CIELAB's ~cube root.
436
8
    WriteICCTag("Lab ", 20, header);
437
2.92k
  } else {
438
2.92k
    WriteICCTag("XYZ ", 20, header);
439
2.92k
  }
440
441
  // Three uint32_t's date/time encoding.
442
  // TODO(lode): encode actual date and time, this is a placeholder
443
2.93k
  uint32_t year = 2019;
444
2.93k
  uint32_t month = 12;
445
2.93k
  uint32_t day = 1;
446
2.93k
  uint32_t hour = 0;
447
2.93k
  uint32_t minute = 0;
448
2.93k
  uint32_t second = 0;
449
2.93k
  WriteICCUint16(year, 24, header);
450
2.93k
  WriteICCUint16(month, 26, header);
451
2.93k
  WriteICCUint16(day, 28, header);
452
2.93k
  WriteICCUint16(hour, 30, header);
453
2.93k
  WriteICCUint16(minute, 32, header);
454
2.93k
  WriteICCUint16(second, 34, header);
455
456
2.93k
  WriteICCTag("acsp", 36, header);
457
2.93k
  WriteICCTag("APPL", 40, header);
458
2.93k
  WriteICCUint32(0, 44, header);  // flags
459
2.93k
  WriteICCUint32(0, 48, header);  // device manufacturer
460
2.93k
  WriteICCUint32(0, 52, header);  // device model
461
2.93k
  WriteICCUint32(0, 56, header);  // device attributes
462
2.93k
  WriteICCUint32(0, 60, header);  // device attributes
463
2.93k
  WriteICCUint32(static_cast<uint32_t>(c.rendering_intent), 64, header);
464
465
  // Mandatory D50 white point of profile connection space
466
2.93k
  WriteICCUint32(0x0000f6d6, 68, header);
467
2.93k
  WriteICCUint32(0x00010000, 72, header);
468
2.93k
  WriteICCUint32(0x0000d32d, 76, header);
469
470
2.93k
  WriteICCTag(kCmm, 80, header);
471
472
2.93k
  return true;
473
2.93k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::CreateICCHeader(JxlColorEncoding const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
color_encoding_internal.cc:jxl::detail::CreateICCHeader(JxlColorEncoding const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Line
Count
Source
416
2.93k
                              std::vector<uint8_t>* header) {
417
  // TODO(lode): choose color management engine name, e.g. "skia" if
418
  // integrated in skia.
419
2.93k
  static const char* kCmm = "jxl ";
420
421
2.93k
  header->resize(128, 0);
422
423
2.93k
  WriteICCUint32(0, 0, header);  // size, correct value filled in at end
424
2.93k
  WriteICCTag(kCmm, 4, header);
425
2.93k
  WriteICCUint32(0x04400000u, 8, header);
426
2.93k
  const char* profile_type =
427
2.93k
      c.color_space == JXL_COLOR_SPACE_XYB ? "scnr" : "mntr";
428
2.93k
  WriteICCTag(profile_type, 12, header);
429
2.93k
  WriteICCTag(c.color_space == JXL_COLOR_SPACE_GRAY ? "GRAY" : "RGB ", 16,
430
2.93k
              header);
431
2.93k
  if (kEnable3DToneMapping && CanToneMap(c)) {
432
    // We are going to use a 3D LUT for tone mapping, which will be more compact
433
    // with an 8-bit LUT to CIELAB than with a 16-bit LUT to XYZ. 8-bit XYZ
434
    // would not be viable due to XYZ being linear, whereas it is fine with
435
    // CIELAB's ~cube root.
436
8
    WriteICCTag("Lab ", 20, header);
437
2.92k
  } else {
438
2.92k
    WriteICCTag("XYZ ", 20, header);
439
2.92k
  }
440
441
  // Three uint32_t's date/time encoding.
442
  // TODO(lode): encode actual date and time, this is a placeholder
443
2.93k
  uint32_t year = 2019;
444
2.93k
  uint32_t month = 12;
445
2.93k
  uint32_t day = 1;
446
2.93k
  uint32_t hour = 0;
447
2.93k
  uint32_t minute = 0;
448
2.93k
  uint32_t second = 0;
449
2.93k
  WriteICCUint16(year, 24, header);
450
2.93k
  WriteICCUint16(month, 26, header);
451
2.93k
  WriteICCUint16(day, 28, header);
452
2.93k
  WriteICCUint16(hour, 30, header);
453
2.93k
  WriteICCUint16(minute, 32, header);
454
2.93k
  WriteICCUint16(second, 34, header);
455
456
2.93k
  WriteICCTag("acsp", 36, header);
457
2.93k
  WriteICCTag("APPL", 40, header);
458
2.93k
  WriteICCUint32(0, 44, header);  // flags
459
2.93k
  WriteICCUint32(0, 48, header);  // device manufacturer
460
2.93k
  WriteICCUint32(0, 52, header);  // device model
461
2.93k
  WriteICCUint32(0, 56, header);  // device attributes
462
2.93k
  WriteICCUint32(0, 60, header);  // device attributes
463
2.93k
  WriteICCUint32(static_cast<uint32_t>(c.rendering_intent), 64, header);
464
465
  // Mandatory D50 white point of profile connection space
466
2.93k
  WriteICCUint32(0x0000f6d6, 68, header);
467
2.93k
  WriteICCUint32(0x00010000, 72, header);
468
2.93k
  WriteICCUint32(0x0000d32d, 76, header);
469
470
2.93k
  WriteICCTag(kCmm, 80, header);
471
472
2.93k
  return true;
473
2.93k
}
Unexecuted instantiation: frame_header.cc:jxl::detail::CreateICCHeader(JxlColorEncoding const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Unexecuted instantiation: image_metadata.cc:jxl::detail::CreateICCHeader(JxlColorEncoding const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
474
475
static void AddToICCTagTable(const char* tag, size_t offset, size_t size,
476
                             std::vector<uint8_t>* tagtable,
477
31.8k
                             std::vector<size_t>* offsets) {
478
31.8k
  WriteICCTag(tag, tagtable->size(), tagtable);
479
  // writing true offset deferred to later
480
31.8k
  WriteICCUint32(0, tagtable->size(), tagtable);
481
31.8k
  offsets->push_back(offset);
482
31.8k
  WriteICCUint32(size, tagtable->size(), tagtable);
483
31.8k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::AddToICCTagTable(char const*, unsigned long, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*, std::__1::vector<unsigned long, std::__1::allocator<unsigned long> >*)
color_encoding_internal.cc:jxl::detail::AddToICCTagTable(char const*, unsigned long, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*, std::__1::vector<unsigned long, std::__1::allocator<unsigned long> >*)
Line
Count
Source
477
31.8k
                             std::vector<size_t>* offsets) {
478
31.8k
  WriteICCTag(tag, tagtable->size(), tagtable);
479
  // writing true offset deferred to later
480
31.8k
  WriteICCUint32(0, tagtable->size(), tagtable);
481
31.8k
  offsets->push_back(offset);
482
31.8k
  WriteICCUint32(size, tagtable->size(), tagtable);
483
31.8k
}
Unexecuted instantiation: frame_header.cc:jxl::detail::AddToICCTagTable(char const*, unsigned long, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*, std::__1::vector<unsigned long, std::__1::allocator<unsigned long> >*)
Unexecuted instantiation: image_metadata.cc:jxl::detail::AddToICCTagTable(char const*, unsigned long, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*, std::__1::vector<unsigned long, std::__1::allocator<unsigned long> >*)
484
485
static void FinalizeICCTag(std::vector<uint8_t>* tags, size_t* offset,
486
26.0k
                           size_t* size) {
487
37.7k
  while ((tags->size() & 3) != 0) {
488
11.6k
    tags->push_back(0);
489
11.6k
  }
490
26.0k
  *offset += *size;
491
26.0k
  *size = tags->size() - *offset;
492
26.0k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::FinalizeICCTag(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*, unsigned long*, unsigned long*)
color_encoding_internal.cc:jxl::detail::FinalizeICCTag(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*, unsigned long*, unsigned long*)
Line
Count
Source
486
26.0k
                           size_t* size) {
487
37.7k
  while ((tags->size() & 3) != 0) {
488
11.6k
    tags->push_back(0);
489
11.6k
  }
490
26.0k
  *offset += *size;
491
26.0k
  *size = tags->size() - *offset;
492
26.0k
}
Unexecuted instantiation: frame_header.cc:jxl::detail::FinalizeICCTag(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*, unsigned long*, unsigned long*)
Unexecuted instantiation: image_metadata.cc:jxl::detail::FinalizeICCTag(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*, unsigned long*, unsigned long*)
493
494
// The input text must be ASCII, writing other characters to UTF-16 is not
495
// implemented.
496
static void CreateICCMlucTag(const std::string& text,
497
5.86k
                             std::vector<uint8_t>* tags) {
498
5.86k
  WriteICCTag("mluc", tags->size(), tags);
499
5.86k
  WriteICCUint32(0, tags->size(), tags);
500
5.86k
  WriteICCUint32(1, tags->size(), tags);
501
5.86k
  WriteICCUint32(12, tags->size(), tags);
502
5.86k
  WriteICCTag("enUS", tags->size(), tags);
503
5.86k
  WriteICCUint32(text.size() * 2, tags->size(), tags);
504
5.86k
  WriteICCUint32(28, tags->size(), tags);
505
65.9k
  for (char c : text) {
506
65.9k
    tags->push_back(0);  // prepend 0 for UTF-16
507
65.9k
    tags->push_back(c);
508
65.9k
  }
509
5.86k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::CreateICCMlucTag(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
color_encoding_internal.cc:jxl::detail::CreateICCMlucTag(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Line
Count
Source
497
5.86k
                             std::vector<uint8_t>* tags) {
498
5.86k
  WriteICCTag("mluc", tags->size(), tags);
499
5.86k
  WriteICCUint32(0, tags->size(), tags);
500
5.86k
  WriteICCUint32(1, tags->size(), tags);
501
5.86k
  WriteICCUint32(12, tags->size(), tags);
502
5.86k
  WriteICCTag("enUS", tags->size(), tags);
503
5.86k
  WriteICCUint32(text.size() * 2, tags->size(), tags);
504
5.86k
  WriteICCUint32(28, tags->size(), tags);
505
65.9k
  for (char c : text) {
506
65.9k
    tags->push_back(0);  // prepend 0 for UTF-16
507
65.9k
    tags->push_back(c);
508
65.9k
  }
509
5.86k
}
Unexecuted instantiation: frame_header.cc:jxl::detail::CreateICCMlucTag(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Unexecuted instantiation: image_metadata.cc:jxl::detail::CreateICCMlucTag(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
510
511
11.5k
static Status CreateICCXYZTag(const Color& xyz, std::vector<uint8_t>* tags) {
512
11.5k
  WriteICCTag("XYZ ", tags->size(), tags);
513
11.5k
  WriteICCUint32(0, tags->size(), tags);
514
46.3k
  for (size_t i = 0; i < 3; ++i) {
515
34.7k
    JXL_RETURN_IF_ERROR(WriteICCS15Fixed16(xyz[i], tags->size(), tags));
516
34.7k
  }
517
11.5k
  return true;
518
11.5k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::CreateICCXYZTag(std::__1::array<float, 3ul> const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
color_encoding_internal.cc:jxl::detail::CreateICCXYZTag(std::__1::array<float, 3ul> const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Line
Count
Source
511
11.5k
static Status CreateICCXYZTag(const Color& xyz, std::vector<uint8_t>* tags) {
512
11.5k
  WriteICCTag("XYZ ", tags->size(), tags);
513
11.5k
  WriteICCUint32(0, tags->size(), tags);
514
46.3k
  for (size_t i = 0; i < 3; ++i) {
515
34.7k
    JXL_RETURN_IF_ERROR(WriteICCS15Fixed16(xyz[i], tags->size(), tags));
516
34.7k
  }
517
11.5k
  return true;
518
11.5k
}
Unexecuted instantiation: frame_header.cc:jxl::detail::CreateICCXYZTag(std::__1::array<float, 3ul> const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Unexecuted instantiation: image_metadata.cc:jxl::detail::CreateICCXYZTag(std::__1::array<float, 3ul> const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
519
520
static Status CreateICCChadTag(const Matrix3x3& chad,
521
2.89k
                               std::vector<uint8_t>* tags) {
522
2.89k
  WriteICCTag("sf32", tags->size(), tags);
523
2.89k
  WriteICCUint32(0, tags->size(), tags);
524
11.5k
  for (size_t j = 0; j < 3; j++) {
525
34.7k
    for (size_t i = 0; i < 3; i++) {
526
26.0k
      JXL_RETURN_IF_ERROR(WriteICCS15Fixed16(chad[j][i], tags->size(), tags));
527
26.0k
    }
528
8.67k
  }
529
2.89k
  return true;
530
2.89k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::CreateICCChadTag(std::__1::array<std::__1::array<float, 3ul>, 3ul> const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
color_encoding_internal.cc:jxl::detail::CreateICCChadTag(std::__1::array<std::__1::array<float, 3ul>, 3ul> const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Line
Count
Source
521
2.89k
                               std::vector<uint8_t>* tags) {
522
2.89k
  WriteICCTag("sf32", tags->size(), tags);
523
2.89k
  WriteICCUint32(0, tags->size(), tags);
524
11.5k
  for (size_t j = 0; j < 3; j++) {
525
34.7k
    for (size_t i = 0; i < 3; i++) {
526
26.0k
      JXL_RETURN_IF_ERROR(WriteICCS15Fixed16(chad[j][i], tags->size(), tags));
527
26.0k
    }
528
8.67k
  }
529
2.89k
  return true;
530
2.89k
}
Unexecuted instantiation: frame_header.cc:jxl::detail::CreateICCChadTag(std::__1::array<std::__1::array<float, 3ul>, 3ul> const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Unexecuted instantiation: image_metadata.cc:jxl::detail::CreateICCChadTag(std::__1::array<std::__1::array<float, 3ul>, 3ul> const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
531
532
static void MaybeCreateICCCICPTag(const JxlColorEncoding& c,
533
                                  std::vector<uint8_t>* tags, size_t* offset,
534
                                  size_t* size, std::vector<uint8_t>* tagtable,
535
2.88k
                                  std::vector<size_t>* offsets) {
536
2.88k
  if (c.color_space != JXL_COLOR_SPACE_RGB) {
537
0
    return;
538
0
  }
539
2.88k
  uint8_t primaries = 0;
540
2.88k
  if (c.primaries == JXL_PRIMARIES_P3) {
541
11
    if (c.white_point == JXL_WHITE_POINT_D65) {
542
5
      primaries = 12;
543
6
    } else if (c.white_point == JXL_WHITE_POINT_DCI) {
544
2
      primaries = 11;
545
4
    } else {
546
4
      return;
547
4
    }
548
2.87k
  } else if (c.primaries != JXL_PRIMARIES_CUSTOM &&
549
2.87k
             c.white_point == JXL_WHITE_POINT_D65) {
550
2.84k
    primaries = static_cast<uint8_t>(c.primaries);
551
2.84k
  } else {
552
37
    return;
553
37
  }
554
2.84k
  JxlTransferFunction tf = c.transfer_function;
555
2.84k
  if (tf == JXL_TRANSFER_FUNCTION_UNKNOWN ||
556
2.84k
      tf == JXL_TRANSFER_FUNCTION_GAMMA) {
557
6
    return;
558
6
  }
559
2.84k
  WriteICCTag("cicp", tags->size(), tags);
560
2.84k
  WriteICCUint32(0, tags->size(), tags);
561
2.84k
  WriteICCUint8(primaries, tags->size(), tags);
562
2.84k
  WriteICCUint8(static_cast<uint8_t>(tf), tags->size(), tags);
563
  // Matrix
564
2.84k
  WriteICCUint8(0, tags->size(), tags);
565
  // Full range
566
2.84k
  WriteICCUint8(1, tags->size(), tags);
567
2.84k
  FinalizeICCTag(tags, offset, size);
568
2.84k
  AddToICCTagTable("cicp", *offset, *size, tagtable, offsets);
569
2.84k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::MaybeCreateICCCICPTag(JxlColorEncoding const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*, unsigned long*, unsigned long*, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*, std::__1::vector<unsigned long, std::__1::allocator<unsigned long> >*)
color_encoding_internal.cc:jxl::detail::MaybeCreateICCCICPTag(JxlColorEncoding const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*, unsigned long*, unsigned long*, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*, std::__1::vector<unsigned long, std::__1::allocator<unsigned long> >*)
Line
Count
Source
535
2.88k
                                  std::vector<size_t>* offsets) {
536
2.88k
  if (c.color_space != JXL_COLOR_SPACE_RGB) {
537
0
    return;
538
0
  }
539
2.88k
  uint8_t primaries = 0;
540
2.88k
  if (c.primaries == JXL_PRIMARIES_P3) {
541
11
    if (c.white_point == JXL_WHITE_POINT_D65) {
542
5
      primaries = 12;
543
6
    } else if (c.white_point == JXL_WHITE_POINT_DCI) {
544
2
      primaries = 11;
545
4
    } else {
546
4
      return;
547
4
    }
548
2.87k
  } else if (c.primaries != JXL_PRIMARIES_CUSTOM &&
549
2.87k
             c.white_point == JXL_WHITE_POINT_D65) {
550
2.84k
    primaries = static_cast<uint8_t>(c.primaries);
551
2.84k
  } else {
552
37
    return;
553
37
  }
554
2.84k
  JxlTransferFunction tf = c.transfer_function;
555
2.84k
  if (tf == JXL_TRANSFER_FUNCTION_UNKNOWN ||
556
2.84k
      tf == JXL_TRANSFER_FUNCTION_GAMMA) {
557
6
    return;
558
6
  }
559
2.84k
  WriteICCTag("cicp", tags->size(), tags);
560
2.84k
  WriteICCUint32(0, tags->size(), tags);
561
2.84k
  WriteICCUint8(primaries, tags->size(), tags);
562
2.84k
  WriteICCUint8(static_cast<uint8_t>(tf), tags->size(), tags);
563
  // Matrix
564
2.84k
  WriteICCUint8(0, tags->size(), tags);
565
  // Full range
566
2.84k
  WriteICCUint8(1, tags->size(), tags);
567
2.84k
  FinalizeICCTag(tags, offset, size);
568
2.84k
  AddToICCTagTable("cicp", *offset, *size, tagtable, offsets);
569
2.84k
}
Unexecuted instantiation: frame_header.cc:jxl::detail::MaybeCreateICCCICPTag(JxlColorEncoding const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*, unsigned long*, unsigned long*, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*, std::__1::vector<unsigned long, std::__1::allocator<unsigned long> >*)
Unexecuted instantiation: image_metadata.cc:jxl::detail::MaybeCreateICCCICPTag(JxlColorEncoding const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*, unsigned long*, unsigned long*, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*, std::__1::vector<unsigned long, std::__1::allocator<unsigned long> >*)
570
571
static void CreateICCCurvCurvTag(const std::vector<uint16_t>& curve,
572
19
                                 std::vector<uint8_t>* tags) {
573
19
  size_t pos = tags->size();
574
19
  tags->resize(tags->size() + 12 + curve.size() * 2, 0);
575
19
  WriteICCTag("curv", pos, tags);
576
19
  WriteICCUint32(0, pos + 4, tags);
577
19
  WriteICCUint32(curve.size(), pos + 8, tags);
578
1.23k
  for (size_t i = 0; i < curve.size(); i++) {
579
1.21k
    WriteICCUint16(curve[i], pos + 12 + i * 2, tags);
580
1.21k
  }
581
19
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::CreateICCCurvCurvTag(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> > const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
color_encoding_internal.cc:jxl::detail::CreateICCCurvCurvTag(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> > const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Line
Count
Source
572
19
                                 std::vector<uint8_t>* tags) {
573
19
  size_t pos = tags->size();
574
19
  tags->resize(tags->size() + 12 + curve.size() * 2, 0);
575
19
  WriteICCTag("curv", pos, tags);
576
19
  WriteICCUint32(0, pos + 4, tags);
577
19
  WriteICCUint32(curve.size(), pos + 8, tags);
578
1.23k
  for (size_t i = 0; i < curve.size(); i++) {
579
1.21k
    WriteICCUint16(curve[i], pos + 12 + i * 2, tags);
580
1.21k
  }
581
19
}
Unexecuted instantiation: frame_header.cc:jxl::detail::CreateICCCurvCurvTag(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> > const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Unexecuted instantiation: image_metadata.cc:jxl::detail::CreateICCCurvCurvTag(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> > const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
582
583
// Writes 12 + 4*params.size() bytes
584
static Status CreateICCCurvParaTag(const std::vector<float>& params,
585
                                   size_t curve_type,
586
2.92k
                                   std::vector<uint8_t>* tags) {
587
2.92k
  WriteICCTag("para", tags->size(), tags);
588
2.92k
  WriteICCUint32(0, tags->size(), tags);
589
2.92k
  WriteICCUint16(curve_type, tags->size(), tags);
590
2.92k
  WriteICCUint16(0, tags->size(), tags);
591
14.3k
  for (float param : params) {
592
14.3k
    JXL_RETURN_IF_ERROR(WriteICCS15Fixed16(param, tags->size(), tags));
593
14.3k
  }
594
2.92k
  return true;
595
2.92k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::CreateICCCurvParaTag(std::__1::vector<float, std::__1::allocator<float> > const&, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
color_encoding_internal.cc:jxl::detail::CreateICCCurvParaTag(std::__1::vector<float, std::__1::allocator<float> > const&, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Line
Count
Source
586
2.92k
                                   std::vector<uint8_t>* tags) {
587
2.92k
  WriteICCTag("para", tags->size(), tags);
588
2.92k
  WriteICCUint32(0, tags->size(), tags);
589
2.92k
  WriteICCUint16(curve_type, tags->size(), tags);
590
2.92k
  WriteICCUint16(0, tags->size(), tags);
591
14.3k
  for (float param : params) {
592
14.3k
    JXL_RETURN_IF_ERROR(WriteICCS15Fixed16(param, tags->size(), tags));
593
14.3k
  }
594
2.92k
  return true;
595
2.92k
}
Unexecuted instantiation: frame_header.cc:jxl::detail::CreateICCCurvParaTag(std::__1::vector<float, std::__1::allocator<float> > const&, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Unexecuted instantiation: image_metadata.cc:jxl::detail::CreateICCCurvParaTag(std::__1::vector<float, std::__1::allocator<float> > const&, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
596
597
2
static Status CreateICCLutAtoBTagForXYB(std::vector<uint8_t>* tags) {
598
2
  WriteICCTag("mAB ", tags->size(), tags);
599
  // 4 reserved bytes set to 0
600
2
  WriteICCUint32(0, tags->size(), tags);
601
  // number of input channels
602
2
  WriteICCUint8(3, tags->size(), tags);
603
  // number of output channels
604
2
  WriteICCUint8(3, tags->size(), tags);
605
  // 2 reserved bytes for padding
606
2
  WriteICCUint16(0, tags->size(), tags);
607
  // offset to first B curve
608
2
  WriteICCUint32(32, tags->size(), tags);
609
  // offset to matrix
610
2
  WriteICCUint32(244, tags->size(), tags);
611
  // offset to first M curve
612
2
  WriteICCUint32(148, tags->size(), tags);
613
  // offset to CLUT
614
2
  WriteICCUint32(80, tags->size(), tags);
615
  // offset to first A curve
616
  // (reuse linear B curves)
617
2
  WriteICCUint32(32, tags->size(), tags);
618
619
  // offset = 32
620
  // no-op curves
621
2
  JXL_RETURN_IF_ERROR(CreateICCCurvParaTag({1.0f}, 0, tags));
622
2
  JXL_RETURN_IF_ERROR(CreateICCCurvParaTag({1.0f}, 0, tags));
623
2
  JXL_RETURN_IF_ERROR(CreateICCCurvParaTag({1.0f}, 0, tags));
624
  // offset = 80
625
  // number of grid points for each input channel
626
34
  for (int i = 0; i < 16; ++i) {
627
32
    WriteICCUint8(i < 3 ? 2 : 0, tags->size(), tags);
628
32
  }
629
  // precision = 2
630
2
  WriteICCUint8(2, tags->size(), tags);
631
  // 3 bytes of padding
632
2
  WriteICCUint8(0, tags->size(), tags);
633
2
  WriteICCUint16(0, tags->size(), tags);
634
  // 2*2*2*3 entries of 2 bytes each = 48 bytes
635
2
  const jxl::cms::ColorCube3D& cube = jxl::cms::UnscaledA2BCube();
636
6
  for (size_t ix = 0; ix < 2; ++ix) {
637
12
    for (size_t iy = 0; iy < 2; ++iy) {
638
24
      for (size_t ib = 0; ib < 2; ++ib) {
639
16
        const jxl::cms::ColorCube0D& out_f = cube[ix][iy][ib];
640
64
        for (int i = 0; i < 3; ++i) {
641
48
          int32_t val = static_cast<int32_t>(std::lroundf(65535 * out_f[i]));
642
48
          JXL_DASSERT(val >= 0 && val <= 65535);
643
48
          WriteICCUint16(val, tags->size(), tags);
644
48
        }
645
16
      }
646
8
    }
647
4
  }
648
  // offset = 148
649
  // 3 curves with 5 parameters = 3 * (12 + 5 * 4) = 96 bytes
650
8
  for (size_t i = 0; i < 3; ++i) {
651
6
    const float b = -jxl::cms::kXYBOffset[i] -
652
6
                    std::cbrt(jxl::cms::kNegOpsinAbsorbanceBiasRGB[i]);
653
6
    std::vector<float> params = {
654
6
        3,
655
6
        1.0f / jxl::cms::kXYBScale[i],
656
6
        b,
657
6
        0,                                           // unused
658
6
        std::max(0.f, -b * jxl::cms::kXYBScale[i]),  // make skcms happy
659
6
    };
660
6
    JXL_RETURN_IF_ERROR(CreateICCCurvParaTag(params, 3, tags));
661
6
  }
662
  // offset = 244
663
2
  const double matrix[] = {1.5170095, -1.1065225, 0.071623,
664
2
                           -0.050022, 0.5683655,  -0.018344,
665
2
                           -1.387676, 1.1145555,  0.6857255};
666
  // 12 * 4 = 48 bytes
667
18
  for (double v : matrix) {
668
18
    JXL_RETURN_IF_ERROR(WriteICCS15Fixed16(v, tags->size(), tags));
669
18
  }
670
8
  for (size_t i = 0; i < 3; ++i) {
671
6
    float intercept = 0;
672
24
    for (size_t j = 0; j < 3; ++j) {
673
18
      intercept += matrix[i * 3 + j] * jxl::cms::kNegOpsinAbsorbanceBiasRGB[j];
674
18
    }
675
6
    JXL_RETURN_IF_ERROR(WriteICCS15Fixed16(intercept, tags->size(), tags));
676
6
  }
677
2
  return true;
678
2
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::CreateICCLutAtoBTagForXYB(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
color_encoding_internal.cc:jxl::detail::CreateICCLutAtoBTagForXYB(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Line
Count
Source
597
2
static Status CreateICCLutAtoBTagForXYB(std::vector<uint8_t>* tags) {
598
2
  WriteICCTag("mAB ", tags->size(), tags);
599
  // 4 reserved bytes set to 0
600
2
  WriteICCUint32(0, tags->size(), tags);
601
  // number of input channels
602
2
  WriteICCUint8(3, tags->size(), tags);
603
  // number of output channels
604
2
  WriteICCUint8(3, tags->size(), tags);
605
  // 2 reserved bytes for padding
606
2
  WriteICCUint16(0, tags->size(), tags);
607
  // offset to first B curve
608
2
  WriteICCUint32(32, tags->size(), tags);
609
  // offset to matrix
610
2
  WriteICCUint32(244, tags->size(), tags);
611
  // offset to first M curve
612
2
  WriteICCUint32(148, tags->size(), tags);
613
  // offset to CLUT
614
2
  WriteICCUint32(80, tags->size(), tags);
615
  // offset to first A curve
616
  // (reuse linear B curves)
617
2
  WriteICCUint32(32, tags->size(), tags);
618
619
  // offset = 32
620
  // no-op curves
621
2
  JXL_RETURN_IF_ERROR(CreateICCCurvParaTag({1.0f}, 0, tags));
622
2
  JXL_RETURN_IF_ERROR(CreateICCCurvParaTag({1.0f}, 0, tags));
623
2
  JXL_RETURN_IF_ERROR(CreateICCCurvParaTag({1.0f}, 0, tags));
624
  // offset = 80
625
  // number of grid points for each input channel
626
34
  for (int i = 0; i < 16; ++i) {
627
32
    WriteICCUint8(i < 3 ? 2 : 0, tags->size(), tags);
628
32
  }
629
  // precision = 2
630
2
  WriteICCUint8(2, tags->size(), tags);
631
  // 3 bytes of padding
632
2
  WriteICCUint8(0, tags->size(), tags);
633
2
  WriteICCUint16(0, tags->size(), tags);
634
  // 2*2*2*3 entries of 2 bytes each = 48 bytes
635
2
  const jxl::cms::ColorCube3D& cube = jxl::cms::UnscaledA2BCube();
636
6
  for (size_t ix = 0; ix < 2; ++ix) {
637
12
    for (size_t iy = 0; iy < 2; ++iy) {
638
24
      for (size_t ib = 0; ib < 2; ++ib) {
639
16
        const jxl::cms::ColorCube0D& out_f = cube[ix][iy][ib];
640
64
        for (int i = 0; i < 3; ++i) {
641
48
          int32_t val = static_cast<int32_t>(std::lroundf(65535 * out_f[i]));
642
48
          JXL_DASSERT(val >= 0 && val <= 65535);
643
48
          WriteICCUint16(val, tags->size(), tags);
644
48
        }
645
16
      }
646
8
    }
647
4
  }
648
  // offset = 148
649
  // 3 curves with 5 parameters = 3 * (12 + 5 * 4) = 96 bytes
650
8
  for (size_t i = 0; i < 3; ++i) {
651
6
    const float b = -jxl::cms::kXYBOffset[i] -
652
6
                    std::cbrt(jxl::cms::kNegOpsinAbsorbanceBiasRGB[i]);
653
6
    std::vector<float> params = {
654
6
        3,
655
6
        1.0f / jxl::cms::kXYBScale[i],
656
6
        b,
657
6
        0,                                           // unused
658
6
        std::max(0.f, -b * jxl::cms::kXYBScale[i]),  // make skcms happy
659
6
    };
660
6
    JXL_RETURN_IF_ERROR(CreateICCCurvParaTag(params, 3, tags));
661
6
  }
662
  // offset = 244
663
2
  const double matrix[] = {1.5170095, -1.1065225, 0.071623,
664
2
                           -0.050022, 0.5683655,  -0.018344,
665
2
                           -1.387676, 1.1145555,  0.6857255};
666
  // 12 * 4 = 48 bytes
667
18
  for (double v : matrix) {
668
18
    JXL_RETURN_IF_ERROR(WriteICCS15Fixed16(v, tags->size(), tags));
669
18
  }
670
8
  for (size_t i = 0; i < 3; ++i) {
671
6
    float intercept = 0;
672
24
    for (size_t j = 0; j < 3; ++j) {
673
18
      intercept += matrix[i * 3 + j] * jxl::cms::kNegOpsinAbsorbanceBiasRGB[j];
674
18
    }
675
6
    JXL_RETURN_IF_ERROR(WriteICCS15Fixed16(intercept, tags->size(), tags));
676
6
  }
677
2
  return true;
678
2
}
Unexecuted instantiation: frame_header.cc:jxl::detail::CreateICCLutAtoBTagForXYB(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Unexecuted instantiation: image_metadata.cc:jxl::detail::CreateICCLutAtoBTagForXYB(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
679
680
static Status CreateICCLutAtoBTagForHDR(JxlColorEncoding c,
681
8
                                        std::vector<uint8_t>* tags) {
682
8
  static constexpr size_t k3DLutDim = 9;
683
8
  WriteICCTag("mft1", tags->size(), tags);
684
  // 4 reserved bytes set to 0
685
8
  WriteICCUint32(0, tags->size(), tags);
686
  // number of input channels
687
8
  WriteICCUint8(3, tags->size(), tags);
688
  // number of output channels
689
8
  WriteICCUint8(3, tags->size(), tags);
690
  // number of CLUT grid points
691
8
  WriteICCUint8(k3DLutDim, tags->size(), tags);
692
  // 1 reserved bytes for padding
693
8
  WriteICCUint8(0, tags->size(), tags);
694
695
  // Matrix (per specification, must be identity if input is not XYZ)
696
32
  for (size_t i = 0; i < 3; ++i) {
697
96
    for (size_t j = 0; j < 3; ++j) {
698
72
      JXL_RETURN_IF_ERROR(
699
72
          WriteICCS15Fixed16(i == j ? 1.f : 0.f, tags->size(), tags));
700
72
    }
701
24
  }
702
703
  // Input tables
704
32
  for (size_t c = 0; c < 3; ++c) {
705
6.16k
    for (size_t i = 0; i < 256; ++i) {
706
6.14k
      WriteICCUint8(i, tags->size(), tags);
707
6.14k
    }
708
24
  }
709
710
80
  for (size_t ix = 0; ix < k3DLutDim; ++ix) {
711
720
    for (size_t iy = 0; iy < k3DLutDim; ++iy) {
712
6.48k
      for (size_t ib = 0; ib < k3DLutDim; ++ib) {
713
5.83k
        float f[3] = {ix * (1.0f / (k3DLutDim - 1)),
714
5.83k
                      iy * (1.0f / (k3DLutDim - 1)),
715
5.83k
                      ib * (1.0f / (k3DLutDim - 1))};
716
5.83k
        uint8_t pcslab_out[3];
717
5.83k
        JXL_RETURN_IF_ERROR(ToneMapPixel(c, f, pcslab_out));
718
17.4k
        for (uint8_t val : pcslab_out) {
719
17.4k
          WriteICCUint8(val, tags->size(), tags);
720
17.4k
        }
721
5.83k
      }
722
648
    }
723
72
  }
724
725
  // Output tables
726
32
  for (size_t c = 0; c < 3; ++c) {
727
6.16k
    for (size_t i = 0; i < 256; ++i) {
728
6.14k
      WriteICCUint8(i, tags->size(), tags);
729
6.14k
    }
730
24
  }
731
732
8
  return true;
733
8
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::CreateICCLutAtoBTagForHDR(JxlColorEncoding, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
color_encoding_internal.cc:jxl::detail::CreateICCLutAtoBTagForHDR(JxlColorEncoding, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Line
Count
Source
681
8
                                        std::vector<uint8_t>* tags) {
682
8
  static constexpr size_t k3DLutDim = 9;
683
8
  WriteICCTag("mft1", tags->size(), tags);
684
  // 4 reserved bytes set to 0
685
8
  WriteICCUint32(0, tags->size(), tags);
686
  // number of input channels
687
8
  WriteICCUint8(3, tags->size(), tags);
688
  // number of output channels
689
8
  WriteICCUint8(3, tags->size(), tags);
690
  // number of CLUT grid points
691
8
  WriteICCUint8(k3DLutDim, tags->size(), tags);
692
  // 1 reserved bytes for padding
693
8
  WriteICCUint8(0, tags->size(), tags);
694
695
  // Matrix (per specification, must be identity if input is not XYZ)
696
32
  for (size_t i = 0; i < 3; ++i) {
697
96
    for (size_t j = 0; j < 3; ++j) {
698
72
      JXL_RETURN_IF_ERROR(
699
72
          WriteICCS15Fixed16(i == j ? 1.f : 0.f, tags->size(), tags));
700
72
    }
701
24
  }
702
703
  // Input tables
704
32
  for (size_t c = 0; c < 3; ++c) {
705
6.16k
    for (size_t i = 0; i < 256; ++i) {
706
6.14k
      WriteICCUint8(i, tags->size(), tags);
707
6.14k
    }
708
24
  }
709
710
80
  for (size_t ix = 0; ix < k3DLutDim; ++ix) {
711
720
    for (size_t iy = 0; iy < k3DLutDim; ++iy) {
712
6.48k
      for (size_t ib = 0; ib < k3DLutDim; ++ib) {
713
5.83k
        float f[3] = {ix * (1.0f / (k3DLutDim - 1)),
714
5.83k
                      iy * (1.0f / (k3DLutDim - 1)),
715
5.83k
                      ib * (1.0f / (k3DLutDim - 1))};
716
5.83k
        uint8_t pcslab_out[3];
717
5.83k
        JXL_RETURN_IF_ERROR(ToneMapPixel(c, f, pcslab_out));
718
17.4k
        for (uint8_t val : pcslab_out) {
719
17.4k
          WriteICCUint8(val, tags->size(), tags);
720
17.4k
        }
721
5.83k
      }
722
648
    }
723
72
  }
724
725
  // Output tables
726
32
  for (size_t c = 0; c < 3; ++c) {
727
6.16k
    for (size_t i = 0; i < 256; ++i) {
728
6.14k
      WriteICCUint8(i, tags->size(), tags);
729
6.14k
    }
730
24
  }
731
732
8
  return true;
733
8
}
Unexecuted instantiation: frame_header.cc:jxl::detail::CreateICCLutAtoBTagForHDR(JxlColorEncoding, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Unexecuted instantiation: image_metadata.cc:jxl::detail::CreateICCLutAtoBTagForHDR(JxlColorEncoding, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
734
735
// Some software (Apple Safari, Preview) requires this.
736
10
static Status CreateICCNoOpBToATag(std::vector<uint8_t>* tags) {
737
10
  WriteICCTag("mBA ", tags->size(), tags);
738
  // 4 reserved bytes set to 0
739
10
  WriteICCUint32(0, tags->size(), tags);
740
  // number of input channels
741
10
  WriteICCUint8(3, tags->size(), tags);
742
  // number of output channels
743
10
  WriteICCUint8(3, tags->size(), tags);
744
  // 2 reserved bytes for padding
745
10
  WriteICCUint16(0, tags->size(), tags);
746
  // offset to first B curve
747
10
  WriteICCUint32(32, tags->size(), tags);
748
  // offset to matrix
749
10
  WriteICCUint32(0, tags->size(), tags);
750
  // offset to first M curve
751
10
  WriteICCUint32(0, tags->size(), tags);
752
  // offset to CLUT
753
10
  WriteICCUint32(0, tags->size(), tags);
754
  // offset to first A curve
755
10
  WriteICCUint32(0, tags->size(), tags);
756
757
10
  JXL_RETURN_IF_ERROR(CreateICCCurvParaTag({1.0f}, 0, tags));
758
10
  JXL_RETURN_IF_ERROR(CreateICCCurvParaTag({1.0f}, 0, tags));
759
10
  JXL_RETURN_IF_ERROR(CreateICCCurvParaTag({1.0f}, 0, tags));
760
761
10
  return true;
762
10
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::CreateICCNoOpBToATag(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
color_encoding_internal.cc:jxl::detail::CreateICCNoOpBToATag(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Line
Count
Source
736
10
static Status CreateICCNoOpBToATag(std::vector<uint8_t>* tags) {
737
10
  WriteICCTag("mBA ", tags->size(), tags);
738
  // 4 reserved bytes set to 0
739
10
  WriteICCUint32(0, tags->size(), tags);
740
  // number of input channels
741
10
  WriteICCUint8(3, tags->size(), tags);
742
  // number of output channels
743
10
  WriteICCUint8(3, tags->size(), tags);
744
  // 2 reserved bytes for padding
745
10
  WriteICCUint16(0, tags->size(), tags);
746
  // offset to first B curve
747
10
  WriteICCUint32(32, tags->size(), tags);
748
  // offset to matrix
749
10
  WriteICCUint32(0, tags->size(), tags);
750
  // offset to first M curve
751
10
  WriteICCUint32(0, tags->size(), tags);
752
  // offset to CLUT
753
10
  WriteICCUint32(0, tags->size(), tags);
754
  // offset to first A curve
755
10
  WriteICCUint32(0, tags->size(), tags);
756
757
10
  JXL_RETURN_IF_ERROR(CreateICCCurvParaTag({1.0f}, 0, tags));
758
10
  JXL_RETURN_IF_ERROR(CreateICCCurvParaTag({1.0f}, 0, tags));
759
10
  JXL_RETURN_IF_ERROR(CreateICCCurvParaTag({1.0f}, 0, tags));
760
761
10
  return true;
762
10
}
Unexecuted instantiation: frame_header.cc:jxl::detail::CreateICCNoOpBToATag(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Unexecuted instantiation: image_metadata.cc:jxl::detail::CreateICCNoOpBToATag(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
763
764
// These strings are baked into Description - do not change.
765
766
2.92k
static std::string ToString(JxlColorSpace color_space) {
767
2.92k
  switch (color_space) {
768
2.89k
    case JXL_COLOR_SPACE_RGB:
769
2.89k
      return "RGB";
770
26
    case JXL_COLOR_SPACE_GRAY:
771
26
      return "Gra";
772
2
    case JXL_COLOR_SPACE_XYB:
773
2
      return "XYB";
774
0
    case JXL_COLOR_SPACE_UNKNOWN:
775
0
      return "CS?";
776
2.92k
  }
777
  // Should not happen - visitor fails if enum is invalid.
778
0
  JXL_UNREACHABLE("Invalid ColorSpace %u", static_cast<uint32_t>(color_space));
779
0
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::ToString(JxlColorSpace)
color_encoding_internal.cc:jxl::detail::ToString(JxlColorSpace)
Line
Count
Source
766
2.92k
static std::string ToString(JxlColorSpace color_space) {
767
2.92k
  switch (color_space) {
768
2.89k
    case JXL_COLOR_SPACE_RGB:
769
2.89k
      return "RGB";
770
26
    case JXL_COLOR_SPACE_GRAY:
771
26
      return "Gra";
772
2
    case JXL_COLOR_SPACE_XYB:
773
2
      return "XYB";
774
0
    case JXL_COLOR_SPACE_UNKNOWN:
775
0
      return "CS?";
776
2.92k
  }
777
  // Should not happen - visitor fails if enum is invalid.
778
0
  JXL_UNREACHABLE("Invalid ColorSpace %u", static_cast<uint32_t>(color_space));
779
0
}
Unexecuted instantiation: frame_header.cc:jxl::detail::ToString(JxlColorSpace)
Unexecuted instantiation: image_metadata.cc:jxl::detail::ToString(JxlColorSpace)
780
781
2.88k
static std::string ToString(JxlWhitePoint white_point) {
782
2.88k
  switch (white_point) {
783
2.87k
    case JXL_WHITE_POINT_D65:
784
2.87k
      return "D65";
785
0
    case JXL_WHITE_POINT_CUSTOM:
786
0
      return "Cst";
787
5
    case JXL_WHITE_POINT_E:
788
5
      return "EER";
789
4
    case JXL_WHITE_POINT_DCI:
790
4
      return "DCI";
791
2.88k
  }
792
  // Should not happen - visitor fails if enum is invalid.
793
0
  JXL_UNREACHABLE("Invalid WhitePoint %u", static_cast<uint32_t>(white_point));
794
0
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::ToString(JxlWhitePoint)
color_encoding_internal.cc:jxl::detail::ToString(JxlWhitePoint)
Line
Count
Source
781
2.88k
static std::string ToString(JxlWhitePoint white_point) {
782
2.88k
  switch (white_point) {
783
2.87k
    case JXL_WHITE_POINT_D65:
784
2.87k
      return "D65";
785
0
    case JXL_WHITE_POINT_CUSTOM:
786
0
      return "Cst";
787
5
    case JXL_WHITE_POINT_E:
788
5
      return "EER";
789
4
    case JXL_WHITE_POINT_DCI:
790
4
      return "DCI";
791
2.88k
  }
792
  // Should not happen - visitor fails if enum is invalid.
793
0
  JXL_UNREACHABLE("Invalid WhitePoint %u", static_cast<uint32_t>(white_point));
794
0
}
Unexecuted instantiation: frame_header.cc:jxl::detail::ToString(JxlWhitePoint)
Unexecuted instantiation: image_metadata.cc:jxl::detail::ToString(JxlWhitePoint)
795
796
2.87k
static std::string ToString(JxlPrimaries primaries) {
797
2.87k
  switch (primaries) {
798
2.85k
    case JXL_PRIMARIES_SRGB:
799
2.85k
      return "SRG";
800
8
    case JXL_PRIMARIES_2100:
801
8
      return "202";
802
10
    case JXL_PRIMARIES_P3:
803
10
      return "DCI";
804
0
    case JXL_PRIMARIES_CUSTOM:
805
0
      return "Cst";
806
2.87k
  }
807
  // Should not happen - visitor fails if enum is invalid.
808
0
  JXL_UNREACHABLE("Invalid Primaries %u", static_cast<uint32_t>(primaries));
809
0
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::ToString(JxlPrimaries)
color_encoding_internal.cc:jxl::detail::ToString(JxlPrimaries)
Line
Count
Source
796
2.87k
static std::string ToString(JxlPrimaries primaries) {
797
2.87k
  switch (primaries) {
798
2.85k
    case JXL_PRIMARIES_SRGB:
799
2.85k
      return "SRG";
800
8
    case JXL_PRIMARIES_2100:
801
8
      return "202";
802
10
    case JXL_PRIMARIES_P3:
803
10
      return "DCI";
804
0
    case JXL_PRIMARIES_CUSTOM:
805
0
      return "Cst";
806
2.87k
  }
807
  // Should not happen - visitor fails if enum is invalid.
808
0
  JXL_UNREACHABLE("Invalid Primaries %u", static_cast<uint32_t>(primaries));
809
0
}
Unexecuted instantiation: frame_header.cc:jxl::detail::ToString(JxlPrimaries)
Unexecuted instantiation: image_metadata.cc:jxl::detail::ToString(JxlPrimaries)
810
811
2.90k
static std::string ToString(JxlTransferFunction transfer_function) {
812
2.90k
  switch (transfer_function) {
813
2.82k
    case JXL_TRANSFER_FUNCTION_SRGB:
814
2.82k
      return "SRG";
815
6
    case JXL_TRANSFER_FUNCTION_LINEAR:
816
6
      return "Lin";
817
39
    case JXL_TRANSFER_FUNCTION_709:
818
39
      return "709";
819
19
    case JXL_TRANSFER_FUNCTION_PQ:
820
19
      return "PeQ";
821
8
    case JXL_TRANSFER_FUNCTION_HLG:
822
8
      return "HLG";
823
3
    case JXL_TRANSFER_FUNCTION_DCI:
824
3
      return "DCI";
825
0
    case JXL_TRANSFER_FUNCTION_UNKNOWN:
826
0
      return "TF?";
827
0
    case JXL_TRANSFER_FUNCTION_GAMMA:
828
0
      JXL_UNREACHABLE("Invalid TransferFunction: gamma");
829
2.90k
  }
830
  // Should not happen - visitor fails if enum is invalid.
831
0
  JXL_UNREACHABLE("Invalid TransferFunction %u",
832
0
                  static_cast<uint32_t>(transfer_function));
833
0
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::ToString(JxlTransferFunction)
color_encoding_internal.cc:jxl::detail::ToString(JxlTransferFunction)
Line
Count
Source
811
2.90k
static std::string ToString(JxlTransferFunction transfer_function) {
812
2.90k
  switch (transfer_function) {
813
2.82k
    case JXL_TRANSFER_FUNCTION_SRGB:
814
2.82k
      return "SRG";
815
6
    case JXL_TRANSFER_FUNCTION_LINEAR:
816
6
      return "Lin";
817
39
    case JXL_TRANSFER_FUNCTION_709:
818
39
      return "709";
819
19
    case JXL_TRANSFER_FUNCTION_PQ:
820
19
      return "PeQ";
821
8
    case JXL_TRANSFER_FUNCTION_HLG:
822
8
      return "HLG";
823
3
    case JXL_TRANSFER_FUNCTION_DCI:
824
3
      return "DCI";
825
0
    case JXL_TRANSFER_FUNCTION_UNKNOWN:
826
0
      return "TF?";
827
0
    case JXL_TRANSFER_FUNCTION_GAMMA:
828
0
      JXL_UNREACHABLE("Invalid TransferFunction: gamma");
829
2.90k
  }
830
  // Should not happen - visitor fails if enum is invalid.
831
0
  JXL_UNREACHABLE("Invalid TransferFunction %u",
832
0
                  static_cast<uint32_t>(transfer_function));
833
0
}
Unexecuted instantiation: frame_header.cc:jxl::detail::ToString(JxlTransferFunction)
Unexecuted instantiation: image_metadata.cc:jxl::detail::ToString(JxlTransferFunction)
834
835
2.92k
static std::string ToString(JxlRenderingIntent rendering_intent) {
836
2.92k
  switch (rendering_intent) {
837
59
    case JXL_RENDERING_INTENT_PERCEPTUAL:
838
59
      return "Per";
839
2.86k
    case JXL_RENDERING_INTENT_RELATIVE:
840
2.86k
      return "Rel";
841
3
    case JXL_RENDERING_INTENT_SATURATION:
842
3
      return "Sat";
843
3
    case JXL_RENDERING_INTENT_ABSOLUTE:
844
3
      return "Abs";
845
2.92k
  }
846
  // Should not happen - visitor fails if enum is invalid.
847
0
  JXL_UNREACHABLE("Invalid RenderingIntent %u",
848
0
                  static_cast<uint32_t>(rendering_intent));
849
0
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::ToString(JxlRenderingIntent)
color_encoding_internal.cc:jxl::detail::ToString(JxlRenderingIntent)
Line
Count
Source
835
2.92k
static std::string ToString(JxlRenderingIntent rendering_intent) {
836
2.92k
  switch (rendering_intent) {
837
59
    case JXL_RENDERING_INTENT_PERCEPTUAL:
838
59
      return "Per";
839
2.86k
    case JXL_RENDERING_INTENT_RELATIVE:
840
2.86k
      return "Rel";
841
3
    case JXL_RENDERING_INTENT_SATURATION:
842
3
      return "Sat";
843
3
    case JXL_RENDERING_INTENT_ABSOLUTE:
844
3
      return "Abs";
845
2.92k
  }
846
  // Should not happen - visitor fails if enum is invalid.
847
0
  JXL_UNREACHABLE("Invalid RenderingIntent %u",
848
0
                  static_cast<uint32_t>(rendering_intent));
849
0
}
Unexecuted instantiation: frame_header.cc:jxl::detail::ToString(JxlRenderingIntent)
Unexecuted instantiation: image_metadata.cc:jxl::detail::ToString(JxlRenderingIntent)
850
851
2.93k
static std::string ColorEncodingDescriptionImpl(const JxlColorEncoding& c) {
852
2.93k
  if (c.color_space == JXL_COLOR_SPACE_RGB &&
853
2.93k
      c.white_point == JXL_WHITE_POINT_D65) {
854
2.86k
    if (c.rendering_intent == JXL_RENDERING_INTENT_PERCEPTUAL &&
855
2.86k
        c.transfer_function == JXL_TRANSFER_FUNCTION_SRGB) {
856
3
      if (c.primaries == JXL_PRIMARIES_SRGB) return "sRGB";
857
2
      if (c.primaries == JXL_PRIMARIES_P3) return "DisplayP3";
858
2
    }
859
2.86k
    if (c.rendering_intent == JXL_RENDERING_INTENT_RELATIVE &&
860
2.86k
        c.primaries == JXL_PRIMARIES_2100) {
861
5
      if (c.transfer_function == JXL_TRANSFER_FUNCTION_PQ) return "Rec2100PQ";
862
4
      if (c.transfer_function == JXL_TRANSFER_FUNCTION_HLG) return "Rec2100HLG";
863
4
    }
864
2.86k
  }
865
866
2.92k
  std::string d = ToString(c.color_space);
867
868
2.92k
  bool explicit_wp_tf = (c.color_space != JXL_COLOR_SPACE_XYB);
869
2.92k
  if (explicit_wp_tf) {
870
2.92k
    d += '_';
871
2.92k
    if (c.white_point == JXL_WHITE_POINT_CUSTOM) {
872
41
      d += jxl::ToString(c.white_point_xy[0]) + ';';
873
41
      d += jxl::ToString(c.white_point_xy[1]);
874
2.88k
    } else {
875
2.88k
      d += ToString(c.white_point);
876
2.88k
    }
877
2.92k
  }
878
879
2.92k
  if ((c.color_space != JXL_COLOR_SPACE_GRAY) &&
880
2.92k
      (c.color_space != JXL_COLOR_SPACE_XYB)) {
881
2.89k
    d += '_';
882
2.89k
    if (c.primaries == JXL_PRIMARIES_CUSTOM) {
883
25
      d += jxl::ToString(c.primaries_red_xy[0]) + ';';
884
25
      d += jxl::ToString(c.primaries_red_xy[1]) + ';';
885
25
      d += jxl::ToString(c.primaries_green_xy[0]) + ';';
886
25
      d += jxl::ToString(c.primaries_green_xy[1]) + ';';
887
25
      d += jxl::ToString(c.primaries_blue_xy[0]) + ';';
888
25
      d += jxl::ToString(c.primaries_blue_xy[1]);
889
2.87k
    } else {
890
2.87k
      d += ToString(c.primaries);
891
2.87k
    }
892
2.89k
  }
893
894
2.92k
  d += '_';
895
2.92k
  d += ToString(c.rendering_intent);
896
897
2.92k
  if (explicit_wp_tf) {
898
2.92k
    JxlTransferFunction tf = c.transfer_function;
899
2.92k
    d += '_';
900
2.92k
    if (tf == JXL_TRANSFER_FUNCTION_GAMMA) {
901
23
      d += 'g';
902
23
      d += jxl::ToString(c.gamma);
903
2.90k
    } else {
904
2.90k
      d += ToString(tf);
905
2.90k
    }
906
2.92k
  }
907
2.92k
  return d;
908
2.93k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::ColorEncodingDescriptionImpl(JxlColorEncoding const&)
color_encoding_internal.cc:jxl::detail::ColorEncodingDescriptionImpl(JxlColorEncoding const&)
Line
Count
Source
851
2.93k
static std::string ColorEncodingDescriptionImpl(const JxlColorEncoding& c) {
852
2.93k
  if (c.color_space == JXL_COLOR_SPACE_RGB &&
853
2.93k
      c.white_point == JXL_WHITE_POINT_D65) {
854
2.86k
    if (c.rendering_intent == JXL_RENDERING_INTENT_PERCEPTUAL &&
855
2.86k
        c.transfer_function == JXL_TRANSFER_FUNCTION_SRGB) {
856
3
      if (c.primaries == JXL_PRIMARIES_SRGB) return "sRGB";
857
2
      if (c.primaries == JXL_PRIMARIES_P3) return "DisplayP3";
858
2
    }
859
2.86k
    if (c.rendering_intent == JXL_RENDERING_INTENT_RELATIVE &&
860
2.86k
        c.primaries == JXL_PRIMARIES_2100) {
861
5
      if (c.transfer_function == JXL_TRANSFER_FUNCTION_PQ) return "Rec2100PQ";
862
4
      if (c.transfer_function == JXL_TRANSFER_FUNCTION_HLG) return "Rec2100HLG";
863
4
    }
864
2.86k
  }
865
866
2.92k
  std::string d = ToString(c.color_space);
867
868
2.92k
  bool explicit_wp_tf = (c.color_space != JXL_COLOR_SPACE_XYB);
869
2.92k
  if (explicit_wp_tf) {
870
2.92k
    d += '_';
871
2.92k
    if (c.white_point == JXL_WHITE_POINT_CUSTOM) {
872
41
      d += jxl::ToString(c.white_point_xy[0]) + ';';
873
41
      d += jxl::ToString(c.white_point_xy[1]);
874
2.88k
    } else {
875
2.88k
      d += ToString(c.white_point);
876
2.88k
    }
877
2.92k
  }
878
879
2.92k
  if ((c.color_space != JXL_COLOR_SPACE_GRAY) &&
880
2.92k
      (c.color_space != JXL_COLOR_SPACE_XYB)) {
881
2.89k
    d += '_';
882
2.89k
    if (c.primaries == JXL_PRIMARIES_CUSTOM) {
883
25
      d += jxl::ToString(c.primaries_red_xy[0]) + ';';
884
25
      d += jxl::ToString(c.primaries_red_xy[1]) + ';';
885
25
      d += jxl::ToString(c.primaries_green_xy[0]) + ';';
886
25
      d += jxl::ToString(c.primaries_green_xy[1]) + ';';
887
25
      d += jxl::ToString(c.primaries_blue_xy[0]) + ';';
888
25
      d += jxl::ToString(c.primaries_blue_xy[1]);
889
2.87k
    } else {
890
2.87k
      d += ToString(c.primaries);
891
2.87k
    }
892
2.89k
  }
893
894
2.92k
  d += '_';
895
2.92k
  d += ToString(c.rendering_intent);
896
897
2.92k
  if (explicit_wp_tf) {
898
2.92k
    JxlTransferFunction tf = c.transfer_function;
899
2.92k
    d += '_';
900
2.92k
    if (tf == JXL_TRANSFER_FUNCTION_GAMMA) {
901
23
      d += 'g';
902
23
      d += jxl::ToString(c.gamma);
903
2.90k
    } else {
904
2.90k
      d += ToString(tf);
905
2.90k
    }
906
2.92k
  }
907
2.92k
  return d;
908
2.93k
}
Unexecuted instantiation: frame_header.cc:jxl::detail::ColorEncodingDescriptionImpl(JxlColorEncoding const&)
Unexecuted instantiation: image_metadata.cc:jxl::detail::ColorEncodingDescriptionImpl(JxlColorEncoding const&)
909
910
static Status MaybeCreateProfileImpl(const JxlColorEncoding& c,
911
2.93k
                                     std::vector<uint8_t>* icc) {
912
2.93k
  std::vector<uint8_t> header;
913
2.93k
  std::vector<uint8_t> tagtable;
914
2.93k
  std::vector<uint8_t> tags;
915
2.93k
  JxlTransferFunction tf = c.transfer_function;
916
2.93k
  if (c.color_space == JXL_COLOR_SPACE_UNKNOWN ||
917
2.93k
      tf == JXL_TRANSFER_FUNCTION_UNKNOWN) {
918
0
    return false;  // Not an error
919
0
  }
920
921
2.93k
  switch (c.color_space) {
922
2.90k
    case JXL_COLOR_SPACE_RGB:
923
2.92k
    case JXL_COLOR_SPACE_GRAY:
924
2.93k
    case JXL_COLOR_SPACE_XYB:
925
2.93k
      break;  // OK
926
0
    default:
927
0
      return JXL_FAILURE("Invalid CS %u",
928
2.93k
                         static_cast<unsigned int>(c.color_space));
929
2.93k
  }
930
931
2.93k
  if (c.color_space == JXL_COLOR_SPACE_XYB &&
932
2.93k
      c.rendering_intent != JXL_RENDERING_INTENT_PERCEPTUAL) {
933
2
    return JXL_FAILURE(
934
2
        "Only perceptual rendering intent implemented for XYB "
935
2
        "ICC profile.");
936
2
  }
937
938
2.93k
  JXL_RETURN_IF_ERROR(CreateICCHeader(c, &header));
939
940
2.93k
  std::vector<size_t> offsets;
941
  // tag count, deferred to later
942
2.93k
  WriteICCUint32(0, tagtable.size(), &tagtable);
943
944
2.93k
  size_t tag_offset = 0;
945
2.93k
  size_t tag_size = 0;
946
947
2.93k
  CreateICCMlucTag(ColorEncodingDescriptionImpl(c), &tags);
948
2.93k
  FinalizeICCTag(&tags, &tag_offset, &tag_size);
949
2.93k
  AddToICCTagTable("desc", tag_offset, tag_size, &tagtable, &offsets);
950
951
2.93k
  const std::string copyright = "CC0";
952
2.93k
  CreateICCMlucTag(copyright, &tags);
953
2.93k
  FinalizeICCTag(&tags, &tag_offset, &tag_size);
954
2.93k
  AddToICCTagTable("cprt", tag_offset, tag_size, &tagtable, &offsets);
955
956
  // TODO(eustas): isn't it the other way round: gray image has d50 WhitePoint?
957
2.93k
  if (c.color_space == JXL_COLOR_SPACE_GRAY) {
958
26
    Color wtpt;
959
26
    JXL_RETURN_IF_ERROR(
960
26
        CIEXYZFromWhiteCIExy(c.white_point_xy[0], c.white_point_xy[1], wtpt));
961
25
    JXL_RETURN_IF_ERROR(CreateICCXYZTag(wtpt, &tags));
962
2.90k
  } else {
963
2.90k
    Color d50{0.964203, 1.0, 0.824905};
964
2.90k
    JXL_RETURN_IF_ERROR(CreateICCXYZTag(d50, &tags));
965
2.90k
  }
966
2.92k
  FinalizeICCTag(&tags, &tag_offset, &tag_size);
967
2.92k
  AddToICCTagTable("wtpt", tag_offset, tag_size, &tagtable, &offsets);
968
969
2.92k
  if (c.color_space != JXL_COLOR_SPACE_GRAY) {
970
    // Chromatic adaptation matrix
971
2.90k
    Matrix3x3 chad;
972
2.90k
    JXL_RETURN_IF_ERROR(
973
2.90k
        CreateICCChadMatrix(c.white_point_xy[0], c.white_point_xy[1], chad));
974
975
2.89k
    JXL_RETURN_IF_ERROR(CreateICCChadTag(chad, &tags));
976
2.89k
    FinalizeICCTag(&tags, &tag_offset, &tag_size);
977
2.89k
    AddToICCTagTable("chad", tag_offset, tag_size, &tagtable, &offsets);
978
2.89k
  }
979
980
2.91k
  if (c.color_space == JXL_COLOR_SPACE_RGB) {
981
2.88k
    MaybeCreateICCCICPTag(c, &tags, &tag_offset, &tag_size, &tagtable,
982
2.88k
                          &offsets);
983
984
2.88k
    Matrix3x3 m;
985
2.88k
    JXL_RETURN_IF_ERROR(CreateICCRGBMatrix(
986
2.88k
        c.primaries_red_xy[0], c.primaries_red_xy[1], c.primaries_green_xy[0],
987
2.88k
        c.primaries_green_xy[1], c.primaries_blue_xy[0], c.primaries_blue_xy[1],
988
2.88k
        c.white_point_xy[0], c.white_point_xy[1], m));
989
2.88k
    Color r{m[0][0], m[1][0], m[2][0]};
990
2.88k
    Color g{m[0][1], m[1][1], m[2][1]};
991
2.88k
    Color b{m[0][2], m[1][2], m[2][2]};
992
993
2.88k
    JXL_RETURN_IF_ERROR(CreateICCXYZTag(r, &tags));
994
2.88k
    FinalizeICCTag(&tags, &tag_offset, &tag_size);
995
2.88k
    AddToICCTagTable("rXYZ", tag_offset, tag_size, &tagtable, &offsets);
996
997
2.88k
    JXL_RETURN_IF_ERROR(CreateICCXYZTag(g, &tags));
998
2.88k
    FinalizeICCTag(&tags, &tag_offset, &tag_size);
999
2.88k
    AddToICCTagTable("gXYZ", tag_offset, tag_size, &tagtable, &offsets);
1000
1001
2.88k
    JXL_RETURN_IF_ERROR(CreateICCXYZTag(b, &tags));
1002
2.88k
    FinalizeICCTag(&tags, &tag_offset, &tag_size);
1003
2.88k
    AddToICCTagTable("bXYZ", tag_offset, tag_size, &tagtable, &offsets);
1004
2.88k
  }
1005
1006
2.90k
  if (c.color_space == JXL_COLOR_SPACE_XYB) {
1007
2
    JXL_RETURN_IF_ERROR(CreateICCLutAtoBTagForXYB(&tags));
1008
2
    FinalizeICCTag(&tags, &tag_offset, &tag_size);
1009
2
    AddToICCTagTable("A2B0", tag_offset, tag_size, &tagtable, &offsets);
1010
2
    JXL_RETURN_IF_ERROR(CreateICCNoOpBToATag(&tags));
1011
2
    FinalizeICCTag(&tags, &tag_offset, &tag_size);
1012
2
    AddToICCTagTable("B2A0", tag_offset, tag_size, &tagtable, &offsets);
1013
2.90k
  } else if (kEnable3DToneMapping && CanToneMap(c)) {
1014
8
    JXL_RETURN_IF_ERROR(CreateICCLutAtoBTagForHDR(c, &tags));
1015
8
    FinalizeICCTag(&tags, &tag_offset, &tag_size);
1016
8
    AddToICCTagTable("A2B0", tag_offset, tag_size, &tagtable, &offsets);
1017
8
    JXL_RETURN_IF_ERROR(CreateICCNoOpBToATag(&tags));
1018
8
    FinalizeICCTag(&tags, &tag_offset, &tag_size);
1019
8
    AddToICCTagTable("B2A0", tag_offset, tag_size, &tagtable, &offsets);
1020
2.89k
  } else {
1021
2.89k
    if (tf == JXL_TRANSFER_FUNCTION_GAMMA) {
1022
19
      float gamma = 1.0 / c.gamma;
1023
19
      JXL_RETURN_IF_ERROR(CreateICCCurvParaTag({gamma}, 0, &tags));
1024
2.87k
    } else if (c.color_space != JXL_COLOR_SPACE_XYB) {
1025
2.87k
      switch (tf) {
1026
7
        case JXL_TRANSFER_FUNCTION_HLG:
1027
7
          CreateICCCurvCurvTag(
1028
7
              CreateTableCurve(64, ExtraTF::kHLG, CanToneMap(c)), &tags);
1029
7
          break;
1030
12
        case JXL_TRANSFER_FUNCTION_PQ:
1031
12
          CreateICCCurvCurvTag(
1032
12
              CreateTableCurve(64, ExtraTF::kPQ, CanToneMap(c)), &tags);
1033
12
          break;
1034
2.82k
        case JXL_TRANSFER_FUNCTION_SRGB:
1035
2.82k
          JXL_RETURN_IF_ERROR(CreateICCCurvParaTag(
1036
2.82k
              {2.4, 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 0.04045}, 3,
1037
2.82k
              &tags));
1038
2.82k
          break;
1039
2.82k
        case JXL_TRANSFER_FUNCTION_709:
1040
25
          JXL_RETURN_IF_ERROR(CreateICCCurvParaTag(
1041
25
              {1.0 / 0.45, 1.0 / 1.099, 0.099 / 1.099, 1.0 / 4.5, 0.081}, 3,
1042
25
              &tags));
1043
25
          break;
1044
25
        case JXL_TRANSFER_FUNCTION_LINEAR:
1045
3
          JXL_RETURN_IF_ERROR(
1046
3
              CreateICCCurvParaTag({1.0, 1.0, 0.0, 1.0, 0.0}, 3, &tags));
1047
3
          break;
1048
3
        case JXL_TRANSFER_FUNCTION_DCI:
1049
3
          JXL_RETURN_IF_ERROR(
1050
3
              CreateICCCurvParaTag({2.6, 1.0, 0.0, 1.0, 0.0}, 3, &tags));
1051
3
          break;
1052
3
        default:
1053
0
          JXL_UNREACHABLE("Unknown TF %u", static_cast<unsigned int>(tf));
1054
2.87k
      }
1055
2.87k
    }
1056
2.89k
    FinalizeICCTag(&tags, &tag_offset, &tag_size);
1057
2.89k
    if (c.color_space == JXL_COLOR_SPACE_GRAY) {
1058
23
      AddToICCTagTable("kTRC", tag_offset, tag_size, &tagtable, &offsets);
1059
2.87k
    } else {
1060
2.87k
      AddToICCTagTable("rTRC", tag_offset, tag_size, &tagtable, &offsets);
1061
2.87k
      AddToICCTagTable("gTRC", tag_offset, tag_size, &tagtable, &offsets);
1062
2.87k
      AddToICCTagTable("bTRC", tag_offset, tag_size, &tagtable, &offsets);
1063
2.87k
    }
1064
2.89k
  }
1065
1066
  // Tag count
1067
2.90k
  WriteICCUint32(offsets.size(), 0, &tagtable);
1068
34.6k
  for (size_t i = 0; i < offsets.size(); i++) {
1069
31.7k
    WriteICCUint32(offsets[i] + header.size() + tagtable.size(), 4 + 12 * i + 4,
1070
31.7k
                   &tagtable);
1071
31.7k
  }
1072
1073
  // ICC profile size
1074
2.90k
  WriteICCUint32(header.size() + tagtable.size() + tags.size(), 0, &header);
1075
1076
2.90k
  *icc = header;
1077
2.90k
  Bytes(tagtable).AppendTo(*icc);
1078
2.90k
  Bytes(tags).AppendTo(*icc);
1079
1080
  // The MD5 checksum must be computed on the profile with profile flags,
1081
  // rendering intent, and region of the checksum itself, set to 0.
1082
  // TODO(lode): manually verify with a reliable tool that this creates correct
1083
  // signature (profile id) for ICC profiles.
1084
2.90k
  std::vector<uint8_t> icc_sum = *icc;
1085
2.90k
  if (icc_sum.size() >= 64 + 4) {
1086
2.90k
    memset(icc_sum.data() + 44, 0, 4);
1087
2.90k
    memset(icc_sum.data() + 64, 0, 4);
1088
2.90k
  }
1089
2.90k
  uint8_t checksum[16];
1090
2.90k
  detail::ICCComputeMD5(icc_sum, checksum);
1091
1092
2.90k
  memcpy(icc->data() + 84, checksum, sizeof(checksum));
1093
1094
2.90k
  return true;
1095
2.90k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::detail::MaybeCreateProfileImpl(JxlColorEncoding const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
color_encoding_internal.cc:jxl::detail::MaybeCreateProfileImpl(JxlColorEncoding const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Line
Count
Source
911
2.93k
                                     std::vector<uint8_t>* icc) {
912
2.93k
  std::vector<uint8_t> header;
913
2.93k
  std::vector<uint8_t> tagtable;
914
2.93k
  std::vector<uint8_t> tags;
915
2.93k
  JxlTransferFunction tf = c.transfer_function;
916
2.93k
  if (c.color_space == JXL_COLOR_SPACE_UNKNOWN ||
917
2.93k
      tf == JXL_TRANSFER_FUNCTION_UNKNOWN) {
918
0
    return false;  // Not an error
919
0
  }
920
921
2.93k
  switch (c.color_space) {
922
2.90k
    case JXL_COLOR_SPACE_RGB:
923
2.92k
    case JXL_COLOR_SPACE_GRAY:
924
2.93k
    case JXL_COLOR_SPACE_XYB:
925
2.93k
      break;  // OK
926
0
    default:
927
0
      return JXL_FAILURE("Invalid CS %u",
928
2.93k
                         static_cast<unsigned int>(c.color_space));
929
2.93k
  }
930
931
2.93k
  if (c.color_space == JXL_COLOR_SPACE_XYB &&
932
2.93k
      c.rendering_intent != JXL_RENDERING_INTENT_PERCEPTUAL) {
933
2
    return JXL_FAILURE(
934
2
        "Only perceptual rendering intent implemented for XYB "
935
2
        "ICC profile.");
936
2
  }
937
938
2.93k
  JXL_RETURN_IF_ERROR(CreateICCHeader(c, &header));
939
940
2.93k
  std::vector<size_t> offsets;
941
  // tag count, deferred to later
942
2.93k
  WriteICCUint32(0, tagtable.size(), &tagtable);
943
944
2.93k
  size_t tag_offset = 0;
945
2.93k
  size_t tag_size = 0;
946
947
2.93k
  CreateICCMlucTag(ColorEncodingDescriptionImpl(c), &tags);
948
2.93k
  FinalizeICCTag(&tags, &tag_offset, &tag_size);
949
2.93k
  AddToICCTagTable("desc", tag_offset, tag_size, &tagtable, &offsets);
950
951
2.93k
  const std::string copyright = "CC0";
952
2.93k
  CreateICCMlucTag(copyright, &tags);
953
2.93k
  FinalizeICCTag(&tags, &tag_offset, &tag_size);
954
2.93k
  AddToICCTagTable("cprt", tag_offset, tag_size, &tagtable, &offsets);
955
956
  // TODO(eustas): isn't it the other way round: gray image has d50 WhitePoint?
957
2.93k
  if (c.color_space == JXL_COLOR_SPACE_GRAY) {
958
26
    Color wtpt;
959
26
    JXL_RETURN_IF_ERROR(
960
26
        CIEXYZFromWhiteCIExy(c.white_point_xy[0], c.white_point_xy[1], wtpt));
961
25
    JXL_RETURN_IF_ERROR(CreateICCXYZTag(wtpt, &tags));
962
2.90k
  } else {
963
2.90k
    Color d50{0.964203, 1.0, 0.824905};
964
2.90k
    JXL_RETURN_IF_ERROR(CreateICCXYZTag(d50, &tags));
965
2.90k
  }
966
2.92k
  FinalizeICCTag(&tags, &tag_offset, &tag_size);
967
2.92k
  AddToICCTagTable("wtpt", tag_offset, tag_size, &tagtable, &offsets);
968
969
2.92k
  if (c.color_space != JXL_COLOR_SPACE_GRAY) {
970
    // Chromatic adaptation matrix
971
2.90k
    Matrix3x3 chad;
972
2.90k
    JXL_RETURN_IF_ERROR(
973
2.90k
        CreateICCChadMatrix(c.white_point_xy[0], c.white_point_xy[1], chad));
974
975
2.89k
    JXL_RETURN_IF_ERROR(CreateICCChadTag(chad, &tags));
976
2.89k
    FinalizeICCTag(&tags, &tag_offset, &tag_size);
977
2.89k
    AddToICCTagTable("chad", tag_offset, tag_size, &tagtable, &offsets);
978
2.89k
  }
979
980
2.91k
  if (c.color_space == JXL_COLOR_SPACE_RGB) {
981
2.88k
    MaybeCreateICCCICPTag(c, &tags, &tag_offset, &tag_size, &tagtable,
982
2.88k
                          &offsets);
983
984
2.88k
    Matrix3x3 m;
985
2.88k
    JXL_RETURN_IF_ERROR(CreateICCRGBMatrix(
986
2.88k
        c.primaries_red_xy[0], c.primaries_red_xy[1], c.primaries_green_xy[0],
987
2.88k
        c.primaries_green_xy[1], c.primaries_blue_xy[0], c.primaries_blue_xy[1],
988
2.88k
        c.white_point_xy[0], c.white_point_xy[1], m));
989
2.88k
    Color r{m[0][0], m[1][0], m[2][0]};
990
2.88k
    Color g{m[0][1], m[1][1], m[2][1]};
991
2.88k
    Color b{m[0][2], m[1][2], m[2][2]};
992
993
2.88k
    JXL_RETURN_IF_ERROR(CreateICCXYZTag(r, &tags));
994
2.88k
    FinalizeICCTag(&tags, &tag_offset, &tag_size);
995
2.88k
    AddToICCTagTable("rXYZ", tag_offset, tag_size, &tagtable, &offsets);
996
997
2.88k
    JXL_RETURN_IF_ERROR(CreateICCXYZTag(g, &tags));
998
2.88k
    FinalizeICCTag(&tags, &tag_offset, &tag_size);
999
2.88k
    AddToICCTagTable("gXYZ", tag_offset, tag_size, &tagtable, &offsets);
1000
1001
2.88k
    JXL_RETURN_IF_ERROR(CreateICCXYZTag(b, &tags));
1002
2.88k
    FinalizeICCTag(&tags, &tag_offset, &tag_size);
1003
2.88k
    AddToICCTagTable("bXYZ", tag_offset, tag_size, &tagtable, &offsets);
1004
2.88k
  }
1005
1006
2.90k
  if (c.color_space == JXL_COLOR_SPACE_XYB) {
1007
2
    JXL_RETURN_IF_ERROR(CreateICCLutAtoBTagForXYB(&tags));
1008
2
    FinalizeICCTag(&tags, &tag_offset, &tag_size);
1009
2
    AddToICCTagTable("A2B0", tag_offset, tag_size, &tagtable, &offsets);
1010
2
    JXL_RETURN_IF_ERROR(CreateICCNoOpBToATag(&tags));
1011
2
    FinalizeICCTag(&tags, &tag_offset, &tag_size);
1012
2
    AddToICCTagTable("B2A0", tag_offset, tag_size, &tagtable, &offsets);
1013
2.90k
  } else if (kEnable3DToneMapping && CanToneMap(c)) {
1014
8
    JXL_RETURN_IF_ERROR(CreateICCLutAtoBTagForHDR(c, &tags));
1015
8
    FinalizeICCTag(&tags, &tag_offset, &tag_size);
1016
8
    AddToICCTagTable("A2B0", tag_offset, tag_size, &tagtable, &offsets);
1017
8
    JXL_RETURN_IF_ERROR(CreateICCNoOpBToATag(&tags));
1018
8
    FinalizeICCTag(&tags, &tag_offset, &tag_size);
1019
8
    AddToICCTagTable("B2A0", tag_offset, tag_size, &tagtable, &offsets);
1020
2.89k
  } else {
1021
2.89k
    if (tf == JXL_TRANSFER_FUNCTION_GAMMA) {
1022
19
      float gamma = 1.0 / c.gamma;
1023
19
      JXL_RETURN_IF_ERROR(CreateICCCurvParaTag({gamma}, 0, &tags));
1024
2.87k
    } else if (c.color_space != JXL_COLOR_SPACE_XYB) {
1025
2.87k
      switch (tf) {
1026
7
        case JXL_TRANSFER_FUNCTION_HLG:
1027
7
          CreateICCCurvCurvTag(
1028
7
              CreateTableCurve(64, ExtraTF::kHLG, CanToneMap(c)), &tags);
1029
7
          break;
1030
12
        case JXL_TRANSFER_FUNCTION_PQ:
1031
12
          CreateICCCurvCurvTag(
1032
12
              CreateTableCurve(64, ExtraTF::kPQ, CanToneMap(c)), &tags);
1033
12
          break;
1034
2.82k
        case JXL_TRANSFER_FUNCTION_SRGB:
1035
2.82k
          JXL_RETURN_IF_ERROR(CreateICCCurvParaTag(
1036
2.82k
              {2.4, 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 0.04045}, 3,
1037
2.82k
              &tags));
1038
2.82k
          break;
1039
2.82k
        case JXL_TRANSFER_FUNCTION_709:
1040
25
          JXL_RETURN_IF_ERROR(CreateICCCurvParaTag(
1041
25
              {1.0 / 0.45, 1.0 / 1.099, 0.099 / 1.099, 1.0 / 4.5, 0.081}, 3,
1042
25
              &tags));
1043
25
          break;
1044
25
        case JXL_TRANSFER_FUNCTION_LINEAR:
1045
3
          JXL_RETURN_IF_ERROR(
1046
3
              CreateICCCurvParaTag({1.0, 1.0, 0.0, 1.0, 0.0}, 3, &tags));
1047
3
          break;
1048
3
        case JXL_TRANSFER_FUNCTION_DCI:
1049
3
          JXL_RETURN_IF_ERROR(
1050
3
              CreateICCCurvParaTag({2.6, 1.0, 0.0, 1.0, 0.0}, 3, &tags));
1051
3
          break;
1052
3
        default:
1053
0
          JXL_UNREACHABLE("Unknown TF %u", static_cast<unsigned int>(tf));
1054
2.87k
      }
1055
2.87k
    }
1056
2.89k
    FinalizeICCTag(&tags, &tag_offset, &tag_size);
1057
2.89k
    if (c.color_space == JXL_COLOR_SPACE_GRAY) {
1058
23
      AddToICCTagTable("kTRC", tag_offset, tag_size, &tagtable, &offsets);
1059
2.87k
    } else {
1060
2.87k
      AddToICCTagTable("rTRC", tag_offset, tag_size, &tagtable, &offsets);
1061
2.87k
      AddToICCTagTable("gTRC", tag_offset, tag_size, &tagtable, &offsets);
1062
2.87k
      AddToICCTagTable("bTRC", tag_offset, tag_size, &tagtable, &offsets);
1063
2.87k
    }
1064
2.89k
  }
1065
1066
  // Tag count
1067
2.90k
  WriteICCUint32(offsets.size(), 0, &tagtable);
1068
34.6k
  for (size_t i = 0; i < offsets.size(); i++) {
1069
31.7k
    WriteICCUint32(offsets[i] + header.size() + tagtable.size(), 4 + 12 * i + 4,
1070
31.7k
                   &tagtable);
1071
31.7k
  }
1072
1073
  // ICC profile size
1074
2.90k
  WriteICCUint32(header.size() + tagtable.size() + tags.size(), 0, &header);
1075
1076
2.90k
  *icc = header;
1077
2.90k
  Bytes(tagtable).AppendTo(*icc);
1078
2.90k
  Bytes(tags).AppendTo(*icc);
1079
1080
  // The MD5 checksum must be computed on the profile with profile flags,
1081
  // rendering intent, and region of the checksum itself, set to 0.
1082
  // TODO(lode): manually verify with a reliable tool that this creates correct
1083
  // signature (profile id) for ICC profiles.
1084
2.90k
  std::vector<uint8_t> icc_sum = *icc;
1085
2.90k
  if (icc_sum.size() >= 64 + 4) {
1086
2.90k
    memset(icc_sum.data() + 44, 0, 4);
1087
2.90k
    memset(icc_sum.data() + 64, 0, 4);
1088
2.90k
  }
1089
2.90k
  uint8_t checksum[16];
1090
2.90k
  detail::ICCComputeMD5(icc_sum, checksum);
1091
1092
2.90k
  memcpy(icc->data() + 84, checksum, sizeof(checksum));
1093
1094
2.90k
  return true;
1095
2.90k
}
Unexecuted instantiation: frame_header.cc:jxl::detail::MaybeCreateProfileImpl(JxlColorEncoding const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Unexecuted instantiation: image_metadata.cc:jxl::detail::MaybeCreateProfileImpl(JxlColorEncoding const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
1096
1097
}  // namespace detail
1098
1099
// Returns a representation of the ColorEncoding fields (not icc).
1100
// Example description: "RGB_D65_SRG_Rel_Lin"
1101
static JXL_MAYBE_UNUSED std::string ColorEncodingDescription(
1102
0
    const JxlColorEncoding& c) {
1103
0
  return detail::ColorEncodingDescriptionImpl(c);
1104
0
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::ColorEncodingDescription(JxlColorEncoding const&)
Unexecuted instantiation: color_encoding_internal.cc:jxl::ColorEncodingDescription(JxlColorEncoding const&)
Unexecuted instantiation: frame_header.cc:jxl::ColorEncodingDescription(JxlColorEncoding const&)
Unexecuted instantiation: image_metadata.cc:jxl::ColorEncodingDescription(JxlColorEncoding const&)
1105
1106
// NOTE: for XYB colorspace, the created profile can be used to transform a
1107
// *scaled* XYB image (created by ScaleXYB()) to another colorspace.
1108
static JXL_MAYBE_UNUSED Status MaybeCreateProfile(const JxlColorEncoding& c,
1109
2.93k
                                                  std::vector<uint8_t>* icc) {
1110
2.93k
  return detail::MaybeCreateProfileImpl(c, icc);
1111
2.93k
}
Unexecuted instantiation: fields_fuzzer.cc:jxl::MaybeCreateProfile(JxlColorEncoding const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
color_encoding_internal.cc:jxl::MaybeCreateProfile(JxlColorEncoding const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Line
Count
Source
1109
2.93k
                                                  std::vector<uint8_t>* icc) {
1110
2.93k
  return detail::MaybeCreateProfileImpl(c, icc);
1111
2.93k
}
Unexecuted instantiation: frame_header.cc:jxl::MaybeCreateProfile(JxlColorEncoding const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
Unexecuted instantiation: image_metadata.cc:jxl::MaybeCreateProfile(JxlColorEncoding const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >*)
1112
1113
}  // namespace jxl
1114
1115
#endif  // LIB_JXL_CMS_JXL_CMS_INTERNAL_H_