/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2009-2012, Open Source Geospatial Foundation (OSGeo)
* (C) 2009-2012, Geomatys
*
* 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.geotoolkit.image.color;
import org.geotoolkit.image.color.MultiBandsIndexColorModel;
import java.util.Arrays;
import java.util.Objects;
import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import org.geotoolkit.lang.Static;
import org.geotoolkit.lang.Workaround;
import org.apache.sis.util.collection.WeakHashSet;
/**
* Shared instances of {@link ColorModel}s. Maintaining shared instance is not that much
* interesting for most kind of color models, except {@link IndexColorModel} which can
* potentially be quite big. This class works for all color models because they were no
* technical reasons to restrict, but the real interest is to share index color models.
*
* @param <T> For internal use only.
*
* @author Martin Desruisseaux (Geomatys)
* @version 3.00
*
* @since 3.00
* @module
*/
public final class ColorModels<T extends ColorModel> extends Static {
/**
* Pool of shared color models.
*/
@SuppressWarnings("rawtypes")
private static final WeakHashSet<ColorModels> POOL = new WeakHashSet<>(ColorModels.class);
/**
* The color model to share.
*/
private final T cm;
/**
* For internal use only.
*/
private ColorModels(final T cm) {
this.cm = cm;
}
/**
* Returns a unique instance of the given color model.
*
* @param <T> The type of the color model to canonicalize.
* @param cm The color model for which to get a unique instance.
* @return A unique (shared) instance of the given color model.
*/
public static <T extends ColorModel> T unique(T cm) {
ColorModels<T> c = new ColorModels<>(cm);
c = POOL.unique(c);
return c.cm;
}
/**
* Returns {@code true} if the given color models are equal. The {@link ColorModel} class
* defines an {@code equals} method, but as of Java 6 that method doesn't compare every
* attributes. For example it doesn't compare the color space and the transfer type, so
* we have to compare them here.
*
* @param cm1 The first color model.
* @param cm2 The second color model.
* @return {@code true} if the two color models are equal.
*/
@Workaround(library="JDK", version="6")
public static boolean equals(final ColorModel cm1, final ColorModel cm2) {
if (cm1 == cm2) {
return true;
}
if (cm1 != null && cm1.equals(cm2) &&
cm1.getClass().equals(cm2.getClass()) &&
cm1.getTransferType() == cm2.getTransferType() &&
Objects.equals(cm1.getColorSpace(), cm2.getColorSpace()))
{
if (cm1 instanceof IndexColorModel) {
final IndexColorModel icm1 = (IndexColorModel) cm1;
final IndexColorModel icm2 = (IndexColorModel) cm2;
final int size = icm1.getMapSize();
if (icm2.getMapSize() == size &&
icm1.getTransparentPixel() == icm2.getTransparentPixel() &&
Objects.equals(icm1.getValidPixels(), icm2.getValidPixels()))
{
for (int i=0; i<size; i++) {
if (icm1.getRGB(i) != icm2.getRGB(i)) {
return false;
}
}
}
if (cm1 instanceof MultiBandsIndexColorModel) {
final MultiBandsIndexColorModel micm1 = (MultiBandsIndexColorModel) cm1;
final MultiBandsIndexColorModel micm2 = (MultiBandsIndexColorModel) cm2;
if (micm1.numBands != micm2.numBands || micm1.visibleBand != micm2.visibleBand) {
return false;
}
}
}
return true;
}
return false;
}
/**
* For internal use only.
*
* @param object Object The object to compare to.
* @return {@code true} if both object are equal.
*/
@Override
public boolean equals(final Object object) {
return (object instanceof ColorModels<?>) && equals(cm, ((ColorModels<?>) object).cm);
}
/**
* For internal use only.
*/
@Override
public int hashCode() {
int code = cm.hashCode() ^ cm.getClass().hashCode();
if (cm instanceof IndexColorModel) {
final IndexColorModel icm = (IndexColorModel) cm;
final int[] ARGB = new int[icm.getMapSize()];
icm.getRGBs(ARGB);
code ^= Arrays.hashCode(ARGB);
}
return code;
}
}