1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/gfx/color_analysis.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "third_party/skia/include/core/SkBitmap.h"
11 #include "third_party/skia/include/core/SkColor.h"
12 #include "ui/gfx/canvas.h"
13 #include "ui/gfx/color_utils.h"
14 #include "ui/gfx/image/image.h"
15 #include "ui/gfx/rect.h"
17 namespace color_utils
{
19 const unsigned char k1x1White
[] = {
20 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
21 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
22 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
23 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53,
24 0xde, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
25 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
26 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00,
27 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00,
28 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74,
29 0x49, 0x4d, 0x45, 0x07, 0xdb, 0x02, 0x11, 0x15,
30 0x16, 0x1b, 0xaa, 0x58, 0x38, 0x76, 0x00, 0x00,
31 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f,
32 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x43, 0x72,
33 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69,
34 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57,
35 0x81, 0x0e, 0x17, 0x00, 0x00, 0x00, 0x0c, 0x49,
36 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0xf8, 0xff,
37 0xff, 0x3f, 0x00, 0x05, 0xfe, 0x02, 0xfe, 0xdc,
38 0xcc, 0x59, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x49,
39 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
42 const unsigned char k1x3BlueWhite
[] = {
43 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
44 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
45 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03,
46 0x08, 0x02, 0x00, 0x00, 0x00, 0xdd, 0xbf, 0xf2,
47 0xd5, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
48 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
49 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00,
50 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00,
51 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74,
52 0x49, 0x4d, 0x45, 0x07, 0xdb, 0x02, 0x12, 0x01,
53 0x0a, 0x2c, 0xfd, 0x08, 0x64, 0x66, 0x00, 0x00,
54 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f,
55 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x43, 0x72,
56 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69,
57 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57,
58 0x81, 0x0e, 0x17, 0x00, 0x00, 0x00, 0x14, 0x49,
59 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0xf8, 0xff,
60 0xff, 0x3f, 0x13, 0x03, 0x03, 0x03, 0x03, 0x03,
61 0xc3, 0x7f, 0x00, 0x1e, 0xfd, 0x03, 0xff, 0xde,
62 0x72, 0x58, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x49,
63 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
66 const unsigned char k1x3BlueRed
[] = {
67 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
68 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
69 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03,
70 0x08, 0x02, 0x00, 0x00, 0x00, 0xdd, 0xbf, 0xf2,
71 0xd5, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
72 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
73 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00,
74 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00,
75 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74,
76 0x49, 0x4d, 0x45, 0x07, 0xdb, 0x02, 0x12, 0x01,
77 0x07, 0x09, 0x03, 0xa2, 0xce, 0x6c, 0x00, 0x00,
78 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f,
79 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x43, 0x72,
80 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69,
81 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57,
82 0x81, 0x0e, 0x17, 0x00, 0x00, 0x00, 0x14, 0x49,
83 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0xf8, 0xcf,
84 0xc0, 0xc0, 0xc4, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
85 0xf0, 0x1f, 0x00, 0x0c, 0x10, 0x02, 0x01, 0x2c,
86 0x8f, 0x8b, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x49,
87 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
90 const HSL kDefaultLowerBound
= {-1, -1, 0.15};
91 const HSL kDefaultUpperBound
= {-1, -1, 0.85};
93 // Creates a 1-dimensional png of the pixel colors found in |colors|.
94 scoped_refptr
<base::RefCountedMemory
> CreateTestPNG(
95 const std::vector
<SkColor
>& colors
) {
97 bitmap
.setConfig(SkBitmap::kARGB_8888_Config
, colors
.size(), 1);
100 SkAutoLockPixels
lock(bitmap
);
101 for (size_t i
= 0; i
< colors
.size(); ++i
) {
102 bitmap
.eraseArea(SkIRect::MakeXYWH(i
, 0, 1, 1), colors
[i
]);
104 return gfx::Image::CreateFrom1xBitmap(bitmap
).As1xPNGBytes();
107 class MockKMeanImageSampler
: public KMeanImageSampler
{
109 MockKMeanImageSampler() : current_result_index_(0) {
112 explicit MockKMeanImageSampler(const std::vector
<int>& samples
)
113 : prebaked_sample_results_(samples
),
114 current_result_index_(0) {
117 virtual ~MockKMeanImageSampler() {
120 void AddSample(int sample
) {
121 prebaked_sample_results_
.push_back(sample
);
124 virtual int GetSample(int width
, int height
) OVERRIDE
{
125 if (current_result_index_
>= prebaked_sample_results_
.size()) {
126 current_result_index_
= 0;
129 if (prebaked_sample_results_
.empty()) {
133 return prebaked_sample_results_
[current_result_index_
++];
137 std::vector
<int> prebaked_sample_results_
;
138 size_t current_result_index_
;
141 // Return true if a color channel is approximately equal to an expected value.
142 bool ChannelApproximatelyEqual(int expected
, uint8_t channel
) {
143 return (abs(expected
- static_cast<int>(channel
)) <= 1);
146 // Compute minimal and maximal graylevel (or alphalevel) of the input |bitmap|.
147 // |bitmap| has to be allocated and configured to kA8_Config.
148 void Calculate8bitBitmapMinMax(const SkBitmap
& bitmap
,
151 SkAutoLockPixels
bitmap_lock(bitmap
);
152 DCHECK(bitmap
.getPixels());
153 DCHECK(bitmap
.config() == SkBitmap::kA8_Config
);
156 *min_gl
= std::numeric_limits
<uint8_t>::max();
157 *max_gl
= std::numeric_limits
<uint8_t>::min();
158 for (int y
= 0; y
< bitmap
.height(); ++y
) {
159 uint8_t* current_color
= bitmap
.getAddr8(0, y
);
160 for (int x
= 0; x
< bitmap
.width(); ++x
, ++current_color
) {
161 *min_gl
= std::min(*min_gl
, *current_color
);
162 *max_gl
= std::max(*max_gl
, *current_color
);
167 class ColorAnalysisTest
: public testing::Test
{
170 TEST_F(ColorAnalysisTest
, CalculatePNGKMeanAllWhite
) {
171 MockKMeanImageSampler test_sampler
;
172 test_sampler
.AddSample(0);
174 scoped_refptr
<base::RefCountedBytes
> png(
175 new base::RefCountedBytes(
176 std::vector
<unsigned char>(
178 k1x1White
+ sizeof(k1x1White
) / sizeof(unsigned char))));
180 SkColor color
= CalculateKMeanColorOfPNG(
181 png
, kDefaultLowerBound
, kDefaultUpperBound
, &test_sampler
);
183 EXPECT_EQ(color
, SK_ColorWHITE
);
186 TEST_F(ColorAnalysisTest
, CalculatePNGKMeanIgnoreWhiteLightness
) {
187 MockKMeanImageSampler test_sampler
;
188 test_sampler
.AddSample(0);
189 test_sampler
.AddSample(1);
190 test_sampler
.AddSample(2);
192 scoped_refptr
<base::RefCountedBytes
> png(
193 new base::RefCountedBytes(
194 std::vector
<unsigned char>(
196 k1x3BlueWhite
+ sizeof(k1x3BlueWhite
) / sizeof(unsigned char))));
198 SkColor color
= CalculateKMeanColorOfPNG(
199 png
, kDefaultLowerBound
, kDefaultUpperBound
, &test_sampler
);
201 EXPECT_EQ(SkColorSetARGB(0xFF, 0x00, 0x00, 0xFF), color
);
204 TEST_F(ColorAnalysisTest
, CalculatePNGKMeanPickMostCommon
) {
205 MockKMeanImageSampler test_sampler
;
206 test_sampler
.AddSample(0);
207 test_sampler
.AddSample(1);
208 test_sampler
.AddSample(2);
210 scoped_refptr
<base::RefCountedBytes
> png(
211 new base::RefCountedBytes(
212 std::vector
<unsigned char>(
214 k1x3BlueRed
+ sizeof(k1x3BlueRed
) / sizeof(unsigned char))));
216 SkColor color
= CalculateKMeanColorOfPNG(
217 png
, kDefaultLowerBound
, kDefaultUpperBound
, &test_sampler
);
219 EXPECT_EQ(SkColorSetARGB(0xFF, 0xFF, 0x00, 0x00), color
);
222 TEST_F(ColorAnalysisTest
, CalculatePNGKMeanIgnoreRedHue
) {
223 MockKMeanImageSampler test_sampler
;
224 test_sampler
.AddSample(0);
225 test_sampler
.AddSample(1);
226 test_sampler
.AddSample(2);
228 std::vector
<SkColor
> colors(4, SK_ColorRED
);
229 colors
[1] = SK_ColorBLUE
;
231 scoped_refptr
<base::RefCountedMemory
> png
= CreateTestPNG(colors
);
233 HSL lower
= {0.2, -1, 0.15};
234 HSL upper
= {0.8, -1, 0.85};
235 SkColor color
= CalculateKMeanColorOfPNG(
236 png
, lower
, upper
, &test_sampler
);
238 EXPECT_EQ(SK_ColorBLUE
, color
);
241 TEST_F(ColorAnalysisTest
, CalculatePNGKMeanIgnoreGreySaturation
) {
242 MockKMeanImageSampler test_sampler
;
243 test_sampler
.AddSample(0);
244 test_sampler
.AddSample(1);
245 test_sampler
.AddSample(2);
247 std::vector
<SkColor
> colors(4, SK_ColorGRAY
);
248 colors
[1] = SK_ColorBLUE
;
250 scoped_refptr
<base::RefCountedMemory
> png
= CreateTestPNG(colors
);
251 HSL lower
= {-1, 0.3, -1};
252 HSL upper
= {-1, 1, -1};
253 SkColor color
= CalculateKMeanColorOfPNG(
254 png
, lower
, upper
, &test_sampler
);
256 EXPECT_EQ(SK_ColorBLUE
, color
);
259 TEST_F(ColorAnalysisTest
, GridSampler
) {
261 const int kWidth
= 16;
262 const int kHeight
= 16;
263 // Sample starts at 1,1.
264 EXPECT_EQ(1 + 1 * kWidth
, sampler
.GetSample(kWidth
, kHeight
));
265 EXPECT_EQ(1 + 4 * kWidth
, sampler
.GetSample(kWidth
, kHeight
));
266 EXPECT_EQ(1 + 7 * kWidth
, sampler
.GetSample(kWidth
, kHeight
));
267 EXPECT_EQ(1 + 10 * kWidth
, sampler
.GetSample(kWidth
, kHeight
));
269 EXPECT_EQ(4 + 1 * kWidth
, sampler
.GetSample(kWidth
, kHeight
));
270 EXPECT_EQ(4 + 4 * kWidth
, sampler
.GetSample(kWidth
, kHeight
));
271 EXPECT_EQ(4 + 7 * kWidth
, sampler
.GetSample(kWidth
, kHeight
));
272 EXPECT_EQ(4 + 10 * kWidth
, sampler
.GetSample(kWidth
, kHeight
));
275 TEST_F(ColorAnalysisTest
, FindClosestColor
) {
276 // Empty image returns input color.
277 SkColor color
= FindClosestColor(NULL
, 0, 0, SK_ColorRED
);
278 EXPECT_EQ(SK_ColorRED
, color
);
280 // Single color image returns that color.
282 bitmap
.setConfig(SkBitmap::kARGB_8888_Config
, 16, 16);
283 bitmap
.allocPixels();
284 bitmap
.eraseColor(SK_ColorWHITE
);
285 color
= FindClosestColor(static_cast<uint8_t*>(bitmap
.getPixels()),
289 EXPECT_EQ(SK_ColorWHITE
, color
);
291 // Write a black pixel into the image. A dark grey input pixel should match
292 // the black one in the image.
293 uint32_t* pixel
= bitmap
.getAddr32(0, 0);
294 *pixel
= SK_ColorBLACK
;
295 color
= FindClosestColor(static_cast<uint8_t*>(bitmap
.getPixels()),
299 EXPECT_EQ(SK_ColorBLACK
, color
);
302 TEST_F(ColorAnalysisTest
, CalculateKMeanColorOfBitmap
) {
303 // Create a 16x16 bitmap to represent a favicon.
305 bitmap
.setConfig(SkBitmap::kARGB_8888_Config
, 16, 16);
306 bitmap
.allocPixels();
307 bitmap
.eraseARGB(255, 100, 150, 200);
309 SkColor color
= CalculateKMeanColorOfBitmap(bitmap
);
310 EXPECT_EQ(255u, SkColorGetA(color
));
311 // Color values are not exactly equal due to reversal of premultiplied alpha.
312 EXPECT_TRUE(ChannelApproximatelyEqual(100, SkColorGetR(color
)));
313 EXPECT_TRUE(ChannelApproximatelyEqual(150, SkColorGetG(color
)));
314 EXPECT_TRUE(ChannelApproximatelyEqual(200, SkColorGetB(color
)));
316 // Test a bitmap with an alpha channel.
317 bitmap
.eraseARGB(128, 100, 150, 200);
318 color
= CalculateKMeanColorOfBitmap(bitmap
);
320 // Alpha channel should be ignored for dominant color calculation.
321 EXPECT_EQ(255u, SkColorGetA(color
));
322 EXPECT_TRUE(ChannelApproximatelyEqual(100, SkColorGetR(color
)));
323 EXPECT_TRUE(ChannelApproximatelyEqual(150, SkColorGetG(color
)));
324 EXPECT_TRUE(ChannelApproximatelyEqual(200, SkColorGetB(color
)));
327 TEST_F(ColorAnalysisTest
, ComputeColorCovarianceTrivial
) {
329 bitmap
.setConfig(SkBitmap::kARGB_8888_Config
, 100, 200);
331 EXPECT_EQ(gfx::Matrix3F::Zeros(), ComputeColorCovariance(bitmap
));
332 bitmap
.allocPixels();
333 bitmap
.eraseARGB(255, 50, 150, 200);
334 gfx::Matrix3F covariance
= ComputeColorCovariance(bitmap
);
335 // The answer should be all zeros.
336 EXPECT_TRUE(covariance
== gfx::Matrix3F::Zeros());
339 TEST_F(ColorAnalysisTest
, ComputeColorCovarianceWithCanvas
) {
340 gfx::Canvas
canvas(gfx::Size(250, 200), 1.0f
, true);
341 // The image consists of vertical stripes, with color bands set to 100
342 // in overlapping stripes 150 pixels wide.
343 canvas
.FillRect(gfx::Rect(0, 0, 50, 200), SkColorSetRGB(100, 0, 0));
344 canvas
.FillRect(gfx::Rect(50, 0, 50, 200), SkColorSetRGB(100, 100, 0));
345 canvas
.FillRect(gfx::Rect(100, 0, 50, 200), SkColorSetRGB(100, 100, 100));
346 canvas
.FillRect(gfx::Rect(150, 0, 50, 200), SkColorSetRGB(0, 100, 100));
347 canvas
.FillRect(gfx::Rect(200, 0, 50, 200), SkColorSetRGB(0, 0, 100));
350 skia::GetTopDevice(*canvas
.sk_canvas())->accessBitmap(false);
351 gfx::Matrix3F covariance
= ComputeColorCovariance(bitmap
);
353 gfx::Matrix3F expected_covariance
= gfx::Matrix3F::Zeros();
354 expected_covariance
.set(2400, 400, -1600,
357 EXPECT_EQ(expected_covariance
, covariance
);
360 TEST_F(ColorAnalysisTest
, ApplyColorReductionSingleColor
) {
361 // The test runs color reduction on a single-colot image, where results are
362 // bound to be uninteresting. This is an important edge case, though.
363 SkBitmap source
, result
;
364 source
.setConfig(SkBitmap::kARGB_8888_Config
, 300, 200);
365 result
.setConfig(SkBitmap::kA8_Config
, 300, 200);
367 source
.allocPixels();
368 result
.allocPixels();
369 source
.eraseARGB(255, 50, 150, 200);
371 gfx::Vector3dF
transform(1.0f
, .5f
, 0.1f
);
372 // This transform, if not scaled, should result in GL=145.
373 EXPECT_TRUE(ApplyColorReduction(source
, transform
, false, &result
));
377 Calculate8bitBitmapMinMax(result
, &min_gl
, &max_gl
);
378 EXPECT_EQ(145, min_gl
);
379 EXPECT_EQ(145, max_gl
);
381 // Now scan requesting rescale. Expect all 0.
382 EXPECT_TRUE(ApplyColorReduction(source
, transform
, true, &result
));
383 Calculate8bitBitmapMinMax(result
, &min_gl
, &max_gl
);
384 EXPECT_EQ(0, min_gl
);
385 EXPECT_EQ(0, max_gl
);
387 // Test cliping to upper limit.
388 transform
.set_z(1.1f
);
389 EXPECT_TRUE(ApplyColorReduction(source
, transform
, false, &result
));
390 Calculate8bitBitmapMinMax(result
, &min_gl
, &max_gl
);
391 EXPECT_EQ(0xFF, min_gl
);
392 EXPECT_EQ(0xFF, max_gl
);
394 // Test cliping to upper limit.
395 transform
.Scale(-1.0f
);
396 EXPECT_TRUE(ApplyColorReduction(source
, transform
, false, &result
));
397 Calculate8bitBitmapMinMax(result
, &min_gl
, &max_gl
);
398 EXPECT_EQ(0x0, min_gl
);
399 EXPECT_EQ(0x0, max_gl
);
402 TEST_F(ColorAnalysisTest
, ApplyColorReductionBlackAndWhite
) {
403 // Check with images with multiple colors. This is really different only when
404 // the result is scaled.
405 gfx::Canvas
canvas(gfx::Size(300, 200), 1.0f
, true);
407 // The image consists of vertical non-overlapping stripes 150 pixels wide.
408 canvas
.FillRect(gfx::Rect(0, 0, 150, 200), SkColorSetRGB(0, 0, 0));
409 canvas
.FillRect(gfx::Rect(150, 0, 150, 200), SkColorSetRGB(255, 255, 255));
411 skia::GetTopDevice(*canvas
.sk_canvas())->accessBitmap(false);
413 result
.setConfig(SkBitmap::kA8_Config
, 300, 200);
414 result
.allocPixels();
416 gfx::Vector3dF
transform(1.0f
, 0.5f
, 0.1f
);
417 EXPECT_TRUE(ApplyColorReduction(source
, transform
, true, &result
));
420 Calculate8bitBitmapMinMax(result
, &min_gl
, &max_gl
);
422 EXPECT_EQ(0, min_gl
);
423 EXPECT_EQ(255, max_gl
);
424 EXPECT_EQ(min_gl
, SkColorGetA(result
.getColor(0, 0)));
425 EXPECT_EQ(max_gl
, SkColorGetA(result
.getColor(299, 199)));
428 transform
.Scale(-1.0f
);
429 EXPECT_TRUE(ApplyColorReduction(source
, transform
, true, &result
));
432 Calculate8bitBitmapMinMax(result
, &min_gl
, &max_gl
);
434 EXPECT_EQ(0, min_gl
);
435 EXPECT_EQ(255, max_gl
);
436 EXPECT_EQ(max_gl
, SkColorGetA(result
.getColor(0, 0)));
437 EXPECT_EQ(min_gl
, SkColorGetA(result
.getColor(299, 199)));
440 TEST_F(ColorAnalysisTest
, ApplyColorReductionMultiColor
) {
441 // Check with images with multiple colors. This is really different only when
442 // the result is scaled.
443 gfx::Canvas
canvas(gfx::Size(300, 200), 1.0f
, true);
445 // The image consists of vertical non-overlapping stripes 100 pixels wide.
446 canvas
.FillRect(gfx::Rect(0, 0, 100, 200), SkColorSetRGB(100, 0, 0));
447 canvas
.FillRect(gfx::Rect(100, 0, 100, 200), SkColorSetRGB(0, 255, 0));
448 canvas
.FillRect(gfx::Rect(200, 0, 100, 200), SkColorSetRGB(0, 0, 128));
450 skia::GetTopDevice(*canvas
.sk_canvas())->accessBitmap(false);
452 result
.setConfig(SkBitmap::kA8_Config
, 300, 200);
453 result
.allocPixels();
455 gfx::Vector3dF
transform(1.0f
, 0.5f
, 0.1f
);
456 EXPECT_TRUE(ApplyColorReduction(source
, transform
, false, &result
));
459 Calculate8bitBitmapMinMax(result
, &min_gl
, &max_gl
);
460 EXPECT_EQ(12, min_gl
);
461 EXPECT_EQ(127, max_gl
);
462 EXPECT_EQ(min_gl
, SkColorGetA(result
.getColor(299, 199)));
463 EXPECT_EQ(max_gl
, SkColorGetA(result
.getColor(150, 0)));
464 EXPECT_EQ(100U, SkColorGetA(result
.getColor(0, 0)));
466 EXPECT_TRUE(ApplyColorReduction(source
, transform
, true, &result
));
467 Calculate8bitBitmapMinMax(result
, &min_gl
, &max_gl
);
468 EXPECT_EQ(0, min_gl
);
469 EXPECT_EQ(255, max_gl
);
470 EXPECT_EQ(min_gl
, SkColorGetA(result
.getColor(299, 199)));
471 EXPECT_EQ(max_gl
, SkColorGetA(result
.getColor(150, 0)));
472 EXPECT_EQ(193U, SkColorGetA(result
.getColor(0, 0)));
475 TEST_F(ColorAnalysisTest
, ComputePrincipalComponentImageNotComputable
) {
476 SkBitmap source
, result
;
477 source
.setConfig(SkBitmap::kARGB_8888_Config
, 300, 200);
478 result
.setConfig(SkBitmap::kA8_Config
, 300, 200);
480 source
.allocPixels();
481 result
.allocPixels();
482 source
.eraseARGB(255, 50, 150, 200);
484 // This computation should fail since all colors always vary together.
485 EXPECT_FALSE(ComputePrincipalComponentImage(source
, &result
));
488 TEST_F(ColorAnalysisTest
, ComputePrincipalComponentImage
) {
489 gfx::Canvas
canvas(gfx::Size(300, 200), 1.0f
, true);
491 // The image consists of vertical non-overlapping stripes 100 pixels wide.
492 canvas
.FillRect(gfx::Rect(0, 0, 100, 200), SkColorSetRGB(10, 10, 10));
493 canvas
.FillRect(gfx::Rect(100, 0, 100, 200), SkColorSetRGB(100, 100, 100));
494 canvas
.FillRect(gfx::Rect(200, 0, 100, 200), SkColorSetRGB(255, 255, 255));
496 skia::GetTopDevice(*canvas
.sk_canvas())->accessBitmap(false);
498 result
.setConfig(SkBitmap::kA8_Config
, 300, 200);
499 result
.allocPixels();
501 // This computation should fail since all colors always vary together.
502 EXPECT_TRUE(ComputePrincipalComponentImage(source
, &result
));
506 Calculate8bitBitmapMinMax(result
, &min_gl
, &max_gl
);
508 EXPECT_EQ(0, min_gl
);
509 EXPECT_EQ(255, max_gl
);
510 EXPECT_EQ(min_gl
, SkColorGetA(result
.getColor(0, 0)));
511 EXPECT_EQ(max_gl
, SkColorGetA(result
.getColor(299, 199)));
512 EXPECT_EQ(93U, SkColorGetA(result
.getColor(150, 0)));
515 } // namespace color_utils