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.Arrays;
20  import java.util.Comparator;
21  import java.util.logging.Logger;
22  
23  final class ColorSpaceSubset {
24  
25      public static class RgbComparator implements Comparator<ColorSpaceSubset> {
26  
27          @Override
28          public int compare(final ColorSpaceSubset c1, final ColorSpaceSubset c2) {
29              return c1.rgb - c2.rgb;
30          }
31      }
32  
33      private static final Logger LOGGER = Logger.getLogger(ColorSpaceSubset.class.getName());
34      public static final RgbComparator RGB_COMPARATOR = new RgbComparator();
35      static final int SHALLOW_SIZE = 40;
36      final int[] mins;
37      final int[] maxs;
38      final int precision;
39      final int precisionMask;
40      final int total;
41  
42      int rgb; // median
43      // the index in the palette.
44      private int index;
45  
46      ColorSpaceSubset(final int total, final int precision) {
47          this.total = total;
48          this.precision = precision;
49          precisionMask = (1 << precision) - 1;
50  
51          mins = new int[PaletteFactory.COMPONENTS];
52          maxs = new int[PaletteFactory.COMPONENTS];
53          Arrays.fill(maxs, precisionMask);
54  
55          rgb = -1;
56      }
57  
58      ColorSpaceSubset(final int total, final int precision, final int[] mins, final int[] maxs) {
59          this.total = total;
60          this.precision = precision;
61          this.mins = mins;
62          this.maxs = maxs;
63          precisionMask = (1 << precision) - 1;
64  
65          rgb = -1;
66      }
67  
68      public boolean contains(int red, int green, int blue) {
69          red >>= 8 - precision;
70          if (mins[0] > red) {
71              return false;
72          }
73          if (maxs[0] < red) {
74              return false;
75          }
76  
77          green >>= 8 - precision;
78          if (mins[1] > green) {
79              return false;
80          }
81          if (maxs[1] < green) {
82              return false;
83          }
84  
85          blue >>= 8 - precision;
86          if (mins[2] > blue) {
87              return false;
88          }
89          if (maxs[2] < blue) {
90              return false;
91          }
92  
93          return true;
94      }
95  
96      public void dump(final String prefix) {
97          final int rdiff = maxs[0] - mins[0] + 1;
98          final int gdiff = maxs[1] - mins[1] + 1;
99          final int bdiff = maxs[2] - mins[2] + 1;
100         final int colorArea = rdiff * gdiff * bdiff;
101 
102         LOGGER.fine(prefix + ": [" + Integer.toHexString(rgb) + "] total : " + total
103         // + " ("
104         // + (100.0 * (double) total / (double) total_area)
105         // + " %)"
106         );
107         LOGGER.fine("\t" + "rgb: " + Integer.toHexString(rgb) + ", " + "red: " + Integer.toHexString(mins[0] << 8 - precision) + ", "
108                 + Integer.toHexString(maxs[0] << 8 - precision) + ", " + "green: " + Integer.toHexString(mins[1] << 8 - precision) + ", "
109                 + Integer.toHexString(maxs[1] << 8 - precision) + ", " + "blue: " + Integer.toHexString(mins[2] << 8 - precision) + ", "
110                 + Integer.toHexString(maxs[2] << 8 - precision));
111         LOGGER.fine("\t" + "red: " + mins[0] + ", " + maxs[0] + ", " + "green: " + mins[1] + ", " + maxs[1] + ", " + "blue: " + mins[2] + ", " + maxs[2]);
112         LOGGER.fine("\t" + "rdiff: " + rdiff + ", " + "gdiff: " + gdiff + ", " + "bdiff: " + bdiff + ", " + "colorArea: " + colorArea);
113     }
114 
115     public void dumpJustRgb(final String prefix) {
116         LOGGER.fine("\t" + "rgb: " + Integer.toHexString(rgb) + ", " + "red: " + Integer.toHexString(mins[0] << 8 - precision) + ", "
117                 + Integer.toHexString(maxs[0] << 8 - precision) + ", " + "green: " + Integer.toHexString(mins[1] << 8 - precision) + ", "
118                 + Integer.toHexString(maxs[1] << 8 - precision) + ", " + "blue: " + Integer.toHexString(mins[2] << 8 - precision) + ", "
119                 + Integer.toHexString(maxs[2] << 8 - precision));
120     }
121 
122     public int getArea() {
123         final int rdiff = maxs[0] - mins[0] + 1;
124         final int gdiff = maxs[1] - mins[1] + 1;
125         final int bdiff = maxs[2] - mins[2] + 1;
126 
127         return rdiff * gdiff * bdiff;
128 
129     }
130 
131     public int getIndex() {
132         return index;
133     }
134 
135     public void setAverageRgb(final int[] table) {
136         long redsum = 0;
137         long greensum = 0;
138         long bluesum = 0;
139 
140         for (int red = mins[0]; red <= maxs[0]; red++) {
141             for (int green = mins[1]; green <= maxs[1]; green++) {
142                 for (int blue = mins[2]; blue <= maxs[2]; blue++) {
143                     // note: order reversed
144                     final int idx = blue << 2 * precision | green << 1 * precision | red << 0 * precision;
145                     final int count = table[idx];
146                     redsum += count * (red << 8 - precision);
147                     greensum += count * (green << 8 - precision);
148                     bluesum += count * (blue << 8 - precision);
149                 }
150             }
151         }
152 
153         redsum /= total;
154         greensum /= total;
155         bluesum /= total;
156         rgb = (int) ((redsum & 0xff) << 16 | (greensum & 0xff) << 8 | (bluesum & 0xff) << 0);
157     }
158 
159     public void setIndex(final int i) {
160         index = i;
161     }
162 }