color_analysis_unittest.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  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
  3. // found in the LICENSE file.
  4. #include "ui/gfx/color_analysis.h"
  5. #include <stddef.h>
  6. #include <stdint.h>
  7. #include <exception>
  8. #include <vector>
  9. #include "base/bind.h"
  10. #include "skia/ext/platform_canvas.h"
  11. #include "testing/gtest/include/gtest/gtest.h"
  12. #include "third_party/skia/include/core/SkBitmap.h"
  13. #include "ui/gfx/canvas.h"
  14. #include "ui/gfx/color_utils.h"
  15. #include "ui/gfx/geometry/rect.h"
  16. #include "ui/gfx/image/image.h"
  17. namespace color_utils {
  18. const unsigned char k1x1White[] = {
  19. 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
  20. 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
  21. 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
  22. 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53,
  23. 0xde, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
  24. 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
  25. 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00,
  26. 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00,
  27. 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74,
  28. 0x49, 0x4d, 0x45, 0x07, 0xdb, 0x02, 0x11, 0x15,
  29. 0x16, 0x1b, 0xaa, 0x58, 0x38, 0x76, 0x00, 0x00,
  30. 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f,
  31. 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x43, 0x72,
  32. 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69,
  33. 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57,
  34. 0x81, 0x0e, 0x17, 0x00, 0x00, 0x00, 0x0c, 0x49,
  35. 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0xf8, 0xff,
  36. 0xff, 0x3f, 0x00, 0x05, 0xfe, 0x02, 0xfe, 0xdc,
  37. 0xcc, 0x59, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x49,
  38. 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
  39. };
  40. const unsigned char k1x3BlueWhite[] = {
  41. 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
  42. 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
  43. 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03,
  44. 0x08, 0x02, 0x00, 0x00, 0x00, 0xdd, 0xbf, 0xf2,
  45. 0xd5, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
  46. 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
  47. 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00,
  48. 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00,
  49. 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74,
  50. 0x49, 0x4d, 0x45, 0x07, 0xdb, 0x02, 0x12, 0x01,
  51. 0x0a, 0x2c, 0xfd, 0x08, 0x64, 0x66, 0x00, 0x00,
  52. 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f,
  53. 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x43, 0x72,
  54. 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69,
  55. 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57,
  56. 0x81, 0x0e, 0x17, 0x00, 0x00, 0x00, 0x14, 0x49,
  57. 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0xf8, 0xff,
  58. 0xff, 0x3f, 0x13, 0x03, 0x03, 0x03, 0x03, 0x03,
  59. 0xc3, 0x7f, 0x00, 0x1e, 0xfd, 0x03, 0xff, 0xde,
  60. 0x72, 0x58, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x49,
  61. 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
  62. };
  63. const unsigned char k1x3BlueRed[] = {
  64. 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
  65. 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
  66. 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03,
  67. 0x08, 0x02, 0x00, 0x00, 0x00, 0xdd, 0xbf, 0xf2,
  68. 0xd5, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
  69. 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
  70. 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00,
  71. 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00,
  72. 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74,
  73. 0x49, 0x4d, 0x45, 0x07, 0xdb, 0x02, 0x12, 0x01,
  74. 0x07, 0x09, 0x03, 0xa2, 0xce, 0x6c, 0x00, 0x00,
  75. 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f,
  76. 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x43, 0x72,
  77. 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69,
  78. 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57,
  79. 0x81, 0x0e, 0x17, 0x00, 0x00, 0x00, 0x14, 0x49,
  80. 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0xf8, 0xcf,
  81. 0xc0, 0xc0, 0xc4, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
  82. 0xf0, 0x1f, 0x00, 0x0c, 0x10, 0x02, 0x01, 0x2c,
  83. 0x8f, 0x8b, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x49,
  84. 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
  85. };
  86. const HSL kDefaultLowerBound = {-1, -1, 0.15};
  87. const HSL kDefaultUpperBound = {-1, -1, 0.85};
  88. // Creates a 1-dimensional png of the pixel colors found in |colors|.
  89. scoped_refptr<base::RefCountedMemory> CreateTestPNG(
  90. const std::vector<SkColor>& colors) {
  91. SkBitmap bitmap;
  92. bitmap.allocN32Pixels(colors.size(), 1);
  93. for (size_t i = 0; i < colors.size(); ++i) {
  94. bitmap.eraseArea(SkIRect::MakeXYWH(i, 0, 1, 1), colors[i]);
  95. }
  96. return gfx::Image::CreateFrom1xBitmap(bitmap).As1xPNGBytes();
  97. }
  98. class MockKMeanImageSampler : public KMeanImageSampler {
  99. public:
  100. MockKMeanImageSampler() : current_result_index_(0) {
  101. }
  102. explicit MockKMeanImageSampler(const std::vector<int>& samples)
  103. : prebaked_sample_results_(samples),
  104. current_result_index_(0) {
  105. }
  106. ~MockKMeanImageSampler() override {}
  107. void AddSample(int sample) {
  108. prebaked_sample_results_.push_back(sample);
  109. }
  110. int GetSample(int width, int height) override {
  111. if (current_result_index_ >= prebaked_sample_results_.size()) {
  112. current_result_index_ = 0;
  113. }
  114. if (prebaked_sample_results_.empty()) {
  115. return 0;
  116. }
  117. return prebaked_sample_results_[current_result_index_++];
  118. }
  119. protected:
  120. std::vector<int> prebaked_sample_results_;
  121. size_t current_result_index_;
  122. };
  123. // Return true if a color channel is approximately equal to an expected value.
  124. bool ChannelApproximatelyEqual(int expected, uint8_t channel) {
  125. return (abs(expected - static_cast<int>(channel)) <= 1);
  126. }
  127. class ColorAnalysisTest : public testing::Test {
  128. };
  129. TEST_F(ColorAnalysisTest, CalculatePNGKMeanAllWhite) {
  130. MockKMeanImageSampler test_sampler;
  131. test_sampler.AddSample(0);
  132. scoped_refptr<base::RefCountedBytes> png(
  133. new base::RefCountedBytes(
  134. std::vector<unsigned char>(
  135. k1x1White,
  136. k1x1White + sizeof(k1x1White) / sizeof(unsigned char))));
  137. SkColor color = CalculateKMeanColorOfPNG(
  138. png, kDefaultLowerBound, kDefaultUpperBound, &test_sampler);
  139. EXPECT_EQ(color, SK_ColorWHITE);
  140. }
  141. TEST_F(ColorAnalysisTest, CalculatePNGKMeanIgnoreWhiteLightness) {
  142. MockKMeanImageSampler test_sampler;
  143. test_sampler.AddSample(0);
  144. test_sampler.AddSample(1);
  145. test_sampler.AddSample(2);
  146. scoped_refptr<base::RefCountedBytes> png(
  147. new base::RefCountedBytes(
  148. std::vector<unsigned char>(
  149. k1x3BlueWhite,
  150. k1x3BlueWhite + sizeof(k1x3BlueWhite) / sizeof(unsigned char))));
  151. SkColor color = CalculateKMeanColorOfPNG(
  152. png, kDefaultLowerBound, kDefaultUpperBound, &test_sampler);
  153. EXPECT_EQ(SkColorSetARGB(0xFF, 0x00, 0x00, 0xFF), color);
  154. }
  155. TEST_F(ColorAnalysisTest, CalculatePNGKMeanPickMostCommon) {
  156. MockKMeanImageSampler test_sampler;
  157. test_sampler.AddSample(0);
  158. test_sampler.AddSample(1);
  159. test_sampler.AddSample(2);
  160. scoped_refptr<base::RefCountedBytes> png(
  161. new base::RefCountedBytes(
  162. std::vector<unsigned char>(
  163. k1x3BlueRed,
  164. k1x3BlueRed + sizeof(k1x3BlueRed) / sizeof(unsigned char))));
  165. SkColor color = CalculateKMeanColorOfPNG(
  166. png, kDefaultLowerBound, kDefaultUpperBound, &test_sampler);
  167. EXPECT_EQ(SkColorSetARGB(0xFF, 0xFF, 0x00, 0x00), color);
  168. }
  169. TEST_F(ColorAnalysisTest, CalculatePNGKMeanIgnoreRedHue) {
  170. MockKMeanImageSampler test_sampler;
  171. test_sampler.AddSample(0);
  172. test_sampler.AddSample(1);
  173. test_sampler.AddSample(2);
  174. std::vector<SkColor> colors(4, SK_ColorRED);
  175. colors[1] = SK_ColorBLUE;
  176. scoped_refptr<base::RefCountedMemory> png = CreateTestPNG(colors);
  177. HSL lower = {0.2, -1, 0.15};
  178. HSL upper = {0.8, -1, 0.85};
  179. SkColor color = CalculateKMeanColorOfPNG(
  180. png, lower, upper, &test_sampler);
  181. EXPECT_EQ(SK_ColorBLUE, color);
  182. }
  183. TEST_F(ColorAnalysisTest, CalculatePNGKMeanIgnoreGreySaturation) {
  184. MockKMeanImageSampler test_sampler;
  185. test_sampler.AddSample(0);
  186. test_sampler.AddSample(1);
  187. test_sampler.AddSample(2);
  188. std::vector<SkColor> colors(4, SK_ColorGRAY);
  189. colors[1] = SK_ColorBLUE;
  190. scoped_refptr<base::RefCountedMemory> png = CreateTestPNG(colors);
  191. HSL lower = {-1, 0.3, -1};
  192. HSL upper = {-1, 1, -1};
  193. SkColor color = CalculateKMeanColorOfPNG(
  194. png, lower, upper, &test_sampler);
  195. EXPECT_EQ(SK_ColorBLUE, color);
  196. }
  197. TEST_F(ColorAnalysisTest, GridSampler) {
  198. GridSampler sampler;
  199. const int kWidth = 16;
  200. const int kHeight = 16;
  201. // Sample starts at 1,1.
  202. EXPECT_EQ(1 + 1 * kWidth, sampler.GetSample(kWidth, kHeight));
  203. EXPECT_EQ(1 + 4 * kWidth, sampler.GetSample(kWidth, kHeight));
  204. EXPECT_EQ(1 + 7 * kWidth, sampler.GetSample(kWidth, kHeight));
  205. EXPECT_EQ(1 + 10 * kWidth, sampler.GetSample(kWidth, kHeight));
  206. // Step over by 3.
  207. EXPECT_EQ(4 + 1 * kWidth, sampler.GetSample(kWidth, kHeight));
  208. EXPECT_EQ(4 + 4 * kWidth, sampler.GetSample(kWidth, kHeight));
  209. EXPECT_EQ(4 + 7 * kWidth, sampler.GetSample(kWidth, kHeight));
  210. EXPECT_EQ(4 + 10 * kWidth, sampler.GetSample(kWidth, kHeight));
  211. }
  212. TEST_F(ColorAnalysisTest, FindClosestColor) {
  213. // Empty image returns input color.
  214. SkColor color = FindClosestColor(NULL, 0, 0, SK_ColorRED);
  215. EXPECT_EQ(SK_ColorRED, color);
  216. // Single color image returns that color.
  217. SkBitmap bitmap;
  218. bitmap.allocN32Pixels(16, 16);
  219. bitmap.eraseColor(SK_ColorWHITE);
  220. color = FindClosestColor(static_cast<uint8_t*>(bitmap.getPixels()),
  221. bitmap.width(),
  222. bitmap.height(),
  223. SK_ColorRED);
  224. EXPECT_EQ(SK_ColorWHITE, color);
  225. // Write a black pixel into the image. A dark grey input pixel should match
  226. // the black one in the image.
  227. uint32_t* pixel = bitmap.getAddr32(0, 0);
  228. *pixel = SK_ColorBLACK;
  229. color = FindClosestColor(static_cast<uint8_t*>(bitmap.getPixels()),
  230. bitmap.width(),
  231. bitmap.height(),
  232. SK_ColorDKGRAY);
  233. EXPECT_EQ(SK_ColorBLACK, color);
  234. }
  235. TEST_F(ColorAnalysisTest, CalculateKMeanColorOfBitmap) {
  236. // Create a 16x16 bitmap to represent a favicon.
  237. SkBitmap bitmap;
  238. bitmap.allocN32Pixels(16, 16);
  239. bitmap.eraseARGB(255, 100, 150, 200);
  240. SkColor color = CalculateKMeanColorOfBitmap(bitmap);
  241. EXPECT_EQ(255u, SkColorGetA(color));
  242. // Color values are not exactly equal due to reversal of premultiplied alpha.
  243. EXPECT_TRUE(ChannelApproximatelyEqual(100, SkColorGetR(color)));
  244. EXPECT_TRUE(ChannelApproximatelyEqual(150, SkColorGetG(color)));
  245. EXPECT_TRUE(ChannelApproximatelyEqual(200, SkColorGetB(color)));
  246. // Test a bitmap with an alpha channel.
  247. bitmap.eraseARGB(128, 100, 150, 200);
  248. color = CalculateKMeanColorOfBitmap(bitmap);
  249. // Alpha channel should be ignored for dominant color calculation.
  250. EXPECT_EQ(255u, SkColorGetA(color));
  251. EXPECT_TRUE(ChannelApproximatelyEqual(100, SkColorGetR(color)));
  252. EXPECT_TRUE(ChannelApproximatelyEqual(150, SkColorGetG(color)));
  253. EXPECT_TRUE(ChannelApproximatelyEqual(200, SkColorGetB(color)));
  254. }
  255. // Regression test for heap-buffer-underflow. https://crbug.com/970343
  256. TEST_F(ColorAnalysisTest, CalculateKMeanColorOfSmallImage) {
  257. SkBitmap bitmap;
  258. // Create a 1x41 bitmap, so it is not wide enough to have 1 pixel of padding
  259. // on both sides.
  260. bitmap.allocN32Pixels(1, 41);
  261. bitmap.eraseARGB(255, 100, 150, 200);
  262. SkColor color = CalculateKMeanColorOfBitmap(bitmap);
  263. EXPECT_EQ(255u, SkColorGetA(color));
  264. EXPECT_TRUE(ChannelApproximatelyEqual(100, SkColorGetR(color)));
  265. EXPECT_TRUE(ChannelApproximatelyEqual(150, SkColorGetG(color)));
  266. EXPECT_TRUE(ChannelApproximatelyEqual(200, SkColorGetB(color)));
  267. // Test a wide but narrow bitmap.
  268. bitmap.allocN32Pixels(41, 1);
  269. bitmap.eraseARGB(255, 100, 150, 200);
  270. color = CalculateKMeanColorOfBitmap(bitmap);
  271. EXPECT_EQ(255u, SkColorGetA(color));
  272. EXPECT_TRUE(ChannelApproximatelyEqual(100, SkColorGetR(color)));
  273. EXPECT_TRUE(ChannelApproximatelyEqual(150, SkColorGetG(color)));
  274. EXPECT_TRUE(ChannelApproximatelyEqual(200, SkColorGetB(color)));
  275. // Test a tiny bitmap.
  276. bitmap.allocN32Pixels(1, 1);
  277. bitmap.eraseARGB(255, 100, 150, 200);
  278. color = CalculateKMeanColorOfBitmap(bitmap);
  279. EXPECT_EQ(255u, SkColorGetA(color));
  280. EXPECT_TRUE(ChannelApproximatelyEqual(100, SkColorGetR(color)));
  281. EXPECT_TRUE(ChannelApproximatelyEqual(150, SkColorGetG(color)));
  282. EXPECT_TRUE(ChannelApproximatelyEqual(200, SkColorGetB(color)));
  283. }
  284. TEST_F(ColorAnalysisTest, ComputeProminentColors) {
  285. LumaRange lumas[] = {LumaRange::DARK, LumaRange::NORMAL, LumaRange::LIGHT};
  286. SaturationRange saturations[] = {SaturationRange::VIBRANT,
  287. SaturationRange::MUTED};
  288. std::vector<ColorProfile> color_profiles;
  289. for (auto s : saturations) {
  290. for (auto l : lumas)
  291. color_profiles.emplace_back(l, s);
  292. }
  293. // A totally dark gray image, which yields no prominent color as it's too
  294. // close to black.
  295. gfx::Canvas canvas(gfx::Size(300, 200), 1.0f, true);
  296. canvas.FillRect(gfx::Rect(0, 0, 300, 200), SkColorSetRGB(10, 10, 10));
  297. SkBitmap bitmap = canvas.GetBitmap();
  298. // All expectations start at SK_ColorTRANSPARENT (i.e. 0).
  299. std::vector<Swatch> expectations(color_profiles.size(),
  300. Swatch(SK_ColorTRANSPARENT, 0));
  301. std::vector<Swatch> computations = CalculateProminentColorsOfBitmap(
  302. bitmap, color_profiles, nullptr /* region */, ColorSwatchFilter());
  303. EXPECT_EQ(expectations, computations);
  304. // Add a green that could hit a couple values.
  305. const SkColor kVibrantGreen = SkColorSetRGB(25, 200, 25);
  306. canvas.FillRect(gfx::Rect(0, 1, 300, 1), kVibrantGreen);
  307. bitmap = canvas.GetBitmap();
  308. expectations[0] = Swatch(kVibrantGreen, 60);
  309. expectations[1] = Swatch(kVibrantGreen, 60);
  310. computations = CalculateProminentColorsOfBitmap(
  311. bitmap, color_profiles, nullptr /* region */, ColorSwatchFilter());
  312. EXPECT_EQ(expectations, computations);
  313. // Add a stripe of a dark, muted green (saturation .33, luma .29).
  314. const SkColor kDarkGreen = SkColorSetRGB(50, 100, 50);
  315. canvas.FillRect(gfx::Rect(0, 2, 300, 1), kDarkGreen);
  316. bitmap = canvas.GetBitmap();
  317. expectations[3] = Swatch(kDarkGreen, 60);
  318. computations = CalculateProminentColorsOfBitmap(
  319. bitmap, color_profiles, nullptr /* region */, ColorSwatchFilter());
  320. EXPECT_EQ(expectations, computations);
  321. // Now draw a little bit of pure green. That should be closer to the goal for
  322. // normal vibrant, but is out of range for other color profiles.
  323. const SkColor kPureGreen = SkColorSetRGB(0, 255, 0);
  324. canvas.FillRect(gfx::Rect(0, 3, 300, 1), kPureGreen);
  325. bitmap = canvas.GetBitmap();
  326. expectations[1] = Swatch(kPureGreen, 60);
  327. computations = CalculateProminentColorsOfBitmap(
  328. bitmap, color_profiles, nullptr /* region */, ColorSwatchFilter());
  329. EXPECT_EQ(expectations, computations);
  330. }
  331. TEST_F(ColorAnalysisTest, ComputeColorSwatches) {
  332. SkBitmap bitmap;
  333. bitmap.allocN32Pixels(100, 100);
  334. bitmap.eraseColor(SK_ColorMAGENTA);
  335. bitmap.erase(SK_ColorGREEN, {10, 10, 90, 90});
  336. bitmap.erase(SK_ColorYELLOW, {40, 40, 60, 60});
  337. const Swatch kYellowSwatch = Swatch(SK_ColorYELLOW, (20u * 20u));
  338. const Swatch kGreenSwatch =
  339. Swatch(SK_ColorGREEN, (80u * 80u) - kYellowSwatch.population);
  340. const Swatch kMagentaSwatch =
  341. Swatch(SK_ColorMAGENTA, (100u * 100u) - kGreenSwatch.population -
  342. kYellowSwatch.population);
  343. {
  344. std::vector<Swatch> colors =
  345. CalculateColorSwatches(bitmap, 10, gfx::Rect(100, 100), absl::nullopt);
  346. EXPECT_EQ(3u, colors.size());
  347. EXPECT_EQ(kGreenSwatch, colors[0]);
  348. EXPECT_EQ(kMagentaSwatch, colors[1]);
  349. EXPECT_EQ(kYellowSwatch, colors[2]);
  350. }
  351. {
  352. std::vector<Swatch> colors = CalculateColorSwatches(
  353. bitmap, 10, gfx::Rect(10, 10, 80, 80), absl::nullopt);
  354. EXPECT_EQ(2u, colors.size());
  355. EXPECT_EQ(kGreenSwatch, colors[0]);
  356. EXPECT_EQ(kYellowSwatch, colors[1]);
  357. }
  358. }
  359. TEST_F(ColorAnalysisTest, ComputeColorSwatches_Filter) {
  360. SkBitmap bitmap;
  361. bitmap.allocN32Pixels(100, 100);
  362. bitmap.eraseColor(SK_ColorMAGENTA);
  363. bitmap.erase(SK_ColorBLACK, {10, 10, 90, 90});
  364. bitmap.erase(SK_ColorWHITE, {40, 40, 60, 60});
  365. const Swatch kWhiteSwatch = Swatch(SK_ColorWHITE, (20u * 20u));
  366. const Swatch kBlackSwatch =
  367. Swatch(SK_ColorBLACK, (80u * 80u) - kWhiteSwatch.population);
  368. const Swatch kMagentaSwatch =
  369. Swatch(SK_ColorMAGENTA,
  370. (100u * 100u) - kBlackSwatch.population - kWhiteSwatch.population);
  371. {
  372. std::vector<Swatch> colors = CalculateColorSwatches(
  373. bitmap, 10, gfx::Rect(100, 100),
  374. base::BindRepeating([](const SkColor& candidate) {
  375. return candidate != SK_ColorBLACK;
  376. }));
  377. EXPECT_EQ(2u, colors.size());
  378. EXPECT_EQ(kMagentaSwatch, colors[0]);
  379. EXPECT_EQ(kWhiteSwatch, colors[1]);
  380. }
  381. {
  382. std::vector<Swatch> colors =
  383. CalculateColorSwatches(bitmap, 10, gfx::Rect(100, 100), absl::nullopt);
  384. EXPECT_EQ(3u, colors.size());
  385. EXPECT_EQ(kBlackSwatch, colors[0]);
  386. EXPECT_EQ(kMagentaSwatch, colors[1]);
  387. EXPECT_EQ(kWhiteSwatch, colors[2]);
  388. }
  389. }
  390. } // namespace color_utils