View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.imaging.palette;
18  
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import org.apache.commons.imaging.ImagingException;
23  
24  final class ColorGroup {
25  
26      // final ColorGroup parent;
27      ColorGroupCut cut;
28      // final List children = new ArrayList();
29      int paletteIndex = -1;
30  
31      private final List<ColorCount> colorCounts;
32      final boolean ignoreAlpha;
33      int minRed = Integer.MAX_VALUE;
34      int maxRed = Integer.MIN_VALUE;
35      int minGreen = Integer.MAX_VALUE;
36      int maxGreen = Integer.MIN_VALUE;
37      int minBlue = Integer.MAX_VALUE;
38      int maxBlue = Integer.MIN_VALUE;
39      int minAlpha = Integer.MAX_VALUE;
40      int maxAlpha = Integer.MIN_VALUE;
41  
42      final int alphaDiff;
43      final int redDiff;
44      final int greenDiff;
45      final int blueDiff;
46  
47      final int maxDiff;
48      final int diffTotal;
49      final int totalPoints;
50  
51      ColorGroup(final List<ColorCount> colorCounts, final boolean ignoreAlpha) throws ImagingException {
52          this.colorCounts = colorCounts;
53          this.ignoreAlpha = ignoreAlpha;
54  
55          if (colorCounts.isEmpty()) {
56              throw new ImagingException("Empty colorCounts");
57          }
58  
59          int total = 0;
60          for (final ColorCount color : colorCounts) {
61              total += color.count;
62  
63              minAlpha = Math.min(minAlpha, color.alpha);
64              maxAlpha = Math.max(maxAlpha, color.alpha);
65              minRed = Math.min(minRed, color.red);
66              maxRed = Math.max(maxRed, color.red);
67              minGreen = Math.min(minGreen, color.green);
68              maxGreen = Math.max(maxGreen, color.green);
69              minBlue = Math.min(minBlue, color.blue);
70              maxBlue = Math.max(maxBlue, color.blue);
71          }
72          this.totalPoints = total;
73  
74          alphaDiff = maxAlpha - minAlpha;
75          redDiff = maxRed - minRed;
76          greenDiff = maxGreen - minGreen;
77          blueDiff = maxBlue - minBlue;
78          maxDiff = Math.max(ignoreAlpha ? redDiff : Math.max(alphaDiff, redDiff), Math.max(greenDiff, blueDiff));
79          diffTotal = (ignoreAlpha ? 0 : alphaDiff) + redDiff + greenDiff + blueDiff;
80      }
81  
82      boolean contains(final int argb) {
83          final int alpha = 0xff & argb >> 24;
84          final int red = 0xff & argb >> 16;
85          final int green = 0xff & argb >> 8;
86          final int blue = 0xff & argb >> 0;
87  
88          if (!ignoreAlpha && (alpha < minAlpha || alpha > maxAlpha)) {
89              return false;
90          }
91          if (red < minRed || red > maxRed) {
92              return false;
93          }
94          if (green < minGreen || green > maxGreen) {
95              return false;
96          }
97          if (blue < minBlue || blue > maxBlue) {
98              return false;
99          }
100         return true;
101     }
102 
103     /**
104      * Gets a copy of the list of color counts.
105      *
106      * @return a copy of the list of color counts
107      */
108     List<ColorCount> getColorCounts() {
109         return new ArrayList<>(colorCounts);
110     }
111 
112     int getMedianValue() {
113         long countTotal = 0;
114         long alphaTotal = 0;
115         long redTotal = 0;
116         long greenTotal = 0;
117         long blueTotal = 0;
118 
119         for (final ColorCount color : colorCounts) {
120             countTotal += color.count;
121             alphaTotal += color.count * color.alpha;
122             redTotal += color.count * color.red;
123             greenTotal += color.count * color.green;
124             blueTotal += color.count * color.blue;
125         }
126 
127         final int alpha = ignoreAlpha ? 0xff : (int) Math.round((double) alphaTotal / countTotal);
128         final int red = (int) Math.round((double) redTotal / countTotal);
129         final int green = (int) Math.round((double) greenTotal / countTotal);
130         final int blue = (int) Math.round((double) blueTotal / countTotal);
131 
132         return alpha << 24 | red << 16 | green << 8 | blue;
133     }
134 
135     @Override
136     public String toString() {
137         return "{ColorGroup. minRed: " + Integer.toHexString(minRed) + ", maxRed: " + Integer.toHexString(maxRed) + ", minGreen: "
138                 + Integer.toHexString(minGreen) + ", maxGreen: " + Integer.toHexString(maxGreen) + ", minBlue: " + Integer.toHexString(minBlue) + ", maxBlue: "
139                 + Integer.toHexString(maxBlue) + ", minAlpha: " + Integer.toHexString(minAlpha) + ", maxAlpha: " + Integer.toHexString(maxAlpha) + ", maxDiff: "
140                 + Integer.toHexString(maxDiff) + ", diffTotal: " + diffTotal + "}";
141     }
142 
143 }