package org.vfny.geoserver.wms.responses.legend.raster; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.awt.image.IndexColorModel; import java.io.File; import java.util.HashMap; import javax.imageio.ImageIO; import org.geotools.styling.ChannelSelection; import org.geotools.styling.ColorMap; import org.geotools.styling.ColorMapEntry; import org.geotools.styling.FeatureTypeStyle; import org.geotools.styling.RasterSymbolizer; import org.geotools.styling.Rule; import org.geotools.styling.Style; import org.geotools.styling.Symbolizer; import org.geotools.util.NumberRange; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.FeatureType; import org.vfny.geoserver.global.GeoserverDataDirectory; import org.vfny.geoserver.wms.requests.GetLegendGraphicRequest; import org.vfny.geoserver.wms.responses.DefaultRasterLegendProducer; import org.vfny.geoserver.wms.responses.ImageUtils; import org.vfny.geoserver.wms.responses.LegendUtils; import org.vfny.geoserver.wms.responses.legend.raster.ColorMapLegendCreator.Builder; /** * Helper class to create legends for raster styles by parsing the rastersymbolizer element. * * @author Simone Giannecchini, GeoSolutions SAS */ @SuppressWarnings("deprecation") public class RasterLayerLegendHelper { /** * The default legend is a simpe image with an R within it which stands for * Raster. */ private final static BufferedImage defaultLegend; static { BufferedImage imgShape = null; try { final File stylesDirectory = GeoserverDataDirectory .findCreateConfigDir("styles"); final File rasterLegend = new File(stylesDirectory, "rasterLegend.png"); if (rasterLegend.exists()) imgShape = ImageIO.read(rasterLegend); else imgShape = ImageIO.read(DefaultRasterLegendProducer.class.getResource("rasterLegend.png")); } catch (Throwable e) { imgShape = null; } // set the default legend defaultLegend = imgShape; } private BufferedImage image; private RasterSymbolizer rasterSymbolizer; private int width; private int height; private boolean transparent; private Color bgColor; private ColorMapLegendCreator cMapLegendCreator; /** * Constructor for a RasterLayerLegendHelper. * * <p> * It takes a {@link GetLegendGraphicRequest} object in order to do its magic. * * @param request the {@link GetLegendGraphicRequest} for which we want to builda legend */ public RasterLayerLegendHelper(final GetLegendGraphicRequest request) { PackagedUtils.ensureNotNull(request, "The provided GetLegendGraphicRequest is null" ); parseRequest(request); } @SuppressWarnings("unchecked") private void parseRequest(final GetLegendGraphicRequest request) { // get the requested layer // and check that it is actually a grid final FeatureType layer = request.getLayer(); boolean found =false; found = LegendUtils.checkGridLayer(layer); if(!found) throw new IllegalArgumentException("Unable to create legend for non raster style"); // get the style and its rules final Style gt2Style = request.getStyle(); final FeatureTypeStyle[] ftStyles = gt2Style.getFeatureTypeStyles(); final double scaleDenominator = request.getScale(); final Rule[] applicableRules; if (request.getRule() != null) { applicableRules = new Rule[] { request.getRule() }; } else { applicableRules = LegendUtils.getApplicableRules(ftStyles, scaleDenominator); } if (applicableRules.length != 1) throw new IllegalArgumentException( "Unable to create a legend for this style, we need exactly 1 rule"); final NumberRange<Double> scaleRange = NumberRange.create(scaleDenominator, scaleDenominator); // get width and height width = request.getWidth(); height = request.getHeight(); if (width <= 0 || height <= 0) throw new IllegalArgumentException("Invalid widht and or height for the GetLegendGraphicRequest"); final Symbolizer[] symbolizers = applicableRules[0].getSymbolizers(); if (symbolizers == null || symbolizers.length != 1| symbolizers[0] == null) throw new IllegalArgumentException( "Unable to create a legend for this style, we need exactly 1 Symbolizer"); final Symbolizer symbolizer = symbolizers[0]; if (!(symbolizer instanceof RasterSymbolizer)) throw new IllegalArgumentException( "Unable to create a legend for this style, we need a RasterSymbolizer"); rasterSymbolizer = (RasterSymbolizer) symbolizer; // is background transparent? transparent = request.isTransparent(); // background bkgColor bgColor = LegendUtils.getBackgroundColor(request); // colormap element final ColorMap cmap = rasterSymbolizer.getColorMap(); final Builder cmapLegendBuilder= new ColorMapLegendCreator.Builder(); if (cmap != null && cmap.getColorMapEntries() != null && cmap.getColorMapEntries().length > 0) { // passing additional options cmapLegendBuilder.setAdditionalOptions(request.getLegendOptions()); // setting type of colormap cmapLegendBuilder.setColorMapType(cmap.getType()); // is this colormap using extended colors cmapLegendBuilder.setExtended(cmap.getExtendedColors()); // setting the requested colormap entries cmapLegendBuilder.setRequestedDimension(new Dimension(width,height)); // setting transparency and background bkgColor cmapLegendBuilder.setTransparent(transparent); cmapLegendBuilder.setBackgroundColor(bgColor); //setting band // Setting label font and font bkgColor cmapLegendBuilder.setLabelFont(LegendUtils.getLabelFont(request)); cmapLegendBuilder.setLabelFontColor(LegendUtils.getLabelFontColor(request)); //set band final ChannelSelection channelSelection = rasterSymbolizer.getChannelSelection(); cmapLegendBuilder.setBand(channelSelection!=null?channelSelection.getGrayChannel():null); // adding the colormap entries final ColorMapEntry[] colorMapEntries = cmap.getColorMapEntries(); for (ColorMapEntry ce : colorMapEntries) if (ce != null) cmapLegendBuilder.addColorMapEntry(ce); //check the additional options before proceeding cmapLegendBuilder.checkAdditionalOptions(); // instantiate the creator cMapLegendCreator=cmapLegendBuilder.create(); } else cMapLegendCreator=null; } /** * Retrieves the legend for the provided request. * * @return a {@link BufferedImage} that represents the legend for the provided request. */ public BufferedImage getLegend() { return createResponse(); } @SuppressWarnings("unchecked") private synchronized BufferedImage createResponse() { if (image == null) { if(cMapLegendCreator!=null) // creating a legend image = cMapLegendCreator.getLegend(); else { if(defaultLegend==null) throw new IllegalStateException("Unable to get default legend"); image = ImageUtils.createImage(width, height,(IndexColorModel) null, transparent); final Graphics2D graphics = ImageUtils.prepareTransparency(transparent, bgColor, image, new HashMap()); graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); graphics.drawImage(defaultLegend, 0, 0, width, height, null); graphics.dispose(); } } return image; } }