/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 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.image.palette; import java.awt.RenderingHints; 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.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.image.WritableRaster; import javax.media.jai.ImageLayout; import javax.media.jai.JAI; import javax.media.jai.PointOpImage; import javax.media.jai.operator.BandMergeDescriptor; import javax.media.jai.operator.BandSelectDescriptor; import javax.media.jai.operator.MultiplyConstDescriptor; /** * {@link PointOpImage} to perform color reduction on an image using the palette builder. * * @author Simone Giannecchini, GeoSolutions * */ @SuppressWarnings("unchecked") public class ColorReduction extends PointOpImage { private int numColors; private int alphaThreshold; private CustomPaletteBuilder paletteBuilder; private boolean initialized = false; private RenderingHints hints; public ColorReduction(RenderedImage image, RenderingHints hints, int numColors, int alpaThreshold, int subsx, int subsy) { super(image, new ImageLayout(image), null, false); this.numColors = numColors; this.alphaThreshold = alpaThreshold; if (image.getColorModel().hasAlpha()) { RenderedImage alpha = BandSelectDescriptor.create(image, new int[] { image.getSampleModel().getNumBands() - 1 }, null); alpha = MultiplyConstDescriptor.create(alpha, new double[] { alphaThreshold }, null); image = BandSelectDescriptor.create(image, new int[] { 0, 1, 2 }, null); final ImageLayout layout = new ImageLayout(); layout.setColorModel(new ComponentColorModel(ColorSpace .getInstance(ColorSpace.CS_sRGB), true, false, Transparency.BITMASK, DataBuffer.TYPE_BYTE)); image = BandMergeDescriptor.create(image, alpha, new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout)) .getNewRendering(); this.setSource(image, 0); } // force palette computation this.paletteBuilder = new CustomPaletteBuilder(image, this.numColors,subsx, subsy, 1); this.hints=hints; } private ImageLayout getImageLayout(RenderedImage image, RenderingHints hints) { ImageLayout layout = (ImageLayout) hints.get(JAI.KEY_IMAGE_LAYOUT); if (layout == null) layout = new ImageLayout(image); layout.setColorModel(this.paletteBuilder.getIndexColorModel()); layout.setSampleModel(paletteBuilder.getIndexColorModel().createCompatibleSampleModel(image.getWidth(),image.getHeight())); return layout; } @Override public Raster computeTile(int tx, int ty) { synchronized (this) { if(!initialized){ this.paletteBuilder.buildPalette(); this.setImageLayout(getImageLayout(getSourceImage(0), hints)); } } final RenderedImage sourceImage = getSourceImage(0); final ColorModel sourceColorModel = sourceImage.getColorModel(); final Raster sourceRaster = sourceImage.getTile(tx, ty); final int w = sourceRaster.getWidth(); final int h = sourceRaster.getHeight(); final int numBands = sourceRaster.getSampleModel().getNumBands(); final int rgba[] = new int[numBands]; final boolean sourceHasAlpha = sourceColorModel.hasAlpha(); final int alphaBand = sourceHasAlpha ? numBands - 1 : -1; final int minx = sourceRaster.getMinX(); final int maxx = minx + w; final int miny = sourceRaster.getMinY(); final int maxy = miny + h; final WritableRaster destRaster = this.colorModel .createCompatibleWritableRaster(w, h) .createWritableTranslatedChild(minx, miny); // scan the provided tile and for each pixel assing the best color we have for (int i = minx; i < maxx; i++) for (int j = miny; j < maxy; j++) { sourceRaster.getPixel(i, j, rgba); destRaster.setSample(i, j, 0, paletteBuilder.findNearestColorIndex(rgba, alphaBand)); } return destRaster; } }