| Index: ui/gfx/color_analysis.cc
|
| diff --git a/ui/gfx/color_analysis.cc b/ui/gfx/color_analysis.cc
|
| index 88785197cbadc19690c49491f685d281cd34b34a..f8987cfb546defe1e1ef5b6a2785f00673d8140e 100644
|
| --- a/ui/gfx/color_analysis.cc
|
| +++ b/ui/gfx/color_analysis.cc
|
| @@ -5,6 +5,7 @@
|
| #include "ui/gfx/color_analysis.h"
|
|
|
| #include <algorithm>
|
| +#include <limits>
|
| #include <vector>
|
|
|
| #include "base/logging.h"
|
| @@ -467,4 +468,96 @@ gfx::Matrix3F ComputeColorCovariance(const SkBitmap& bitmap) {
|
| return covariance;
|
| }
|
|
|
| +bool ApplyColorReduction(const SkBitmap& source_bitmap,
|
| + const gfx::Vector3dF& color_transform,
|
| + bool fit_to_range,
|
| + SkBitmap* target_bitmap) {
|
| + DCHECK(target_bitmap);
|
| + SkAutoLockPixels source_lock(source_bitmap);
|
| + SkAutoLockPixels target_lock(*target_bitmap);
|
| +
|
| + DCHECK(source_bitmap.getPixels());
|
| + DCHECK(target_bitmap->getPixels());
|
| + DCHECK_EQ(SkBitmap::kARGB_8888_Config, source_bitmap.config());
|
| + DCHECK_EQ(SkBitmap::kA8_Config, target_bitmap->config());
|
| + DCHECK_EQ(source_bitmap.height(), target_bitmap->height());
|
| + DCHECK_EQ(source_bitmap.width(), target_bitmap->width());
|
| + DCHECK(!source_bitmap.empty());
|
| +
|
| + // Elements of color_transform are explicitly off-loaded to local values for
|
| + // efficiency reasons. Note that in practice images may correspond to entire
|
| + // tab captures.
|
| + float t0 = 0.0;
|
| + float tr = color_transform.x();
|
| + float tg = color_transform.y();
|
| + float tb = color_transform.z();
|
| +
|
| + if (fit_to_range) {
|
| + // We will figure out min/max in a preprocessing step and adjust
|
| + // actual_transform as required.
|
| + float max_val = std::numeric_limits<float>::min();
|
| + float min_val = std::numeric_limits<float>::max();
|
| + for (int y = 0; y < source_bitmap.height(); ++y) {
|
| + const SkPMColor* source_color_row = static_cast<SkPMColor*>(
|
| + source_bitmap.getAddr32(0, y));
|
| + for (int x = 0; x < source_bitmap.width(); ++x) {
|
| + SkColor c = SkUnPreMultiply::PMColorToColor(source_color_row[x]);
|
| + float r = SkColorGetR(c);
|
| + float g = SkColorGetG(c);
|
| + float b = SkColorGetB(c);
|
| + float gray_level = tr * r + tg * g + tb * b;
|
| + max_val = std::max(max_val, gray_level);
|
| + min_val = std::min(min_val, gray_level);
|
| + }
|
| + }
|
| +
|
| + // Adjust the transform so that the result is scaling.
|
| + float scale = 0.0;
|
| + t0 = -min_val;
|
| + if (max_val > min_val)
|
| + scale = 255.0 / (max_val - min_val);
|
| + t0 *= scale;
|
| + tr *= scale;
|
| + tg *= scale;
|
| + tb *= scale;
|
| + }
|
| +
|
| + for (int y = 0; y < source_bitmap.height(); ++y) {
|
| + const SkPMColor* source_color_row = static_cast<SkPMColor*>(
|
| + source_bitmap.getAddr32(0, y));
|
| + uint8_t* target_color_row = target_bitmap->getAddr8(0, y);
|
| + for (int x = 0; x < source_bitmap.width(); ++x) {
|
| + SkColor c = SkUnPreMultiply::PMColorToColor(source_color_row[x]);
|
| + float r = SkColorGetR(c);
|
| + float g = SkColorGetG(c);
|
| + float b = SkColorGetB(c);
|
| +
|
| + float gl = t0 + tr * r + tg * g + tb * b;
|
| + if (gl < 0)
|
| + gl = 0;
|
| + if (gl > 0xFF)
|
| + gl = 0xFF;
|
| + target_color_row[x] = static_cast<uint8_t>(gl);
|
| + }
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool ComputePrincipalComponentImage(const SkBitmap& source_bitmap,
|
| + SkBitmap* target_bitmap) {
|
| + if (!target_bitmap) {
|
| + NOTREACHED();
|
| + return false;
|
| + }
|
| +
|
| + gfx::Matrix3F covariance = ComputeColorCovariance(source_bitmap);
|
| + gfx::Matrix3F eigenvectors = gfx::Matrix3F::Zeros();
|
| + gfx::Vector3dF eigenvals = covariance.SolveEigenproblem(&eigenvectors);
|
| + gfx::Vector3dF principal = eigenvectors.get_column(0);
|
| + if (eigenvals == gfx::Vector3dF() || principal == gfx::Vector3dF())
|
| + return false; // This may happen for some edge cases.
|
| + return ApplyColorReduction(source_bitmap, principal, true, target_bitmap);
|
| +}
|
| +
|
| } // color_utils
|
|
|