1/*
2 * Copyright 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *       http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.support.v7.graphics;
18
19import java.util.Arrays;
20
21/**
22 * Class which provides a histogram for RGB values.
23 */
24final class ColorHistogram {
25
26    private final int[] mColors;
27    private final int[] mColorCounts;
28    private final int mNumberColors;
29
30    /**
31     * A new {@link ColorHistogram} instance.
32     *
33     * @param pixels array of image contents
34     */
35    ColorHistogram(final int[] pixels) {
36        // Sort the pixels to enable counting below
37        Arrays.sort(pixels);
38
39        // Count number of distinct colors
40        mNumberColors = countDistinctColors(pixels);
41
42        // Create arrays
43        mColors = new int[mNumberColors];
44        mColorCounts = new int[mNumberColors];
45
46        // Finally count the frequency of each color
47        countFrequencies(pixels);
48    }
49
50    /**
51     * @return number of distinct colors in the image.
52     */
53    int getNumberOfColors() {
54        return mNumberColors;
55    }
56
57    /**
58     * @return an array containing all of the distinct colors in the image.
59     */
60    int[] getColors() {
61        return mColors;
62    }
63
64    /**
65     * @return an array containing the frequency of a distinct colors within the image.
66     */
67    int[] getColorCounts() {
68        return mColorCounts;
69    }
70
71    private static int countDistinctColors(final int[] pixels) {
72        if (pixels.length < 2) {
73            // If we have less than 2 pixels we can stop here
74            return pixels.length;
75        }
76
77        // If we have at least 2 pixels, we have a minimum of 1 color...
78        int colorCount = 1;
79        int currentColor = pixels[0];
80
81        // Now iterate from the second pixel to the end, counting distinct colors
82        for (int i = 1; i < pixels.length; i++) {
83            // If we encounter a new color, increase the population
84            if (pixels[i] != currentColor) {
85                currentColor = pixels[i];
86                colorCount++;
87            }
88        }
89
90        return colorCount;
91    }
92
93    private void countFrequencies(final int[] pixels) {
94        if (pixels.length == 0) {
95            return;
96        }
97
98        int currentColorIndex = 0;
99        int currentColor = pixels[0];
100
101        mColors[currentColorIndex] = currentColor;
102        mColorCounts[currentColorIndex] = 1;
103
104        if (pixels.length == 1) {
105            // If we only have one pixel, we can stop here
106            return;
107        }
108
109        // Now iterate from the second pixel to the end, population distinct colors
110        for (int i = 1; i < pixels.length; i++) {
111            if (pixels[i] == currentColor) {
112                // We've hit the same color as before, increase population
113                mColorCounts[currentColorIndex]++;
114            } else {
115                // We've hit a new color, increase index
116                currentColor = pixels[i];
117
118                currentColorIndex++;
119                mColors[currentColorIndex] = currentColor;
120                mColorCounts[currentColorIndex] = 1;
121            }
122        }
123    }
124
125}
126