Index: ui/gfx/color_utils.cc |
diff --git a/ui/gfx/color_utils.cc b/ui/gfx/color_utils.cc |
index 07980d84d8c2cc37d832e3efe3e303a9afd10362..a7b91aea66d1e9b0c18d452d6615c93d8ae8de8e 100644 |
--- a/ui/gfx/color_utils.cc |
+++ b/ui/gfx/color_utils.cc |
@@ -10,6 +10,7 @@ |
#endif |
#include <algorithm> |
+#include <limits> |
#include "base/basictypes.h" |
#include "base/logging.h" |
@@ -18,6 +19,10 @@ |
#include "skia/ext/skia_utils_win.h" |
#endif |
#include "third_party/skia/include/core/SkBitmap.h" |
+#include "third_party/skia/include/core/SkUnPreMultiply.h" |
+#include "ui/gfx/color_analysis.h" |
+#include "ui/gfx/matrix3_f.h" |
+#include "ui/gfx/vector3d_f.h" |
namespace color_utils { |
@@ -261,4 +266,97 @@ SkColor GetSysSkColor(int which) { |
#endif |
} |
+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(source_bitmap.config() == SkBitmap::kARGB_8888_Config); |
Alexei Svitkine (slow)
2013/02/22 02:24:06
I am assuming DCHECK_EQ() results in a compile fai
motek.
2013/02/22 15:42:56
Done.
|
+ DCHECK(target_bitmap->config() == SkBitmap::kA8_Config); |
+ DCHECK_EQ(source_bitmap.height(), target_bitmap->height()); |
+ DCHECK_EQ(source_bitmap.width(), target_bitmap->width()); |
+ |
+ DCHECK(source_bitmap.height() > 0 && source_bitmap.width() > 0); |
Alexei Svitkine (slow)
2013/02/22 02:24:06
Nit: DCHECK(!source_bitmap.empty()) instead
motek.
2013/02/22 15:42:56
Done.
|
+ |
+ // 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) { |
+ SkPMColor* current_color = static_cast<SkPMColor*>( |
+ source_bitmap.getAddr32(0, y)); |
+ for (int x = 0; x < source_bitmap.width(); ++x, ++current_color) { |
+ SkColor c = SkUnPreMultiply::PMColorToColor(*current_color); |
+ 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) { |
+ SkPMColor* current_color = static_cast<SkPMColor*>( |
Alexei Svitkine (slow)
2013/02/22 02:24:06
Nit: How about |source_color_row| and make it cons
motek.
2013/02/22 15:42:56
Done.
|
+ source_bitmap.getAddr32(0, y)); |
+ uint8_t* target_color = target_bitmap->getAddr8(0, y); |
Alexei Svitkine (slow)
2013/02/22 02:24:06
Nit: How about |target_color_row|
Here and in the
motek.
2013/02/22 15:42:56
Done.
|
+ for (int x = 0; x < source_bitmap.width(); ++x, ++current_color) { |
+ SkColor c = SkUnPreMultiply::PMColorToColor(*current_color); |
Alexei Svitkine (slow)
2013/02/22 02:24:06
Nit: How about source_color_row[x] instead of doin
motek.
2013/02/22 15:42:56
Done.
|
+ 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[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); |
+} |
+ |
} // namespace color_utils |