OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/gfx/color_analysis.h" | 5 #include "ui/gfx/color_analysis.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "testing/gtest/include/gtest/gtest.h" | 9 #include "testing/gtest/include/gtest/gtest.h" |
10 #include "third_party/skia/include/core/SkBitmap.h" | 10 #include "third_party/skia/include/core/SkBitmap.h" |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
87 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 | 87 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 |
88 }; | 88 }; |
89 | 89 |
90 const HSL kDefaultLowerBound = {-1, -1, 0.15}; | 90 const HSL kDefaultLowerBound = {-1, -1, 0.15}; |
91 const HSL kDefaultUpperBound = {-1, -1, 0.85}; | 91 const HSL kDefaultUpperBound = {-1, -1, 0.85}; |
92 | 92 |
93 // Creates a 1-dimensional png of the pixel colors found in |colors|. | 93 // Creates a 1-dimensional png of the pixel colors found in |colors|. |
94 scoped_refptr<base::RefCountedMemory> CreateTestPNG( | 94 scoped_refptr<base::RefCountedMemory> CreateTestPNG( |
95 const std::vector<SkColor>& colors) { | 95 const std::vector<SkColor>& colors) { |
96 SkBitmap bitmap; | 96 SkBitmap bitmap; |
97 bitmap.setConfig(SkBitmap::kARGB_8888_Config, colors.size(), 1); | 97 bitmap.allocN32Pixels(colors.size(), 1); |
98 bitmap.allocPixels(); | |
99 | 98 |
100 SkAutoLockPixels lock(bitmap); | 99 SkAutoLockPixels lock(bitmap); |
101 for (size_t i = 0; i < colors.size(); ++i) { | 100 for (size_t i = 0; i < colors.size(); ++i) { |
102 bitmap.eraseArea(SkIRect::MakeXYWH(i, 0, 1, 1), colors[i]); | 101 bitmap.eraseArea(SkIRect::MakeXYWH(i, 0, 1, 1), colors[i]); |
103 } | 102 } |
104 return gfx::Image::CreateFrom1xBitmap(bitmap).As1xPNGBytes(); | 103 return gfx::Image::CreateFrom1xBitmap(bitmap).As1xPNGBytes(); |
105 } | 104 } |
106 | 105 |
107 class MockKMeanImageSampler : public KMeanImageSampler { | 106 class MockKMeanImageSampler : public KMeanImageSampler { |
108 public: | 107 public: |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
272 EXPECT_EQ(4 + 10 * kWidth, sampler.GetSample(kWidth, kHeight)); | 271 EXPECT_EQ(4 + 10 * kWidth, sampler.GetSample(kWidth, kHeight)); |
273 } | 272 } |
274 | 273 |
275 TEST_F(ColorAnalysisTest, FindClosestColor) { | 274 TEST_F(ColorAnalysisTest, FindClosestColor) { |
276 // Empty image returns input color. | 275 // Empty image returns input color. |
277 SkColor color = FindClosestColor(NULL, 0, 0, SK_ColorRED); | 276 SkColor color = FindClosestColor(NULL, 0, 0, SK_ColorRED); |
278 EXPECT_EQ(SK_ColorRED, color); | 277 EXPECT_EQ(SK_ColorRED, color); |
279 | 278 |
280 // Single color image returns that color. | 279 // Single color image returns that color. |
281 SkBitmap bitmap; | 280 SkBitmap bitmap; |
282 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 16, 16); | 281 bitmap.allocN32Pixels(16, 16); |
283 bitmap.allocPixels(); | |
284 bitmap.eraseColor(SK_ColorWHITE); | 282 bitmap.eraseColor(SK_ColorWHITE); |
285 color = FindClosestColor(static_cast<uint8_t*>(bitmap.getPixels()), | 283 color = FindClosestColor(static_cast<uint8_t*>(bitmap.getPixels()), |
286 bitmap.width(), | 284 bitmap.width(), |
287 bitmap.height(), | 285 bitmap.height(), |
288 SK_ColorRED); | 286 SK_ColorRED); |
289 EXPECT_EQ(SK_ColorWHITE, color); | 287 EXPECT_EQ(SK_ColorWHITE, color); |
290 | 288 |
291 // Write a black pixel into the image. A dark grey input pixel should match | 289 // Write a black pixel into the image. A dark grey input pixel should match |
292 // the black one in the image. | 290 // the black one in the image. |
293 uint32_t* pixel = bitmap.getAddr32(0, 0); | 291 uint32_t* pixel = bitmap.getAddr32(0, 0); |
294 *pixel = SK_ColorBLACK; | 292 *pixel = SK_ColorBLACK; |
295 color = FindClosestColor(static_cast<uint8_t*>(bitmap.getPixels()), | 293 color = FindClosestColor(static_cast<uint8_t*>(bitmap.getPixels()), |
296 bitmap.width(), | 294 bitmap.width(), |
297 bitmap.height(), | 295 bitmap.height(), |
298 SK_ColorDKGRAY); | 296 SK_ColorDKGRAY); |
299 EXPECT_EQ(SK_ColorBLACK, color); | 297 EXPECT_EQ(SK_ColorBLACK, color); |
300 } | 298 } |
301 | 299 |
302 TEST_F(ColorAnalysisTest, CalculateKMeanColorOfBitmap) { | 300 TEST_F(ColorAnalysisTest, CalculateKMeanColorOfBitmap) { |
303 // Create a 16x16 bitmap to represent a favicon. | 301 // Create a 16x16 bitmap to represent a favicon. |
304 SkBitmap bitmap; | 302 SkBitmap bitmap; |
305 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 16, 16); | 303 bitmap.allocN32Pixels(16, 16); |
306 bitmap.allocPixels(); | |
307 bitmap.eraseARGB(255, 100, 150, 200); | 304 bitmap.eraseARGB(255, 100, 150, 200); |
308 | 305 |
309 SkColor color = CalculateKMeanColorOfBitmap(bitmap); | 306 SkColor color = CalculateKMeanColorOfBitmap(bitmap); |
310 EXPECT_EQ(255u, SkColorGetA(color)); | 307 EXPECT_EQ(255u, SkColorGetA(color)); |
311 // Color values are not exactly equal due to reversal of premultiplied alpha. | 308 // Color values are not exactly equal due to reversal of premultiplied alpha. |
312 EXPECT_TRUE(ChannelApproximatelyEqual(100, SkColorGetR(color))); | 309 EXPECT_TRUE(ChannelApproximatelyEqual(100, SkColorGetR(color))); |
313 EXPECT_TRUE(ChannelApproximatelyEqual(150, SkColorGetG(color))); | 310 EXPECT_TRUE(ChannelApproximatelyEqual(150, SkColorGetG(color))); |
314 EXPECT_TRUE(ChannelApproximatelyEqual(200, SkColorGetB(color))); | 311 EXPECT_TRUE(ChannelApproximatelyEqual(200, SkColorGetB(color))); |
315 | 312 |
316 // Test a bitmap with an alpha channel. | 313 // Test a bitmap with an alpha channel. |
317 bitmap.eraseARGB(128, 100, 150, 200); | 314 bitmap.eraseARGB(128, 100, 150, 200); |
318 color = CalculateKMeanColorOfBitmap(bitmap); | 315 color = CalculateKMeanColorOfBitmap(bitmap); |
319 | 316 |
320 // Alpha channel should be ignored for dominant color calculation. | 317 // Alpha channel should be ignored for dominant color calculation. |
321 EXPECT_EQ(255u, SkColorGetA(color)); | 318 EXPECT_EQ(255u, SkColorGetA(color)); |
322 EXPECT_TRUE(ChannelApproximatelyEqual(100, SkColorGetR(color))); | 319 EXPECT_TRUE(ChannelApproximatelyEqual(100, SkColorGetR(color))); |
323 EXPECT_TRUE(ChannelApproximatelyEqual(150, SkColorGetG(color))); | 320 EXPECT_TRUE(ChannelApproximatelyEqual(150, SkColorGetG(color))); |
324 EXPECT_TRUE(ChannelApproximatelyEqual(200, SkColorGetB(color))); | 321 EXPECT_TRUE(ChannelApproximatelyEqual(200, SkColorGetB(color))); |
325 } | 322 } |
326 | 323 |
327 TEST_F(ColorAnalysisTest, ComputeColorCovarianceTrivial) { | 324 TEST_F(ColorAnalysisTest, ComputeColorCovarianceTrivial) { |
328 SkBitmap bitmap; | 325 SkBitmap bitmap; |
329 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 100, 200); | 326 bitmap.setInfo(SkImageInfo::MakeN32Premul(100, 200)); |
330 | 327 |
331 EXPECT_EQ(gfx::Matrix3F::Zeros(), ComputeColorCovariance(bitmap)); | 328 EXPECT_EQ(gfx::Matrix3F::Zeros(), ComputeColorCovariance(bitmap)); |
332 bitmap.allocPixels(); | 329 bitmap.allocPixels(); |
333 bitmap.eraseARGB(255, 50, 150, 200); | 330 bitmap.eraseARGB(255, 50, 150, 200); |
334 gfx::Matrix3F covariance = ComputeColorCovariance(bitmap); | 331 gfx::Matrix3F covariance = ComputeColorCovariance(bitmap); |
335 // The answer should be all zeros. | 332 // The answer should be all zeros. |
336 EXPECT_TRUE(covariance == gfx::Matrix3F::Zeros()); | 333 EXPECT_TRUE(covariance == gfx::Matrix3F::Zeros()); |
337 } | 334 } |
338 | 335 |
339 TEST_F(ColorAnalysisTest, ComputeColorCovarianceWithCanvas) { | 336 TEST_F(ColorAnalysisTest, ComputeColorCovarianceWithCanvas) { |
(...skipping 14 matching lines...) Expand all Loading... |
354 expected_covariance.set(2400, 400, -1600, | 351 expected_covariance.set(2400, 400, -1600, |
355 400, 2400, 400, | 352 400, 2400, 400, |
356 -1600, 400, 2400); | 353 -1600, 400, 2400); |
357 EXPECT_EQ(expected_covariance, covariance); | 354 EXPECT_EQ(expected_covariance, covariance); |
358 } | 355 } |
359 | 356 |
360 TEST_F(ColorAnalysisTest, ApplyColorReductionSingleColor) { | 357 TEST_F(ColorAnalysisTest, ApplyColorReductionSingleColor) { |
361 // The test runs color reduction on a single-colot image, where results are | 358 // 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. | 359 // bound to be uninteresting. This is an important edge case, though. |
363 SkBitmap source, result; | 360 SkBitmap source, result; |
364 source.setConfig(SkBitmap::kARGB_8888_Config, 300, 200); | 361 source.allocN32Pixels(300, 200); |
365 result.setConfig(SkBitmap::kA8_Config, 300, 200); | 362 result.allocPixels(SkImageInfo::MakeA8(300, 200)); |
366 | 363 |
367 source.allocPixels(); | |
368 result.allocPixels(); | |
369 source.eraseARGB(255, 50, 150, 200); | 364 source.eraseARGB(255, 50, 150, 200); |
370 | 365 |
371 gfx::Vector3dF transform(1.0f, .5f, 0.1f); | 366 gfx::Vector3dF transform(1.0f, .5f, 0.1f); |
372 // This transform, if not scaled, should result in GL=145. | 367 // This transform, if not scaled, should result in GL=145. |
373 EXPECT_TRUE(ApplyColorReduction(source, transform, false, &result)); | 368 EXPECT_TRUE(ApplyColorReduction(source, transform, false, &result)); |
374 | 369 |
375 uint8_t min_gl = 0; | 370 uint8_t min_gl = 0; |
376 uint8_t max_gl = 0; | 371 uint8_t max_gl = 0; |
377 Calculate8bitBitmapMinMax(result, &min_gl, &max_gl); | 372 Calculate8bitBitmapMinMax(result, &min_gl, &max_gl); |
378 EXPECT_EQ(145, min_gl); | 373 EXPECT_EQ(145, min_gl); |
(...skipping 24 matching lines...) Expand all Loading... |
403 // Check with images with multiple colors. This is really different only when | 398 // Check with images with multiple colors. This is really different only when |
404 // the result is scaled. | 399 // the result is scaled. |
405 gfx::Canvas canvas(gfx::Size(300, 200), 1.0f, true); | 400 gfx::Canvas canvas(gfx::Size(300, 200), 1.0f, true); |
406 | 401 |
407 // The image consists of vertical non-overlapping stripes 150 pixels wide. | 402 // The image consists of vertical non-overlapping stripes 150 pixels wide. |
408 canvas.FillRect(gfx::Rect(0, 0, 150, 200), SkColorSetRGB(0, 0, 0)); | 403 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)); | 404 canvas.FillRect(gfx::Rect(150, 0, 150, 200), SkColorSetRGB(255, 255, 255)); |
410 SkBitmap source = | 405 SkBitmap source = |
411 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); | 406 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); |
412 SkBitmap result; | 407 SkBitmap result; |
413 result.setConfig(SkBitmap::kA8_Config, 300, 200); | 408 result.allocPixels(SkImageInfo::MakeA8(300, 200)); |
414 result.allocPixels(); | |
415 | 409 |
416 gfx::Vector3dF transform(1.0f, 0.5f, 0.1f); | 410 gfx::Vector3dF transform(1.0f, 0.5f, 0.1f); |
417 EXPECT_TRUE(ApplyColorReduction(source, transform, true, &result)); | 411 EXPECT_TRUE(ApplyColorReduction(source, transform, true, &result)); |
418 uint8_t min_gl = 0; | 412 uint8_t min_gl = 0; |
419 uint8_t max_gl = 0; | 413 uint8_t max_gl = 0; |
420 Calculate8bitBitmapMinMax(result, &min_gl, &max_gl); | 414 Calculate8bitBitmapMinMax(result, &min_gl, &max_gl); |
421 | 415 |
422 EXPECT_EQ(0, min_gl); | 416 EXPECT_EQ(0, min_gl); |
423 EXPECT_EQ(255, max_gl); | 417 EXPECT_EQ(255, max_gl); |
424 EXPECT_EQ(min_gl, SkColorGetA(result.getColor(0, 0))); | 418 EXPECT_EQ(min_gl, SkColorGetA(result.getColor(0, 0))); |
(...skipping 17 matching lines...) Expand all Loading... |
442 // the result is scaled. | 436 // the result is scaled. |
443 gfx::Canvas canvas(gfx::Size(300, 200), 1.0f, true); | 437 gfx::Canvas canvas(gfx::Size(300, 200), 1.0f, true); |
444 | 438 |
445 // The image consists of vertical non-overlapping stripes 100 pixels wide. | 439 // The image consists of vertical non-overlapping stripes 100 pixels wide. |
446 canvas.FillRect(gfx::Rect(0, 0, 100, 200), SkColorSetRGB(100, 0, 0)); | 440 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)); | 441 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)); | 442 canvas.FillRect(gfx::Rect(200, 0, 100, 200), SkColorSetRGB(0, 0, 128)); |
449 SkBitmap source = | 443 SkBitmap source = |
450 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); | 444 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); |
451 SkBitmap result; | 445 SkBitmap result; |
452 result.setConfig(SkBitmap::kA8_Config, 300, 200); | 446 result.allocPixels(SkImageInfo::MakeA8(300, 200)); |
453 result.allocPixels(); | |
454 | 447 |
455 gfx::Vector3dF transform(1.0f, 0.5f, 0.1f); | 448 gfx::Vector3dF transform(1.0f, 0.5f, 0.1f); |
456 EXPECT_TRUE(ApplyColorReduction(source, transform, false, &result)); | 449 EXPECT_TRUE(ApplyColorReduction(source, transform, false, &result)); |
457 uint8_t min_gl = 0; | 450 uint8_t min_gl = 0; |
458 uint8_t max_gl = 0; | 451 uint8_t max_gl = 0; |
459 Calculate8bitBitmapMinMax(result, &min_gl, &max_gl); | 452 Calculate8bitBitmapMinMax(result, &min_gl, &max_gl); |
460 EXPECT_EQ(12, min_gl); | 453 EXPECT_EQ(12, min_gl); |
461 EXPECT_EQ(127, max_gl); | 454 EXPECT_EQ(127, max_gl); |
462 EXPECT_EQ(min_gl, SkColorGetA(result.getColor(299, 199))); | 455 EXPECT_EQ(min_gl, SkColorGetA(result.getColor(299, 199))); |
463 EXPECT_EQ(max_gl, SkColorGetA(result.getColor(150, 0))); | 456 EXPECT_EQ(max_gl, SkColorGetA(result.getColor(150, 0))); |
464 EXPECT_EQ(100U, SkColorGetA(result.getColor(0, 0))); | 457 EXPECT_EQ(100U, SkColorGetA(result.getColor(0, 0))); |
465 | 458 |
466 EXPECT_TRUE(ApplyColorReduction(source, transform, true, &result)); | 459 EXPECT_TRUE(ApplyColorReduction(source, transform, true, &result)); |
467 Calculate8bitBitmapMinMax(result, &min_gl, &max_gl); | 460 Calculate8bitBitmapMinMax(result, &min_gl, &max_gl); |
468 EXPECT_EQ(0, min_gl); | 461 EXPECT_EQ(0, min_gl); |
469 EXPECT_EQ(255, max_gl); | 462 EXPECT_EQ(255, max_gl); |
470 EXPECT_EQ(min_gl, SkColorGetA(result.getColor(299, 199))); | 463 EXPECT_EQ(min_gl, SkColorGetA(result.getColor(299, 199))); |
471 EXPECT_EQ(max_gl, SkColorGetA(result.getColor(150, 0))); | 464 EXPECT_EQ(max_gl, SkColorGetA(result.getColor(150, 0))); |
472 EXPECT_EQ(193U, SkColorGetA(result.getColor(0, 0))); | 465 EXPECT_EQ(193U, SkColorGetA(result.getColor(0, 0))); |
473 } | 466 } |
474 | 467 |
475 TEST_F(ColorAnalysisTest, ComputePrincipalComponentImageNotComputable) { | 468 TEST_F(ColorAnalysisTest, ComputePrincipalComponentImageNotComputable) { |
476 SkBitmap source, result; | 469 SkBitmap source, result; |
477 source.setConfig(SkBitmap::kARGB_8888_Config, 300, 200); | 470 source.allocN32Pixels(300, 200); |
478 result.setConfig(SkBitmap::kA8_Config, 300, 200); | 471 result.allocPixels(SkImageInfo::MakeA8(300, 200)); |
479 | 472 |
480 source.allocPixels(); | |
481 result.allocPixels(); | |
482 source.eraseARGB(255, 50, 150, 200); | 473 source.eraseARGB(255, 50, 150, 200); |
483 | 474 |
484 // This computation should fail since all colors always vary together. | 475 // This computation should fail since all colors always vary together. |
485 EXPECT_FALSE(ComputePrincipalComponentImage(source, &result)); | 476 EXPECT_FALSE(ComputePrincipalComponentImage(source, &result)); |
486 } | 477 } |
487 | 478 |
488 TEST_F(ColorAnalysisTest, ComputePrincipalComponentImage) { | 479 TEST_F(ColorAnalysisTest, ComputePrincipalComponentImage) { |
489 gfx::Canvas canvas(gfx::Size(300, 200), 1.0f, true); | 480 gfx::Canvas canvas(gfx::Size(300, 200), 1.0f, true); |
490 | 481 |
491 // The image consists of vertical non-overlapping stripes 100 pixels wide. | 482 // The image consists of vertical non-overlapping stripes 100 pixels wide. |
492 canvas.FillRect(gfx::Rect(0, 0, 100, 200), SkColorSetRGB(10, 10, 10)); | 483 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)); | 484 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)); | 485 canvas.FillRect(gfx::Rect(200, 0, 100, 200), SkColorSetRGB(255, 255, 255)); |
495 SkBitmap source = | 486 SkBitmap source = |
496 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); | 487 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); |
497 SkBitmap result; | 488 SkBitmap result; |
498 result.setConfig(SkBitmap::kA8_Config, 300, 200); | 489 result.allocPixels(SkImageInfo::MakeA8(300, 200)); |
499 result.allocPixels(); | |
500 | 490 |
501 // This computation should fail since all colors always vary together. | 491 // This computation should fail since all colors always vary together. |
502 EXPECT_TRUE(ComputePrincipalComponentImage(source, &result)); | 492 EXPECT_TRUE(ComputePrincipalComponentImage(source, &result)); |
503 | 493 |
504 uint8_t min_gl = 0; | 494 uint8_t min_gl = 0; |
505 uint8_t max_gl = 0; | 495 uint8_t max_gl = 0; |
506 Calculate8bitBitmapMinMax(result, &min_gl, &max_gl); | 496 Calculate8bitBitmapMinMax(result, &min_gl, &max_gl); |
507 | 497 |
508 EXPECT_EQ(0, min_gl); | 498 EXPECT_EQ(0, min_gl); |
509 EXPECT_EQ(255, max_gl); | 499 EXPECT_EQ(255, max_gl); |
510 EXPECT_EQ(min_gl, SkColorGetA(result.getColor(0, 0))); | 500 EXPECT_EQ(min_gl, SkColorGetA(result.getColor(0, 0))); |
511 EXPECT_EQ(max_gl, SkColorGetA(result.getColor(299, 199))); | 501 EXPECT_EQ(max_gl, SkColorGetA(result.getColor(299, 199))); |
512 EXPECT_EQ(93U, SkColorGetA(result.getColor(150, 0))); | 502 EXPECT_EQ(93U, SkColorGetA(result.getColor(150, 0))); |
513 } | 503 } |
514 | 504 |
515 } // namespace color_utils | 505 } // namespace color_utils |
OLD | NEW |