Source Code Cross Referenced for ColorUtilities.java in  » GIS » GeoTools-2.4.1 » org » geotools » resources » image » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » GIS » GeoTools 2.4.1 » org.geotools.resources.image 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *    GeoTools - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *    (C) 2003-2006, Geotools Project Managment Committee (PMC)
005:         *    (C) 2001, Institut de Recherche pour le Développement
006:         *
007:         *    This library is free software; you can redistribute it and/or
008:         *    modify it under the terms of the GNU Lesser General Public
009:         *    License as published by the Free Software Foundation; either
010:         *    version 2.1 of the License, or (at your option) any later version.
011:         *
012:         *    This library is distributed in the hope that it will be useful,
013:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
014:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015:         *    Lesser General Public License for more details.
016:         */
017:        package org.geotools.resources.image;
018:
019:        // J2SE dependencies
020:        import java.awt.Color;
021:        import java.awt.color.ColorSpace;
022:        import java.awt.image.ColorModel;
023:        import java.awt.image.DataBuffer;
024:        import java.awt.image.IndexColorModel;
025:        import java.math.BigInteger;
026:        import java.util.Arrays;
027:
028:        // Geotools dependencies
029:        import org.geotools.resources.XMath;
030:
031:        /**
032:         * A set of static methods for handling of colors informations. Some of those methods
033:         * are useful, but not really rigorous. This is why they do not appear in any "official"
034:         * package, but instead in this private one.
035:         *
036:         *                      <strong>Do not rely on this API!</strong>
037:         *
038:         * It may change in incompatible way in any future version.
039:         *
040:         * @since 2.0
041:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/coverage/src/main/java/org/geotools/resources/image/ColorUtilities.java $
042:         * @version $Id: ColorUtilities.java 26799 2007-08-31 21:31:21Z desruisseaux $
043:         * @author Martin Desruisseaux
044:         * @author Simone Giannecchini
045:         */
046:        public final class ColorUtilities {
047:            /**
048:             * Small number for rounding errors.
049:             */
050:            private static final double EPS = 1E-6;
051:
052:            /**
053:             * Do not allow creation of instances of this class.
054:             */
055:            private ColorUtilities() {
056:            }
057:
058:            /**
059:             * Creates an sRGB color with the specified red, green, blue, and alpha
060:             * values in the range (0 - 255).
061:             * 
062:             * @param  r the red component
063:             * @param  g the green component
064:             * @param  b the blue component
065:             * @param  a the alpha component
066:             * @throws IllegalArgumentException if {@coder}, {@code g}, {@code b}
067:             *         or {@code a} are outside of the range 0 to 255, inclusive.
068:             */
069:            public static int getIntFromColor(int r, int g, int b, int a) {
070:                return ((a & 0xFF) << 24) | ((r & 0xFF) << 16)
071:                        | ((g & 0xFF) << 8) | ((b & 0xFF) << 0);
072:            }
073:
074:            /**
075:             * Returns a subarray of the specified color array. The {@code lower} and
076:             * {@code upper} index will be clamb into the {@code palette} range.
077:             * If they are completly out of range, or if they would result in an empty array,
078:             * then {@code null} is returned.
079:             *
080:             * This method is used by {@link org.geotools.cv.SampleDimension} as an heuristic
081:             * approach for distributing palette colors into a list of categories.
082:             *
083:             * @param  palette The color array (may be {@code null}).
084:             * @param  lower  The lower index, inclusive.
085:             * @param  upper  The upper index, inclusive.
086:             * @return The subarray (may be {@code palette} if the original array already fit),
087:             *         or {@code null} if the {@code lower} and {@code upper} index
088:             *         are out of {@code palette} bounds.
089:             */
090:            public static Color[] subarray(final Color[] palette, int lower,
091:                    int upper) {
092:                if (palette != null) {
093:                    lower = Math.max(lower, 0);
094:                    upper = Math.min(upper, palette.length);
095:                    if (lower >= upper) {
096:                        return null;
097:                    }
098:                    if (lower != 0 || upper != palette.length) {
099:                        final Color[] sub = new Color[upper - lower];
100:                        System.arraycopy(palette, lower, sub, 0, sub.length);
101:                        return sub;
102:                    }
103:                }
104:                return palette;
105:            }
106:
107:            /**
108:             * Copy {@code colors} into array {@code ARGB} from index {@code lower}
109:             * inclusive to index {@code upper} exclusive. If {@code upper-lower} is not
110:             * equals to the length of {@code colors} array, then colors will be interpolated.
111:             *
112:             * @param colors Colors to copy into the {@code ARGB} array.
113:             * @param ARGB   Array of integer to write ARGB values to.
114:             * @param lower  Index (inclusive) of the first element of {@code ARGB} to change.
115:             * @param upper  Index (exclusive) of the last  element of {@code ARGB} to change.
116:             */
117:            public static void expand(final Color[] colors, final int[] ARGB,
118:                    final int lower, final int upper) {
119:                switch (colors.length) {
120:                case 1:
121:                    Arrays.fill(ARGB, lower, upper, colors[0].getRGB()); // fall through
122:                case 0:
123:                    return; // Note: getRGB() is really getARGB()
124:                }
125:                switch (upper - lower) {
126:                case 1:
127:                    ARGB[lower] = colors[0].getRGB(); // fall through
128:                case 0:
129:                    return; // Note: getRGB() is really getARGB()
130:                }
131:                final int maxBase = colors.length - 2;
132:                final double scale = (double) (colors.length - 1)
133:                        / (double) (upper - 1 - lower);
134:                for (int i = lower; i < upper; i++) {
135:                    final double index = (i - lower) * scale;
136:                    final int base = Math.min(maxBase, (int) (index + EPS)); // Round toward 0, which is really what we want.
137:                    final double delta = index - base;
138:                    final Color C0 = colors[base + 0];
139:                    final Color C1 = colors[base + 1];
140:                    int A = C0.getAlpha();
141:                    int R = C0.getRed();
142:                    int G = C0.getGreen();
143:                    int B = C0.getBlue();
144:                    ARGB[i] = (roundByte(A + delta * (C1.getAlpha() - A)) << 24)
145:                            | (roundByte(R + delta * (C1.getRed() - R)) << 16)
146:                            | (roundByte(G + delta * (C1.getGreen() - G)) << 8)
147:                            | (roundByte(B + delta * (C1.getBlue() - B)) << 0);
148:                }
149:            }
150:
151:            /**
152:             * Round a float value and clamp the
153:             * result between 0 and 255 inclusive.
154:             */
155:            public static int roundByte(final double value) {
156:                return Math.min(Math.max((int) Math.round(value), 0), 255);
157:            }
158:
159:            /**
160:             * Returns an index color model for specified ARGB codes.   If the specified
161:             * array has not transparent color (i.e. all alpha values are 255), then the
162:             * returned color model will be opaque. Otherwise, if the specified array has
163:             * one and only one color with alpha value of 0, the returned color model will
164:             * have only this transparent color. Otherwise, the returned color model will
165:             * be translucent.
166:             *
167:             * @param  ARGB An array of ARGB values.
168:             * @return An index color model for the specified array.
169:             */
170:            public static IndexColorModel getIndexColorModel(final int[] ARGB) {
171:                return getIndexColorModel(ARGB, 1, 0);
172:            }
173:
174:            /**
175:             * Returns a tolerant index color model for the specified ARGB code. This color model accept
176:             * image with the specified number of bands.
177:             *
178:             * @param  ARGB        An array of ARGB values.
179:             * @param  numBands    The number of bands.
180:             * @param  visibleBand The band to display.
181:             * @return An index color model for the specified array.
182:             *
183:             * @todo Considerer caching previously created instances using weak references. Index color
184:             *       model may be big (up to 256 kb), so it may be worth to cache big instances. NOTE:
185:             *       IndexColorModel inherits a equals(Object) implementation from ColorModel, but do
186:             *       not override it, so the definition is incomplete.
187:             */
188:            public static IndexColorModel getIndexColorModel(final int[] ARGB,
189:                    final int numBands, final int visibleBand) {
190:                boolean hasAlpha = false;
191:                int transparent = -1;
192:                final int length = ARGB.length;
193:                for (int i = 0; i < length; i++) {
194:                    final int alpha = (ARGB[i] & 0xFF000000);
195:                    if (alpha != 0xFF000000) {
196:                        if (alpha == 0x00000000 && transparent < 0) {
197:                            transparent = i;
198:                            continue;
199:                        }
200:                        hasAlpha = true;
201:                        break;
202:                    }
203:                }
204:                final int bits = getBitCount(length);
205:                final int type = getTransferType(length);
206:                if (numBands == 1) {
207:                    return new IndexColorModel(bits, length, ARGB, 0, hasAlpha,
208:                            transparent, type);
209:                } else {
210:                    return new MultiBandsIndexColorModel(bits, length, ARGB, 0,
211:                            hasAlpha, transparent, type, numBands, visibleBand);
212:                }
213:            }
214:
215:            /**
216:             * Returns a bit count for an {@link IndexColorModel} mapping {@code mapSize} colors.
217:             * It is guaranteed that the following relation is hold:
218:             *
219:             * <center><pre>(1 << getBitCount(mapSize)) >= mapSize</pre></center>
220:             */
221:            public static int getBitCount(final int mapSize) {
222:                int max = mapSize - 1;
223:                if (max <= 1) {
224:                    return 1;
225:                }
226:                int count = 0;
227:                do {
228:                    count++;
229:                    max >>= 1;
230:                } while (max != 0);
231:                assert (1 << count) >= mapSize : mapSize;
232:                assert (1 << (count - 1)) < mapSize : mapSize;
233:                return count;
234:            }
235:
236:            /**
237:             * Returns a suggered type for an {@link IndexColorModel}
238:             * of {@code mapSize} colors. This method returns
239:             * {@link DataBuffer#TYPE_BYTE} or {@link DataBuffer#TYPE_USHORT}.
240:             */
241:            public static int getTransferType(final int mapSize) {
242:                return (mapSize <= 256) ? DataBuffer.TYPE_BYTE
243:                        : DataBuffer.TYPE_USHORT;
244:            }
245:
246:            /**
247:             * Transforms a color from XYZ color space to LAB. The color are transformed
248:             * in place. This method returns {@code color} for convenience.
249:             * Reference: http://www.brucelindbloom.com/index.html?ColorDifferenceCalc.html
250:             */
251:            public static float[] XYZtoLAB(final float[] color) {
252:                color[0] /= 0.9642; // Other refeference: 0.95047;
253:                color[1] /= 1.0000; //                    1.00000;
254:                color[2] /= 0.8249; //                    1.08883;
255:                for (int i = 0; i < 3; i++) {
256:                    final float c = color[i];
257:                    color[i] = (float) ((c > 216 / 24389f) ? Math.pow(c,
258:                            1.0 / 3) : ((24389 / 27.0) * c + 16) / 116);
259:                }
260:                final float L = 116 * color[1] - 16;
261:                final float a = 500 * (color[0] - color[1]);
262:                final float b = 200 * (color[1] - color[2]);
263:                assert !Float.isNaN(L) && !Float.isNaN(a) && !Float.isNaN(b);
264:                color[0] = L;
265:                color[1] = a;
266:                color[2] = b;
267:                return color;
268:            }
269:
270:            /**
271:             * Computes the distance E (CIE 1994) between two colors in LAB color space.
272:             * Reference: http://www.brucelindbloom.com/index.html?ColorDifferenceCalc.html
273:             */
274:            public static float colorDistance(final float[] lab1,
275:                    final float[] lab2) {
276:                if (false) {
277:                    // Compute distance using CIE94 formula.
278:                    // NOTE: this formula sometime fails because of negative
279:                    //       value in the first Math.sqrt(...) expression.
280:                    final double dL = (double) lab1[0] - lab2[0];
281:                    final double da = (double) lab1[1] - lab2[1];
282:                    final double db = (double) lab1[2] - lab2[2];
283:                    final double C1 = XMath.hypot(lab1[1], lab1[2]);
284:                    final double C2 = XMath.hypot(lab2[1], lab2[2]);
285:                    final double dC = C1 - C2;
286:                    final double dH = Math.sqrt(da * da + db * db - dC * dC);
287:                    final double sL = dL / 2;
288:                    final double sC = dC / (1 + 0.048 * C1);
289:                    final double sH = dH / (1 + 0.014 * C1);
290:                    return (float) Math.sqrt(sL * sL + sC * sC + sH * sH);
291:                } else {
292:                    // Compute distance using delta E formula.
293:                    double sum = 0;
294:                    for (int i = Math.min(lab1.length, lab2.length); --i >= 0;) {
295:                        final double delta = lab1[i] - lab2[i];
296:                        sum += delta * delta;
297:                    }
298:                    return (float) Math.sqrt(sum);
299:                }
300:            }
301:
302:            /**
303:             * Returns the most transparent pixel in the specified color model. If many colors has
304:             * the same alpha value, than the darkest one is returned. This method never returns
305:             * a negative value (0 is returned if the color model has no colors).
306:             *
307:             * @param  colors The color model in which to look for a transparent color.
308:             * @return The index of a transparent color, or 0.
309:             */
310:            public static int getTransparentPixel(final IndexColorModel colors) {
311:                int index = colors.getTransparentPixel();
312:                if (index < 0) {
313:                    index = 0;
314:                    int alpha = Integer.MAX_VALUE;
315:                    float delta = Float.POSITIVE_INFINITY;
316:                    final ColorSpace space = colors.getColorSpace();
317:                    final float[] RGB = new float[3];
318:                    final float[] BLACK = XYZtoLAB(space.toCIEXYZ(RGB)); // Black in Lab color space.
319:                    assert BLACK != RGB;
320:                    for (int i = colors.getMapSize(); --i >= 0;) {
321:                        final int a = colors.getAlpha(i);
322:                        if (a <= alpha) {
323:                            RGB[0] = colors.getRed(i) / 255f;
324:                            RGB[1] = colors.getGreen(i) / 255f;
325:                            RGB[2] = colors.getBlue(i) / 255f;
326:                            final float d = colorDistance(XYZtoLAB(space
327:                                    .toCIEXYZ(RGB)), BLACK);
328:                            assert d >= 0 : i; // Check mostly for NaN value
329:                            if (a < alpha || d < delta) {
330:                                alpha = a;
331:                                delta = d;
332:                                index = i;
333:                            }
334:                        }
335:                    }
336:                }
337:                return index;
338:            }
339:
340:            /**
341:             * Returns the index of the specified color, excluding the specified one. If the color
342:             * is not explicitly found, a close color is returned. This method never returns a negative
343:             * value (0 is returned if the color model has no colors).
344:             *
345:             * @param  colors The color model in which to look for a color index.
346:             * @param  color The color to search for.
347:             * @param  exclude An index to exclude from the search (usually the background or the
348:             *         {@linkplain #getTransparentPixel transparent} pixel), or -1 if none.
349:             * @return The index of the color, or 0.
350:             */
351:            public static int getColorIndex(final IndexColorModel colors,
352:                    final Color color, final int exclude) {
353:                final ColorSpace space = colors.getColorSpace();
354:                final float[] RGB = { color.getRed() / 255f,
355:                        color.getGreen() / 255f, color.getBlue() / 255f };
356:                final float[] REF = XYZtoLAB(space.toCIEXYZ(RGB));
357:                float delta = Float.POSITIVE_INFINITY;
358:                int index = 0;
359:                assert REF != RGB;
360:                for (int i = colors.getMapSize(); --i >= 0;) {
361:                    if (i != exclude) {
362:                        RGB[0] = colors.getRed(i) / 255f;
363:                        RGB[1] = colors.getGreen(i) / 255f;
364:                        RGB[2] = colors.getBlue(i) / 255f;
365:                        final float d = colorDistance(XYZtoLAB(space
366:                                .toCIEXYZ(RGB)), REF);
367:                        assert d >= 0 : i; // Check mostly for NaN value
368:                        if (d <= delta) {
369:                            delta = d;
370:                            index = i;
371:                        }
372:                    }
373:                }
374:                return index;
375:            }
376:
377:            /**
378:             * Tries to guess the number of bands from the specified color model. The recommanded approach
379:             * is to invoke {@link java.awt.image.SampleModel#getNumBands}. This method should be used only
380:             * as a fallback when the sample model is not available. This method uses some heuristic rules
381:             * for guessing the number of bands, so the return value may not be exact in all cases.
382:             */
383:            public static int getNumBands(final ColorModel model) {
384:                if (model instanceof  IndexColorModel) {
385:                    if (model instanceof  MultiBandsIndexColorModel) {
386:                        return ((MultiBandsIndexColorModel) model).numBands;
387:                    }
388:                    return 1;
389:                }
390:                return model.getNumComponents();
391:            }
392:
393:            /**
394:             * Tells us if a specific {@link IndexColorModel} contains only gray color
395:             * or not, ignoring alpha information.
396:             *
397:             * @param  icm {@link IndexColorModel} to be inspected.
398:             * @param  ignoreTransparents {@code true} if the RGB values of fully transparent pixels
399:             *         (the ones with an {@linkplain IndexColorModel#getAlpha(int) alpha} value of 0)
400:             *         should not be taken in account during the check for gray color.
401:             * @return {@code true} if the palette is grayscale, {@code false} otherwise.
402:             */
403:            public static boolean isGrayPalette(final IndexColorModel icm,
404:                    boolean ignoreTransparents) {
405:                if (!icm.hasAlpha()) {
406:                    // We will not check transparent pixels if there is none in the color model.
407:                    ignoreTransparents = false;
408:                }
409:                final int mapSize = icm.getMapSize();
410:                for (int i = 0; i < mapSize; i++) {
411:                    if (ignoreTransparents) {
412:                        // If this entry is transparent and we were asked
413:                        // to check transparents pixels, let's leave.
414:                        final int a = icm.getAlpha(i);
415:                        if (a == 0) {
416:                            continue;
417:                        }
418:                    }
419:                    // get the color for this pixel including the
420:                    // alpha information only if it is requested.
421:                    final int r = icm.getRed(i);
422:                    final int g = icm.getGreen(i);
423:                    final int b = icm.getBlue(i);
424:                    // If gray, all components are the same.
425:                    if (r != g || g != b) {
426:                        return false;
427:                    }
428:                }
429:                return true;
430:            }
431:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.