/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2001-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.coverage; import java.awt.Transparency; import java.awt.color.ColorSpace; import java.awt.image.ColorModel; import java.awt.image.ComponentColorModel; import java.awt.image.DataBuffer; import java.util.Arrays; import java.util.Map; import javax.media.jai.FloatDoubleColorModel; import javax.media.jai.RasterFactory; import org.geotools.resources.i18n.Errors; import org.geotools.resources.i18n.ErrorKeys; import org.geotools.resources.image.ColorUtilities; import org.geotools.resources.image.ComponentColorModelJAI; import org.geotools.util.WeakValueHashMap; /** * A factory for {@link ColorModel} objects built from a list of {@link Category} objects. * This factory provides only one public static method: {@link #getColorModel}. Instances * of {@link ColorModel} are shared among all callers in the running virtual machine. * * @since 2.1 * @source $URL$ * @version $Id$ * @author Martin Desruisseaux (IRD) */ final class ColorModelFactory { /** * A pool of color models previously created by {@link #getColorModel}. * * Note: we use {@linkplain java.lang.ref.WeakReference weak references} instead of * {@linkplain java.lang.ref.SoftReference soft references} because the intend is not to * cache the values. The intend is to share existing instances in order to reduce memory * usage. Rational: * *
{@linkplain CategoryList#getRange}
range.
*/
public static ColorModel getColorModel(final Category[] categories, final int type,
final int visibleBand, final int numBands)
{
synchronized (colors) {
ColorModelFactory key = new ColorModelFactory(categories, type, visibleBand, numBands);
ColorModel model = colors.get(key);
if (model == null) {
model = key.getColorModel();
colors.put(key, model);
}
return model;
}
}
/**
* Constructs the color model.
*/
private ColorModel getColorModel() {
double minimum = 0;
double maximum = 1;
final int categoryCount = categories.length;
if (categoryCount != 0) {
minimum = categories[0].minimum;
for (int i=categoryCount; --i >= 0;) {
final double value = categories[i].maximum;
if (!Double.isNaN(value)) {
maximum = value;
break;
}
}
}
if (type != DataBuffer.TYPE_BYTE && type != DataBuffer.TYPE_USHORT) {
// If the requested type is any type not supported by IndexColorModel,
// fallback on a generic (but very slow!) color model.
final int transparency = Transparency.OPAQUE;
final ColorSpace colors = new ScaledColorSpace(visibleBand, numBands, minimum, maximum);
if (true) {
// This is the J2SE implementation of color model. It should be our preferred one.
// In JAI 1.1 we had to use JAI implementation instead of J2SE's one because
// javax.media.jai.iterator.RectIter didn't work with J2SE's DataBuffer
// when the data type is float or double.
return new ComponentColorModel(colors, false, false, transparency, type);
}
if (false) {
// This is the JAI implementation of color model. This implementation work with
// JAI's RectIter and should in theory support float and double data buffer.
// Unfortunatly, it seems to completly ignore our custom ColorSpace. We end
// up basically with all-black or all-white images.
return new FloatDoubleColorModel(colors, false, false, transparency, type);
}
if (false) {
// Our patched color model extends J2SE's ComponentColorModel (which work correctly
// with our custom ColorSpace), but create JAI's SampleModel instead of J2SE's one.
// It make RectIter happy and display colors correctly.
return new ComponentColorModelJAI(colors, false, false, transparency, type);
}
// This factory is not really different from a direct construction of
// FloatDoubleColorModel. We provide it here just because we must end
// with something.
return RasterFactory.createComponentColorModel(type, colors, false, false, transparency);
}
if (numBands == 1 && categoryCount == 0) {
// Construct a gray scale palette.
final ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
final int[] nBits = {
DataBuffer.getDataTypeSize(type)
};
return new ComponentColorModel(cs, nBits, false, true, Transparency.OPAQUE, type);
}
/*
* Computes the number of entries required for the color palette.
* We take the upper range value of the last non-NaN category.
*/
final int mapSize = ((int) Math.round(maximum)) + 1;
final int[] ARGB = new int[mapSize];
/*
* Interpolates the colors in the color palette. Colors that do not fall
* in the range of a category will be set to a transparent color.
*/
for (int i=0; i