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