| 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 <limits.h> | 7 #include <limits.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 uint32_t counter_; | 133 uint32_t counter_; |
| 134 | 134 |
| 135 // The weight of the cluster, determined by how many points were used | 135 // The weight of the cluster, determined by how many points were used |
| 136 // to generate the previous centroid. | 136 // to generate the previous centroid. |
| 137 uint32_t weight_; | 137 uint32_t weight_; |
| 138 }; | 138 }; |
| 139 | 139 |
| 140 // Un-premultiplies each pixel in |bitmap| into an output |buffer|. Requires | 140 // Un-premultiplies each pixel in |bitmap| into an output |buffer|. Requires |
| 141 // approximately 10 microseconds for a 16x16 icon on an Intel Core i5. | 141 // approximately 10 microseconds for a 16x16 icon on an Intel Core i5. |
| 142 void UnPreMultiply(const SkBitmap& bitmap, uint32_t* buffer, int buffer_size) { | 142 void UnPreMultiply(const SkBitmap& bitmap, uint32_t* buffer, int buffer_size) { |
| 143 SkAutoLockPixels auto_lock(bitmap); | |
| 144 uint32_t* in = static_cast<uint32_t*>(bitmap.getPixels()); | 143 uint32_t* in = static_cast<uint32_t*>(bitmap.getPixels()); |
| 145 uint32_t* out = buffer; | 144 uint32_t* out = buffer; |
| 146 int pixel_count = std::min(bitmap.width() * bitmap.height(), buffer_size); | 145 int pixel_count = std::min(bitmap.width() * bitmap.height(), buffer_size); |
| 147 for (int i = 0; i < pixel_count; ++i) | 146 for (int i = 0; i < pixel_count; ++i) |
| 148 *out++ = SkUnPreMultiply::PMColorToColor(*in++); | 147 *out++ = SkUnPreMultiply::PMColorToColor(*in++); |
| 149 } | 148 } |
| 150 | 149 |
| 151 // Prominent color utilities --------------------------------------------------- | 150 // Prominent color utilities --------------------------------------------------- |
| 152 | 151 |
| 153 // A color value with an associated weight. | 152 // A color value with an associated weight. |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 // different color profiles. | 356 // different color profiles. |
| 358 // * This code doesn't try to heuristically derive missing colors from | 357 // * This code doesn't try to heuristically derive missing colors from |
| 359 // existing colors. | 358 // existing colors. |
| 360 SkColor CalculateProminentColor(const SkBitmap& bitmap, | 359 SkColor CalculateProminentColor(const SkBitmap& bitmap, |
| 361 const HSL& lower_bound, | 360 const HSL& lower_bound, |
| 362 const HSL& upper_bound, | 361 const HSL& upper_bound, |
| 363 const HSL& goal) { | 362 const HSL& goal) { |
| 364 DCHECK(!bitmap.empty()); | 363 DCHECK(!bitmap.empty()); |
| 365 DCHECK(!bitmap.isNull()); | 364 DCHECK(!bitmap.isNull()); |
| 366 | 365 |
| 367 SkAutoLockPixels auto_lock(bitmap); | |
| 368 const uint32_t* pixels = static_cast<uint32_t*>(bitmap.getPixels()); | 366 const uint32_t* pixels = static_cast<uint32_t*>(bitmap.getPixels()); |
| 369 const int pixel_count = bitmap.width() * bitmap.height(); | 367 const int pixel_count = bitmap.width() * bitmap.height(); |
| 370 | 368 |
| 371 // For better performance, only consider at most 10k pixels (evenly | 369 // For better performance, only consider at most 10k pixels (evenly |
| 372 // distributed throughout the image). This has a very minor impact on the | 370 // distributed throughout the image). This has a very minor impact on the |
| 373 // outcome but improves runtime substantially for large images. 10,007 is a | 371 // outcome but improves runtime substantially for large images. 10,007 is a |
| 374 // prime number to reduce the chance of picking an unrepresentative sample. | 372 // prime number to reduce the chance of picking an unrepresentative sample. |
| 375 constexpr int kMaxConsideredPixels = 10007; | 373 constexpr int kMaxConsideredPixels = 10007; |
| 376 const int pixel_increment = std::max(1, pixel_count / kMaxConsideredPixels); | 374 const int pixel_increment = std::max(1, pixel_count / kMaxConsideredPixels); |
| 377 std::unordered_map<SkColor, int> color_counts(kMaxConsideredPixels); | 375 std::unordered_map<SkColor, int> color_counts(kMaxConsideredPixels); |
| (...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 771 upper_bound.s = 0.4f; | 769 upper_bound.s = 0.4f; |
| 772 goal.s = 0.3f; | 770 goal.s = 0.3f; |
| 773 break; | 771 break; |
| 774 } | 772 } |
| 775 | 773 |
| 776 return CalculateProminentColor(bitmap, lower_bound, upper_bound, goal); | 774 return CalculateProminentColor(bitmap, lower_bound, upper_bound, goal); |
| 777 } | 775 } |
| 778 | 776 |
| 779 gfx::Matrix3F ComputeColorCovariance(const SkBitmap& bitmap) { | 777 gfx::Matrix3F ComputeColorCovariance(const SkBitmap& bitmap) { |
| 780 // First need basic stats to normalize each channel separately. | 778 // First need basic stats to normalize each channel separately. |
| 781 SkAutoLockPixels bitmap_lock(bitmap); | |
| 782 gfx::Matrix3F covariance = gfx::Matrix3F::Zeros(); | 779 gfx::Matrix3F covariance = gfx::Matrix3F::Zeros(); |
| 783 if (!bitmap.getPixels()) | 780 if (!bitmap.getPixels()) |
| 784 return covariance; | 781 return covariance; |
| 785 | 782 |
| 786 // Assume ARGB_8888 format. | 783 // Assume ARGB_8888 format. |
| 787 DCHECK(bitmap.colorType() == kN32_SkColorType); | 784 DCHECK(bitmap.colorType() == kN32_SkColorType); |
| 788 | 785 |
| 789 int64_t r_sum = 0; | 786 int64_t r_sum = 0; |
| 790 int64_t g_sum = 0; | 787 int64_t g_sum = 0; |
| 791 int64_t b_sum = 0; | 788 int64_t b_sum = 0; |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 850 static_cast<double>(bb_sum) / pixel_n - | 847 static_cast<double>(bb_sum) / pixel_n - |
| 851 static_cast<double>(b_sum * b_sum) / pixel_n / pixel_n)); | 848 static_cast<double>(b_sum * b_sum) / pixel_n / pixel_n)); |
| 852 return covariance; | 849 return covariance; |
| 853 } | 850 } |
| 854 | 851 |
| 855 bool ApplyColorReduction(const SkBitmap& source_bitmap, | 852 bool ApplyColorReduction(const SkBitmap& source_bitmap, |
| 856 const gfx::Vector3dF& color_transform, | 853 const gfx::Vector3dF& color_transform, |
| 857 bool fit_to_range, | 854 bool fit_to_range, |
| 858 SkBitmap* target_bitmap) { | 855 SkBitmap* target_bitmap) { |
| 859 DCHECK(target_bitmap); | 856 DCHECK(target_bitmap); |
| 860 SkAutoLockPixels source_lock(source_bitmap); | |
| 861 SkAutoLockPixels target_lock(*target_bitmap); | |
| 862 | |
| 863 DCHECK(source_bitmap.getPixels()); | 857 DCHECK(source_bitmap.getPixels()); |
| 864 DCHECK(target_bitmap->getPixels()); | 858 DCHECK(target_bitmap->getPixels()); |
| 865 DCHECK_EQ(kN32_SkColorType, source_bitmap.colorType()); | 859 DCHECK_EQ(kN32_SkColorType, source_bitmap.colorType()); |
| 866 DCHECK_EQ(kAlpha_8_SkColorType, target_bitmap->colorType()); | 860 DCHECK_EQ(kAlpha_8_SkColorType, target_bitmap->colorType()); |
| 867 DCHECK_EQ(source_bitmap.height(), target_bitmap->height()); | 861 DCHECK_EQ(source_bitmap.height(), target_bitmap->height()); |
| 868 DCHECK_EQ(source_bitmap.width(), target_bitmap->width()); | 862 DCHECK_EQ(source_bitmap.width(), target_bitmap->width()); |
| 869 DCHECK(!source_bitmap.empty()); | 863 DCHECK(!source_bitmap.empty()); |
| 870 | 864 |
| 871 // Elements of color_transform are explicitly off-loaded to local values for | 865 // Elements of color_transform are explicitly off-loaded to local values for |
| 872 // efficiency reasons. Note that in practice images may correspond to entire | 866 // efficiency reasons. Note that in practice images may correspond to entire |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 938 gfx::Matrix3F covariance = ComputeColorCovariance(source_bitmap); | 932 gfx::Matrix3F covariance = ComputeColorCovariance(source_bitmap); |
| 939 gfx::Matrix3F eigenvectors = gfx::Matrix3F::Zeros(); | 933 gfx::Matrix3F eigenvectors = gfx::Matrix3F::Zeros(); |
| 940 gfx::Vector3dF eigenvals = covariance.SolveEigenproblem(&eigenvectors); | 934 gfx::Vector3dF eigenvals = covariance.SolveEigenproblem(&eigenvectors); |
| 941 gfx::Vector3dF principal = eigenvectors.get_column(0); | 935 gfx::Vector3dF principal = eigenvectors.get_column(0); |
| 942 if (eigenvals == gfx::Vector3dF() || principal == gfx::Vector3dF()) | 936 if (eigenvals == gfx::Vector3dF() || principal == gfx::Vector3dF()) |
| 943 return false; // This may happen for some edge cases. | 937 return false; // This may happen for some edge cases. |
| 944 return ApplyColorReduction(source_bitmap, principal, true, target_bitmap); | 938 return ApplyColorReduction(source_bitmap, principal, true, target_bitmap); |
| 945 } | 939 } |
| 946 | 940 |
| 947 } // color_utils | 941 } // color_utils |
| OLD | NEW |