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 <algorithm> | 7 #include <algorithm> |
| 8 #include <limits> |
8 #include <vector> | 9 #include <vector> |
9 | 10 |
10 #include "base/logging.h" | 11 #include "base/logging.h" |
11 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
12 #include "third_party/skia/include/core/SkBitmap.h" | 13 #include "third_party/skia/include/core/SkBitmap.h" |
13 #include "third_party/skia/include/core/SkUnPreMultiply.h" | 14 #include "third_party/skia/include/core/SkUnPreMultiply.h" |
14 #include "ui/gfx/codec/png_codec.h" | 15 #include "ui/gfx/codec/png_codec.h" |
15 | 16 |
16 namespace { | 17 namespace { |
17 | 18 |
(...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
460 static_cast<double>(g_sum * b_sum) / pixel_n / pixel_n), | 461 static_cast<double>(g_sum * b_sum) / pixel_n / pixel_n), |
461 (static_cast<double>(rb_sum) / pixel_n - | 462 (static_cast<double>(rb_sum) / pixel_n - |
462 static_cast<double>(r_sum * b_sum) / pixel_n / pixel_n), | 463 static_cast<double>(r_sum * b_sum) / pixel_n / pixel_n), |
463 (static_cast<double>(gb_sum) / pixel_n - | 464 (static_cast<double>(gb_sum) / pixel_n - |
464 static_cast<double>(g_sum * b_sum) / pixel_n / pixel_n), | 465 static_cast<double>(g_sum * b_sum) / pixel_n / pixel_n), |
465 (static_cast<double>(bb_sum) / pixel_n - | 466 (static_cast<double>(bb_sum) / pixel_n - |
466 static_cast<double>(b_sum * b_sum) / pixel_n / pixel_n)); | 467 static_cast<double>(b_sum * b_sum) / pixel_n / pixel_n)); |
467 return covariance; | 468 return covariance; |
468 } | 469 } |
469 | 470 |
| 471 bool ApplyColorReduction(const SkBitmap& source_bitmap, |
| 472 const gfx::Vector3dF& color_transform, |
| 473 bool fit_to_range, |
| 474 SkBitmap* target_bitmap) { |
| 475 DCHECK(target_bitmap); |
| 476 SkAutoLockPixels source_lock(source_bitmap); |
| 477 SkAutoLockPixels target_lock(*target_bitmap); |
| 478 |
| 479 DCHECK(source_bitmap.getPixels()); |
| 480 DCHECK(target_bitmap->getPixels()); |
| 481 DCHECK_EQ(SkBitmap::kARGB_8888_Config, source_bitmap.config()); |
| 482 DCHECK_EQ(SkBitmap::kA8_Config, target_bitmap->config()); |
| 483 DCHECK_EQ(source_bitmap.height(), target_bitmap->height()); |
| 484 DCHECK_EQ(source_bitmap.width(), target_bitmap->width()); |
| 485 DCHECK(!source_bitmap.empty()); |
| 486 |
| 487 // Elements of color_transform are explicitly off-loaded to local values for |
| 488 // efficiency reasons. Note that in practice images may correspond to entire |
| 489 // tab captures. |
| 490 float t0 = 0.0; |
| 491 float tr = color_transform.x(); |
| 492 float tg = color_transform.y(); |
| 493 float tb = color_transform.z(); |
| 494 |
| 495 if (fit_to_range) { |
| 496 // We will figure out min/max in a preprocessing step and adjust |
| 497 // actual_transform as required. |
| 498 float max_val = std::numeric_limits<float>::min(); |
| 499 float min_val = std::numeric_limits<float>::max(); |
| 500 for (int y = 0; y < source_bitmap.height(); ++y) { |
| 501 const SkPMColor* source_color_row = static_cast<SkPMColor*>( |
| 502 source_bitmap.getAddr32(0, y)); |
| 503 for (int x = 0; x < source_bitmap.width(); ++x) { |
| 504 SkColor c = SkUnPreMultiply::PMColorToColor(source_color_row[x]); |
| 505 float r = SkColorGetR(c); |
| 506 float g = SkColorGetG(c); |
| 507 float b = SkColorGetB(c); |
| 508 float gray_level = tr * r + tg * g + tb * b; |
| 509 max_val = std::max(max_val, gray_level); |
| 510 min_val = std::min(min_val, gray_level); |
| 511 } |
| 512 } |
| 513 |
| 514 // Adjust the transform so that the result is scaling. |
| 515 float scale = 0.0; |
| 516 t0 = -min_val; |
| 517 if (max_val > min_val) |
| 518 scale = 255.0 / (max_val - min_val); |
| 519 t0 *= scale; |
| 520 tr *= scale; |
| 521 tg *= scale; |
| 522 tb *= scale; |
| 523 } |
| 524 |
| 525 for (int y = 0; y < source_bitmap.height(); ++y) { |
| 526 const SkPMColor* source_color_row = static_cast<SkPMColor*>( |
| 527 source_bitmap.getAddr32(0, y)); |
| 528 uint8_t* target_color_row = target_bitmap->getAddr8(0, y); |
| 529 for (int x = 0; x < source_bitmap.width(); ++x) { |
| 530 SkColor c = SkUnPreMultiply::PMColorToColor(source_color_row[x]); |
| 531 float r = SkColorGetR(c); |
| 532 float g = SkColorGetG(c); |
| 533 float b = SkColorGetB(c); |
| 534 |
| 535 float gl = t0 + tr * r + tg * g + tb * b; |
| 536 if (gl < 0) |
| 537 gl = 0; |
| 538 if (gl > 0xFF) |
| 539 gl = 0xFF; |
| 540 target_color_row[x] = static_cast<uint8_t>(gl); |
| 541 } |
| 542 } |
| 543 |
| 544 return true; |
| 545 } |
| 546 |
| 547 bool ComputePrincipalComponentImage(const SkBitmap& source_bitmap, |
| 548 SkBitmap* target_bitmap) { |
| 549 if (!target_bitmap) { |
| 550 NOTREACHED(); |
| 551 return false; |
| 552 } |
| 553 |
| 554 gfx::Matrix3F covariance = ComputeColorCovariance(source_bitmap); |
| 555 gfx::Matrix3F eigenvectors = gfx::Matrix3F::Zeros(); |
| 556 gfx::Vector3dF eigenvals = covariance.SolveEigenproblem(&eigenvectors); |
| 557 gfx::Vector3dF principal = eigenvectors.get_column(0); |
| 558 if (eigenvals == gfx::Vector3dF() || principal == gfx::Vector3dF()) |
| 559 return false; // This may happen for some edge cases. |
| 560 return ApplyColorReduction(source_bitmap, principal, true, target_bitmap); |
| 561 } |
| 562 |
470 } // color_utils | 563 } // color_utils |
OLD | NEW |