summaryrefslogtreecommitdiffstats
path: root/third_party/jpeg-xl/lib/jxl/cms
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/jpeg-xl/lib/jxl/cms')
-rw-r--r--third_party/jpeg-xl/lib/jxl/cms/color_encoding_cms.h4
-rw-r--r--third_party/jpeg-xl/lib/jxl/cms/jxl_cms.cc95
-rw-r--r--third_party/jpeg-xl/lib/jxl/cms/jxl_cms_internal.h179
-rw-r--r--third_party/jpeg-xl/lib/jxl/cms/opsin_params.h27
-rw-r--r--third_party/jpeg-xl/lib/jxl/cms/tone_mapping-inl.h6
-rw-r--r--third_party/jpeg-xl/lib/jxl/cms/tone_mapping.h52
-rw-r--r--third_party/jpeg-xl/lib/jxl/cms/tone_mapping_test.cc30
7 files changed, 215 insertions, 178 deletions
diff --git a/third_party/jpeg-xl/lib/jxl/cms/color_encoding_cms.h b/third_party/jpeg-xl/lib/jxl/cms/color_encoding_cms.h
index db61f820ca..3b7ae09d6f 100644
--- a/third_party/jpeg-xl/lib/jxl/cms/color_encoding_cms.h
+++ b/third_party/jpeg-xl/lib/jxl/cms/color_encoding_cms.h
@@ -96,6 +96,8 @@ enum class RenderingIntent : uint32_t {
// Chromaticity (Y is omitted because it is 1 for white points and implicit for
// primaries)
struct CIExy {
+ CIExy() = default;
+ CIExy(double x, double y) : x(x), y(y) {}
double x = 0.0;
double y = 0.0;
};
@@ -516,7 +518,7 @@ struct ColorEncoding {
JXL_RETURN_IF_ERROR(cms.set_fields_from_icc(cms.set_fields_data,
new_icc.data(), new_icc.size(),
&external, &new_cmyk));
- cmyk = new_cmyk;
+ cmyk = static_cast<bool>(new_cmyk);
JXL_RETURN_IF_ERROR(FromExternal(external));
icc = std::move(new_icc);
return true;
diff --git a/third_party/jpeg-xl/lib/jxl/cms/jxl_cms.cc b/third_party/jpeg-xl/lib/jxl/cms/jxl_cms.cc
index dd00b8b81f..e35b3ce172 100644
--- a/third_party/jpeg-xl/lib/jxl/cms/jxl_cms.cc
+++ b/third_party/jpeg-xl/lib/jxl/cms/jxl_cms.cc
@@ -307,7 +307,7 @@ int DoColorSpaceTransform(void* t, size_t thread, const float* buf_src,
#if JPEGXL_ENABLE_SKCMS
-JXL_MUST_USE_RESULT CIExy CIExyFromXYZ(const float XYZ[3]) {
+JXL_MUST_USE_RESULT CIExy CIExyFromXYZ(const Color& XYZ) {
const float factor = 1.f / (XYZ[0] + XYZ[1] + XYZ[2]);
CIExy xy;
xy.x = XYZ[0] * factor;
@@ -405,8 +405,8 @@ ColorSpace ColorSpaceFromProfile(const skcms_ICCProfile& profile) {
}
// vector_out := matmul(matrix, vector_in)
-void MatrixProduct(const skcms_Matrix3x3& matrix, const float vector_in[3],
- float vector_out[3]) {
+void MatrixProduct(const skcms_Matrix3x3& matrix, const Color& vector_in,
+ Color& vector_out) {
for (int i = 0; i < 3; ++i) {
vector_out[i] = 0;
for (int j = 0; j < 3; ++j) {
@@ -418,8 +418,8 @@ void MatrixProduct(const skcms_Matrix3x3& matrix, const float vector_in[3],
// Returns white point that was specified when creating the profile.
JXL_MUST_USE_RESULT Status UnadaptedWhitePoint(const skcms_ICCProfile& profile,
CIExy* out) {
- float media_white_point_XYZ[3];
- if (!skcms_GetWTPT(&profile, media_white_point_XYZ)) {
+ Color media_white_point_XYZ;
+ if (!skcms_GetWTPT(&profile, media_white_point_XYZ.data())) {
return JXL_FAILURE("ICC profile does not contain WhitePoint tag");
}
skcms_Matrix3x3 CHAD;
@@ -435,7 +435,7 @@ JXL_MUST_USE_RESULT Status UnadaptedWhitePoint(const skcms_ICCProfile& profile,
if (!skcms_Matrix3x3_invert(&CHAD, &inverse_CHAD)) {
return JXL_FAILURE("Non-invertible ChromaticAdaptation matrix");
}
- float unadapted_white_point_XYZ[3];
+ Color unadapted_white_point_XYZ;
MatrixProduct(inverse_CHAD, media_white_point_XYZ, unadapted_white_point_XYZ);
*out = CIExyFromXYZ(unadapted_white_point_XYZ);
return true;
@@ -445,7 +445,8 @@ Status IdentifyPrimaries(const skcms_ICCProfile& profile,
const CIExy& wp_unadapted, ColorEncoding* c) {
if (!c->HasPrimaries()) return true;
- skcms_Matrix3x3 CHAD, inverse_CHAD;
+ skcms_Matrix3x3 CHAD;
+ skcms_Matrix3x3 inverse_CHAD;
if (skcms_GetCHAD(&profile, &CHAD)) {
JXL_RETURN_IF_ERROR(skcms_Matrix3x3_invert(&CHAD, &inverse_CHAD));
} else {
@@ -457,11 +458,12 @@ Status IdentifyPrimaries(const skcms_ICCProfile& profile,
{{0.9869929, -0.1470543, 0.1599627},
{0.4323053, 0.5183603, 0.0492912},
{-0.0085287, 0.0400428, 0.9684867}}};
- static constexpr float kWpD50XYZ[3] = {0.96420288, 1.0, 0.82490540};
- float wp_unadapted_XYZ[3];
+ static constexpr Color kWpD50XYZ{0.96420288, 1.0, 0.82490540};
+ Color wp_unadapted_XYZ;
JXL_RETURN_IF_ERROR(
CIEXYZFromWhiteCIExy(wp_unadapted.x, wp_unadapted.y, wp_unadapted_XYZ));
- float wp_D50_LMS[3], wp_unadapted_LMS[3];
+ Color wp_D50_LMS;
+ Color wp_unadapted_LMS;
MatrixProduct(kLMSFromXYZ, kWpD50XYZ, wp_D50_LMS);
MatrixProduct(kLMSFromXYZ, wp_unadapted_XYZ, wp_unadapted_LMS);
inverse_CHAD = {{{wp_unadapted_LMS[0] / wp_D50_LMS[0], 0, 0},
@@ -471,16 +473,16 @@ Status IdentifyPrimaries(const skcms_ICCProfile& profile,
inverse_CHAD = skcms_Matrix3x3_concat(&inverse_CHAD, &kLMSFromXYZ);
}
- float XYZ[3];
+ Color XYZ;
PrimariesCIExy primaries;
CIExy* const chromaticities[] = {&primaries.r, &primaries.g, &primaries.b};
for (int i = 0; i < 3; ++i) {
float RGB[3] = {};
RGB[i] = 1;
skcms_Transform(RGB, skcms_PixelFormat_RGB_fff, skcms_AlphaFormat_Opaque,
- &profile, XYZ, skcms_PixelFormat_RGB_fff,
+ &profile, XYZ.data(), skcms_PixelFormat_RGB_fff,
skcms_AlphaFormat_Opaque, skcms_XYZD50_profile(), 1);
- float unadapted_XYZ[3];
+ Color unadapted_XYZ;
MatrixProduct(inverse_CHAD, XYZ, unadapted_XYZ);
*chromaticities[i] = CIExyFromXYZ(unadapted_XYZ);
}
@@ -829,17 +831,17 @@ Status GetPrimariesLuminances(const ColorEncoding& encoding,
// From there, by multiplying each total by its corresponding y, we get Y for
// that primary.
- float white_XYZ[3];
+ Color white_XYZ;
CIExy wp = encoding.GetWhitePoint();
JXL_RETURN_IF_ERROR(CIEXYZFromWhiteCIExy(wp.x, wp.y, white_XYZ));
const PrimariesCIExy primaries = encoding.GetPrimaries();
- double chromaticities[3][3] = {
- {primaries.r.x, primaries.g.x, primaries.b.x},
- {primaries.r.y, primaries.g.y, primaries.b.y},
- {1 - primaries.r.x - primaries.r.y, 1 - primaries.g.x - primaries.g.y,
- 1 - primaries.b.x - primaries.b.y}};
- JXL_RETURN_IF_ERROR(Inv3x3Matrix(&chromaticities[0][0]));
+ Matrix3x3d chromaticities{
+ {{primaries.r.x, primaries.g.x, primaries.b.x},
+ {primaries.r.y, primaries.g.y, primaries.b.y},
+ {1 - primaries.r.x - primaries.r.y, 1 - primaries.g.x - primaries.g.y,
+ 1 - primaries.b.x - primaries.b.y}}};
+ JXL_RETURN_IF_ERROR(Inv3x3Matrix(chromaticities));
const double ys[3] = {primaries.r.y, primaries.g.y, primaries.b.y};
for (size_t i = 0; i < 3; ++i) {
luminances[i] = ys[i] * (chromaticities[i][0] * white_XYZ[0] +
@@ -971,14 +973,31 @@ JXL_BOOL JxlCmsSetFieldsFromICC(void* user_data, const uint8_t* icc_data,
JXL_RETURN_IF_ERROR(skcms_Parse(icc_data, icc_size, &profile));
// skcms does not return the rendering intent, so get it from the file. It
- // is encoded as big-endian 32-bit integer in bytes 60..63.
- uint32_t rendering_intent32 = icc_data[67];
- if (rendering_intent32 > 3 || icc_data[64] != 0 || icc_data[65] != 0 ||
- icc_data[66] != 0) {
- return JXL_FAILURE("Invalid rendering intent %u\n", rendering_intent32);
+ // should be encoded as big-endian 32-bit integer in bytes 60..63.
+ uint32_t big_endian_rendering_intent = icc_data[67] + (icc_data[66] << 8) +
+ (icc_data[65] << 16) +
+ (icc_data[64] << 24);
+ // Some files encode rendering intent as little endian, which is not spec
+ // compliant. However we accept those with a warning.
+ uint32_t little_endian_rendering_intent = (icc_data[67] << 24) +
+ (icc_data[66] << 16) +
+ (icc_data[65] << 8) + icc_data[64];
+ uint32_t candidate_rendering_intent =
+ std::min(big_endian_rendering_intent, little_endian_rendering_intent);
+ if (candidate_rendering_intent != big_endian_rendering_intent) {
+ JXL_WARNING(
+ "Invalid rendering intent bytes: [0x%02X 0x%02X 0x%02X 0x%02X], "
+ "assuming %u was meant",
+ icc_data[64], icc_data[65], icc_data[66], icc_data[67],
+ candidate_rendering_intent);
+ }
+ if (candidate_rendering_intent > 3) {
+ return JXL_FAILURE("Invalid rendering intent %u\n",
+ candidate_rendering_intent);
}
// ICC and RenderingIntent have the same values (0..3).
- c_enc.rendering_intent = static_cast<RenderingIntent>(rendering_intent32);
+ c_enc.rendering_intent =
+ static_cast<RenderingIntent>(candidate_rendering_intent);
if (profile.has_CICP &&
ApplyCICP(profile.CICP.color_primaries,
@@ -986,11 +1005,11 @@ JXL_BOOL JxlCmsSetFieldsFromICC(void* user_data, const uint8_t* icc_data,
profile.CICP.matrix_coefficients,
profile.CICP.video_full_range_flag, &c_enc)) {
*c = c_enc.ToExternal();
- return true;
+ return JXL_TRUE;
}
c_enc.color_space = ColorSpaceFromProfile(profile);
- *cmyk = (profile.data_color_space == skcms_Signature_CMYK);
+ *cmyk = TO_JXL_BOOL(profile.data_color_space == skcms_Signature_CMYK);
CIExy wp_unadapted;
JXL_RETURN_IF_ERROR(UnadaptedWhitePoint(profile, &wp_unadapted));
@@ -1026,14 +1045,14 @@ JXL_BOOL JxlCmsSetFieldsFromICC(void* user_data, const uint8_t* icc_data,
ApplyCICP(cicp_buffer[8], cicp_buffer[9], cicp_buffer[10],
cicp_buffer[11], &c_enc)) {
*c = c_enc.ToExternal();
- return true;
+ return JXL_TRUE;
}
c_enc.color_space = ColorSpaceFromProfile(profile);
if (cmsGetColorSpace(profile.get()) == cmsSigCmykData) {
*cmyk = JXL_TRUE;
*c = c_enc.ToExternal();
- return true;
+ return JXL_TRUE;
}
const cmsCIEXYZ wp_unadapted = UnadaptedWhitePoint(context, profile, c_enc);
@@ -1049,7 +1068,7 @@ JXL_BOOL JxlCmsSetFieldsFromICC(void* user_data, const uint8_t* icc_data,
#endif // JPEGXL_ENABLE_SKCMS
*c = c_enc.ToExternal();
- return true;
+ return JXL_TRUE;
}
} // namespace
@@ -1084,9 +1103,10 @@ void* JxlCmsInit(void* init_data, size_t num_threads, size_t xsize,
const JxlColorProfile* input, const JxlColorProfile* output,
float intensity_target) {
JXL_ASSERT(init_data != nullptr);
- auto cms = static_cast<const JxlCmsInterface*>(init_data);
+ const auto* cms = static_cast<const JxlCmsInterface*>(init_data);
auto t = jxl::make_unique<JxlCms>();
- IccBytes icc_src, icc_dst;
+ IccBytes icc_src;
+ IccBytes icc_dst;
if (input->icc.size == 0) {
JXL_NOTIFY_ERROR("JxlCmsInit: empty input ICC");
return nullptr;
@@ -1259,8 +1279,6 @@ void* JxlCmsInit(void* init_data, size_t num_threads, size_t xsize,
// Not including alpha channel (copied separately).
const size_t channels_src = (c_src.cmyk ? 4 : c_src.Channels());
const size_t channels_dst = c_dst.Channels();
- JXL_CHECK(channels_src == channels_dst ||
- (channels_src == 4 && channels_dst == 3));
#if JXL_CMS_VERBOSE
printf("Channels: %" PRIuS "; Threads: %" PRIuS "\n", channels_src,
num_threads);
@@ -1294,13 +1312,14 @@ void* JxlCmsInit(void* init_data, size_t num_threads, size_t xsize,
// outputs (or vice versa), we use floating point input/output.
t->channels_src = channels_src;
t->channels_dst = channels_dst;
+#if !JPEGXL_ENABLE_SKCMS
size_t actual_channels_src = channels_src;
size_t actual_channels_dst = channels_dst;
-#if JPEGXL_ENABLE_SKCMS
+#else
// SkiaCMS doesn't support grayscale float buffers, so we create space for RGB
// float buffers anyway.
- actual_channels_src = (channels_src == 4 ? 4 : 3);
- actual_channels_dst = 3;
+ size_t actual_channels_src = (channels_src == 4 ? 4 : 3);
+ size_t actual_channels_dst = 3;
#endif
AllocateBuffer(xsize * actual_channels_src, num_threads, &t->src_storage,
&t->buf_src);
diff --git a/third_party/jpeg-xl/lib/jxl/cms/jxl_cms_internal.h b/third_party/jpeg-xl/lib/jxl/cms/jxl_cms_internal.h
index c00fe82d8c..7f59e688d0 100644
--- a/third_party/jpeg-xl/lib/jxl/cms/jxl_cms_internal.h
+++ b/third_party/jpeg-xl/lib/jxl/cms/jxl_cms_internal.h
@@ -41,7 +41,7 @@ enum class ExtraTF {
};
static Status PrimariesToXYZ(float rx, float ry, float gx, float gy, float bx,
- float by, float wx, float wy, float matrix[9]) {
+ float by, float wx, float wy, Matrix3x3& matrix) {
bool ok = (wx >= 0) && (wx <= 1) && (wy > 0) && (wy <= 1);
if (!ok) {
return JXL_FAILURE("Invalid white point");
@@ -49,51 +49,48 @@ static Status PrimariesToXYZ(float rx, float ry, float gx, float gy, float bx,
// TODO(lode): also require rx, ry, gx, gy, bx, to be in range 0-1? ICC
// profiles in theory forbid negative XYZ values, but in practice the ACES P0
// color space uses a negative y for the blue primary.
- float primaries[9] = {
- rx, gx, bx, ry, gy, by, 1.0f - rx - ry, 1.0f - gx - gy, 1.0f - bx - by};
- float primaries_inv[9];
- memcpy(primaries_inv, primaries, sizeof(float) * 9);
+ Matrix3x3 primaries{{{rx, gx, bx},
+ {ry, gy, by},
+ {1.0f - rx - ry, 1.0f - gx - gy, 1.0f - bx - by}}};
+ Matrix3x3 primaries_inv;
+ primaries_inv = primaries;
JXL_RETURN_IF_ERROR(Inv3x3Matrix(primaries_inv));
- float w[3] = {wx / wy, 1.0f, (1.0f - wx - wy) / wy};
+ Vector3 w{wx / wy, 1.0f, (1.0f - wx - wy) / wy};
// 1 / tiny float can still overflow
JXL_RETURN_IF_ERROR(std::isfinite(w[0]) && std::isfinite(w[2]));
- float xyz[3];
+ Vector3 xyz;
Mul3x3Vector(primaries_inv, w, xyz);
- float a[9] = {
- xyz[0], 0, 0, 0, xyz[1], 0, 0, 0, xyz[2],
- };
+ Matrix3x3 a{{{xyz[0], 0, 0}, {0, xyz[1], 0}, {0, 0, xyz[2]}}};
Mul3x3Matrix(primaries, a, matrix);
return true;
}
/* Chromatic adaptation matrices*/
-constexpr float kBradford[9] = {
- 0.8951f, 0.2664f, -0.1614f, -0.7502f, 1.7135f,
- 0.0367f, 0.0389f, -0.0685f, 1.0296f,
-};
-constexpr float kBradfordInv[9] = {
- 0.9869929f, -0.1470543f, 0.1599627f, 0.4323053f, 0.5183603f,
- 0.0492912f, -0.0085287f, 0.0400428f, 0.9684867f,
-};
+constexpr Matrix3x3 kBradford{{{0.8951f, 0.2664f, -0.1614f},
+ {-0.7502f, 1.7135f, 0.0367f},
+ {0.0389f, -0.0685f, 1.0296f}}};
+constexpr Matrix3x3 kBradfordInv{{{0.9869929f, -0.1470543f, 0.1599627f},
+ {0.4323053f, 0.5183603f, 0.0492912f},
+ {-0.0085287f, 0.0400428f, 0.9684867f}}};
// Adapts whitepoint x, y to D50
-static Status AdaptToXYZD50(float wx, float wy, float matrix[9]) {
+static Status AdaptToXYZD50(float wx, float wy, Matrix3x3& matrix) {
bool ok = (wx >= 0) && (wx <= 1) && (wy > 0) && (wy <= 1);
if (!ok) {
// Out of range values can cause division through zero
// further down with the bradford adaptation too.
return JXL_FAILURE("Invalid white point");
}
- float w[3] = {wx / wy, 1.0f, (1.0f - wx - wy) / wy};
+ Vector3 w{wx / wy, 1.0f, (1.0f - wx - wy) / wy};
// 1 / tiny float can still overflow
JXL_RETURN_IF_ERROR(std::isfinite(w[0]) && std::isfinite(w[2]));
- float w50[3] = {0.96422f, 1.0f, 0.82521f};
+ Vector3 w50{0.96422f, 1.0f, 0.82521f};
- float lms[3];
- float lms50[3];
+ Vector3 lms;
+ Vector3 lms50;
Mul3x3Vector(kBradford, w, lms);
Mul3x3Vector(kBradford, w50, lms50);
@@ -101,15 +98,15 @@ static Status AdaptToXYZD50(float wx, float wy, float matrix[9]) {
if (lms[0] == 0 || lms[1] == 0 || lms[2] == 0) {
return JXL_FAILURE("Invalid white point");
}
- float a[9] = {
- // /----> 0, 1, 2, 3, /----> 4, 5, 6, 7, /----> 8,
- lms50[0] / lms[0], 0, 0, 0, lms50[1] / lms[1], 0, 0, 0, lms50[2] / lms[2],
- };
- if (!std::isfinite(a[0]) || !std::isfinite(a[4]) || !std::isfinite(a[8])) {
+ Matrix3x3 a{{{lms50[0] / lms[0], 0, 0},
+ {0, lms50[1] / lms[1], 0},
+ {0, 0, lms50[2] / lms[2]}}};
+ if (!std::isfinite(a[0][0]) || !std::isfinite(a[1][1]) ||
+ !std::isfinite(a[2][2])) {
return JXL_FAILURE("Invalid white point");
}
- float b[9];
+ Matrix3x3 b;
Mul3x3Matrix(a, kBradford, b);
Mul3x3Matrix(kBradfordInv, b, matrix);
@@ -118,10 +115,10 @@ static Status AdaptToXYZD50(float wx, float wy, float matrix[9]) {
static Status PrimariesToXYZD50(float rx, float ry, float gx, float gy,
float bx, float by, float wx, float wy,
- float matrix[9]) {
- float toXYZ[9];
+ Matrix3x3& matrix) {
+ Matrix3x3 toXYZ;
JXL_RETURN_IF_ERROR(PrimariesToXYZ(rx, ry, gx, gy, bx, by, wx, wy, toXYZ));
- float d50[9];
+ Matrix3x3 d50;
JXL_RETURN_IF_ERROR(AdaptToXYZD50(wx, wy, d50));
Mul3x3Matrix(d50, toXYZ, matrix);
@@ -130,14 +127,13 @@ static Status PrimariesToXYZD50(float rx, float ry, float gx, float gy,
static Status ToneMapPixel(const JxlColorEncoding& c, const float in[3],
uint8_t pcslab_out[3]) {
- float primaries_XYZ[9];
+ Matrix3x3 primaries_XYZ;
JXL_RETURN_IF_ERROR(PrimariesToXYZ(
c.primaries_red_xy[0], c.primaries_red_xy[1], c.primaries_green_xy[0],
c.primaries_green_xy[1], c.primaries_blue_xy[0], c.primaries_blue_xy[1],
c.white_point_xy[0], c.white_point_xy[1], primaries_XYZ));
- const float luminances[3] = {primaries_XYZ[3], primaries_XYZ[4],
- primaries_XYZ[5]};
- float linear[3];
+ const Vector3 luminances = primaries_XYZ[1];
+ Color linear;
JxlTransferFunction tf = c.transfer_function;
if (tf == JXL_TRANSFER_FUNCTION_PQ) {
for (size_t i = 0; i < 3; ++i) {
@@ -151,25 +147,25 @@ static Status ToneMapPixel(const JxlColorEncoding& c, const float in[3],
}
if (tf == JXL_TRANSFER_FUNCTION_PQ) {
Rec2408ToneMapperBase tone_mapper({0, 10000}, {0, 250}, luminances);
- tone_mapper.ToneMap(&linear[0], &linear[1], &linear[2]);
+ tone_mapper.ToneMap(linear);
} else {
HlgOOTF_Base ootf(/*source_luminance=*/300, /*target_luminance=*/80,
luminances);
- ootf.Apply(&linear[0], &linear[1], &linear[2]);
+ ootf.Apply(linear);
}
- GamutMapScalar(&linear[0], &linear[1], &linear[2], luminances,
+ GamutMapScalar(linear, luminances,
/*preserve_saturation=*/0.3f);
- float chad[9];
+ Matrix3x3 chad;
JXL_RETURN_IF_ERROR(
AdaptToXYZD50(c.white_point_xy[0], c.white_point_xy[1], chad));
- float to_xyzd50[9];
+ Matrix3x3 to_xyzd50;
Mul3x3Matrix(chad, primaries_XYZ, to_xyzd50);
- float xyz[3] = {0, 0, 0};
+ Vector3 xyz{0, 0, 0};
for (size_t xyz_c = 0; xyz_c < 3; ++xyz_c) {
for (size_t rgb_c = 0; rgb_c < 3; ++rgb_c) {
- xyz[xyz_c] += linear[rgb_c] * to_xyzd50[3 * xyz_c + rgb_c];
+ xyz[xyz_c] += linear[rgb_c] * to_xyzd50[xyz_c][rgb_c];
}
}
@@ -206,7 +202,7 @@ static std::vector<uint16_t> CreateTableCurve(uint32_t N, const ExtraTF tf,
JXL_ASSERT(N <= 4096); // ICC MFT2 only allows 4K entries
JXL_ASSERT(tf == ExtraTF::kPQ || tf == ExtraTF::kHLG);
- static constexpr float kLuminances[] = {1.f / 3, 1.f / 3, 1.f / 3};
+ static constexpr Vector3 kLuminances{1.f / 3, 1.f / 3, 1.f / 3};
Rec2408ToneMapperBase tone_mapper({0, kPQIntensityTarget},
{0, kDefaultIntensityTarget}, kLuminances);
// No point using float - LCMS converts to 16-bit for A2B/MFT.
@@ -220,9 +216,10 @@ static std::vector<uint16_t> CreateTableCurve(uint32_t N, const ExtraTF tf,
: TF_PQ_Base::DisplayFromEncoded(kPQIntensityTarget, dx);
if (tone_map && tf == ExtraTF::kPQ &&
kPQIntensityTarget > kDefaultIntensityTarget) {
- float r = y * 10000 / kPQIntensityTarget, g = r, b = r;
- tone_mapper.ToneMap(&r, &g, &b);
- y = r;
+ float l = y * 10000 / kPQIntensityTarget;
+ Color gray{l, l, l};
+ tone_mapper.ToneMap(gray);
+ y = gray[0];
}
JXL_ASSERT(y >= 0.0);
// Clamp to table range - necessary for HLG.
@@ -233,7 +230,7 @@ static std::vector<uint16_t> CreateTableCurve(uint32_t N, const ExtraTF tf,
return table;
}
-static Status CIEXYZFromWhiteCIExy(double wx, double wy, float XYZ[3]) {
+static Status CIEXYZFromWhiteCIExy(double wx, double wy, Color& XYZ) {
// Target Y = 1.
if (std::abs(wy) < 1e-12) return JXL_FAILURE("Y value is too small");
const float factor = 1 / wy;
@@ -292,10 +289,18 @@ static void ICCComputeMD5(const std::vector<uint8_t>& data, uint8_t sum[16])
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
};
- uint32_t a0 = 0x67452301, b0 = 0xefcdab89, c0 = 0x98badcfe, d0 = 0x10325476;
+ uint32_t a0 = 0x67452301;
+ uint32_t b0 = 0xefcdab89;
+ uint32_t c0 = 0x98badcfe;
+ uint32_t d0 = 0x10325476;
for (size_t i = 0; i < data64.size(); i += 64) {
- uint32_t a = a0, b = b0, c = c0, d = d0, f, g;
+ uint32_t a = a0;
+ uint32_t b = b0;
+ uint32_t c = c0;
+ uint32_t d = d0;
+ uint32_t f;
+ uint32_t g;
for (size_t j = 0; j < 64; j++) {
if (j < 16) {
f = (b & c) | ((~b) & d);
@@ -310,8 +315,10 @@ static void ICCComputeMD5(const std::vector<uint8_t>& data, uint8_t sum[16])
f = c ^ (b | (~d));
g = (7 * j) & 0xf;
}
- uint32_t dg0 = data64[i + g * 4 + 0], dg1 = data64[i + g * 4 + 1],
- dg2 = data64[i + g * 4 + 2], dg3 = data64[i + g * 4 + 3];
+ uint32_t dg0 = data64[i + g * 4 + 0];
+ uint32_t dg1 = data64[i + g * 4 + 1];
+ uint32_t dg2 = data64[i + g * 4 + 2];
+ uint32_t dg3 = data64[i + g * 4 + 3];
uint32_t u = dg0 | (dg1 << 8u) | (dg2 << 16u) | (dg3 << 24u);
f += a + sineparts[j] + u;
a = d;
@@ -342,23 +349,23 @@ static void ICCComputeMD5(const std::vector<uint8_t>& data, uint8_t sum[16])
sum[15] = d0 >> 24u;
}
-static Status CreateICCChadMatrix(double wx, double wy, float result[9]) {
- float m[9];
+static Status CreateICCChadMatrix(double wx, double wy, Matrix3x3& result) {
+ Matrix3x3 m;
if (wy == 0) { // WhitePoint can not be pitch-black.
return JXL_FAILURE("Invalid WhitePoint");
}
JXL_RETURN_IF_ERROR(AdaptToXYZD50(wx, wy, m));
- memcpy(result, m, sizeof(float) * 9);
+ result = m;
return true;
}
// Creates RGB to XYZ matrix given RGB primaries and whitepoint in xy.
static Status CreateICCRGBMatrix(double rx, double ry, double gx, double gy,
double bx, double by, double wx, double wy,
- float result[9]) {
- float m[9];
+ Matrix3x3& result) {
+ Matrix3x3 m;
JXL_RETURN_IF_ERROR(PrimariesToXYZD50(rx, ry, gx, gy, bx, by, wx, wy, m));
- memcpy(result, m, sizeof(float) * 9);
+ result = m;
return true;
}
@@ -433,8 +440,12 @@ static Status CreateICCHeader(const JxlColorEncoding& c,
// Three uint32_t's date/time encoding.
// TODO(lode): encode actual date and time, this is a placeholder
- uint32_t year = 2019, month = 12, day = 1;
- uint32_t hour = 0, minute = 0, second = 0;
+ uint32_t year = 2019;
+ uint32_t month = 12;
+ uint32_t day = 1;
+ uint32_t hour = 0;
+ uint32_t minute = 0;
+ uint32_t second = 0;
WriteICCUint16(year, 24, header);
WriteICCUint16(month, 26, header);
WriteICCUint16(day, 28, header);
@@ -491,13 +502,13 @@ static void CreateICCMlucTag(const std::string& text,
WriteICCTag("enUS", tags->size(), tags);
WriteICCUint32(text.size() * 2, tags->size(), tags);
WriteICCUint32(28, tags->size(), tags);
- for (size_t i = 0; i < text.size(); i++) {
+ for (char c : text) {
tags->push_back(0); // prepend 0 for UTF-16
- tags->push_back(text[i]);
+ tags->push_back(c);
}
}
-static Status CreateICCXYZTag(float xyz[3], std::vector<uint8_t>* tags) {
+static Status CreateICCXYZTag(const Color& xyz, std::vector<uint8_t>* tags) {
WriteICCTag("XYZ ", tags->size(), tags);
WriteICCUint32(0, tags->size(), tags);
for (size_t i = 0; i < 3; ++i) {
@@ -506,11 +517,14 @@ static Status CreateICCXYZTag(float xyz[3], std::vector<uint8_t>* tags) {
return true;
}
-static Status CreateICCChadTag(float chad[9], std::vector<uint8_t>* tags) {
+static Status CreateICCChadTag(const Matrix3x3& chad,
+ std::vector<uint8_t>* tags) {
WriteICCTag("sf32", tags->size(), tags);
WriteICCUint32(0, tags->size(), tags);
- for (size_t i = 0; i < 9; i++) {
- JXL_RETURN_IF_ERROR(WriteICCS15Fixed16(chad[i], tags->size(), tags));
+ for (size_t j = 0; j < 3; j++) {
+ for (size_t i = 0; i < 3; i++) {
+ JXL_RETURN_IF_ERROR(WriteICCS15Fixed16(chad[j][i], tags->size(), tags));
+ }
}
return true;
}
@@ -573,8 +587,8 @@ static Status CreateICCCurvParaTag(std::vector<float> params, size_t curve_type,
WriteICCUint32(0, tags->size(), tags);
WriteICCUint16(curve_type, tags->size(), tags);
WriteICCUint16(0, tags->size(), tags);
- for (size_t i = 0; i < params.size(); i++) {
- JXL_RETURN_IF_ERROR(WriteICCS15Fixed16(params[i], tags->size(), tags));
+ for (float param : params) {
+ JXL_RETURN_IF_ERROR(WriteICCS15Fixed16(param, tags->size(), tags));
}
return true;
}
@@ -649,8 +663,8 @@ static Status CreateICCLutAtoBTagForXYB(std::vector<uint8_t>* tags) {
-0.050022, 0.5683655, -0.018344,
-1.387676, 1.1145555, 0.6857255};
// 12 * 4 = 48 bytes
- for (size_t i = 0; i < 9; ++i) {
- JXL_RETURN_IF_ERROR(WriteICCS15Fixed16(matrix[i], tags->size(), tags));
+ for (double v : matrix) {
+ JXL_RETURN_IF_ERROR(WriteICCS15Fixed16(v, tags->size(), tags));
}
for (size_t i = 0; i < 3; ++i) {
float intercept = 0;
@@ -880,7 +894,9 @@ static std::string ColorEncodingDescriptionImpl(const JxlColorEncoding& c) {
static Status MaybeCreateProfileImpl(const JxlColorEncoding& c,
std::vector<uint8_t>* icc) {
- std::vector<uint8_t> header, tagtable, tags;
+ std::vector<uint8_t> header;
+ std::vector<uint8_t> tagtable;
+ std::vector<uint8_t> tags;
JxlTransferFunction tf = c.transfer_function;
if (c.color_space == JXL_COLOR_SPACE_UNKNOWN ||
tf == JXL_TRANSFER_FUNCTION_UNKNOWN) {
@@ -910,7 +926,8 @@ static Status MaybeCreateProfileImpl(const JxlColorEncoding& c,
// tag count, deferred to later
WriteICCUint32(0, tagtable.size(), &tagtable);
- size_t tag_offset = 0, tag_size = 0;
+ size_t tag_offset = 0;
+ size_t tag_size = 0;
CreateICCMlucTag(ColorEncodingDescriptionImpl(c), &tags);
FinalizeICCTag(&tags, &tag_offset, &tag_size);
@@ -923,12 +940,12 @@ static Status MaybeCreateProfileImpl(const JxlColorEncoding& c,
// TODO(eustas): isn't it the other way round: gray image has d50 WhitePoint?
if (c.color_space == JXL_COLOR_SPACE_GRAY) {
- float wtpt[3];
+ Color wtpt;
JXL_RETURN_IF_ERROR(
CIEXYZFromWhiteCIExy(c.white_point_xy[0], c.white_point_xy[1], wtpt));
JXL_RETURN_IF_ERROR(CreateICCXYZTag(wtpt, &tags));
} else {
- float d50[3] = {0.964203, 1.0, 0.824905};
+ Color d50{0.964203, 1.0, 0.824905};
JXL_RETURN_IF_ERROR(CreateICCXYZTag(d50, &tags));
}
FinalizeICCTag(&tags, &tag_offset, &tag_size);
@@ -936,7 +953,7 @@ static Status MaybeCreateProfileImpl(const JxlColorEncoding& c,
if (c.color_space != JXL_COLOR_SPACE_GRAY) {
// Chromatic adaptation matrix
- float chad[9];
+ Matrix3x3 chad;
JXL_RETURN_IF_ERROR(
CreateICCChadMatrix(c.white_point_xy[0], c.white_point_xy[1], chad));
@@ -949,14 +966,14 @@ static Status MaybeCreateProfileImpl(const JxlColorEncoding& c,
MaybeCreateICCCICPTag(c, &tags, &tag_offset, &tag_size, &tagtable,
&offsets);
- float m[9];
+ Matrix3x3 m;
JXL_RETURN_IF_ERROR(CreateICCRGBMatrix(
c.primaries_red_xy[0], c.primaries_red_xy[1], c.primaries_green_xy[0],
c.primaries_green_xy[1], c.primaries_blue_xy[0], c.primaries_blue_xy[1],
c.white_point_xy[0], c.white_point_xy[1], m));
- float r[3] = {m[0], m[3], m[6]};
- float g[3] = {m[1], m[4], m[7]};
- float b[3] = {m[2], m[5], m[8]};
+ Color r{m[0][0], m[1][0], m[2][0]};
+ Color g{m[0][1], m[1][1], m[2][1]};
+ Color b{m[0][2], m[1][2], m[2][2]};
JXL_RETURN_IF_ERROR(CreateICCXYZTag(r, &tags));
FinalizeICCTag(&tags, &tag_offset, &tag_size);
@@ -1042,8 +1059,8 @@ static Status MaybeCreateProfileImpl(const JxlColorEncoding& c,
WriteICCUint32(header.size() + tagtable.size() + tags.size(), 0, &header);
*icc = header;
- Bytes(tagtable).AppendTo(icc);
- Bytes(tags).AppendTo(icc);
+ Bytes(tagtable).AppendTo(*icc);
+ Bytes(tags).AppendTo(*icc);
// The MD5 checksum must be computed on the profile with profile flags,
// rendering intent, and region of the checksum itself, set to 0.
diff --git a/third_party/jpeg-xl/lib/jxl/cms/opsin_params.h b/third_party/jpeg-xl/lib/jxl/cms/opsin_params.h
index 48e8e254f7..69dcd0b512 100644
--- a/third_party/jpeg-xl/lib/jxl/cms/opsin_params.h
+++ b/third_party/jpeg-xl/lib/jxl/cms/opsin_params.h
@@ -6,7 +6,7 @@
#ifndef LIB_JXL_CMS_OPSIN_PARAMS_H_
#define LIB_JXL_CMS_OPSIN_PARAMS_H_
-#include <array>
+#include "lib/jxl/base/matrix_ops.h"
// Constants that define the XYB color space.
@@ -35,21 +35,20 @@ constexpr float kOpsinAbsorbanceBias1 = kOpsinAbsorbanceBias0;
constexpr float kOpsinAbsorbanceBias2 = kOpsinAbsorbanceBias0;
// Opsin absorbance matrix is now frozen.
-constexpr std::array<float, 9> kOpsinAbsorbanceMatrix = {
- kM00, kM01, kM02, kM10, kM11, kM12, kM20, kM21, kM22,
-};
+constexpr Matrix3x3 kOpsinAbsorbanceMatrix{
+ {{kM00, kM01, kM02}, {kM10, kM11, kM12}, {kM20, kM21, kM22}}};
-constexpr std::array<float, 9> kDefaultInverseOpsinAbsorbanceMatrix = {
- 11.031566901960783f, -9.866943921568629f, -0.16462299647058826f,
- -3.254147380392157f, 4.418770392156863f, -0.16462299647058826f,
- -3.6588512862745097f, 2.7129230470588235f, 1.9459282392156863f};
+constexpr Matrix3x3 kDefaultInverseOpsinAbsorbanceMatrix{
+ {{11.031566901960783f, -9.866943921568629f, -0.16462299647058826f},
+ {-3.254147380392157f, 4.418770392156863f, -0.16462299647058826f},
+ {-3.6588512862745097f, 2.7129230470588235f, 1.9459282392156863f}}};
// Must be the inverse matrix of kOpsinAbsorbanceMatrix and match the spec.
-static inline const float* DefaultInverseOpsinAbsorbanceMatrix() {
- return kDefaultInverseOpsinAbsorbanceMatrix.data();
+static inline const Matrix3x3& DefaultInverseOpsinAbsorbanceMatrix() {
+ return kDefaultInverseOpsinAbsorbanceMatrix;
}
-constexpr std::array<float, 3> kOpsinAbsorbanceBias = {
+constexpr Vector3 kOpsinAbsorbanceBias = {
kOpsinAbsorbanceBias0,
kOpsinAbsorbanceBias1,
kOpsinAbsorbanceBias2,
@@ -63,14 +62,14 @@ constexpr float kScaledXYBOffset0 = 0.015386134f;
constexpr float kScaledXYBOffset1 = 0.0f;
constexpr float kScaledXYBOffset2 = 0.27770459f;
-constexpr std::array<float, 3> kScaledXYBOffset = {
- kScaledXYBOffset0, kScaledXYBOffset1, kScaledXYBOffset2};
+constexpr Vector3 kScaledXYBOffset = {kScaledXYBOffset0, kScaledXYBOffset1,
+ kScaledXYBOffset2};
constexpr float kScaledXYBScale0 = 22.995788804f;
constexpr float kScaledXYBScale1 = 1.183000077f;
constexpr float kScaledXYBScale2 = 1.502141333f;
-constexpr std::array<float, 3> kScaledXYBScale = {
+constexpr Vector3 kScaledXYBScale = {
kScaledXYBScale0,
kScaledXYBScale1,
kScaledXYBScale2,
diff --git a/third_party/jpeg-xl/lib/jxl/cms/tone_mapping-inl.h b/third_party/jpeg-xl/lib/jxl/cms/tone_mapping-inl.h
index 3d94ccea12..7d09beed32 100644
--- a/third_party/jpeg-xl/lib/jxl/cms/tone_mapping-inl.h
+++ b/third_party/jpeg-xl/lib/jxl/cms/tone_mapping-inl.h
@@ -100,14 +100,14 @@ class HlgOOTF : HlgOOTF_Base {
using HlgOOTF_Base::HlgOOTF_Base;
static HlgOOTF FromSceneLight(float display_luminance,
- const float primaries_luminances[3]) {
+ const Vector3& primaries_luminances) {
return HlgOOTF(/*gamma=*/1.2f *
std::pow(1.111f, std::log2(display_luminance / 1000.f)),
primaries_luminances);
}
static HlgOOTF ToSceneLight(float display_luminance,
- const float primaries_luminances[3]) {
+ const Vector3& primaries_luminances) {
return HlgOOTF(
/*gamma=*/(1 / 1.2f) *
std::pow(1.111f, -std::log2(display_luminance / 1000.f)),
@@ -132,7 +132,7 @@ class HlgOOTF : HlgOOTF_Base {
};
template <typename V>
-void GamutMap(V* red, V* green, V* blue, const float primaries_luminances[3],
+void GamutMap(V* red, V* green, V* blue, const Vector3& primaries_luminances,
float preserve_saturation = 0.1f) {
hwy::HWY_NAMESPACE::DFromV<V> df;
const V luminance =
diff --git a/third_party/jpeg-xl/lib/jxl/cms/tone_mapping.h b/third_party/jpeg-xl/lib/jxl/cms/tone_mapping.h
index a114109ea6..81f301a31d 100644
--- a/third_party/jpeg-xl/lib/jxl/cms/tone_mapping.h
+++ b/third_party/jpeg-xl/lib/jxl/cms/tone_mapping.h
@@ -12,6 +12,7 @@
#include "lib/jxl/base/common.h"
#include "lib/jxl/base/compiler_specific.h"
+#include "lib/jxl/base/matrix_ops.h"
#include "lib/jxl/cms/transfer_functions.h"
namespace jxl {
@@ -20,7 +21,7 @@ class Rec2408ToneMapperBase {
public:
explicit Rec2408ToneMapperBase(std::pair<float, float> source_range,
std::pair<float, float> target_range,
- const float primaries_luminances[3])
+ const Vector3& primaries_luminances)
: source_range_(source_range),
target_range_(target_range),
red_Y_(primaries_luminances[0]),
@@ -28,10 +29,10 @@ class Rec2408ToneMapperBase {
blue_Y_(primaries_luminances[2]) {}
// TODO(eustas): test me
- void ToneMap(float* red, float* green, float* blue) const {
+ void ToneMap(Color& rgb) const {
const float luminance =
source_range_.second *
- (red_Y_ * *red + green_Y_ * *green + blue_Y_ * *blue);
+ (red_Y_ * rgb[0] + green_Y_ * rgb[1] + blue_Y_ * rgb[2]);
const float normalized_pq =
std::min(1.f, (InvEOTF(luminance) - pq_mastering_min_) *
inv_pq_mastering_range_);
@@ -49,8 +50,8 @@ class Rec2408ToneMapperBase {
const float ratio = new_luminance / std::max(luminance, min_luminance);
const float cap = new_luminance * inv_target_peak_;
const float multiplier = ratio * normalizer_;
- for (float* const val : {red, green, blue}) {
- *val = use_cap ? cap : *val * multiplier;
+ for (size_t idx : {0, 1, 2}) {
+ rgb[idx] = use_cap ? cap : rgb[idx] * multiplier;
}
}
@@ -96,23 +97,24 @@ class Rec2408ToneMapperBase {
class HlgOOTF_Base {
public:
explicit HlgOOTF_Base(float source_luminance, float target_luminance,
- const float primaries_luminances[3])
+ const Vector3& primaries_luminances)
: HlgOOTF_Base(/*gamma=*/std::pow(1.111f, std::log2(target_luminance /
source_luminance)),
primaries_luminances) {}
// TODO(eustas): test me
- void Apply(float* red, float* green, float* blue) const {
+ void Apply(Color& rgb) const {
if (!apply_ootf_) return;
- const float luminance = red_Y_ * *red + green_Y_ * *green + blue_Y_ * *blue;
+ const float luminance =
+ red_Y_ * rgb[0] + green_Y_ * rgb[1] + blue_Y_ * rgb[2];
const float ratio = std::min<float>(powf(luminance, exponent_), 1e9);
- *red *= ratio;
- *green *= ratio;
- *blue *= ratio;
+ rgb[0] *= ratio;
+ rgb[1] *= ratio;
+ rgb[2] *= ratio;
}
protected:
- explicit HlgOOTF_Base(float gamma, const float luminances[3])
+ explicit HlgOOTF_Base(float gamma, const Vector3& luminances)
: exponent_(gamma - 1),
red_Y_(luminances[0]),
green_Y_(luminances[1]),
@@ -124,13 +126,12 @@ class HlgOOTF_Base {
const float blue_Y_;
};
-static JXL_MAYBE_UNUSED void GamutMapScalar(float* red, float* green,
- float* blue,
- const float primaries_luminances[3],
+static JXL_MAYBE_UNUSED void GamutMapScalar(Color& rgb,
+ const Vector3& primaries_luminances,
float preserve_saturation = 0.1f) {
- const float luminance = primaries_luminances[0] * *red +
- primaries_luminances[1] * *green +
- primaries_luminances[2] * *blue;
+ const float luminance = primaries_luminances[0] * rgb[0] +
+ primaries_luminances[1] * rgb[1] +
+ primaries_luminances[2] * rgb[2];
// Desaturate out-of-gamut pixels. This is done by mixing each pixel
// with just enough gray of the target luminance to make all
@@ -142,8 +143,8 @@ static JXL_MAYBE_UNUSED void GamutMapScalar(float* red, float* green,
// done by mixing in yet more gray. That will desaturate it further.
float gray_mix_saturation = 0.0f;
float gray_mix_luminance = 0.0f;
- for (const float* ch : {red, green, blue}) {
- const float& val = *ch;
+ for (size_t idx : {0, 1, 2}) {
+ const float& val = rgb[idx];
const float val_minus_gray = val - luminance;
const float inv_val_minus_gray =
1.0f / ((val_minus_gray == 0.0f) ? 1.0f : val_minus_gray);
@@ -162,15 +163,14 @@ static JXL_MAYBE_UNUSED void GamutMapScalar(float* red, float* green,
Clamp1((preserve_saturation * (gray_mix_saturation - gray_mix_luminance) +
gray_mix_luminance),
0.0f, 1.0f);
- for (float* const ch : {red, green, blue}) {
- float& val = *ch;
+ for (size_t idx : {0, 1, 2}) {
+ float& val = rgb[idx];
val = gray_mix * (luminance - val) + val;
}
- const float max_clr = std::max({1.0f, *red, *green, *blue});
+ const float max_clr = std::max({1.0f, rgb[0], rgb[1], rgb[2]});
const float normalizer = 1.0f / max_clr;
- for (float* const ch : {red, green, blue}) {
- float& val = *ch;
- val *= normalizer;
+ for (size_t idx : {0, 1, 2}) {
+ rgb[idx] *= normalizer;
}
}
diff --git a/third_party/jpeg-xl/lib/jxl/cms/tone_mapping_test.cc b/third_party/jpeg-xl/lib/jxl/cms/tone_mapping_test.cc
index dda2bbb0aa..76165d26e7 100644
--- a/third_party/jpeg-xl/lib/jxl/cms/tone_mapping_test.cc
+++ b/third_party/jpeg-xl/lib/jxl/cms/tone_mapping_test.cc
@@ -30,17 +30,17 @@ HWY_NOINLINE void TestRec2408ToneMap() {
for (size_t i = 0; i < kNumTrials; i++) {
float src = 11000.0 + rng.UniformF(-150.0f, 150.0f);
float tgt = 250 + rng.UniformF(-5.0f, 5.0f);
- float luminances[3] = {rng.UniformF(0.2f, 0.4f), rng.UniformF(0.2f, 0.4f),
- rng.UniformF(0.2f, 0.4f)};
- float rgb[3] = {rng.UniformF(0.0f, 1.0f), rng.UniformF(0.0f, 1.0f),
- rng.UniformF(0.0f, 1.0f)};
+ Vector3 luminances{rng.UniformF(0.2f, 0.4f), rng.UniformF(0.2f, 0.4f),
+ rng.UniformF(0.2f, 0.4f)};
+ Color rgb{rng.UniformF(0.0f, 1.0f), rng.UniformF(0.0f, 1.0f),
+ rng.UniformF(0.0f, 1.0f)};
Rec2408ToneMapper<decltype(d)> tone_mapper({0, src}, {0, tgt}, luminances);
auto r = Set(d, rgb[0]);
auto g = Set(d, rgb[1]);
auto b = Set(d, rgb[2]);
tone_mapper.ToneMap(&r, &g, &b);
Rec2408ToneMapperBase tone_mapper_base({0, src}, {0, tgt}, luminances);
- tone_mapper_base.ToneMap(&rgb[0], &rgb[1], &rgb[2]);
+ tone_mapper_base.ToneMap(rgb);
const float actual_r = GetLane(r);
const float expected_r = rgb[0];
const float abs_err_r = std::abs(expected_r - actual_r);
@@ -66,17 +66,17 @@ HWY_NOINLINE void TestHlgOotfApply() {
for (size_t i = 0; i < kNumTrials; i++) {
float src = 300.0 + rng.UniformF(-50.0f, 50.0f);
float tgt = 80 + rng.UniformF(-5.0f, 5.0f);
- float luminances[3] = {rng.UniformF(0.2f, 0.4f), rng.UniformF(0.2f, 0.4f),
- rng.UniformF(0.2f, 0.4f)};
- float rgb[3] = {rng.UniformF(0.0f, 1.0f), rng.UniformF(0.0f, 1.0f),
- rng.UniformF(0.0f, 1.0f)};
+ Vector3 luminances{rng.UniformF(0.2f, 0.4f), rng.UniformF(0.2f, 0.4f),
+ rng.UniformF(0.2f, 0.4f)};
+ Color rgb{rng.UniformF(0.0f, 1.0f), rng.UniformF(0.0f, 1.0f),
+ rng.UniformF(0.0f, 1.0f)};
HlgOOTF ootf(src, tgt, luminances);
auto r = Set(d, rgb[0]);
auto g = Set(d, rgb[1]);
auto b = Set(d, rgb[2]);
ootf.Apply(&r, &g, &b);
HlgOOTF_Base ootf_base(src, tgt, luminances);
- ootf_base.Apply(&rgb[0], &rgb[1], &rgb[2]);
+ ootf_base.Apply(rgb);
const float actual_r = GetLane(r);
const float expected_r = rgb[0];
const float abs_err_r = std::abs(expected_r - actual_r);
@@ -101,15 +101,15 @@ HWY_NOINLINE void TestGamutMap() {
HWY_FULL(float) d;
for (size_t i = 0; i < kNumTrials; i++) {
float preserve_saturation = rng.UniformF(0.2f, 0.4f);
- float luminances[3] = {rng.UniformF(0.2f, 0.4f), rng.UniformF(0.2f, 0.4f),
- rng.UniformF(0.2f, 0.4f)};
- float rgb[3] = {rng.UniformF(0.0f, 1.0f), rng.UniformF(0.0f, 1.0f),
- rng.UniformF(0.0f, 1.0f)};
+ Vector3 luminances{rng.UniformF(0.2f, 0.4f), rng.UniformF(0.2f, 0.4f),
+ rng.UniformF(0.2f, 0.4f)};
+ Color rgb{rng.UniformF(0.0f, 1.0f), rng.UniformF(0.0f, 1.0f),
+ rng.UniformF(0.0f, 1.0f)};
auto r = Set(d, rgb[0]);
auto g = Set(d, rgb[1]);
auto b = Set(d, rgb[2]);
GamutMap(&r, &g, &b, luminances, preserve_saturation);
- GamutMapScalar(&rgb[0], &rgb[1], &rgb[2], luminances, preserve_saturation);
+ GamutMapScalar(rgb, luminances, preserve_saturation);
const float actual_r = GetLane(r);
const float expected_r = rgb[0];
const float abs_err_r = std::abs(expected_r - actual_r);