1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file. 4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/thumbnails/content_analysis.h" 6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <algorithm> 8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <cmath> 9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <cstdlib> 10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <functional> 11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <limits> 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <numeric> 13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <vector> 14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/memory/scoped_ptr.h" 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h" 18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "third_party/skia/include/core/SkColor.h" 19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/canvas.h" 20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/color_analysis.h" 21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/color_utils.h" 22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/image/image.h" 23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/rect.h" 24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/size.h" 25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace { 27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#ifndef M_PI 29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#define M_PI 3.14159265358979323846 30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif 31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)unsigned long ImagePixelSum(const SkBitmap& bitmap, const gfx::Rect& rect) { 33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Get the sum of pixel values in the rectangle. Applicable only to 34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // monochrome bitmaps. 35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK_EQ(kAlpha_8_SkColorType, bitmap.colorType()); 36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) unsigned long total = 0; 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int r = rect.y(); r < rect.bottom(); ++r) { 38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const uint8* row_data = static_cast<const uint8*>( 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bitmap.getPixels()) + r * bitmap.rowBytes(); 40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int c = rect.x(); c < rect.right(); ++c) 41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) total += row_data[c]; 42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return total; 45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool CompareImageFragments(const SkBitmap& bitmap_left, 48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const SkBitmap& bitmap_right, 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const gfx::Size& comparison_area, 50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const gfx::Point& origin_left, 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const gfx::Point& origin_right) { 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkAutoLockPixels left_lock(bitmap_left); 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkAutoLockPixels right_lock(bitmap_right); 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int r = 0; r < comparison_area.height(); ++r) { 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int c = 0; c < comparison_area.width(); ++c) { 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkColor color_left = bitmap_left.getColor(origin_left.x() + c, 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) origin_left.y() + r); 58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkColor color_right = bitmap_right.getColor(origin_right.x() + c, 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) origin_right.y() + r); 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (color_left != color_right) 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)float AspectDifference(const gfx::Size& reference, const gfx::Size& candidate) { 69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return std::abs(static_cast<float>(candidate.width()) / candidate.height() - 70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<float>(reference.width()) / reference.height()); 71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} // namespace 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace thumbnailing_utils { 76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class ThumbnailContentAnalysisTest : public testing::Test { 78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)TEST_F(ThumbnailContentAnalysisTest, ApplyGradientMagnitudeOnImpulse) { 8168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) gfx::Canvas canvas(gfx::Size(800, 600), 1.0f, true); 82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // The image consists of a point spike on uniform (non-zero) background. 844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) canvas.FillRect(gfx::Rect(0, 0, 800, 600), SkColorSetRGB(10, 10, 10)); 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) canvas.FillRect(gfx::Rect(400, 300, 1, 1), SkColorSetRGB(255, 255, 255)); 86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkBitmap source = 88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); 89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkBitmap reduced_color; 91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch reduced_color.allocPixels(SkImageInfo::MakeA8(source.width(), 92116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch source.height())); 93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Vector3dF transform(0.299f, 0.587f, 0.114f); 95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_TRUE(color_utils::ApplyColorReduction( 96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) source, transform, true, &reduced_color)); 97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) float sigma = 2.5f; 99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ApplyGaussianGradientMagnitudeFilter(&reduced_color, sigma); 100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Expect everything to be within 8 * sigma. 102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int tail_length = static_cast<int>(8.0f * sigma + 0.5f); 103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Rect echo_rect(399 - tail_length, 299 - tail_length, 104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2 * tail_length + 1, 2 * tail_length + 1); 105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) unsigned long data_sum = ImagePixelSum(reduced_color, echo_rect); 106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) unsigned long all_sum = ImagePixelSum(reduced_color, gfx::Rect(800, 600)); 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_GT(data_sum, 0U); 108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(data_sum, all_sum); 109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) sigma = 5.0f; 111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ApplyGaussianGradientMagnitudeFilter(&reduced_color, sigma); 112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Expect everything to be within 8 * sigma. 114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) tail_length = static_cast<int>(8.0f * sigma + 0.5f); 115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) echo_rect = gfx::Rect(399 - tail_length, 299 - tail_length, 116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2 * tail_length + 1, 2 * tail_length + 1); 117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) data_sum = ImagePixelSum(reduced_color, echo_rect); 118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) all_sum = ImagePixelSum(reduced_color, gfx::Rect(800, 600)); 119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_GT(data_sum, 0U); 120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(data_sum, all_sum); 121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TEST_F(ThumbnailContentAnalysisTest, ApplyGradientMagnitudeOnFrame) { 12468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) gfx::Canvas canvas(gfx::Size(800, 600), 1.0f, true); 125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // The image consists of a single white block in the centre. 127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Rect draw_rect(300, 200, 200, 200); 1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) canvas.FillRect(gfx::Rect(0, 0, 800, 600), SkColorSetRGB(0, 0, 0)); 129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) canvas.DrawRect(draw_rect, SkColorSetRGB(255, 255, 255)); 130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkBitmap source = 132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); 133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkBitmap reduced_color; 135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch reduced_color.allocPixels(SkImageInfo::MakeA8(source.width(), 136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch source.height())); 137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Vector3dF transform(0.299f, 0.587f, 0.114f); 139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_TRUE(color_utils::ApplyColorReduction( 140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) source, transform, true, &reduced_color)); 141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) float sigma = 2.5f; 143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ApplyGaussianGradientMagnitudeFilter(&reduced_color, sigma); 144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int tail_length = static_cast<int>(8.0f * sigma + 0.5f); 146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Rect outer_rect(draw_rect.x() - tail_length, 147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) draw_rect.y() - tail_length, 148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) draw_rect.width() + 2 * tail_length, 149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) draw_rect.height() + 2 * tail_length); 150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Rect inner_rect(draw_rect.x() + tail_length, 151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) draw_rect.y() + tail_length, 152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) draw_rect.width() - 2 * tail_length, 153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) draw_rect.height() - 2 * tail_length); 154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) unsigned long data_sum = ImagePixelSum(reduced_color, outer_rect); 155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) unsigned long all_sum = ImagePixelSum(reduced_color, gfx::Rect(800, 600)); 156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_GT(data_sum, 0U); 157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(data_sum, all_sum); 158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(ImagePixelSum(reduced_color, inner_rect), 0U); 159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)TEST_F(ThumbnailContentAnalysisTest, ExtractImageProfileInformation) { 16268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) gfx::Canvas canvas(gfx::Size(800, 600), 1.0f, true); 163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // The image consists of a white frame drawn in the centre. 165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Rect draw_rect(100, 100, 200, 100); 166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Rect image_rect(0, 0, 800, 600); 1674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) canvas.FillRect(image_rect, SkColorSetRGB(0, 0, 0)); 168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) canvas.DrawRect(draw_rect, SkColorSetRGB(255, 255, 255)); 169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkBitmap source = 171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); 172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkBitmap reduced_color; 173116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch reduced_color.allocPixels(SkImageInfo::MakeA8(source.width(), 174116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch source.height())); 175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Vector3dF transform(1, 0, 0); 177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_TRUE(color_utils::ApplyColorReduction( 178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) source, transform, true, &reduced_color)); 179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<float> column_profile; 180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<float> row_profile; 181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ExtractImageProfileInformation(reduced_color, 182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) image_rect, 183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Size(), 184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) false, 185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &row_profile, 186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &column_profile); 187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(0, std::accumulate(column_profile.begin(), 188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) column_profile.begin() + draw_rect.x() - 1, 189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 0)); 190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(column_profile[draw_rect.x()], 255U * (draw_rect.height() + 1)); 191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(2 * 255 * (draw_rect.width() - 2), 192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::accumulate(column_profile.begin() + draw_rect.x() + 1, 193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) column_profile.begin() + draw_rect.right() - 1, 194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 0)); 195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(0, std::accumulate(row_profile.begin(), 197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) row_profile.begin() + draw_rect.y() - 1, 198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 0)); 199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(row_profile[draw_rect.y()], 255U * (draw_rect.width() + 1)); 200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(2 * 255 * (draw_rect.height() - 2), 201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::accumulate(row_profile.begin() + draw_rect.y() + 1, 202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) row_profile.begin() + draw_rect.bottom() - 1, 203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 0)); 204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Rect test_rect(150, 80, 400, 100); 206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ExtractImageProfileInformation(reduced_color, 207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) test_rect, 208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Size(), 209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) false, 210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &row_profile, 211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &column_profile); 212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Some overlap with the drawn rectagle. If you work it out on a piece of 214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // paper, sums should be as follows. 215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(255 * (test_rect.bottom() - draw_rect.y()) + 216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 255 * (draw_rect.right() - test_rect.x()), 217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::accumulate(row_profile.begin(), row_profile.end(), 0)); 218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(255 * (test_rect.bottom() - draw_rect.y()) + 219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 255 * (draw_rect.right() - test_rect.x()), 220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::accumulate(column_profile.begin(), column_profile.end(), 0)); 221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)TEST_F(ThumbnailContentAnalysisTest, 2244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ExtractImageProfileInformationWithClosing) { 22568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) gfx::Canvas canvas(gfx::Size(800, 600), 1.0f, true); 226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // The image consists of a two white frames drawn side by side, with a 228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // single-pixel vertical gap in between. 229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Rect image_rect(0, 0, 800, 600); 2304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) canvas.FillRect(image_rect, SkColorSetRGB(0, 0, 0)); 231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) canvas.DrawRect(gfx::Rect(300, 250, 99, 100), SkColorSetRGB(255, 255, 255)); 232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) canvas.DrawRect(gfx::Rect(401, 250, 99, 100), SkColorSetRGB(255, 255, 255)); 233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkBitmap source = 235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); 236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkBitmap reduced_color; 237116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch reduced_color.allocPixels(SkImageInfo::MakeA8(source.width(), 238116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch source.height())); 239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Vector3dF transform(1, 0, 0); 241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_TRUE(color_utils::ApplyColorReduction( 242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) source, transform, true, &reduced_color)); 243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<float> column_profile; 244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<float> row_profile; 245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ExtractImageProfileInformation(reduced_color, 247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) image_rect, 248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Size(), 249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) true, 250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &row_profile, 251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &column_profile); 252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Column profiles should have two spikes in the middle, with a single 253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // 0-valued value between them. 254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_GT(column_profile[398], 0.0f); 255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_GT(column_profile[399], column_profile[398]); 256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_GT(column_profile[402], 0.0f); 257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_GT(column_profile[401], column_profile[402]); 258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(column_profile[401], column_profile[399]); 259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(column_profile[402], column_profile[398]); 260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(column_profile[400], 0.0f); 261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(column_profile[299], 0.0f); 262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(column_profile[502], 0.0f); 263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Now the same with closing applied. The space in the middle will be closed. 265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ExtractImageProfileInformation(reduced_color, 266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) image_rect, 267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Size(200, 100), 268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) true, 269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &row_profile, 270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &column_profile); 271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_GT(column_profile[398], 0); 272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_GT(column_profile[400], 0); 273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_GT(column_profile[402], 0); 274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(column_profile[299], 0); 275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(column_profile[502], 0); 276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(column_profile[399], column_profile[401]); 277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(column_profile[398], column_profile[402]); 278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 280868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(ThumbnailContentAnalysisTest, AdjustClippingSizeToAspectRatio) { 281868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // The test will exercise several relations of sizes. Basic invariants 282868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // checked in each case: each dimension in adjusted_size ougth not be greater 283868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // than the source image and not lesser than requested target. Aspect ratio 284868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // of adjusted_size should never be worse than that of computed_size. 285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) gfx::Size target_size(212, 100); 286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) gfx::Size image_size(1000, 2000); 287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) gfx::Size computed_size(420, 200); 288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 289868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) gfx::Size adjusted_size = AdjustClippingSizeToAspectRatio( 290868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) target_size, image_size, computed_size); 291868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 292868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(adjusted_size.width(), image_size.width()); 293868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(adjusted_size.height(), image_size.height()); 294868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(adjusted_size.width(), target_size.width()); 295868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(adjusted_size.height(), target_size.height()); 296868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(AspectDifference(target_size, adjusted_size), 297868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) AspectDifference(target_size, computed_size)); 298868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // This case is special (and trivial): no change expected. 299868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_EQ(computed_size, adjusted_size); 300868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 301868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Computed size is too tall. Adjusted size has to add rows. 302868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) computed_size.SetSize(600, 150); 303868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) adjusted_size = AdjustClippingSizeToAspectRatio( 304868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) target_size, image_size, computed_size); 305868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Invariant check. 306868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(adjusted_size.width(), image_size.width()); 307868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(adjusted_size.height(), image_size.height()); 308868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(adjusted_size.width(), target_size.width()); 309868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(adjusted_size.height(), target_size.height()); 310868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(AspectDifference(target_size, adjusted_size), 311868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) AspectDifference(target_size, computed_size)); 312868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Specific to this case. 313868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_EQ(computed_size.width(), adjusted_size.width()); 314868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(computed_size.height(), adjusted_size.height()); 315868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_NEAR( 316868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<float>(target_size.width()) / target_size.height(), 317868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<float>(adjusted_size.width()) / adjusted_size.height(), 318868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 0.02f); 319868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 320868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Computed size is too wide. Adjusted size has to add columns. 321868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) computed_size.SetSize(200, 400); 322868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) adjusted_size = AdjustClippingSizeToAspectRatio( 323868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) target_size, image_size, computed_size); 324868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Invariant check. 325868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(adjusted_size.width(), image_size.width()); 326868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(adjusted_size.height(), image_size.height()); 327868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(adjusted_size.width(), target_size.width()); 328868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(adjusted_size.height(), target_size.height()); 329868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(AspectDifference(target_size, adjusted_size), 330868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) AspectDifference(target_size, computed_size)); 331868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_NEAR( 332868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<float>(target_size.width()) / target_size.height(), 333868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<float>(adjusted_size.width()) / adjusted_size.height(), 334868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 0.02f); 335868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 336868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) target_size.SetSize(416, 205); 337868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) image_size.SetSize(1200, 1200); 338868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) computed_size.SetSize(900, 300); 339868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) adjusted_size = AdjustClippingSizeToAspectRatio( 340868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) target_size, image_size, computed_size); 341868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Invariant check. 342868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(adjusted_size.width(), image_size.width()); 343868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(adjusted_size.height(), image_size.height()); 344868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(adjusted_size.width(), target_size.width()); 345868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(adjusted_size.height(), target_size.height()); 346868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(AspectDifference(target_size, adjusted_size), 347868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) AspectDifference(target_size, computed_size)); 348868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Specific to this case. 349868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_EQ(computed_size.width(), adjusted_size.width()); 350868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(computed_size.height(), adjusted_size.height()); 351868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_NEAR( 352868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<float>(target_size.width()) / target_size.height(), 353868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<float>(adjusted_size.width()) / adjusted_size.height(), 354868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 0.02f); 355868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 356868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) target_size.SetSize(416, 205); 357868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) image_size.SetSize(1200, 1200); 358868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) computed_size.SetSize(300, 300); 359868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) adjusted_size = AdjustClippingSizeToAspectRatio( 360868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) target_size, image_size, computed_size); 361868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Invariant check. 362868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(adjusted_size.width(), image_size.width()); 363868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(adjusted_size.height(), image_size.height()); 364868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(adjusted_size.width(), target_size.width()); 365868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(adjusted_size.height(), target_size.height()); 366868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(AspectDifference(target_size, adjusted_size), 367868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) AspectDifference(target_size, computed_size)); 368868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Specific to this case. 369868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_EQ(computed_size.height(), adjusted_size.height()); 370868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(computed_size.width(), adjusted_size.width()); 371868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_NEAR( 372868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<float>(target_size.width()) / target_size.height(), 373868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<float>(adjusted_size.width()) / adjusted_size.height(), 374868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 0.02f); 375868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 376868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) computed_size.SetSize(200, 300); 377868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) adjusted_size = AdjustClippingSizeToAspectRatio( 378868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) target_size, image_size, computed_size); 379868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Invariant check. 380868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(adjusted_size.width(), image_size.width()); 381868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(adjusted_size.height(), image_size.height()); 382868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(adjusted_size.width(), target_size.width()); 383868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(adjusted_size.height(), target_size.height()); 384868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(AspectDifference(target_size, adjusted_size), 385868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) AspectDifference(target_size, computed_size)); 386868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Specific to this case. 387868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_EQ(computed_size.height(), adjusted_size.height()); 388868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(computed_size.width(), adjusted_size.width()); 389868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_NEAR( 390868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<float>(target_size.width()) / target_size.height(), 391868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<float>(adjusted_size.width()) / adjusted_size.height(), 392868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 0.02f); 393868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 394868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) target_size.SetSize(416, 205); 395868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) image_size.SetSize(1400, 600); 396868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) computed_size.SetSize(300, 300); 397868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) adjusted_size = AdjustClippingSizeToAspectRatio( 398868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) target_size, image_size, computed_size); 399868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Invariant check. 400868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(adjusted_size.width(), image_size.width()); 401868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(adjusted_size.height(), image_size.height()); 402868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(adjusted_size.width(), target_size.width()); 403868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(adjusted_size.height(), target_size.height()); 404868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(AspectDifference(target_size, adjusted_size), 405868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) AspectDifference(target_size, computed_size)); 406868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Specific to this case. 407868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_EQ(computed_size.height(), adjusted_size.height()); 408868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(computed_size.width(), adjusted_size.width()); 409868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_NEAR( 410868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<float>(target_size.width()) / target_size.height(), 411868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<float>(adjusted_size.width()) / adjusted_size.height(), 412868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 0.02f); 413868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 414868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) computed_size.SetSize(900, 300); 415868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) adjusted_size = AdjustClippingSizeToAspectRatio( 416868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) target_size, image_size, computed_size); 417868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Invariant check. 418868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(adjusted_size.width(), image_size.width()); 419868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(adjusted_size.height(), image_size.height()); 420868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(adjusted_size.width(), target_size.width()); 421868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(adjusted_size.height(), target_size.height()); 422868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(AspectDifference(target_size, adjusted_size), 423868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) AspectDifference(target_size, computed_size)); 424868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Specific to this case. 425868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LE(computed_size.height(), adjusted_size.height()); 426868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_NEAR( 427868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<float>(target_size.width()) / target_size.height(), 428868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<float>(adjusted_size.width()) / adjusted_size.height(), 429868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 0.02f); 430868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 431868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 432c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)TEST_F(ThumbnailContentAnalysisTest, AutoSegmentPeaks) { 433c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<float> profile_info; 434c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 435c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(AutoSegmentPeaks(profile_info), std::numeric_limits<float>::max()); 436c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) profile_info.resize(1000, 1.0f); 437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(AutoSegmentPeaks(profile_info), 1.0f); 438c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::srand(42); 439c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::generate(profile_info.begin(), profile_info.end(), std::rand); 440c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) float threshold = AutoSegmentPeaks(profile_info); 441c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_GT(threshold, 0); // Not much to expect. 442c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 443c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // There should be roughly 50% above and below the threshold. 444c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Random is not really random thanks to srand, so we can sort-of compare. 445c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int above_count = std::count_if( 446c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) profile_info.begin(), 447c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) profile_info.end(), 448c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::bind2nd(std::greater<float>(), threshold)); 449c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_GT(above_count, 450); // Not much to expect. 450c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_LT(above_count, 550); 451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 452c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (unsigned i = 0; i < profile_info.size(); ++i) { 453c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) float y = std::sin(M_PI * i / 250.0f); 454c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) profile_info[i] = y > 0 ? y : 0; 455c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 456c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) threshold = AutoSegmentPeaks(profile_info); 457c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 458c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) above_count = std::count_if( 459c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) profile_info.begin(), 460c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) profile_info.end(), 461c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::bind2nd(std::greater<float>(), threshold)); 462c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_LT(above_count, 500); // Negative y expected to fall below threshold. 463c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 464c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Expect two peaks around between 0 and 250 and 500 and 750. 465c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<bool> thresholded_values(profile_info.size(), false); 466c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::transform(profile_info.begin(), 467c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) profile_info.end(), 468c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) thresholded_values.begin(), 469c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::bind2nd(std::greater<float>(), threshold)); 470c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_TRUE(thresholded_values[125]); 471c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_TRUE(thresholded_values[625]); 472c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int transitions = 0; 473c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (unsigned i = 1; i < thresholded_values.size(); ++i) { 474c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (thresholded_values[i] != thresholded_values[i-1]) 475c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) transitions++; 476c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 477c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(transitions, 4); // We have two contiguous peaks. Good going! 478c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 479c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 480868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(ThumbnailContentAnalysisTest, ConstrainedProfileSegmentation) { 481868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const size_t kRowCount = 800; 482868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const size_t kColumnCount = 1400; 483868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const gfx::Size target_size(300, 150); 484868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::vector<float> rows_profile(kRowCount); 485868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::vector<float> columns_profile(kColumnCount); 486868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 487868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::srand(42); 488868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::generate(rows_profile.begin(), rows_profile.end(), std::rand); 489868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::generate(columns_profile.begin(), columns_profile.end(), std::rand); 490868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 491868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Bring noise level to 0-1. 492868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::transform(rows_profile.begin(), 493868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) rows_profile.end(), 494868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) rows_profile.begin(), 495868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::bind2nd(std::divides<float>(), RAND_MAX)); 496868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::transform(columns_profile.begin(), 497868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) columns_profile.end(), 498868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) columns_profile.begin(), 499868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::bind2nd(std::divides<float>(), RAND_MAX)); 500868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 501868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Set up values to 0-1. 502868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::transform(rows_profile.begin(), 503868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) rows_profile.end(), 504868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) rows_profile.begin(), 505868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::bind2nd(std::plus<float>(), 1.0f)); 506868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::transform(columns_profile.begin(), 507868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) columns_profile.end(), 508868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) columns_profile.begin(), 509868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::bind2nd(std::plus<float>(), 1.0f)); 510868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 511868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::transform(rows_profile.begin() + 300, 512868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) rows_profile.begin() + 450, 513868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) rows_profile.begin() + 300, 514868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::bind2nd(std::plus<float>(), 8.0f)); 515868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::transform(columns_profile.begin() + 400, 516868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) columns_profile.begin() + 1000, 517868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) columns_profile.begin() + 400, 518868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::bind2nd(std::plus<float>(), 10.0f)); 519868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 520868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Make sure that threshold falls somewhere reasonable. 521868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) float row_threshold = AutoSegmentPeaks(rows_profile); 522868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GT(row_threshold, 1.0f); 523868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LT(row_threshold, 9.0f); 524868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 525868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int row_above_count = std::count_if( 526868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) rows_profile.begin(), 527868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) rows_profile.end(), 528868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::bind2nd(std::greater<float>(), row_threshold)); 529868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_EQ(row_above_count, 150); 530868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 531868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) float column_threshold = AutoSegmentPeaks(columns_profile); 532868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GT(column_threshold, 1.0f); 533868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_LT(column_threshold, 11.0f); 534868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 535868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int column_above_count = std::count_if( 536868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) columns_profile.begin(), 537868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) columns_profile.end(), 538868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::bind2nd(std::greater<float>(), column_threshold)); 539868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_EQ(column_above_count, 600); 540868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 541868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 542868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::vector<bool> rows_guide; 543868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::vector<bool> columns_guide; 544868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ConstrainedProfileSegmentation( 545868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) rows_profile, columns_profile, target_size, &rows_guide, &columns_guide); 546868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 547868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int row_count = std::count(rows_guide.begin(), rows_guide.end(), true); 548868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int column_count = std::count( 549868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) columns_guide.begin(), columns_guide.end(), true); 550868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) float expected_aspect = 551868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<float>(target_size.width()) / target_size.height(); 552868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) float actual_aspect = static_cast<float>(column_count) / row_count; 553868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(1.05f, expected_aspect / actual_aspect); 554868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_GE(1.05f, actual_aspect / expected_aspect); 555868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 556868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 557c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)TEST_F(ThumbnailContentAnalysisTest, ComputeDecimatedImage) { 558c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Size image_size(1600, 1200); 55968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) gfx::Canvas canvas(image_size, 1.0f, true); 560c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 561c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Make some content we will later want to keep. 5624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) canvas.FillRect(gfx::Rect(100, 200, 100, 100), SkColorSetRGB(125, 0, 0)); 5634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) canvas.FillRect(gfx::Rect(300, 200, 100, 100), SkColorSetRGB(0, 200, 0)); 5644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) canvas.FillRect(gfx::Rect(500, 200, 100, 100), SkColorSetRGB(0, 0, 225)); 5654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) canvas.FillRect(gfx::Rect(100, 400, 600, 100), SkColorSetRGB(125, 200, 225)); 566c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 567c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<bool> rows(image_size.height(), false); 568c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::fill_n(rows.begin() + 200, 100, true); 569c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::fill_n(rows.begin() + 400, 100, true); 570c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 571c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<bool> columns(image_size.width(), false); 572c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::fill_n(columns.begin() + 100, 100, true); 573c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::fill_n(columns.begin() + 300, 100, true); 574c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::fill_n(columns.begin() + 500, 100, true); 575c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 576c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkBitmap source = 577c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); 578c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkBitmap result = ComputeDecimatedImage(source, rows, columns); 579c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_FALSE(result.empty()); 580c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(300, result.width()); 581c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(200, result.height()); 582c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 583c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // The call should have removed all empty spaces. 584c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_TRUE(CompareImageFragments(source, 585c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) result, 586c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Size(100, 100), 587c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Point(100, 200), 588c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Point(0, 0))); 589c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_TRUE(CompareImageFragments(source, 590c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) result, 591c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Size(100, 100), 592c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Point(300, 200), 593c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Point(100, 0))); 594c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_TRUE(CompareImageFragments(source, 595c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) result, 596c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Size(100, 100), 597c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Point(500, 200), 598c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Point(200, 0))); 599c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_TRUE(CompareImageFragments(source, 600c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) result, 601c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Size(100, 100), 602c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Point(100, 400), 6034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) gfx::Point(0, 100))); 604c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 605c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 606868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(ThumbnailContentAnalysisTest, CreateRetargetedThumbnailImage) { 607c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Size image_size(1200, 1300); 60868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) gfx::Canvas canvas(image_size, 1.0f, true); 609c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 610c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // The following will create a 'fake image' consisting of color blocks placed 611c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // on a neutral background. The entire layout is supposed to mimic a 612c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // screenshot of a web page. 613c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // The tested function is supposed to locate the interesing areas in the 614c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // middle. 615c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const int margin_horizontal = 60; 616c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const int margin_vertical = 20; 617c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) canvas.FillRect(gfx::Rect(image_size), SkColorSetRGB(200, 210, 210)); 618c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const gfx::Rect header_rect(margin_horizontal, 619c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) margin_vertical, 620c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) image_size.width() - 2 * margin_horizontal, 621c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 100); 622c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const gfx::Rect footer_rect(margin_horizontal, 623c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) image_size.height() - margin_vertical - 100, 624c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) image_size.width() - 2 * margin_horizontal, 625c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 100); 626c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const gfx::Rect body_rect(margin_horizontal, 627c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) header_rect.bottom() + margin_vertical, 628c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) image_size.width() - 2 * margin_horizontal, 629c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) footer_rect.y() - header_rect.bottom() - 630c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2 * margin_vertical); 631c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) canvas.FillRect(header_rect, SkColorSetRGB(200, 40, 10)); 632c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) canvas.FillRect(footer_rect, SkColorSetRGB(10, 40, 180)); 633c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) canvas.FillRect(body_rect, SkColorSetRGB(150, 180, 40)); 634c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 635c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // 'Fine print' at the bottom. 636c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const int fine_print = 8; 637c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const SkColor print_color = SkColorSetRGB(45, 30, 30); 638c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int y = footer_rect.y() + fine_print; 639c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) y < footer_rect.bottom() - fine_print; 640c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) y += 2 * fine_print) { 641c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int x = footer_rect.x() + fine_print; 642c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) x < footer_rect.right() - fine_print; 643c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) x += 2 * fine_print) { 644c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) canvas.DrawRect(gfx::Rect(x, y, fine_print, fine_print), print_color); 645c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 646c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 647c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 648c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Blocky content at the top. 649c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const int block_size = header_rect.height() - margin_vertical; 650c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int x = header_rect.x() + margin_horizontal; 651c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) x < header_rect.right() - block_size; 652c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) x += block_size + margin_horizontal) { 653c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const int half_block = block_size / 2 - 5; 654c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const SkColor block_color = SkColorSetRGB(255, 255, 255); 655c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const int y = header_rect.y() + margin_vertical / 2; 656c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int second_col = x + half_block + 10; 657c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int second_row = y + half_block + 10; 658c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) canvas.FillRect(gfx::Rect(x, y, half_block, block_size), block_color); 659c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) canvas.FillRect(gfx::Rect(second_col, y, half_block, half_block), 660c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) block_color); 661c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) canvas.FillRect(gfx::Rect(second_col, second_row, half_block, half_block), 662c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) block_color); 663c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 664c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 665c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Now the main body. Mostly text with some 'pictures'. 666c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int y = body_rect.y() + fine_print; 667c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) y < body_rect.bottom() - fine_print; 668c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) y += 2 * fine_print) { 669c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int x = body_rect.x() + fine_print; 670c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) x < body_rect.right() - fine_print; 671c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) x += 2 * fine_print) { 672c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) canvas.DrawRect(gfx::Rect(x, y, fine_print, fine_print), print_color); 673c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 674c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 675c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 676c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int line = 0; line < 3; ++line) { 677c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int alignment = line % 2; 678c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const int y = body_rect.y() + 679c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) body_rect.height() / 3 * line + margin_vertical; 680c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const int x = body_rect.x() + 681c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) alignment * body_rect.width() / 2 + margin_vertical; 682c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Rect pict_rect(x, y, 683c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) body_rect.width() / 2 - 2 * margin_vertical, 684c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) body_rect.height() / 3 - 2 * margin_vertical); 685c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) canvas.FillRect(pict_rect, SkColorSetRGB(255, 255, 255)); 686c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) canvas.DrawRect(pict_rect, SkColorSetRGB(0, 0, 0)); 687c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 688c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 689c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SkBitmap source = 690c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false); 691c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 692868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) SkBitmap result = CreateRetargetedThumbnailImage( 693c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) source, gfx::Size(424, 264), 2.5); 694c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_FALSE(result.empty()); 695c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 696c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Given the nature of computation We can't really assert much here about the 697c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // image itself. We know it should have been computed, should be smaller than 698c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // the original and it must not be zero. 699c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_LT(result.width(), image_size.width()); 700c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_LT(result.height(), image_size.height()); 701c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 702c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int histogram[256] = {}; 703c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) color_utils::BuildLumaHistogram(result, histogram); 704c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int non_zero_color_count = std::count_if( 705c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) histogram, histogram + 256, std::bind2nd(std::greater<int>(), 0)); 706c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_GT(non_zero_color_count, 4); 707c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 708c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 709c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 710c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} // namespace thumbnailing_utils 711