1caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy/*
2caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy * Copyright 2013 The Android Open Source Project
3caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy *
4caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy * Licensed under the Apache License, Version 2.0 (the "License");
5caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy * you may not use this file except in compliance with the License.
6caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy * You may obtain a copy of the License at
7caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy *
8caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy *      http://www.apache.org/licenses/LICENSE-2.0
9caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy *
10caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy * Unless required by applicable law or agreed to in writing, software
11caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy * distributed under the License is distributed on an "AS IS" BASIS,
12caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy * See the License for the specific language governing permissions and
14caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy * limitations under the License.
15caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy */
16caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
17caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy#define LOG_TAG "ColorSpaceTest"
18caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
19caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy#include <math.h>
20caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy#include <stdlib.h>
21caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
22caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy#include <ui/ColorSpace.h>
23caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
24caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy#include <gtest/gtest.h>
25caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
26caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guynamespace android {
27caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
28caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guyclass ColorSpaceTest : public testing::Test {
29caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guyprotected:
30caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy};
31caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
32caf2ca414f69d460c516e2370cf42bcf49178d95Romain GuyTEST_F(ColorSpaceTest, XYZ) {
33caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    mat3 sRGBToXYZ(transpose(mat3{
34caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        0.412391f, 0.357584f, 0.180481f,
35caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        0.212639f, 0.715169f, 0.072192f,
36caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        0.019331f, 0.119195f, 0.950532f
37caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    }));
38caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
39caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    mat3 XYZtoSRGB(inverse(sRGBToXYZ));
40caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
41caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    ColorSpace sRGB("sRGB", sRGBToXYZ);
42caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
43caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    EXPECT_EQ(sRGBToXYZ, sRGB.getRGBtoXYZ());
44caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    EXPECT_EQ(XYZtoSRGB, sRGB.getXYZtoRGB());
45caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy}
46caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
47caf2ca414f69d460c516e2370cf42bcf49178d95Romain GuyTEST_F(ColorSpaceTest, XYZPrimaries) {
48caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    mat3 sRGBToXYZ(transpose(mat3{
49caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        0.412391f, 0.357584f, 0.180481f,
50caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        0.212639f, 0.715169f, 0.072192f,
51caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        0.019331f, 0.119195f, 0.950532f
52caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    }));
53caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
54caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    ColorSpace sRGB("sRGB", sRGBToXYZ);
55caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
56caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    EXPECT_NEAR(0.640f, sRGB.getPrimaries()[0].x, 1e-5f);
57caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    EXPECT_NEAR(0.330f, sRGB.getPrimaries()[0].y, 1e-5f);
58caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
59caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    EXPECT_NEAR(0.300f, sRGB.getPrimaries()[1].x, 1e-5f);
60caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    EXPECT_NEAR(0.600f, sRGB.getPrimaries()[1].y, 1e-5f);
61caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
62caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    EXPECT_NEAR(0.150f, sRGB.getPrimaries()[2].x, 1e-5f);
63caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    EXPECT_NEAR(0.060f, sRGB.getPrimaries()[2].y, 1e-5f);
64caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy}
65caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
66caf2ca414f69d460c516e2370cf42bcf49178d95Romain GuyTEST_F(ColorSpaceTest, XYZWhitePoint) {
67caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    mat3 sRGBToXYZ(transpose(mat3{
68caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        0.412391f, 0.357584f, 0.180481f,
69caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        0.212639f, 0.715169f, 0.072192f,
70caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        0.019331f, 0.119195f, 0.950532f
71caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    }));
72caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
73caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    ColorSpace sRGB("sRGB", sRGBToXYZ);
74caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
75caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    EXPECT_NEAR(0.3127f, sRGB.getWhitePoint().x, 1e-5f);
76caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    EXPECT_NEAR(0.3290f, sRGB.getWhitePoint().y, 1e-5f);
77caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy}
78caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
79caf2ca414f69d460c516e2370cf42bcf49178d95Romain GuyTEST_F(ColorSpaceTest, XYZFromPrimaries) {
80caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    mat3 sRGBToXYZ(transpose(mat3{
81caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        0.412391f, 0.357584f, 0.180481f,
82caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        0.212639f, 0.715169f, 0.072192f,
83caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        0.019331f, 0.119195f, 0.950532f
84caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    }));
85caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
86caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    ColorSpace sRGB1("sRGB", sRGBToXYZ);
87caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    ColorSpace sRGB2(
88caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy          "sRGB",
89caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy          {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
90caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy          {0.3127f, 0.3290f}
91caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    );
92caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
93caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    for (size_t i = 0; i < 3; i++) {
94caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        for (size_t j= 0; j < 3; j++) {
95caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy            ASSERT_NEAR(sRGB1.getRGBtoXYZ()[i][j], sRGB2.getRGBtoXYZ()[i][j], 1e-5f);
96caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        }
97caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    }
98caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
99caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    for (size_t i = 0; i < 3; i++) {
100caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        for (size_t j= 0; j < 3; j++) {
101caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy            ASSERT_NEAR(sRGB2.getXYZtoRGB()[i][j], sRGB2.getXYZtoRGB()[i][j], 1e-5f);
102caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        }
103caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    }
104caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy}
105caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
106caf2ca414f69d460c516e2370cf42bcf49178d95Romain GuyTEST_F(ColorSpaceTest, TransferFunctions) {
107caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    ColorSpace sRGB = ColorSpace::sRGB();
108caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
1093944d06ee0b2762475538690a35dfd66d363a567Romain Guy    EXPECT_NEAR(0.0f, sRGB.getEOTF()(0.0f), 1e-6f);
1103944d06ee0b2762475538690a35dfd66d363a567Romain Guy    EXPECT_NEAR(0.0f, sRGB.getOETF()(0.0f), 1e-6f);
1113944d06ee0b2762475538690a35dfd66d363a567Romain Guy    EXPECT_NEAR(1.0f, sRGB.getEOTF()(1.0f), 1e-6f);
1123944d06ee0b2762475538690a35dfd66d363a567Romain Guy    EXPECT_NEAR(1.0f, sRGB.getOETF()(1.0f), 1e-6f);
1133944d06ee0b2762475538690a35dfd66d363a567Romain Guy
114caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    for (float v = 0.0f; v <= 0.5f; v += 1e-3f) {
115caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        ASSERT_TRUE(v >= sRGB.getEOTF()(v));
116caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        ASSERT_TRUE(v <= sRGB.getOETF()(v));
117caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    }
118caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
119caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    float previousEOTF = std::numeric_limits<float>::lowest();
120caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    float previousOETF = std::numeric_limits<float>::lowest();
121caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    for (float v = 0.0f; v <= 1.0f; v += 1e-3f) {
122caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        ASSERT_TRUE(previousEOTF < sRGB.getEOTF()(v));
123caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        previousEOTF = sRGB.getEOTF()(v);
124caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        ASSERT_TRUE(previousOETF < sRGB.getOETF()(v));
125caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        previousOETF = sRGB.getOETF()(v);
126caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    }
127caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
128caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    ColorSpace sRGB2(
129caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy          "sRGB",
130caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy          {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
131caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy          {0.3127f, 0.3290f}
132caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy          // linear transfer functions
133caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    );
134caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    for (float v = 0.0f; v <= 1.0f; v += 1e-3f) {
135caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        ASSERT_EQ(v, sRGB2.getEOTF()(v));
136caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy        ASSERT_EQ(v, sRGB2.getOETF()(v));
137caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    }
138caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy}
139caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
140caf2ca414f69d460c516e2370cf42bcf49178d95Romain GuyTEST_F(ColorSpaceTest, Clamping) {
141caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    // Pick a color outside of sRGB
142597cd600ab062758857772f266fd82cae89cc75dRomain Guy    float3 c(ColorSpace::BT2020().rgbToXYZ(float3{0, 1, 0}));
143caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
144caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    // The color will be clamped
145caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    float3 sRGB(ColorSpace::sRGB().xyzToRGB(c));
146caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    EXPECT_TRUE(sRGB > float3{0.0} && sRGB < float3{1.0});
147caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
148caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    // The color will not be clamped
149caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    float3 extendedSRGB(ColorSpace::linearExtendedSRGB().xyzToRGB(c));
150caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    EXPECT_TRUE(extendedSRGB.g > 1.0f);
151caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy}
152caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
153545347429606f5ef7facbb1639b42e5c9b44b6ecRomain GuyTEST_F(ColorSpaceTest, Connect) {
154545347429606f5ef7facbb1639b42e5c9b44b6ecRomain Guy    // No chromatic adaptation
155982cf471dcdcda1f29ad0928864d18f8e5243446Romain Guy    auto r = ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::AdobeRGB())
156545347429606f5ef7facbb1639b42e5c9b44b6ecRomain Guy            .transform({1.0f, 0.5f, 0.0f});
157545347429606f5ef7facbb1639b42e5c9b44b6ecRomain Guy    EXPECT_TRUE(all(lessThan(abs(r - float3{0.8912f, 0.4962f, 0.1164f}), float3{1e-4f})));
158545347429606f5ef7facbb1639b42e5c9b44b6ecRomain Guy
159545347429606f5ef7facbb1639b42e5c9b44b6ecRomain Guy    // Test with chromatic adaptation
160982cf471dcdcda1f29ad0928864d18f8e5243446Romain Guy    r = ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::ProPhotoRGB())
161545347429606f5ef7facbb1639b42e5c9b44b6ecRomain Guy            .transform({1.0f, 0.0f, 0.0f});
162545347429606f5ef7facbb1639b42e5c9b44b6ecRomain Guy    EXPECT_TRUE(all(lessThan(abs(r - float3{0.70226f, 0.2757f, 0.1036f}), float3{1e-4f})));
163545347429606f5ef7facbb1639b42e5c9b44b6ecRomain Guy}
164545347429606f5ef7facbb1639b42e5c9b44b6ecRomain Guy
165eedb69abbde29ad3dd624f1f9dfc72e4f35d5234Romain GuyTEST_F(ColorSpaceTest, LUT) {
166eedb69abbde29ad3dd624f1f9dfc72e4f35d5234Romain Guy    auto lut = ColorSpace::createLUT(17, ColorSpace::sRGB(), ColorSpace::AdobeRGB());
167eedb69abbde29ad3dd624f1f9dfc72e4f35d5234Romain Guy    EXPECT_TRUE(lut != nullptr);
168eedb69abbde29ad3dd624f1f9dfc72e4f35d5234Romain Guy
169eedb69abbde29ad3dd624f1f9dfc72e4f35d5234Romain Guy    // {1.0f, 0.5f, 0.0f}
170eedb69abbde29ad3dd624f1f9dfc72e4f35d5234Romain Guy    auto r = lut.get()[0 * 17 * 17 + 8 * 17 + 16];
171eedb69abbde29ad3dd624f1f9dfc72e4f35d5234Romain Guy    EXPECT_TRUE(all(lessThan(abs(r - float3{0.8912f, 0.4962f, 0.1164f}), float3{1e-4f})));
172eedb69abbde29ad3dd624f1f9dfc72e4f35d5234Romain Guy
173eedb69abbde29ad3dd624f1f9dfc72e4f35d5234Romain Guy    // {1.0f, 1.0f, 0.5f}
174eedb69abbde29ad3dd624f1f9dfc72e4f35d5234Romain Guy    r = lut.get()[8 * 17 * 17 + 0 * 17 + 16]; // y (G) is flipped
175eedb69abbde29ad3dd624f1f9dfc72e4f35d5234Romain Guy    EXPECT_TRUE(all(lessThan(abs(r - float3{1.0f, 1.0f, 0.5290f}), float3{1e-4f})));
176eedb69abbde29ad3dd624f1f9dfc72e4f35d5234Romain Guy
177eedb69abbde29ad3dd624f1f9dfc72e4f35d5234Romain Guy    // {1.0f, 1.0f, 1.0f}
178eedb69abbde29ad3dd624f1f9dfc72e4f35d5234Romain Guy    r = lut.get()[16 * 17 * 17 + 0 * 17 + 16]; // y (G) is flipped
179eedb69abbde29ad3dd624f1f9dfc72e4f35d5234Romain Guy    EXPECT_TRUE(all(lessThan(abs(r - float3{1.0f, 1.0f, 1.0f}), float3{1e-4f})));
180eedb69abbde29ad3dd624f1f9dfc72e4f35d5234Romain Guy
181eedb69abbde29ad3dd624f1f9dfc72e4f35d5234Romain Guy}
182eedb69abbde29ad3dd624f1f9dfc72e4f35d5234Romain Guy
183caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy}; // namespace android
184