Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
ICCTest.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
13#include "modules/skcms/skcms.h"
14#include "tests/Test.h"
15#include "tools/Resources.h"
16
17#include <cmath>
18#include <cstdint>
19#include <cstdlib>
20
21DEF_TEST(AdobeRGB, r) {
22 if (sk_sp<SkData> profile = GetResourceAsData("icc_profiles/AdobeRGB1998.icc")) {
23 skcms_ICCProfile parsed;
24 REPORTER_ASSERT(r, skcms_Parse(profile->data(), profile->size(), &parsed));
25 REPORTER_ASSERT(r, !parsed.has_CICP);
26
27 auto got = SkColorSpace::Make(parsed);
29 REPORTER_ASSERT(r, SkColorSpace::Equals(got.get(), want.get()));
30 }
31}
32
33DEF_TEST(HDR_ICC, r) {
34 constexpr size_t kTestCount = 3;
35 sk_sp<SkData> profile[kTestCount] = {
39 };
40
41 sk_sp<SkData> dst_profile[kTestCount] = {
45 };
46
47 constexpr size_t kPixelCount = 7;
48
49 // clang-format off
50 float pixels[kPixelCount][3] = {
51 { 0.00f, 0.00f, 0.00f, },
52 { 0.50f, 0.50f, 0.50f, },
53 { 0.50f, 0.00f, 0.00f, },
54 { 0.00f, 0.50f, 0.00f, },
55 { 0.00f, 0.00f, 0.50f, },
56 { 0.25f, 0.50f, 0.00f, },
57 { 0.75f, 0.75f, 0.75f, },
58 };
59
60 // The tone mapped value of PQ 0.5 and 0.75.
61 constexpr float kPQ_05 = 0.3182877451f;
62 constexpr float kPQ_075 = 0.9943588777f;
63
64 // The tone mapped value of PQ 0.25, when maxRGB is 0.5.
65 constexpr float kPQ_025 = 0.020679904f;
66
67 // The tone mapped value of HLG 0.5 and 0.75 (when all channels are equal).
68 constexpr float kHLG_05 = 0.20188954163f;
69 constexpr float kHLG_075 = 0.5208149688f;
70
71 // The linearized values of sRGB 0.25, 0.5, and 0.75.
72 constexpr float kSRGB_025 = 0.05087607f;
73 constexpr float kSRGB_05 = 0.21404112f;
74 constexpr float kSRGB_075 = 0.52252153f;
75
76 float dst_pixels_expected[kTestCount][kPixelCount][3] = {
77 {
78 { 0.f, 0.f, 0.f, },
79 { kPQ_05, kPQ_05, kPQ_05, },
80 { kPQ_05, 0.f, 0.f, },
81 { 0.f, kPQ_05, 0.f, },
82 { 0.f, 0.f, kPQ_05, },
83 { kPQ_025, kPQ_05, 0.f, },
84 { kPQ_075, kPQ_075, kPQ_075, }, // PQ maps 0.75 ~ 1000 nits to 1.0
85 },
86 {
87 { 0.f, 0.f, 0.f, },
88 { kHLG_05, kHLG_05, kHLG_05, },
89 { 0.1618f, 0.f, 0.f, }, // HLG will map 0.5 to different values
90 { 0.f, 0.1895f, 0.f, }, // if it is the R, G, or B channel, because
91 { 0.f, 0.f, 0.1251f, }, // of the OOTF.
92 { 0.0513f, 0.1924f, 0.f, },
93 { kHLG_075, kHLG_075, kHLG_075, },
94 },
95 {
96 { 0.f, 0.f, 0.f, },
97 { kSRGB_05, kSRGB_05, kSRGB_05, }, // This is just the sRGB transfer function
98 { kSRGB_05, 0.f, 0.f, },
99 { 0.f, kSRGB_05, 0.f, },
100 { 0.f, 0.f, kSRGB_05, },
101 { kSRGB_025, kSRGB_05, 0.f, },
102 { kSRGB_075, kSRGB_075, kSRGB_075, },
103 },
104 };
105 // clang-format on
106 bool cicp_expected[kTestCount] = {true, true, false};
107 bool a2b_expected[kTestCount] = {true, true, false};
108 uint32_t cicp_primaries_expected[kTestCount] = {9, 12, 0};
109 uint32_t cicp_trfn_expected[kTestCount] = {16, 18, 0};
110
111 for (size_t test = 0; test < kTestCount; ++test) {
112 skcms_ICCProfile parsed;
113 REPORTER_ASSERT(r, skcms_Parse(profile[test]->data(), profile[test]->size(), &parsed));
114
115 REPORTER_ASSERT(r, parsed.has_A2B == a2b_expected[test]);
116 REPORTER_ASSERT(r, parsed.has_CICP == cicp_expected[test]);
117 if (cicp_expected[test]) {
118 REPORTER_ASSERT(r, parsed.CICP.color_primaries == cicp_primaries_expected[test]);
119 REPORTER_ASSERT(r, parsed.CICP.transfer_characteristics == cicp_trfn_expected[test]);
122 }
123
124 skcms_ICCProfile dst_parsed;
126 r, skcms_Parse(dst_profile[test]->data(), dst_profile[test]->size(), &dst_parsed));
127
128 for (size_t pixel = 0; pixel < kPixelCount; ++pixel) {
129 float dst_pixel_actual[3]{0.f, 0.f, 0.f};
130 bool xform_result = skcms_Transform(pixels[pixel],
133 &parsed,
134 dst_pixel_actual,
137 &dst_parsed,
138 1);
139 REPORTER_ASSERT(r, xform_result);
140
141 auto approx_equal = [=](float x, float y) { return std::abs(x - y) < 1.f / 64.f; };
142 for (size_t i = 0; i < 3; ++i) {
144 r, approx_equal(dst_pixel_actual[i], dst_pixels_expected[test][pixel][i]));
145 }
146 }
147 }
148}
#define test(name)
static bool approx_equal(const SkColor4f &a, const SkColor4f &b)
sk_sp< SkData > GetResourceAsData(const char *resource)
Definition Resources.cpp:42
SK_API sk_sp< SkData > SkWriteICCProfile(const skcms_TransferFunction &, const skcms_Matrix3x3 &toXYZD50)
Definition SkICC.cpp:679
#define DEF_TEST(name, reporter)
Definition Test.h:312
#define REPORTER_ASSERT(r, cond,...)
Definition Test.h:286
static bool Equals(const SkColorSpace *, const SkColorSpace *)
static sk_sp< SkColorSpace > MakeRGB(const skcms_TransferFunction &transferFn, const skcms_Matrix3x3 &toXYZ)
static sk_sp< SkColorSpace > Make(const skcms_ICCProfile &)
double y
double x
static constexpr skcms_Matrix3x3 kSRGB
static constexpr skcms_Matrix3x3 kAdobeRGB
static constexpr skcms_Matrix3x3 kRec2020
static constexpr skcms_Matrix3x3 kDisplayP3
static constexpr skcms_TransferFunction k2Dot2
static constexpr skcms_TransferFunction kSRGB
static constexpr skcms_TransferFunction kHLG
static constexpr skcms_TransferFunction kPQ
static constexpr skcms_TransferFunction kLinear
bool skcms_Transform(const void *src, skcms_PixelFormat srcFmt, skcms_AlphaFormat srcAlpha, const skcms_ICCProfile *srcProfile, void *dst, skcms_PixelFormat dstFmt, skcms_AlphaFormat dstAlpha, const skcms_ICCProfile *dstProfile, size_t nz)
Definition skcms.cc:2494
@ skcms_PixelFormat_RGB_fff
static bool skcms_Parse(const void *buf, size_t len, skcms_ICCProfile *profile)
@ skcms_AlphaFormat_Opaque
uint8_t color_primaries
uint8_t matrix_coefficients
uint8_t video_full_range_flag
uint8_t transfer_characteristics