| Index: ui/gfx/color_analysis.h
|
| diff --git a/ui/gfx/color_analysis.h b/ui/gfx/color_analysis.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c71a38603b7119ee684a35ffdd27adba7b7dcf1a
|
| --- /dev/null
|
| +++ b/ui/gfx/color_analysis.h
|
| @@ -0,0 +1,112 @@
|
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#ifndef UI_GFX_COLOR_ANALYSIS_H_
|
| +#define UI_GFX_COLOR_ANALYSIS_H_
|
| +#pragma once
|
| +
|
| +#include "base/basictypes.h"
|
| +#include "base/compiler_specific.h"
|
| +#include "base/memory/ref_counted.h"
|
| +#include "base/memory/ref_counted_memory.h"
|
| +#include "third_party/skia/include/core/SkColor.h"
|
| +
|
| +namespace color_utils {
|
| +
|
| +// This class exposes the sampling method to the caller, which allows
|
| +// stubbing out for things like unit tests. Might be useful to pass more
|
| +// arguments into the GetSample method in the future (such as which
|
| +// cluster is being worked on, etc.).
|
| +class KMeanImageSampler {
|
| + public:
|
| + virtual int GetSample(int width, int height) = 0;
|
| +
|
| + protected:
|
| + KMeanImageSampler();
|
| + virtual ~KMeanImageSampler();
|
| +};
|
| +
|
| +// This sampler will pick a random pixel as a sample centroid.
|
| +class RandomSampler : public KMeanImageSampler {
|
| + public:
|
| + RandomSampler();
|
| + virtual ~RandomSampler();
|
| +
|
| + virtual int GetSample(int width, int height) OVERRIDE;
|
| +};
|
| +
|
| +// This sampler will pick pixels from an evenly spaced grid.
|
| +class GridSampler : public KMeanImageSampler {
|
| + public:
|
| + GridSampler();
|
| + virtual ~GridSampler();
|
| +
|
| + virtual int GetSample(int width, int height) OVERRIDE;
|
| +
|
| + private:
|
| + // The number of times GetSample has been called.
|
| + int calls_;
|
| +};
|
| +
|
| +// Returns a recommended background color for a PNG image. This color might
|
| +// not even exist in the image, but it is typically representative of the
|
| +// image and tinted towards the white end of the spectrum.
|
| +// The function CalculateKMeanColorOfPNG is used to grab the KMean calculated
|
| +// color of the image, then the color is moved to HSV space so the saturation
|
| +// and luminance can be modified to move the color towards the white end of
|
| +// the spectrum. The color is then moved back to RGB space and returned.
|
| +SkColor CalculateRecommendedBgColorForPNG(scoped_refptr<RefCountedMemory> png);
|
| +
|
| +SkColor CalculateRecommendedBgColorForPNG(scoped_refptr<RefCountedMemory> png,
|
| + KMeanImageSampler& sampler);
|
| +
|
| +// Returns an SkColor that represents the calculated dominant color in the png.
|
| +// This uses a KMean clustering algorithm to find clusters of pixel colors in
|
| +// RGB space.
|
| +// |png| represents the data of a png encoded image.
|
| +// |darkness_limit| represents the minimum sum of the RGB components that is
|
| +// acceptable as a color choice. This can be from 0 to 765.
|
| +// |brightness_limit| represents the maximum sum of the RGB components that is
|
| +// acceptable as a color choice. This can be from 0 to 765.
|
| +//
|
| +// RGB KMean Algorithm (N clusters, M iterations):
|
| +// TODO (dtrainor): Try moving most/some of this to HSV space? Better for
|
| +// color comparisons/averages?
|
| +// 1.Pick N starting colors by randomly sampling the pixels. If you see a
|
| +// color you already saw keep sampling. After a certain number of tries
|
| +// just remove the cluster and continue with N = N-1 clusters (for an image
|
| +// with just one color this should devolve to N=1). These colors are the
|
| +// centers of your N clusters.
|
| +// TODO (dtrainor): Check to ignore colors with an alpha of 0?
|
| +// 2.For each pixel in the image find the cluster that it is closest to in RGB
|
| +// space. Add that pixel's color to that cluster (we keep a sum and a count
|
| +// of all of the pixels added to the space, so just add it to the sum and
|
| +// increment count).
|
| +// 3.Calculate the new cluster centroids by getting the average color of all of
|
| +// the pixels in each cluster (dividing the sum by the count).
|
| +// 4.See if the new centroids are the same as the old centroids.
|
| +// a) If this is the case for all N clusters than we have converged and
|
| +// can move on.
|
| +// b) If any centroid moved, repeat step 2 with the new centroids for up
|
| +// to M iterations.
|
| +// 5.Once the clusters have converged or M iterations have been tried, sort
|
| +// the clusters by weight (where weight is the number of pixels that make up
|
| +// this cluster).
|
| +// 6.Going through the sorted list of clusters, pick the first cluster with the
|
| +// largest weight that's centroid fulfills the equation
|
| +// |darkness_limit| < SUM(R, G, B) < |brightness_limit|. Return that color.
|
| +// If no color fulfills that requirement return the color with the largest
|
| +// weight regardless of whether or not it fulfills the equation above.
|
| +SkColor CalculateKMeanColorOfPNG(scoped_refptr<RefCountedMemory> png,
|
| + uint32_t darkness_limit,
|
| + uint32_t brightness_limit);
|
| +
|
| +SkColor CalculateKMeanColorOfPNG(scoped_refptr<RefCountedMemory> png,
|
| + uint32_t darkness_limit,
|
| + uint32_t brightness_limit,
|
| + KMeanImageSampler& sampler);
|
| +
|
| +} // namespace color_utils
|
| +
|
| +#endif // UI_GFX_COLOR_ANALYSIS_H_
|
|
|