blob: 4a644603707c7e16c30eac49d59ffee50820b788 [file] [log] [blame]
msarett6a738212016-03-04 13:27:35 -08001/*
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
8#include "Resources.h"
9#include "SkCodec.h"
10#include "SkColorSpace.h"
msarett8cc20912016-05-23 09:29:29 -070011#include "SkColorSpace_Base.h"
msarett6a738212016-03-04 13:27:35 -080012#include "Test.h"
13
msarett53add952016-03-07 17:25:12 -080014#include "png.h"
15
reed50d3b572016-05-03 12:13:21 -070016static bool almost_equal(float a, float b) {
17 return SkTAbs(a - b) < 0.001f;
18}
19
20static void test_space(skiatest::Reporter* r, SkColorSpace* space,
21 const float red[], const float green[], const float blue[],
msarett600c7372016-09-07 12:03:53 -070022 const SkGammaNamed expectedGamma) {
msarettbb9f7742016-05-17 09:31:20 -070023
msarett9d15dab2016-08-24 07:36:06 -070024 REPORTER_ASSERT(r, nullptr != space);
msarett600c7372016-09-07 12:03:53 -070025 REPORTER_ASSERT(r, expectedGamma == as_CSB(space)->gammaNamed());
msarettbb9f7742016-05-17 09:31:20 -070026
brianosman971cd492016-09-08 10:10:11 -070027 const SkMatrix44& mat = space->toXYZD50();
reed50d3b572016-05-03 12:13:21 -070028 const float src[] = {
29 1, 0, 0, 1,
30 0, 1, 0, 1,
31 0, 0, 1, 1,
32 };
brianosmande68d6c2016-09-09 10:36:17 -070033 const float* ref[3] = { red, green, blue };
reed50d3b572016-05-03 12:13:21 -070034 float dst[4];
35 for (int i = 0; i < 3; ++i) {
36 mat.mapScalars(&src[i*4], dst);
brianosmande68d6c2016-09-09 10:36:17 -070037 REPORTER_ASSERT(r, almost_equal(ref[i][0], dst[0]));
38 REPORTER_ASSERT(r, almost_equal(ref[i][1], dst[1]));
39 REPORTER_ASSERT(r, almost_equal(ref[i][2], dst[2]));
reed50d3b572016-05-03 12:13:21 -070040 }
41}
42
msarett6a738212016-03-04 13:27:35 -080043static SkStreamAsset* resource(const char path[]) {
44 SkString fullPath = GetResourcePath(path);
45 return SkStream::NewFromFile(fullPath.c_str());
46}
47
msarett9d15dab2016-08-24 07:36:06 -070048static void test_path(skiatest::Reporter* r, const char* path,
49 const float red[], const float green[], const float blue[],
msarett600c7372016-09-07 12:03:53 -070050 const SkGammaNamed expectedGamma) {
msarett9d15dab2016-08-24 07:36:06 -070051 SkAutoTDelete<SkStream> stream(resource(path));
msarett0e6274f2016-03-21 08:04:40 -070052 REPORTER_ASSERT(r, nullptr != stream);
Brian Salomond2100f22016-03-25 17:02:20 -040053 if (!stream) {
54 return;
55 }
msarett0e6274f2016-03-21 08:04:40 -070056
57 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release()));
58 REPORTER_ASSERT(r, nullptr != codec);
Brian Salomond2100f22016-03-25 17:02:20 -040059 if (!codec) {
60 return;
61 }
msarett0e6274f2016-03-21 08:04:40 -070062
msarett530c8442016-07-21 11:57:49 -070063 SkColorSpace* colorSpace = codec->getInfo().colorSpace();
msarett9d15dab2016-08-24 07:36:06 -070064 test_space(r, colorSpace, red, green, blue, expectedGamma);
65}
66
brianosmande68d6c2016-09-09 10:36:17 -070067static constexpr float g_sRGB_XYZ[]{
68 0.4358f, 0.3853f, 0.1430f, // Rx, Gx, Bx
69 0.2224f, 0.7170f, 0.0606f, // Ry, Gy, Gz
70 0.0139f, 0.0971f, 0.7139f, // Rz, Gz, Bz
71};
72
73static constexpr float g_sRGB_R[]{ 0.4358f, 0.2224f, 0.0139f };
74static constexpr float g_sRGB_G[]{ 0.3853f, 0.7170f, 0.0971f };
75static constexpr float g_sRGB_B[]{ 0.1430f, 0.0606f, 0.7139f };
msarett9d15dab2016-08-24 07:36:06 -070076
77DEF_TEST(ColorSpace_sRGB, r) {
78 test_space(r, SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named).get(),
brianosmande68d6c2016-09-09 10:36:17 -070079 g_sRGB_R, g_sRGB_G, g_sRGB_B, kSRGB_SkGammaNamed);
msarett9d15dab2016-08-24 07:36:06 -070080
81}
82
83DEF_TEST(ColorSpaceParseICCProfiles, r) {
84
85#if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6)
brianosmande68d6c2016-09-09 10:36:17 -070086 test_path(r, "color_wheel_with_profile.png", g_sRGB_R, g_sRGB_G, g_sRGB_B,
msarett600c7372016-09-07 12:03:53 -070087 kSRGB_SkGammaNamed);
msarett9d15dab2016-08-24 07:36:06 -070088#endif
msarett0e6274f2016-03-21 08:04:40 -070089
reed50d3b572016-05-03 12:13:21 -070090 const float red[] = { 0.385117f, 0.716904f, 0.0970612f };
91 const float green[] = { 0.143051f, 0.0606079f, 0.713913f };
92 const float blue[] = { 0.436035f, 0.222488f, 0.013916f };
msarett600c7372016-09-07 12:03:53 -070093 test_path(r, "icc-v2-gbr.jpg", red, green, blue, k2Dot2Curve_SkGammaNamed);
msarett9d15dab2016-08-24 07:36:06 -070094
95 test_path(r, "webp-color-profile-crash.webp",
msarett600c7372016-09-07 12:03:53 -070096 red, green, blue, kNonStandard_SkGammaNamed);
msarett9d15dab2016-08-24 07:36:06 -070097 test_path(r, "webp-color-profile-lossless.webp",
msarett600c7372016-09-07 12:03:53 -070098 red, green, blue, kNonStandard_SkGammaNamed);
msarett9d15dab2016-08-24 07:36:06 -070099 test_path(r, "webp-color-profile-lossy.webp",
msarett600c7372016-09-07 12:03:53 -0700100 red, green, blue, kNonStandard_SkGammaNamed);
msarett9d15dab2016-08-24 07:36:06 -0700101 test_path(r, "webp-color-profile-lossy-alpha.webp",
msarett600c7372016-09-07 12:03:53 -0700102 red, green, blue, kNonStandard_SkGammaNamed);
msarett0e6274f2016-03-21 08:04:40 -0700103}
msarett02125d12016-05-03 14:24:47 -0700104
105DEF_TEST(ColorSpaceSRGBCompare, r) {
106 // Create an sRGB color space by name
107 sk_sp<SkColorSpace> namedColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
108
109 // Create an sRGB color space by value
110 SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor);
msarettc1a3e242016-06-23 12:42:29 -0700111 srgbToxyzD50.set3x3RowMajorf(g_sRGB_XYZ);
msarett48ba2b82016-09-07 18:55:49 -0700112 sk_sp<SkColorSpace> rgbColorSpace =
113 SkColorSpace::NewRGB(SkColorSpace::kSRGB_RenderTargetGamma, srgbToxyzD50);
msarettab926f02016-05-25 08:53:40 -0700114 REPORTER_ASSERT(r, rgbColorSpace == namedColorSpace);
msarett02125d12016-05-03 14:24:47 -0700115
116 // Change a single value from the sRGB matrix
117 srgbToxyzD50.set(2, 2, 0.5f);
msarett48ba2b82016-09-07 18:55:49 -0700118 sk_sp<SkColorSpace> strangeColorSpace =
119 SkColorSpace::NewRGB(SkColorSpace::kSRGB_RenderTargetGamma, srgbToxyzD50);
msarett02125d12016-05-03 14:24:47 -0700120 REPORTER_ASSERT(r, strangeColorSpace != namedColorSpace);
121}
msarettab926f02016-05-25 08:53:40 -0700122
msarettc213f0d2016-08-01 14:23:32 -0700123class ColorSpaceTest {
124public:
125 static sk_sp<SkData> WriteToICC(SkColorSpace* space) {
126 return as_CSB(space)->writeToICC();
127 }
128};
129
msarettab926f02016-05-25 08:53:40 -0700130DEF_TEST(ColorSpaceWriteICC, r) {
131 // Test writing a new ICC profile
132 sk_sp<SkColorSpace> namedColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
msarettc213f0d2016-08-01 14:23:32 -0700133 sk_sp<SkData> namedData = ColorSpaceTest::WriteToICC(namedColorSpace.get());
msarettab926f02016-05-25 08:53:40 -0700134 sk_sp<SkColorSpace> iccColorSpace = SkColorSpace::NewICC(namedData->data(), namedData->size());
brianosmande68d6c2016-09-09 10:36:17 -0700135 test_space(r, iccColorSpace.get(), g_sRGB_R, g_sRGB_G, g_sRGB_B, k2Dot2Curve_SkGammaNamed);
msarettc4ce6b52016-06-16 07:37:41 -0700136 // FIXME (msarett): Test disabled. sRGB profiles are written approximately as 2.2f curves.
137 // REPORTER_ASSERT(r, iccColorSpace == namedColorSpace);
msarettab926f02016-05-25 08:53:40 -0700138
139 // Test saving the original ICC data
140 sk_sp<SkData> monitorData = SkData::MakeFromFileName(
msaretta714bc32016-07-29 08:58:33 -0700141 GetResourcePath("icc_profiles/HP_ZR30w.icc").c_str());
msarettab926f02016-05-25 08:53:40 -0700142 REPORTER_ASSERT(r, monitorData);
143 if (!monitorData) {
144 return;
145 }
146 sk_sp<SkColorSpace> monitorSpace = SkColorSpace::NewICC(monitorData->data(),
147 monitorData->size());
msarettc213f0d2016-08-01 14:23:32 -0700148 sk_sp<SkData> newMonitorData = ColorSpaceTest::WriteToICC(monitorSpace.get());
msarettab926f02016-05-25 08:53:40 -0700149 sk_sp<SkColorSpace> newMonitorSpace = SkColorSpace::NewICC(newMonitorData->data(),
150 newMonitorData->size());
brianosman971cd492016-09-08 10:10:11 -0700151 REPORTER_ASSERT(r, monitorSpace->toXYZD50() == newMonitorSpace->toXYZD50());
msarett600c7372016-09-07 12:03:53 -0700152 REPORTER_ASSERT(r, as_CSB(monitorSpace)->gammaNamed() == as_CSB(newMonitorSpace)->gammaNamed());
msarettab926f02016-05-25 08:53:40 -0700153}
reedfbce71f2016-06-02 12:40:22 -0700154
155DEF_TEST(ColorSpace_Named, r) {
156 const struct {
157 SkColorSpace::Named fNamed;
msarettc4ce6b52016-06-16 07:37:41 -0700158 bool fIsSRGB;
reedfbce71f2016-06-02 12:40:22 -0700159 } recs[] {
msarett47ae5c52016-09-06 10:01:48 -0700160 { SkColorSpace::kSRGB_Named, true },
161 { SkColorSpace::kAdobeRGB_Named, false },
reedfbce71f2016-06-02 12:40:22 -0700162 };
163
164 for (auto rec : recs) {
165 auto cs = SkColorSpace::NewNamed(rec.fNamed);
msarett47ae5c52016-09-06 10:01:48 -0700166 REPORTER_ASSERT(r, cs);
reedfbce71f2016-06-02 12:40:22 -0700167 if (cs) {
msarettc4ce6b52016-06-16 07:37:41 -0700168 if (rec.fIsSRGB) {
msarett600c7372016-09-07 12:03:53 -0700169 REPORTER_ASSERT(r, kSRGB_SkGammaNamed == as_CSB(cs)->gammaNamed());
msarettc4ce6b52016-06-16 07:37:41 -0700170 } else {
msarett600c7372016-09-07 12:03:53 -0700171 REPORTER_ASSERT(r, k2Dot2Curve_SkGammaNamed == as_CSB(cs)->gammaNamed());
msarettc4ce6b52016-06-16 07:37:41 -0700172 }
reedfbce71f2016-06-02 12:40:22 -0700173 }
174 }
175
176 SkImageInfo info = SkImageInfo::MakeS32(10, 10, kPremul_SkAlphaType);
reeddabe5d32016-06-21 10:28:14 -0700177 REPORTER_ASSERT(r, info.gammaCloseToSRGB());
reedfbce71f2016-06-02 12:40:22 -0700178}
msarett111a42d2016-06-22 08:18:54 -0700179
180static void test_serialize(skiatest::Reporter* r, SkColorSpace* space, bool isNamed) {
msaretta0605bf2016-07-28 10:47:50 -0700181 sk_sp<SkData> data1 = space->serialize();
182
183 size_t bytes = space->writeToMemory(nullptr);
184 sk_sp<SkData> data2 = SkData::MakeUninitialized(bytes);
185 space->writeToMemory(data2->writable_data());
186
187 sk_sp<SkColorSpace> newSpace1 = SkColorSpace::Deserialize(data1->data(), data1->size());
188 sk_sp<SkColorSpace> newSpace2 = SkColorSpace::Deserialize(data2->data(), data2->size());
msarett111a42d2016-06-22 08:18:54 -0700189
190 if (isNamed) {
msaretta0605bf2016-07-28 10:47:50 -0700191 REPORTER_ASSERT(r, space == newSpace1.get());
192 REPORTER_ASSERT(r, space == newSpace2.get());
msarett111a42d2016-06-22 08:18:54 -0700193 } else {
msarettd9015a42016-08-22 12:29:31 -0700194 REPORTER_ASSERT(r, SkColorSpace::Equals(space, newSpace1.get()));
195 REPORTER_ASSERT(r, SkColorSpace::Equals(space, newSpace2.get()));
msarett111a42d2016-06-22 08:18:54 -0700196 }
197}
198
199DEF_TEST(ColorSpace_Serialize, r) {
200 test_serialize(r, SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named).get(), true);
201 test_serialize(r, SkColorSpace::NewNamed(SkColorSpace::kAdobeRGB_Named).get(), true);
202
203 sk_sp<SkData> monitorData = SkData::MakeFromFileName(
msaretta714bc32016-07-29 08:58:33 -0700204 GetResourcePath("icc_profiles/HP_ZR30w.icc").c_str());
205 test_serialize(r, SkColorSpace::NewICC(monitorData->data(), monitorData->size()).get(), false);
206 monitorData = SkData::MakeFromFileName( GetResourcePath("icc_profiles/HP_Z32x.icc").c_str());
207 test_serialize(r, SkColorSpace::NewICC(monitorData->data(), monitorData->size()).get(), false);
208 monitorData = SkData::MakeFromFileName(GetResourcePath("icc_profiles/upperLeft.icc").c_str());
209 test_serialize(r, SkColorSpace::NewICC(monitorData->data(), monitorData->size()).get(), false);
210 monitorData = SkData::MakeFromFileName(GetResourcePath("icc_profiles/upperRight.icc").c_str());
msarett111a42d2016-06-22 08:18:54 -0700211 test_serialize(r, SkColorSpace::NewICC(monitorData->data(), monitorData->size()).get(), false);
msarettd9015a42016-08-22 12:29:31 -0700212
213 const float gammas[] = { 1.1f, 1.2f, 1.7f, };
214 SkMatrix44 toXYZ(SkMatrix44::kIdentity_Constructor);
215 test_serialize(r, SkColorSpace_Base::NewRGB(gammas, toXYZ).get(), false);
msarett111a42d2016-06-22 08:18:54 -0700216}
217
msarettabbd6d52016-08-01 09:43:08 -0700218DEF_TEST(ColorSpace_Equals, r) {
219 sk_sp<SkColorSpace> srgb = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
220 sk_sp<SkColorSpace> adobe = SkColorSpace::NewNamed(SkColorSpace::kAdobeRGB_Named);
221 sk_sp<SkData> data = SkData::MakeFromFileName(
222 GetResourcePath("icc_profiles/HP_ZR30w.icc").c_str());
223 sk_sp<SkColorSpace> z30 = SkColorSpace::NewICC(data->data(), data->size());
224 data = SkData::MakeFromFileName( GetResourcePath("icc_profiles/HP_Z32x.icc").c_str());
225 sk_sp<SkColorSpace> z32 = SkColorSpace::NewICC(data->data(), data->size());
226 data = SkData::MakeFromFileName(GetResourcePath("icc_profiles/upperLeft.icc").c_str());
227 sk_sp<SkColorSpace> upperLeft = SkColorSpace::NewICC(data->data(), data->size());
228 data = SkData::MakeFromFileName(GetResourcePath("icc_profiles/upperRight.icc").c_str());
229 sk_sp<SkColorSpace> upperRight = SkColorSpace::NewICC(data->data(), data->size());
msarettd9015a42016-08-22 12:29:31 -0700230 const float gammas1[] = { 1.1f, 1.2f, 1.3f, };
231 const float gammas2[] = { 1.1f, 1.2f, 1.7f, };
232 SkMatrix44 toXYZ(SkMatrix44::kIdentity_Constructor);
233 sk_sp<SkColorSpace> rgb1 = SkColorSpace_Base::NewRGB(gammas1, toXYZ);
234 sk_sp<SkColorSpace> rgb2 = SkColorSpace_Base::NewRGB(gammas2, toXYZ);
235 sk_sp<SkColorSpace> rgb3 = SkColorSpace_Base::NewRGB(gammas1, toXYZ);
msarettabbd6d52016-08-01 09:43:08 -0700236
237 REPORTER_ASSERT(r, SkColorSpace::Equals(nullptr, nullptr));
238 REPORTER_ASSERT(r, SkColorSpace::Equals(srgb.get(), srgb.get()));
239 REPORTER_ASSERT(r, SkColorSpace::Equals(adobe.get(), adobe.get()));
240 REPORTER_ASSERT(r, SkColorSpace::Equals(z30.get(), z30.get()));
241 REPORTER_ASSERT(r, SkColorSpace::Equals(z32.get(), z32.get()));
242 REPORTER_ASSERT(r, SkColorSpace::Equals(upperLeft.get(), upperLeft.get()));
243 REPORTER_ASSERT(r, SkColorSpace::Equals(upperRight.get(), upperRight.get()));
msarettd9015a42016-08-22 12:29:31 -0700244 REPORTER_ASSERT(r, SkColorSpace::Equals(rgb1.get(), rgb1.get()));
245 REPORTER_ASSERT(r, SkColorSpace::Equals(rgb1.get(), rgb3.get()));
msarettabbd6d52016-08-01 09:43:08 -0700246
247 REPORTER_ASSERT(r, !SkColorSpace::Equals(nullptr, srgb.get()));
248 REPORTER_ASSERT(r, !SkColorSpace::Equals(srgb.get(), nullptr));
249 REPORTER_ASSERT(r, !SkColorSpace::Equals(adobe.get(), srgb.get()));
250 REPORTER_ASSERT(r, !SkColorSpace::Equals(z30.get(), srgb.get()));
251 REPORTER_ASSERT(r, !SkColorSpace::Equals(z32.get(), z30.get()));
252 REPORTER_ASSERT(r, !SkColorSpace::Equals(upperLeft.get(), srgb.get()));
253 REPORTER_ASSERT(r, !SkColorSpace::Equals(upperLeft.get(), upperRight.get()));
254 REPORTER_ASSERT(r, !SkColorSpace::Equals(z30.get(), upperRight.get()));
255 REPORTER_ASSERT(r, !SkColorSpace::Equals(upperRight.get(), adobe.get()));
msarettd9015a42016-08-22 12:29:31 -0700256 REPORTER_ASSERT(r, !SkColorSpace::Equals(rgb1.get(), rgb2.get()));
msarettabbd6d52016-08-01 09:43:08 -0700257}