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 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
128 protected: | 128 protected: |
129 std::vector<int> prebaked_sample_results_; | 129 std::vector<int> prebaked_sample_results_; |
130 size_t current_result_index_; | 130 size_t current_result_index_; |
131 }; | 131 }; |
132 | 132 |
133 // Return true if a color channel is approximately equal to an expected value. | 133 // Return true if a color channel is approximately equal to an expected value. |
134 bool ChannelApproximatelyEqual(int expected, uint8_t channel) { | 134 bool ChannelApproximatelyEqual(int expected, uint8_t channel) { |
135 return (abs(expected - static_cast<int>(channel)) <= 1); | 135 return (abs(expected - static_cast<int>(channel)) <= 1); |
136 } | 136 } |
137 | 137 |
| 138 // Compute minimal and maximal graylevel (or alphalevel) of the input |bitmap|. |
| 139 // |bitmap| has to be allocated and configured to kA8_Config. |
| 140 void Calculate8bitBitmapMinMax(const SkBitmap& bitmap, |
| 141 uint8_t* min_gl, |
| 142 uint8_t* max_gl) { |
| 143 SkAutoLockPixels bitmap_lock(bitmap); |
| 144 DCHECK(bitmap.getPixels()); |
| 145 DCHECK(bitmap.config() == SkBitmap::kA8_Config); |
| 146 DCHECK(min_gl); |
| 147 DCHECK(max_gl); |
| 148 *min_gl = std::numeric_limits<uint8_t>::max(); |
| 149 *max_gl = std::numeric_limits<uint8_t>::min(); |
| 150 for (int y = 0; y < bitmap.height(); ++y) { |
| 151 uint8_t* current_color = bitmap.getAddr8(0, y); |
| 152 for (int x = 0; x < bitmap.width(); ++x, ++current_color) { |
| 153 *min_gl = std::min(*min_gl, *current_color); |
| 154 *max_gl = std::max(*max_gl, *current_color); |
| 155 } |
| 156 } |
| 157 } |
| 158 |
138 } // namespace | 159 } // namespace |
139 | 160 |
140 class ColorAnalysisTest : public testing::Test { | 161 class ColorAnalysisTest : public testing::Test { |
141 }; | 162 }; |
142 | 163 |
143 TEST_F(ColorAnalysisTest, CalculatePNGKMeanAllWhite) { | 164 TEST_F(ColorAnalysisTest, CalculatePNGKMeanAllWhite) { |
144 MockKMeanImageSampler test_sampler; | 165 MockKMeanImageSampler test_sampler; |
145 test_sampler.AddSample(0); | 166 test_sampler.AddSample(0); |
146 | 167 |
147 scoped_refptr<base::RefCountedBytes> png( | 168 scoped_refptr<base::RefCountedBytes> png( |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
286 SkBitmap bitmap = | 307 SkBitmap bitmap = |
287 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); | 308 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); |
288 gfx::Matrix3F covariance = color_utils::ComputeColorCovariance(bitmap); | 309 gfx::Matrix3F covariance = color_utils::ComputeColorCovariance(bitmap); |
289 | 310 |
290 gfx::Matrix3F expected_covariance = gfx::Matrix3F::Zeros(); | 311 gfx::Matrix3F expected_covariance = gfx::Matrix3F::Zeros(); |
291 expected_covariance.set(2400, 400, -1600, | 312 expected_covariance.set(2400, 400, -1600, |
292 400, 2400, 400, | 313 400, 2400, 400, |
293 -1600, 400, 2400); | 314 -1600, 400, 2400); |
294 EXPECT_EQ(expected_covariance, covariance); | 315 EXPECT_EQ(expected_covariance, covariance); |
295 } | 316 } |
| 317 |
| 318 TEST_F(ColorAnalysisTest, ApplyColorReductionSingleColor) { |
| 319 // The test runs color reduction on a single-colot image, where results are |
| 320 // bound to be uninteresting. This is an important edge case, though. |
| 321 SkBitmap source, result; |
| 322 source.setConfig(SkBitmap::kARGB_8888_Config, 300, 200); |
| 323 result.setConfig(SkBitmap::kA8_Config, 300, 200); |
| 324 |
| 325 source.allocPixels(); |
| 326 result.allocPixels(); |
| 327 source.eraseRGB(50, 150, 200); |
| 328 |
| 329 gfx::Vector3dF transform(1.0f, .5f, 0.1f); |
| 330 // This transform, if not scaled, should result in GL=145. |
| 331 EXPECT_TRUE(color_utils::ApplyColorReduction( |
| 332 source, transform, false, &result)); |
| 333 |
| 334 uint8_t min_gl = 0; |
| 335 uint8_t max_gl = 0; |
| 336 Calculate8bitBitmapMinMax(result, &min_gl, &max_gl); |
| 337 EXPECT_EQ(145, min_gl); |
| 338 EXPECT_EQ(145, max_gl); |
| 339 |
| 340 // Now scan requesting rescale. Expect all 0. |
| 341 EXPECT_TRUE(color_utils::ApplyColorReduction( |
| 342 source, transform, true, &result)); |
| 343 Calculate8bitBitmapMinMax(result, &min_gl, &max_gl); |
| 344 EXPECT_EQ(0, min_gl); |
| 345 EXPECT_EQ(0, max_gl); |
| 346 |
| 347 // Test cliping to upper limit. |
| 348 transform.set_z(1.1f); |
| 349 EXPECT_TRUE(color_utils::ApplyColorReduction( |
| 350 source, transform, false, &result)); |
| 351 Calculate8bitBitmapMinMax(result, &min_gl, &max_gl); |
| 352 EXPECT_EQ(0xFF, min_gl); |
| 353 EXPECT_EQ(0xFF, max_gl); |
| 354 |
| 355 // Test cliping to upper limit. |
| 356 transform.Scale(-1.0f); |
| 357 EXPECT_TRUE(color_utils::ApplyColorReduction( |
| 358 source, transform, false, &result)); |
| 359 Calculate8bitBitmapMinMax(result, &min_gl, &max_gl); |
| 360 EXPECT_EQ(0x0, min_gl); |
| 361 EXPECT_EQ(0x0, max_gl); |
| 362 } |
| 363 |
| 364 TEST_F(ColorAnalysisTest, ApplyColorReductionBlackAndWhite) { |
| 365 // Check with images with multiple colors. This is really different only when |
| 366 // the result is scaled. |
| 367 gfx::Canvas canvas(gfx::Size(300, 200), ui::SCALE_FACTOR_100P, true); |
| 368 |
| 369 // The image consists of vertical non-overlapping stripes 150 pixels wide. |
| 370 canvas.FillRect(gfx::Rect(0, 0, 150, 200), SkColorSetRGB(0, 0, 0)); |
| 371 canvas.FillRect(gfx::Rect(150, 0, 150, 200), SkColorSetRGB(255, 255, 255)); |
| 372 SkBitmap source = |
| 373 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); |
| 374 SkBitmap result; |
| 375 result.setConfig(SkBitmap::kA8_Config, 300, 200); |
| 376 result.allocPixels(); |
| 377 |
| 378 gfx::Vector3dF transform(1.0f, 0.5f, 0.1f); |
| 379 EXPECT_TRUE(color_utils::ApplyColorReduction( |
| 380 source, transform, true, &result)); |
| 381 uint8_t min_gl = 0; |
| 382 uint8_t max_gl = 0; |
| 383 Calculate8bitBitmapMinMax(result, &min_gl, &max_gl); |
| 384 |
| 385 EXPECT_EQ(0, min_gl); |
| 386 EXPECT_EQ(255, max_gl); |
| 387 EXPECT_EQ(min_gl, SkColorGetA(result.getColor(0, 0))); |
| 388 EXPECT_EQ(max_gl, SkColorGetA(result.getColor(299, 199))); |
| 389 |
| 390 // Reverse test. |
| 391 transform.Scale(-1.0f); |
| 392 EXPECT_TRUE(color_utils::ApplyColorReduction( |
| 393 source, transform, true, &result)); |
| 394 min_gl = 0; |
| 395 max_gl = 0; |
| 396 Calculate8bitBitmapMinMax(result, &min_gl, &max_gl); |
| 397 |
| 398 EXPECT_EQ(0, min_gl); |
| 399 EXPECT_EQ(255, max_gl); |
| 400 EXPECT_EQ(max_gl, SkColorGetA(result.getColor(0, 0))); |
| 401 EXPECT_EQ(min_gl, SkColorGetA(result.getColor(299, 199))); |
| 402 } |
| 403 |
| 404 TEST_F(ColorAnalysisTest, ApplyColorReductionMultiColor) { |
| 405 // Check with images with multiple colors. This is really different only when |
| 406 // the result is scaled. |
| 407 gfx::Canvas canvas(gfx::Size(300, 200), ui::SCALE_FACTOR_100P, true); |
| 408 |
| 409 // The image consists of vertical non-overlapping stripes 100 pixels wide. |
| 410 canvas.FillRect(gfx::Rect(0, 0, 100, 200), SkColorSetRGB(100, 0, 0)); |
| 411 canvas.FillRect(gfx::Rect(100, 0, 100, 200), SkColorSetRGB(0, 255, 0)); |
| 412 canvas.FillRect(gfx::Rect(200, 0, 100, 200), SkColorSetRGB(0, 0, 128)); |
| 413 SkBitmap source = |
| 414 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); |
| 415 SkBitmap result; |
| 416 result.setConfig(SkBitmap::kA8_Config, 300, 200); |
| 417 result.allocPixels(); |
| 418 |
| 419 gfx::Vector3dF transform(1.0f, 0.5f, 0.1f); |
| 420 EXPECT_TRUE(color_utils::ApplyColorReduction( |
| 421 source, transform, false, &result)); |
| 422 uint8_t min_gl = 0; |
| 423 uint8_t max_gl = 0; |
| 424 Calculate8bitBitmapMinMax(result, &min_gl, &max_gl); |
| 425 EXPECT_EQ(12, min_gl); |
| 426 EXPECT_EQ(127, max_gl); |
| 427 EXPECT_EQ(min_gl, SkColorGetA(result.getColor(299, 199))); |
| 428 EXPECT_EQ(max_gl, SkColorGetA(result.getColor(150, 0))); |
| 429 EXPECT_EQ(100U, SkColorGetA(result.getColor(0, 0))); |
| 430 |
| 431 EXPECT_TRUE(color_utils::ApplyColorReduction( |
| 432 source, transform, true, &result)); |
| 433 Calculate8bitBitmapMinMax(result, &min_gl, &max_gl); |
| 434 EXPECT_EQ(0, min_gl); |
| 435 EXPECT_EQ(255, max_gl); |
| 436 EXPECT_EQ(min_gl, SkColorGetA(result.getColor(299, 199))); |
| 437 EXPECT_EQ(max_gl, SkColorGetA(result.getColor(150, 0))); |
| 438 EXPECT_EQ(193U, SkColorGetA(result.getColor(0, 0))); |
| 439 } |
| 440 |
| 441 TEST_F(ColorAnalysisTest, ComputePrincipalComponentImageNotComputable) { |
| 442 SkBitmap source, result; |
| 443 source.setConfig(SkBitmap::kARGB_8888_Config, 300, 200); |
| 444 result.setConfig(SkBitmap::kA8_Config, 300, 200); |
| 445 |
| 446 source.allocPixels(); |
| 447 result.allocPixels(); |
| 448 source.eraseRGB(50, 150, 200); |
| 449 |
| 450 // This computation should fail since all colors always vary together. |
| 451 EXPECT_FALSE(color_utils::ComputePrincipalComponentImage(source, &result)); |
| 452 } |
| 453 |
| 454 TEST_F(ColorAnalysisTest, ComputePrincipalComponentImage) { |
| 455 gfx::Canvas canvas(gfx::Size(300, 200), ui::SCALE_FACTOR_100P, true); |
| 456 |
| 457 // The image consists of vertical non-overlapping stripes 100 pixels wide. |
| 458 canvas.FillRect(gfx::Rect(0, 0, 100, 200), SkColorSetRGB(10, 10, 10)); |
| 459 canvas.FillRect(gfx::Rect(100, 0, 100, 200), SkColorSetRGB(100, 100, 100)); |
| 460 canvas.FillRect(gfx::Rect(200, 0, 100, 200), SkColorSetRGB(255, 255, 255)); |
| 461 SkBitmap source = |
| 462 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); |
| 463 SkBitmap result; |
| 464 result.setConfig(SkBitmap::kA8_Config, 300, 200); |
| 465 result.allocPixels(); |
| 466 |
| 467 // This computation should fail since all colors always vary together. |
| 468 EXPECT_TRUE(color_utils::ComputePrincipalComponentImage(source, &result)); |
| 469 |
| 470 uint8_t min_gl = 0; |
| 471 uint8_t max_gl = 0; |
| 472 Calculate8bitBitmapMinMax(result, &min_gl, &max_gl); |
| 473 |
| 474 EXPECT_EQ(0, min_gl); |
| 475 EXPECT_EQ(255, max_gl); |
| 476 EXPECT_EQ(min_gl, SkColorGetA(result.getColor(0, 0))); |
| 477 EXPECT_EQ(max_gl, SkColorGetA(result.getColor(299, 199))); |
| 478 EXPECT_EQ(93U, SkColorGetA(result.getColor(150, 0))); |
| 479 } |
OLD | NEW |