blob: 66860da590d12dd4838ce0a714514b3cb18f8d50 [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[],
msarettc4ce6b52016-06-16 07:37:41 -070022 const SkColorSpace::GammaNamed expectedGamma) {
msarettbb9f7742016-05-17 09:31:20 -070023
msarettc4ce6b52016-06-16 07:37:41 -070024 REPORTER_ASSERT(r, expectedGamma == space->gammaNamed());
msarettbb9f7742016-05-17 09:31:20 -070025
reed50d3b572016-05-03 12:13:21 -070026
27 SkMatrix44 mat = space->xyz();
28 const float src[] = {
29 1, 0, 0, 1,
30 0, 1, 0, 1,
31 0, 0, 1, 1,
32 };
33 float dst[4];
34 for (int i = 0; i < 3; ++i) {
35 mat.mapScalars(&src[i*4], dst);
36 REPORTER_ASSERT(r, almost_equal(red[i], dst[0]));
37 REPORTER_ASSERT(r, almost_equal(green[i], dst[1]));
38 REPORTER_ASSERT(r, almost_equal(blue[i], dst[2]));
39 }
40}
41
msarett02125d12016-05-03 14:24:47 -070042const float g_sRGB_XYZ[] = { 0.4358f, 0.2224f, 0.0139f, // R
43 0.3853f, 0.7170f, 0.0971f, // G
44 0.1430f, 0.0606f, 0.7139f }; // B
45
reed50d3b572016-05-03 12:13:21 -070046DEF_TEST(ColorSpace_sRGB, r) {
reed50d3b572016-05-03 12:13:21 -070047 test_space(r, SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named).get(),
msarettc4ce6b52016-06-16 07:37:41 -070048 g_sRGB_XYZ, &g_sRGB_XYZ[3], &g_sRGB_XYZ[6], SkColorSpace::kSRGB_GammaNamed);
reed50d3b572016-05-03 12:13:21 -070049
50}
51
msarett6a738212016-03-04 13:27:35 -080052static SkStreamAsset* resource(const char path[]) {
53 SkString fullPath = GetResourcePath(path);
54 return SkStream::NewFromFile(fullPath.c_str());
55}
56
msarett0e6274f2016-03-21 08:04:40 -070057DEF_TEST(ColorSpaceParsePngICCProfile, r) {
msarett6a738212016-03-04 13:27:35 -080058 SkAutoTDelete<SkStream> stream(resource("color_wheel_with_profile.png"));
59 REPORTER_ASSERT(r, nullptr != stream);
Brian Salomon92271fc2016-03-25 21:38:09 -040060 if (!stream) {
61 return;
62 }
msarett6a738212016-03-04 13:27:35 -080063
mtklein18300a32016-03-16 13:53:35 -070064 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release()));
scroggod8d68552016-06-06 11:26:17 -070065 REPORTER_ASSERT(r, nullptr != codec);
msarett6a738212016-03-04 13:27:35 -080066
msarett53add952016-03-07 17:25:12 -080067#if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6)
msarett530c8442016-07-21 11:57:49 -070068 SkColorSpace* colorSpace = codec->getInfo().colorSpace();
msarett6a738212016-03-04 13:27:35 -080069 REPORTER_ASSERT(r, nullptr != colorSpace);
70
msarettc4ce6b52016-06-16 07:37:41 -070071 test_space(r, colorSpace, &g_sRGB_XYZ[0], &g_sRGB_XYZ[3], &g_sRGB_XYZ[6],
72 SkColorSpace::kSRGB_GammaNamed);
msarett53add952016-03-07 17:25:12 -080073#endif
msarett6a738212016-03-04 13:27:35 -080074}
msarett0e6274f2016-03-21 08:04:40 -070075
76DEF_TEST(ColorSpaceParseJpegICCProfile, r) {
77 SkAutoTDelete<SkStream> stream(resource("icc-v2-gbr.jpg"));
78 REPORTER_ASSERT(r, nullptr != stream);
Brian Salomond2100f22016-03-25 17:02:20 -040079 if (!stream) {
80 return;
81 }
msarett0e6274f2016-03-21 08:04:40 -070082
83 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release()));
84 REPORTER_ASSERT(r, nullptr != codec);
Brian Salomond2100f22016-03-25 17:02:20 -040085 if (!codec) {
86 return;
87 }
msarett0e6274f2016-03-21 08:04:40 -070088
msarett530c8442016-07-21 11:57:49 -070089 SkColorSpace* colorSpace = codec->getInfo().colorSpace();
msarett0e6274f2016-03-21 08:04:40 -070090 REPORTER_ASSERT(r, nullptr != colorSpace);
91
reed50d3b572016-05-03 12:13:21 -070092 const float red[] = { 0.385117f, 0.716904f, 0.0970612f };
93 const float green[] = { 0.143051f, 0.0606079f, 0.713913f };
94 const float blue[] = { 0.436035f, 0.222488f, 0.013916f };
msarettc4ce6b52016-06-16 07:37:41 -070095 test_space(r, colorSpace, red, green, blue, SkColorSpace::k2Dot2Curve_GammaNamed);
msarett0e6274f2016-03-21 08:04:40 -070096}
msarett02125d12016-05-03 14:24:47 -070097
98DEF_TEST(ColorSpaceSRGBCompare, r) {
99 // Create an sRGB color space by name
100 sk_sp<SkColorSpace> namedColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
101
102 // Create an sRGB color space by value
103 SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor);
msarettc1a3e242016-06-23 12:42:29 -0700104 srgbToxyzD50.set3x3RowMajorf(g_sRGB_XYZ);
msarettc4ce6b52016-06-16 07:37:41 -0700105 sk_sp<SkColorSpace> rgbColorSpace = SkColorSpace::NewRGB(SkColorSpace::kSRGB_GammaNamed,
106 srgbToxyzD50);
msarettab926f02016-05-25 08:53:40 -0700107 REPORTER_ASSERT(r, rgbColorSpace == namedColorSpace);
msarett02125d12016-05-03 14:24:47 -0700108
109 // Change a single value from the sRGB matrix
110 srgbToxyzD50.set(2, 2, 0.5f);
msarettc4ce6b52016-06-16 07:37:41 -0700111 sk_sp<SkColorSpace> strangeColorSpace = SkColorSpace::NewRGB(SkColorSpace::kSRGB_GammaNamed,
112 srgbToxyzD50);
msarett02125d12016-05-03 14:24:47 -0700113 REPORTER_ASSERT(r, strangeColorSpace != namedColorSpace);
114}
msarettab926f02016-05-25 08:53:40 -0700115
msarettc213f0d2016-08-01 14:23:32 -0700116class ColorSpaceTest {
117public:
118 static sk_sp<SkData> WriteToICC(SkColorSpace* space) {
119 return as_CSB(space)->writeToICC();
120 }
121};
122
msarettab926f02016-05-25 08:53:40 -0700123DEF_TEST(ColorSpaceWriteICC, r) {
124 // Test writing a new ICC profile
125 sk_sp<SkColorSpace> namedColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
msarettc213f0d2016-08-01 14:23:32 -0700126 sk_sp<SkData> namedData = ColorSpaceTest::WriteToICC(namedColorSpace.get());
msarettab926f02016-05-25 08:53:40 -0700127 sk_sp<SkColorSpace> iccColorSpace = SkColorSpace::NewICC(namedData->data(), namedData->size());
msarettc4ce6b52016-06-16 07:37:41 -0700128 test_space(r, iccColorSpace.get(), g_sRGB_XYZ, &g_sRGB_XYZ[3], &g_sRGB_XYZ[6],
129 SkColorSpace::k2Dot2Curve_GammaNamed);
130 // FIXME (msarett): Test disabled. sRGB profiles are written approximately as 2.2f curves.
131 // REPORTER_ASSERT(r, iccColorSpace == namedColorSpace);
msarettab926f02016-05-25 08:53:40 -0700132
133 // Test saving the original ICC data
134 sk_sp<SkData> monitorData = SkData::MakeFromFileName(
msaretta714bc32016-07-29 08:58:33 -0700135 GetResourcePath("icc_profiles/HP_ZR30w.icc").c_str());
msarettab926f02016-05-25 08:53:40 -0700136 REPORTER_ASSERT(r, monitorData);
137 if (!monitorData) {
138 return;
139 }
140 sk_sp<SkColorSpace> monitorSpace = SkColorSpace::NewICC(monitorData->data(),
141 monitorData->size());
msarettc213f0d2016-08-01 14:23:32 -0700142 sk_sp<SkData> newMonitorData = ColorSpaceTest::WriteToICC(monitorSpace.get());
msarettab926f02016-05-25 08:53:40 -0700143 sk_sp<SkColorSpace> newMonitorSpace = SkColorSpace::NewICC(newMonitorData->data(),
144 newMonitorData->size());
145 REPORTER_ASSERT(r, monitorSpace->xyz() == newMonitorSpace->xyz());
msarettc4ce6b52016-06-16 07:37:41 -0700146 REPORTER_ASSERT(r, monitorSpace->gammaNamed() == newMonitorSpace->gammaNamed());
msarettab926f02016-05-25 08:53:40 -0700147}
reedfbce71f2016-06-02 12:40:22 -0700148
149DEF_TEST(ColorSpace_Named, r) {
150 const struct {
151 SkColorSpace::Named fNamed;
152 bool fExpectedToSucceed;
msarettc4ce6b52016-06-16 07:37:41 -0700153 bool fIsSRGB;
reedfbce71f2016-06-02 12:40:22 -0700154 } recs[] {
msarettc4ce6b52016-06-16 07:37:41 -0700155 { SkColorSpace::kUnknown_Named, false, false },
156 { SkColorSpace::kSRGB_Named, true, true },
157 { SkColorSpace::kAdobeRGB_Named, true, false },
reedfbce71f2016-06-02 12:40:22 -0700158 };
159
160 for (auto rec : recs) {
161 auto cs = SkColorSpace::NewNamed(rec.fNamed);
162 REPORTER_ASSERT(r, !cs == !rec.fExpectedToSucceed);
163 if (cs) {
msarettc4ce6b52016-06-16 07:37:41 -0700164 if (rec.fIsSRGB) {
165 REPORTER_ASSERT(r, SkColorSpace::kSRGB_GammaNamed == cs->gammaNamed());
166 } else {
167 REPORTER_ASSERT(r, SkColorSpace::k2Dot2Curve_GammaNamed == cs->gammaNamed());
168 }
reedfbce71f2016-06-02 12:40:22 -0700169 }
170 }
171
172 SkImageInfo info = SkImageInfo::MakeS32(10, 10, kPremul_SkAlphaType);
reeddabe5d32016-06-21 10:28:14 -0700173 REPORTER_ASSERT(r, info.gammaCloseToSRGB());
reedfbce71f2016-06-02 12:40:22 -0700174}
msarett111a42d2016-06-22 08:18:54 -0700175
msaretta0605bf2016-07-28 10:47:50 -0700176static void matrix_equals(skiatest::Reporter* r, SkColorSpace* space1, SkColorSpace* space2) {
177 REPORTER_ASSERT(r, space1->xyz().getFloat(0, 0) == space2->xyz().getFloat(0, 0));
178 REPORTER_ASSERT(r, space1->xyz().getFloat(0, 1) == space2->xyz().getFloat(0, 1));
179 REPORTER_ASSERT(r, space1->xyz().getFloat(0, 2) == space2->xyz().getFloat(0, 2));
180 REPORTER_ASSERT(r, space1->xyz().getFloat(0, 3) == space2->xyz().getFloat(0, 3));
181 REPORTER_ASSERT(r, space1->xyz().getFloat(1, 0) == space2->xyz().getFloat(1, 0));
182 REPORTER_ASSERT(r, space1->xyz().getFloat(1, 1) == space2->xyz().getFloat(1, 1));
183 REPORTER_ASSERT(r, space1->xyz().getFloat(1, 2) == space2->xyz().getFloat(1, 2));
184 REPORTER_ASSERT(r, space1->xyz().getFloat(1, 3) == space2->xyz().getFloat(1, 3));
185 REPORTER_ASSERT(r, space1->xyz().getFloat(2, 0) == space2->xyz().getFloat(2, 0));
186 REPORTER_ASSERT(r, space1->xyz().getFloat(2, 1) == space2->xyz().getFloat(2, 1));
187 REPORTER_ASSERT(r, space1->xyz().getFloat(2, 2) == space2->xyz().getFloat(2, 2));
188 REPORTER_ASSERT(r, space1->xyz().getFloat(2, 3) == space2->xyz().getFloat(2, 3));
189 REPORTER_ASSERT(r, space1->xyz().getFloat(3, 0) == space2->xyz().getFloat(3, 0));
190 REPORTER_ASSERT(r, space1->xyz().getFloat(3, 1) == space2->xyz().getFloat(3, 1));
191 REPORTER_ASSERT(r, space1->xyz().getFloat(3, 2) == space2->xyz().getFloat(3, 2));
192 REPORTER_ASSERT(r, space1->xyz().getFloat(3, 3) == space2->xyz().getFloat(3, 3));
193}
194
msarett111a42d2016-06-22 08:18:54 -0700195static void test_serialize(skiatest::Reporter* r, SkColorSpace* space, bool isNamed) {
msaretta0605bf2016-07-28 10:47:50 -0700196 sk_sp<SkData> data1 = space->serialize();
197
198 size_t bytes = space->writeToMemory(nullptr);
199 sk_sp<SkData> data2 = SkData::MakeUninitialized(bytes);
200 space->writeToMemory(data2->writable_data());
201
202 sk_sp<SkColorSpace> newSpace1 = SkColorSpace::Deserialize(data1->data(), data1->size());
203 sk_sp<SkColorSpace> newSpace2 = SkColorSpace::Deserialize(data2->data(), data2->size());
msarett111a42d2016-06-22 08:18:54 -0700204
205 if (isNamed) {
msaretta0605bf2016-07-28 10:47:50 -0700206 REPORTER_ASSERT(r, space == newSpace1.get());
207 REPORTER_ASSERT(r, space == newSpace2.get());
msarett111a42d2016-06-22 08:18:54 -0700208 } else {
msaretta0605bf2016-07-28 10:47:50 -0700209 REPORTER_ASSERT(r, space->gammaNamed() == newSpace1->gammaNamed());
210 REPORTER_ASSERT(r, space->gammaNamed() == newSpace2->gammaNamed());
211 matrix_equals(r, space, newSpace1.get());
212 matrix_equals(r, space, newSpace2.get());
msarett111a42d2016-06-22 08:18:54 -0700213 }
214}
215
216DEF_TEST(ColorSpace_Serialize, r) {
217 test_serialize(r, SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named).get(), true);
218 test_serialize(r, SkColorSpace::NewNamed(SkColorSpace::kAdobeRGB_Named).get(), true);
219
220 sk_sp<SkData> monitorData = SkData::MakeFromFileName(
msaretta714bc32016-07-29 08:58:33 -0700221 GetResourcePath("icc_profiles/HP_ZR30w.icc").c_str());
222 test_serialize(r, SkColorSpace::NewICC(monitorData->data(), monitorData->size()).get(), false);
223 monitorData = SkData::MakeFromFileName( GetResourcePath("icc_profiles/HP_Z32x.icc").c_str());
224 test_serialize(r, SkColorSpace::NewICC(monitorData->data(), monitorData->size()).get(), false);
225 monitorData = SkData::MakeFromFileName(GetResourcePath("icc_profiles/upperLeft.icc").c_str());
226 test_serialize(r, SkColorSpace::NewICC(monitorData->data(), monitorData->size()).get(), false);
227 monitorData = SkData::MakeFromFileName(GetResourcePath("icc_profiles/upperRight.icc").c_str());
msarett111a42d2016-06-22 08:18:54 -0700228 test_serialize(r, SkColorSpace::NewICC(monitorData->data(), monitorData->size()).get(), false);
229}
230
msarettabbd6d52016-08-01 09:43:08 -0700231DEF_TEST(ColorSpace_Equals, r) {
232 sk_sp<SkColorSpace> srgb = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
233 sk_sp<SkColorSpace> adobe = SkColorSpace::NewNamed(SkColorSpace::kAdobeRGB_Named);
234 sk_sp<SkData> data = SkData::MakeFromFileName(
235 GetResourcePath("icc_profiles/HP_ZR30w.icc").c_str());
236 sk_sp<SkColorSpace> z30 = SkColorSpace::NewICC(data->data(), data->size());
237 data = SkData::MakeFromFileName( GetResourcePath("icc_profiles/HP_Z32x.icc").c_str());
238 sk_sp<SkColorSpace> z32 = SkColorSpace::NewICC(data->data(), data->size());
239 data = SkData::MakeFromFileName(GetResourcePath("icc_profiles/upperLeft.icc").c_str());
240 sk_sp<SkColorSpace> upperLeft = SkColorSpace::NewICC(data->data(), data->size());
241 data = SkData::MakeFromFileName(GetResourcePath("icc_profiles/upperRight.icc").c_str());
242 sk_sp<SkColorSpace> upperRight = SkColorSpace::NewICC(data->data(), data->size());
243
244 REPORTER_ASSERT(r, SkColorSpace::Equals(nullptr, nullptr));
245 REPORTER_ASSERT(r, SkColorSpace::Equals(srgb.get(), srgb.get()));
246 REPORTER_ASSERT(r, SkColorSpace::Equals(adobe.get(), adobe.get()));
247 REPORTER_ASSERT(r, SkColorSpace::Equals(z30.get(), z30.get()));
248 REPORTER_ASSERT(r, SkColorSpace::Equals(z32.get(), z32.get()));
249 REPORTER_ASSERT(r, SkColorSpace::Equals(upperLeft.get(), upperLeft.get()));
250 REPORTER_ASSERT(r, SkColorSpace::Equals(upperRight.get(), upperRight.get()));
251
252 REPORTER_ASSERT(r, !SkColorSpace::Equals(nullptr, srgb.get()));
253 REPORTER_ASSERT(r, !SkColorSpace::Equals(srgb.get(), nullptr));
254 REPORTER_ASSERT(r, !SkColorSpace::Equals(adobe.get(), srgb.get()));
255 REPORTER_ASSERT(r, !SkColorSpace::Equals(z30.get(), srgb.get()));
256 REPORTER_ASSERT(r, !SkColorSpace::Equals(z32.get(), z30.get()));
257 REPORTER_ASSERT(r, !SkColorSpace::Equals(upperLeft.get(), srgb.get()));
258 REPORTER_ASSERT(r, !SkColorSpace::Equals(upperLeft.get(), upperRight.get()));
259 REPORTER_ASSERT(r, !SkColorSpace::Equals(z30.get(), upperRight.get()));
260 REPORTER_ASSERT(r, !SkColorSpace::Equals(upperRight.get(), adobe.get()));
261}