blob: 442ed3df30cf370246a5fd502eca950e579e7cff [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)
msarett6a738212016-03-04 13:27:35 -080068 SkColorSpace* colorSpace = codec->getColorSpace();
69 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
89 SkColorSpace* colorSpace = codec->getColorSpace();
90 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
116DEF_TEST(ColorSpaceWriteICC, r) {
117 // Test writing a new ICC profile
118 sk_sp<SkColorSpace> namedColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
119 sk_sp<SkData> namedData = as_CSB(namedColorSpace)->writeToICC();
120 sk_sp<SkColorSpace> iccColorSpace = SkColorSpace::NewICC(namedData->data(), namedData->size());
msarettc4ce6b52016-06-16 07:37:41 -0700121 test_space(r, iccColorSpace.get(), g_sRGB_XYZ, &g_sRGB_XYZ[3], &g_sRGB_XYZ[6],
122 SkColorSpace::k2Dot2Curve_GammaNamed);
123 // FIXME (msarett): Test disabled. sRGB profiles are written approximately as 2.2f curves.
124 // REPORTER_ASSERT(r, iccColorSpace == namedColorSpace);
msarettab926f02016-05-25 08:53:40 -0700125
126 // Test saving the original ICC data
127 sk_sp<SkData> monitorData = SkData::MakeFromFileName(
128 GetResourcePath("monitor_profiles/HP_ZR30w.icc").c_str());
129 REPORTER_ASSERT(r, monitorData);
130 if (!monitorData) {
131 return;
132 }
133 sk_sp<SkColorSpace> monitorSpace = SkColorSpace::NewICC(monitorData->data(),
134 monitorData->size());
135 sk_sp<SkData> newMonitorData = as_CSB(monitorSpace)->writeToICC();
136 sk_sp<SkColorSpace> newMonitorSpace = SkColorSpace::NewICC(newMonitorData->data(),
137 newMonitorData->size());
138 REPORTER_ASSERT(r, monitorSpace->xyz() == newMonitorSpace->xyz());
msarettc4ce6b52016-06-16 07:37:41 -0700139 REPORTER_ASSERT(r, monitorSpace->gammaNamed() == newMonitorSpace->gammaNamed());
msarettab926f02016-05-25 08:53:40 -0700140}
reedfbce71f2016-06-02 12:40:22 -0700141
142DEF_TEST(ColorSpace_Named, r) {
143 const struct {
144 SkColorSpace::Named fNamed;
145 bool fExpectedToSucceed;
msarettc4ce6b52016-06-16 07:37:41 -0700146 bool fIsSRGB;
reedfbce71f2016-06-02 12:40:22 -0700147 } recs[] {
msarettc4ce6b52016-06-16 07:37:41 -0700148 { SkColorSpace::kUnknown_Named, false, false },
149 { SkColorSpace::kSRGB_Named, true, true },
150 { SkColorSpace::kAdobeRGB_Named, true, false },
reedfbce71f2016-06-02 12:40:22 -0700151 };
152
153 for (auto rec : recs) {
154 auto cs = SkColorSpace::NewNamed(rec.fNamed);
155 REPORTER_ASSERT(r, !cs == !rec.fExpectedToSucceed);
156 if (cs) {
msarettc4ce6b52016-06-16 07:37:41 -0700157 if (rec.fIsSRGB) {
158 REPORTER_ASSERT(r, SkColorSpace::kSRGB_GammaNamed == cs->gammaNamed());
159 } else {
160 REPORTER_ASSERT(r, SkColorSpace::k2Dot2Curve_GammaNamed == cs->gammaNamed());
161 }
reedfbce71f2016-06-02 12:40:22 -0700162 }
163 }
164
165 SkImageInfo info = SkImageInfo::MakeS32(10, 10, kPremul_SkAlphaType);
reeddabe5d32016-06-21 10:28:14 -0700166 REPORTER_ASSERT(r, info.gammaCloseToSRGB());
reedfbce71f2016-06-02 12:40:22 -0700167}
msarett111a42d2016-06-22 08:18:54 -0700168
169static void test_serialize(skiatest::Reporter* r, SkColorSpace* space, bool isNamed) {
170 sk_sp<SkData> data = space->serialize();
171 sk_sp<SkColorSpace> newSpace = SkColorSpace::Deserialize(data->data(), data->size());
172
173 if (isNamed) {
174 REPORTER_ASSERT(r, space == newSpace.get());
175 } else {
176 REPORTER_ASSERT(r, space->gammaNamed() == newSpace->gammaNamed());
177
178 REPORTER_ASSERT(r, space->xyz().getFloat(0, 0) == newSpace->xyz().getFloat(0, 0));
179 REPORTER_ASSERT(r, space->xyz().getFloat(0, 1) == newSpace->xyz().getFloat(0, 1));
180 REPORTER_ASSERT(r, space->xyz().getFloat(0, 2) == newSpace->xyz().getFloat(0, 2));
181 REPORTER_ASSERT(r, space->xyz().getFloat(0, 3) == newSpace->xyz().getFloat(0, 3));
182 REPORTER_ASSERT(r, space->xyz().getFloat(1, 0) == newSpace->xyz().getFloat(1, 0));
183 REPORTER_ASSERT(r, space->xyz().getFloat(1, 1) == newSpace->xyz().getFloat(1, 1));
184 REPORTER_ASSERT(r, space->xyz().getFloat(1, 2) == newSpace->xyz().getFloat(1, 2));
185 REPORTER_ASSERT(r, space->xyz().getFloat(1, 3) == newSpace->xyz().getFloat(1, 3));
186 REPORTER_ASSERT(r, space->xyz().getFloat(2, 0) == newSpace->xyz().getFloat(2, 0));
187 REPORTER_ASSERT(r, space->xyz().getFloat(2, 1) == newSpace->xyz().getFloat(2, 1));
188 REPORTER_ASSERT(r, space->xyz().getFloat(2, 2) == newSpace->xyz().getFloat(2, 2));
189 REPORTER_ASSERT(r, space->xyz().getFloat(2, 3) == newSpace->xyz().getFloat(2, 3));
190 REPORTER_ASSERT(r, space->xyz().getFloat(3, 0) == newSpace->xyz().getFloat(3, 0));
191 REPORTER_ASSERT(r, space->xyz().getFloat(3, 1) == newSpace->xyz().getFloat(3, 1));
192 REPORTER_ASSERT(r, space->xyz().getFloat(3, 2) == newSpace->xyz().getFloat(3, 2));
193 REPORTER_ASSERT(r, space->xyz().getFloat(3, 3) == newSpace->xyz().getFloat(3, 3));
194 }
195}
196
197DEF_TEST(ColorSpace_Serialize, r) {
198 test_serialize(r, SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named).get(), true);
199 test_serialize(r, SkColorSpace::NewNamed(SkColorSpace::kAdobeRGB_Named).get(), true);
200
201 sk_sp<SkData> monitorData = SkData::MakeFromFileName(
202 GetResourcePath("monitor_profiles/HP_ZR30w.icc").c_str());
203 test_serialize(r, SkColorSpace::NewICC(monitorData->data(), monitorData->size()).get(), false);
204}
205