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 |