OLD | NEW |
---|---|
(Empty) | |
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 | |
5 #include "ui/gfx/content_analysis.h" | |
6 | |
7 #include <algorithm> | |
8 #include <cmath> | |
9 #include <cstdlib> | |
10 #include <fstream> | |
11 #include <iostream> | |
12 #include <limits> | |
13 #include <numeric> | |
14 #include <vector> | |
15 | |
16 #include "base/file_util.h" | |
17 #include "base/files/file_path.h" | |
18 #include "base/memory/scoped_ptr.h" | |
19 #include "testing/gtest/include/gtest/gtest.h" | |
20 #include "third_party/skia/include/core/SkBitmap.h" | |
21 #include "third_party/skia/include/core/SkColor.h" | |
22 #include "ui/gfx/canvas.h" | |
23 #include "ui/gfx/color_analysis.h" | |
24 #include "ui/gfx/color_utils.h" | |
25 #include "ui/gfx/image/image.h" | |
26 #include "ui/gfx/rect.h" | |
27 #include "ui/gfx/size.h" | |
28 | |
29 namespace { | |
30 | |
31 #ifndef M_PI | |
32 #define M_PI 3.14159265358979323846 | |
33 #endif | |
34 | |
35 void DumpBitmapToFile(const SkBitmap& bitmap) { | |
Alexei Svitkine (slow)
2013/04/09 18:02:23
If you're not using these in your tests, please re
motek.
2013/04/11 16:18:38
Done.
| |
36 SkAutoLockPixels bitmap_lock(bitmap); | |
37 scoped_refptr<base::RefCountedMemory> png_bytes = | |
38 gfx::Image::CreateFrom1xBitmap(bitmap).As1xPNGBytes(); | |
39 base::FilePath file_path; | |
40 if (file_util::CreateTemporaryFile(&file_path)) { | |
41 file_util::WriteFile(file_path, | |
42 reinterpret_cast<const char*>(png_bytes->front()), | |
43 png_bytes->size()); | |
44 DLOG(INFO) << "Image content writen out to " << file_path.value(); | |
45 } else { | |
46 NOTREACHED(); | |
47 } | |
48 } | |
49 | |
50 void DumpBitmapBytesToFile(const SkBitmap& bitmap) { | |
51 SkAutoLockPixels bitmap_lock(bitmap); | |
52 base::FilePath file_path; | |
53 if (file_util::CreateTemporaryFile(&file_path)) { | |
54 file_util::WriteFile(file_path, | |
55 static_cast<const char*>(bitmap.getPixels()), | |
56 bitmap.getSafeSize()); | |
57 DLOG(INFO) << "Image content writen out to " << file_path.value(); | |
58 } else { | |
59 NOTREACHED(); | |
60 } | |
61 } | |
62 | |
63 template<class InputIterator> | |
64 void DumpVectorToFile(InputIterator first, InputIterator last) { | |
65 base::FilePath file_path; | |
66 if (file_util::CreateTemporaryFile(&file_path)) { | |
67 std::ofstream outfile; | |
68 outfile.open(file_path.value().c_str()); | |
69 for (; first < last; ++first) { | |
70 outfile << *first; | |
71 outfile << "\n"; | |
72 } | |
73 outfile.close(); | |
74 DLOG(INFO) << "Vector content writen out to " << file_path.value(); | |
75 } | |
76 } | |
77 | |
78 unsigned long ImagePixelSum(const SkBitmap& bitmap, const gfx::Rect& rect) { | |
79 // Get the sum of pixel values in the rectangle. Applicable only to | |
80 // monochrome bitmaps. | |
81 DCHECK_EQ(SkBitmap::kA8_Config, bitmap.config()); | |
82 unsigned long total = 0; | |
83 for (int r = rect.y(); r < rect.bottom(); ++r) { | |
84 const uint8* row_data = static_cast<const uint8*>( | |
85 bitmap.getPixels()) + r * bitmap.rowBytes(); | |
86 for (int c = rect.x(); c < rect.right(); ++c) | |
87 total += row_data[c]; | |
88 } | |
89 | |
90 return total; | |
91 } | |
92 | |
93 bool CompareImageFragments(const SkBitmap& bitmap_left, | |
94 const SkBitmap& bitmap_right, | |
95 const gfx::Size& comparison_area, | |
96 const gfx::Point& origin_left, | |
97 const gfx::Point& origin_right) { | |
98 SkAutoLockPixels left_lock(bitmap_left); | |
99 SkAutoLockPixels right_lock(bitmap_right); | |
100 for (int r = 0; r < comparison_area.height(); ++r) { | |
101 for (int c = 0; c < comparison_area.width(); ++c) { | |
102 SkColor clr_left = bitmap_left.getColor(origin_left.x() + c, | |
103 origin_left.y() + r); | |
104 SkColor clr_right = bitmap_right.getColor(origin_right.x() + c, | |
105 origin_right.y() + r); | |
106 if (clr_left != clr_right) | |
107 return false; | |
108 } | |
109 } | |
110 | |
111 return true; | |
112 } | |
113 | |
114 } | |
Alexei Svitkine (slow)
2013/04/09 18:02:23
Add " // namespace"
motek.
2013/04/11 16:18:38
Done.
| |
115 | |
116 class ContentAnalysisTest : public testing::Test { | |
117 }; | |
118 | |
119 TEST_F(ContentAnalysisTest, ApplyGradientMagnitudeOnImpulse) { | |
120 gfx::Canvas canvas(gfx::Size(800, 600), ui::SCALE_FACTOR_100P, true); | |
121 | |
122 // The image consists of vertical non-overlapping stripes 100 pixels wide. | |
123 canvas.FillRect(gfx::Rect(0, 0, 800, 600), SkColorSetARGB(0, 10, 10, 10)); | |
124 canvas.FillRect(gfx::Rect(400, 300, 1, 1), SkColorSetRGB(255, 255, 255)); | |
125 | |
126 SkBitmap source = | |
127 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); | |
128 | |
129 SkBitmap reduced_color; | |
130 reduced_color.setConfig( | |
131 SkBitmap::kA8_Config, source.width(), source.height()); | |
132 reduced_color.allocPixels(); | |
133 | |
134 gfx::Vector3dF transform(0.299f, 0.587f, 0.114f); | |
135 EXPECT_TRUE(color_utils::ApplyColorReduction( | |
136 source, transform, true, &reduced_color)); | |
137 | |
138 float sigma = 2.5f; | |
139 color_utils::ApplyGaussianGradientMagnitudeFilter(&reduced_color, sigma); | |
140 | |
141 // Expect everything to be within 8 * sigma. | |
142 int tail_length = static_cast<int>(8.0f * sigma + 0.5f); | |
143 gfx::Rect echo_rect(399 - tail_length, 299 - tail_length, | |
144 2 * tail_length + 1, 2 * tail_length + 1); | |
145 unsigned long data_sum = ImagePixelSum(reduced_color, echo_rect); | |
146 unsigned long all_sum = ImagePixelSum(reduced_color, gfx::Rect(800, 600)); | |
147 EXPECT_GT(data_sum, 0U); | |
148 EXPECT_EQ(data_sum, all_sum); | |
149 | |
150 sigma = 5.0f; | |
151 color_utils::ApplyGaussianGradientMagnitudeFilter(&reduced_color, sigma); | |
152 | |
153 // Expect everything to be within 8 * sigma. | |
154 tail_length = static_cast<int>(8.0f * sigma + 0.5f); | |
155 echo_rect = gfx::Rect(399 - tail_length, 299 - tail_length, | |
156 2 * tail_length + 1, 2 * tail_length + 1); | |
157 data_sum = ImagePixelSum(reduced_color, echo_rect); | |
158 all_sum = ImagePixelSum(reduced_color, gfx::Rect(800, 600)); | |
159 EXPECT_GT(data_sum, 0U); | |
160 EXPECT_EQ(data_sum, all_sum); | |
161 } | |
162 | |
163 TEST_F(ContentAnalysisTest, ApplyGradientMagnitudeOnFrame) { | |
164 gfx::Canvas canvas(gfx::Size(800, 600), ui::SCALE_FACTOR_100P, true); | |
165 | |
166 // The image consists of a single white block in the centre. | |
167 gfx::Rect draw_rect(300, 200, 200, 200); | |
168 canvas.FillRect(gfx::Rect(0, 0, 800, 600), SkColorSetARGB(0, 0, 0, 0)); | |
169 canvas.DrawRect(draw_rect, SkColorSetRGB(255, 255, 255)); | |
170 | |
171 SkBitmap source = | |
172 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); | |
173 | |
174 SkBitmap reduced_color; | |
175 reduced_color.setConfig( | |
176 SkBitmap::kA8_Config, source.width(), source.height()); | |
177 reduced_color.allocPixels(); | |
178 | |
179 gfx::Vector3dF transform(0.299f, 0.587f, 0.114f); | |
180 EXPECT_TRUE(color_utils::ApplyColorReduction( | |
181 source, transform, true, &reduced_color)); | |
182 | |
183 float sigma = 2.5f; | |
184 color_utils::ApplyGaussianGradientMagnitudeFilter(&reduced_color, sigma); | |
185 | |
186 int tail_length = static_cast<int>(8.0f * sigma + 0.5f); | |
187 gfx::Rect outer_rect(draw_rect.x() - tail_length, | |
188 draw_rect.y() - tail_length, | |
189 draw_rect.width() + 2 * tail_length, | |
190 draw_rect.height() + 2 * tail_length); | |
191 gfx::Rect inner_rect(draw_rect.x() + tail_length, | |
192 draw_rect.y() + tail_length, | |
193 draw_rect.width() - 2 * tail_length, | |
194 draw_rect.height() - 2 * tail_length); | |
195 unsigned long data_sum = ImagePixelSum(reduced_color, outer_rect); | |
196 unsigned long all_sum = ImagePixelSum(reduced_color, gfx::Rect(800, 600)); | |
197 EXPECT_GT(data_sum, 0U); | |
198 EXPECT_EQ(data_sum, all_sum); | |
199 EXPECT_EQ(ImagePixelSum(reduced_color, inner_rect), 0U); | |
200 } | |
201 | |
202 TEST_F(ContentAnalysisTest, ExtractImageProfileInformation) { | |
203 gfx::Canvas canvas(gfx::Size(800, 600), ui::SCALE_FACTOR_100P, true); | |
204 | |
205 // The image consists of a white frame drawn in the centre. | |
206 gfx::Rect draw_rect(100, 100, 200, 100); | |
207 gfx::Rect image_rect(0, 0, 800, 600); | |
208 canvas.FillRect(image_rect, SkColorSetARGB(0, 0, 0, 0)); | |
209 canvas.DrawRect(draw_rect, SkColorSetRGB(255, 255, 255)); | |
210 | |
211 SkBitmap source = | |
212 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); | |
213 SkBitmap reduced_color; | |
214 reduced_color.setConfig( | |
215 SkBitmap::kA8_Config, source.width(), source.height()); | |
216 reduced_color.allocPixels(); | |
217 | |
218 gfx::Vector3dF transform(1, 0, 0); | |
219 EXPECT_TRUE(color_utils::ApplyColorReduction( | |
220 source, transform, true, &reduced_color)); | |
221 std::vector<float> column_profile; | |
222 std::vector<float> row_profile; | |
223 color_utils::ExtractImageProfileInformation(reduced_color, | |
224 image_rect, | |
225 gfx::Size(), | |
226 false, | |
227 &row_profile, | |
228 &column_profile); | |
229 EXPECT_EQ(0, std::accumulate(column_profile.begin(), | |
230 column_profile.begin() + draw_rect.x() - 1, | |
231 0)); | |
232 EXPECT_EQ(column_profile[draw_rect.x()], 255U * (draw_rect.height() + 1)); | |
233 EXPECT_EQ(2 * 255 * (draw_rect.width() - 2), | |
234 std::accumulate(column_profile.begin() + draw_rect.x() + 1, | |
235 column_profile.begin() + draw_rect.right() - 1, | |
236 0)); | |
237 | |
238 EXPECT_EQ(0, std::accumulate(row_profile.begin(), | |
239 row_profile.begin() + draw_rect.y() - 1, | |
240 0)); | |
241 EXPECT_EQ(row_profile[draw_rect.y()], 255U * (draw_rect.width() + 1)); | |
242 EXPECT_EQ(2 * 255 * (draw_rect.height() - 2), | |
243 std::accumulate(row_profile.begin() + draw_rect.y() + 1, | |
244 row_profile.begin() + draw_rect.bottom() - 1, | |
245 0)); | |
246 | |
247 gfx::Rect test_rect(150, 80, 400, 100); | |
248 color_utils::ExtractImageProfileInformation(reduced_color, | |
249 test_rect, | |
250 gfx::Size(), | |
251 false, | |
252 &row_profile, | |
253 &column_profile); | |
254 | |
255 // Some overlap with the drawn rectagle. If you work it out on a piece of | |
256 // paper, sums should be as follows. | |
257 EXPECT_EQ(255 * (test_rect.bottom() - draw_rect.y()) + | |
258 255 * (draw_rect.right() - test_rect.x()), | |
259 std::accumulate(row_profile.begin(), row_profile.end(), 0)); | |
260 EXPECT_EQ(255 * (test_rect.bottom() - draw_rect.y()) + | |
261 255 * (draw_rect.right() - test_rect.x()), | |
262 std::accumulate(column_profile.begin(), column_profile.end(), 0)); | |
263 } | |
264 | |
265 TEST_F(ContentAnalysisTest, ExtractImageProfileInformationWithClosing) { | |
266 gfx::Canvas canvas(gfx::Size(800, 600), ui::SCALE_FACTOR_100P, true); | |
267 | |
268 // The image consists of a two white frames drawn side by side, with a | |
269 // single-pixel vertical gap in between. | |
270 gfx::Rect image_rect(0, 0, 800, 600); | |
271 canvas.FillRect(image_rect, SkColorSetARGB(0, 0, 0, 0)); | |
272 canvas.DrawRect(gfx::Rect(300, 250, 99, 100), SkColorSetRGB(255, 255, 255)); | |
273 canvas.DrawRect(gfx::Rect(401, 250, 99, 100), SkColorSetRGB(255, 255, 255)); | |
274 | |
275 SkBitmap source = | |
276 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); | |
277 SkBitmap reduced_color; | |
278 reduced_color.setConfig( | |
279 SkBitmap::kA8_Config, source.width(), source.height()); | |
280 reduced_color.allocPixels(); | |
281 | |
282 gfx::Vector3dF transform(1, 0, 0); | |
283 EXPECT_TRUE(color_utils::ApplyColorReduction( | |
284 source, transform, true, &reduced_color)); | |
285 std::vector<float> column_profile; | |
286 std::vector<float> row_profile; | |
287 | |
288 color_utils::ExtractImageProfileInformation(reduced_color, | |
289 image_rect, | |
290 gfx::Size(), | |
291 true, | |
292 &row_profile, | |
293 &column_profile); | |
294 // Column profiles should have two spikes in the middle, with a single | |
295 // 0-valued value between them. | |
296 EXPECT_GT(column_profile[398], 0.0f); | |
297 EXPECT_GT(column_profile[399], column_profile[398]); | |
298 EXPECT_GT(column_profile[402], 0.0f); | |
299 EXPECT_GT(column_profile[401], column_profile[402]); | |
300 EXPECT_EQ(column_profile[401], column_profile[399]); | |
301 EXPECT_EQ(column_profile[402], column_profile[398]); | |
302 EXPECT_EQ(column_profile[400], 0.0f); | |
303 EXPECT_EQ(column_profile[299], 0.0f); | |
304 EXPECT_EQ(column_profile[502], 0.0f); | |
305 | |
306 // Now the same with closing applied. The space in the middle will be closed. | |
307 color_utils::ExtractImageProfileInformation(reduced_color, | |
308 image_rect, | |
309 gfx::Size(200, 100), | |
310 true, | |
311 &row_profile, | |
312 &column_profile); | |
313 EXPECT_GT(column_profile[398], 0); | |
314 EXPECT_GT(column_profile[400], 0); | |
315 EXPECT_GT(column_profile[402], 0); | |
316 EXPECT_EQ(column_profile[299], 0); | |
317 EXPECT_EQ(column_profile[502], 0); | |
318 EXPECT_EQ(column_profile[399], column_profile[401]); | |
319 EXPECT_EQ(column_profile[398], column_profile[402]); | |
320 } | |
321 | |
322 TEST_F(ContentAnalysisTest, AutoSegmentPeaks) { | |
323 std::vector<float> profile_info; | |
324 | |
325 EXPECT_EQ(color_utils::AutoSegmentPeaks(profile_info), | |
326 std::numeric_limits<float>::max()); | |
327 profile_info.resize(1000, 1.0f); | |
328 EXPECT_EQ(color_utils::AutoSegmentPeaks(profile_info), 1.0f); | |
329 std::srand(42); | |
330 std::generate(profile_info.begin(), profile_info.end(), std::rand); | |
331 float threshold = color_utils::AutoSegmentPeaks(profile_info); | |
332 EXPECT_GT(threshold, 0); // Not much to expect. | |
333 | |
334 // There should be roughly 50% above and below the threshold. | |
335 // Random is not really random thanks to srand, so we can sort-of compare. | |
336 int above_count = std::count_if( | |
337 profile_info.begin(), | |
338 profile_info.end(), | |
339 std::bind2nd(std::greater<float>(), threshold)); | |
340 EXPECT_GT(above_count, 475); // Not much to expect. | |
341 EXPECT_LT(above_count, 525); | |
342 | |
343 for (unsigned i = 0; i < profile_info.size(); ++i) { | |
344 float y = std::sin(M_PI * i / 250.0f); | |
345 profile_info[i] = y > 0 ? y : 0; | |
346 } | |
347 threshold = color_utils::AutoSegmentPeaks(profile_info); | |
348 | |
349 above_count = std::count_if( | |
350 profile_info.begin(), | |
351 profile_info.end(), | |
352 std::bind2nd(std::greater<float>(), threshold)); | |
353 EXPECT_LT(above_count, 500); // Negative y expected to fall below threshold. | |
354 | |
355 // Expect two peaks around between 0 and 250 and 500 and 750. | |
356 std::vector<bool> thresholded_values(profile_info.size(), false); | |
357 std::transform(profile_info.begin(), | |
358 profile_info.end(), | |
359 thresholded_values.begin(), | |
360 std::bind2nd(std::greater<float>(), threshold)); | |
361 EXPECT_TRUE(thresholded_values[125]); | |
362 EXPECT_TRUE(thresholded_values[625]); | |
363 int transitions = 0; | |
364 for (unsigned i = 1; i < thresholded_values.size(); ++i) { | |
365 if (thresholded_values[i] != thresholded_values[i-1]) | |
366 transitions++; | |
367 } | |
368 EXPECT_EQ(transitions, 4); // We have two contiguous peaks. Good going! | |
369 } | |
370 | |
371 TEST_F(ContentAnalysisTest, ComputeDecimatedImage) { | |
372 gfx::Size image_size(1600, 1200); | |
373 gfx::Canvas canvas(image_size, ui::SCALE_FACTOR_100P, true); | |
374 | |
375 // Make some content we will later want to keep. | |
376 canvas.FillRect(gfx::Rect(100, 200, 100, 100), SkColorSetARGB(0, 125, 0, 0)); | |
377 canvas.FillRect(gfx::Rect(300, 200, 100, 100), SkColorSetARGB(0, 0, 200, 0)); | |
378 canvas.FillRect(gfx::Rect(500, 200, 100, 100), SkColorSetARGB(0, 0, 0, 225)); | |
379 canvas.FillRect(gfx::Rect(100, 400, 600, 100), | |
380 SkColorSetARGB(0, 125, 200, 225)); | |
381 | |
382 std::vector<bool> rows(image_size.height(), false); | |
383 std::fill_n(rows.begin() + 200, 100, true); | |
384 std::fill_n(rows.begin() + 400, 100, true); | |
385 | |
386 std::vector<bool> columns(image_size.width(), false); | |
387 std::fill_n(columns.begin() + 100, 100, true); | |
388 std::fill_n(columns.begin() + 300, 100, true); | |
389 std::fill_n(columns.begin() + 500, 100, true); | |
390 | |
391 SkBitmap source = | |
392 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); | |
393 scoped_ptr<SkBitmap> result( | |
394 color_utils::ComputeDecimatedImage(source, rows, columns)); | |
395 EXPECT_FALSE(result.get() == NULL); | |
396 EXPECT_EQ(300, result->width()); | |
397 EXPECT_EQ(200, result->height()); | |
398 | |
399 // The call should have removed all empty spaces. | |
400 ASSERT_TRUE(CompareImageFragments(source, | |
401 *result, | |
402 gfx::Size(100, 100), | |
403 gfx::Point(100, 200), | |
404 gfx::Point(0, 0))); | |
405 ASSERT_TRUE(CompareImageFragments(source, | |
406 *result, | |
407 gfx::Size(100, 100), | |
408 gfx::Point(300, 200), | |
409 gfx::Point(100, 0))); | |
410 ASSERT_TRUE(CompareImageFragments(source, | |
411 *result, | |
412 gfx::Size(100, 100), | |
413 gfx::Point(500, 200), | |
414 gfx::Point(200, 0))); | |
415 ASSERT_TRUE(CompareImageFragments(source, | |
416 *result, | |
417 gfx::Size(100, 100), | |
418 gfx::Point(100, 400), | |
419 gfx::Point(0, 0))); | |
420 } | |
421 | |
422 TEST_F(ContentAnalysisTest, CreateRetargettedThumbnailImage) { | |
423 gfx::Size image_size(1200, 1300); | |
424 gfx::Canvas canvas(image_size, ui::SCALE_FACTOR_100P, true); | |
425 | |
426 // The following will create a 'fake image' consisting of color blocks placed | |
427 // on a neutral background. The entire layout is supposed to mimic a | |
428 // screenshot of a web page. | |
429 // The tested function is supposed to locate the interesing areas in the | |
430 // middle. | |
431 const int margin_horizontal = 60; | |
432 const int margin_vertical = 20; | |
433 canvas.FillRect(gfx::Rect(image_size), SkColorSetRGB(200, 210, 210)); | |
434 const gfx::Rect header_rect(margin_horizontal, | |
435 margin_vertical, | |
436 image_size.width() - 2 * margin_horizontal, | |
437 100); | |
438 const gfx::Rect footer_rect(margin_horizontal, | |
439 image_size.height() - margin_vertical - 100, | |
440 image_size.width() - 2 * margin_horizontal, | |
441 100); | |
442 const gfx::Rect body_rect(margin_horizontal, | |
443 header_rect.bottom() + margin_vertical, | |
444 image_size.width() - 2 * margin_horizontal, | |
445 footer_rect.y() - header_rect.bottom() - | |
446 2 * margin_vertical); | |
447 canvas.FillRect(header_rect, SkColorSetRGB(200, 40, 10)); | |
448 canvas.FillRect(footer_rect, SkColorSetRGB(10, 40, 180)); | |
449 canvas.FillRect(body_rect, SkColorSetRGB(150, 180, 40)); | |
450 | |
451 // 'Fine print' at the bottom. | |
452 const int fine_print = 8; | |
453 const SkColor print_color = SkColorSetRGB(45, 30, 30); | |
454 for (int y = footer_rect.y() + fine_print; | |
455 y < footer_rect.bottom() - fine_print; | |
456 y += 2 * fine_print) { | |
457 for (int x = footer_rect.x() + fine_print; | |
458 x < footer_rect.right() - fine_print; | |
459 x += 2 * fine_print) { | |
460 canvas.DrawRect(gfx::Rect(x, y, fine_print, fine_print), print_color); | |
461 } | |
462 } | |
463 | |
464 // Blocky content at the top. | |
465 const int block_size = header_rect.height() - margin_vertical; | |
466 for (int x = header_rect.x() + margin_horizontal; | |
467 x < header_rect.right() - block_size; | |
468 x += block_size + margin_horizontal) { | |
469 const int half_block = block_size / 2 - 5; | |
470 const SkColor block_color = SkColorSetRGB(255, 255, 255); | |
471 const int y = header_rect.y() + margin_vertical / 2; | |
472 int second_col = x + half_block + 10; | |
473 int second_row = y + half_block + 10; | |
474 canvas.FillRect(gfx::Rect(x, y, half_block, block_size), block_color); | |
475 canvas.FillRect(gfx::Rect(second_col, y, half_block, half_block), | |
476 block_color); | |
477 canvas.FillRect(gfx::Rect(second_col, second_row, half_block, half_block), | |
478 block_color); | |
479 } | |
480 | |
481 // Now the main body. Mostly text with some 'pictures'. | |
482 for (int y = body_rect.y() + fine_print; | |
483 y < body_rect.bottom() - fine_print; | |
484 y += 2 * fine_print) { | |
485 for (int x = body_rect.x() + fine_print; | |
486 x < body_rect.right() - fine_print; | |
487 x += 2 * fine_print) { | |
488 canvas.DrawRect(gfx::Rect(x, y, fine_print, fine_print), print_color); | |
489 } | |
490 } | |
491 | |
492 for (int line = 0; line < 3; ++line) { | |
493 int alignment = line % 2; | |
494 const int y = body_rect.y() + | |
495 body_rect.height() / 3 * line + margin_vertical; | |
496 const int x = body_rect.x() + | |
497 alignment * body_rect.width() / 2 + margin_vertical; | |
498 gfx::Rect pict_rect(x, y, | |
499 body_rect.width() / 2 - 2 * margin_vertical, | |
500 body_rect.height() / 3 - 2 * margin_vertical); | |
501 canvas.FillRect(pict_rect, SkColorSetRGB(255, 255, 255)); | |
502 canvas.DrawRect(pict_rect, SkColorSetRGB(0, 0, 0)); | |
503 } | |
504 | |
505 SkBitmap source = | |
506 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); | |
507 | |
508 scoped_ptr<SkBitmap> result(color_utils::CreateRetargettedThumbnailImage( | |
509 source, gfx::Size(424, 264), 2.5)); | |
510 EXPECT_FALSE(result.get() == NULL); | |
511 | |
512 // Given the nature of computation We can't really assert much here about the | |
513 // image itself. We know it should have been computed, should be smaller than | |
514 // the original and it must not be zero. | |
515 EXPECT_LT(result->width(), image_size.width()); | |
516 EXPECT_LT(result->height(), image_size.height()); | |
517 | |
518 int histogram[256]; | |
519 color_utils::BuildLumaHistogram(*result, histogram); | |
520 int non_zero_color_count = std::count_if( | |
521 histogram, histogram + 256, std::bind2nd(std::greater<int>(), 0)); | |
522 EXPECT_GT(non_zero_color_count, 4); | |
523 } | |
OLD | NEW |