/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved. * This code is licensed under the GPL 2.0 license, availible at the root * application directory. */ package org.geoserver.wms.legendgraphic; import java.awt.Color; import java.awt.Dimension; import java.awt.GradientPaint; import java.awt.Graphics2D; import java.awt.Point; 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.geoserver.wms.GetLegendGraphicRequest; import org.geoserver.wms.legendgraphic.ColorMapLegendCreator.Builder; import org.geoserver.wms.map.ImageUtils; 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.vfny.geoserver.global.GeoserverDataDirectory; /** * 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); } 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(); } private synchronized BufferedImage createResponse() { if (image == null) { if (cMapLegendCreator != null) // creating a legend image = cMapLegendCreator.getLegend(); else { image = ImageUtils.createImage(width, height, (IndexColorModel) null, transparent); final Graphics2D graphics = ImageUtils.prepareTransparency(transparent, bgColor, image, new HashMap<RenderingHints.Key, Object>()); if (defaultLegend == null) { drawRasterIcon(graphics); } else { graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); graphics.drawImage(defaultLegend, 0, 0, width, height, null); } graphics.dispose(); } } return image; } /** * Builds a geosilk like raster icon */ void drawRasterIcon(Graphics2D graphics) { Color blue = new Color(Integer.parseInt("5e72be", 16)); Color cyan = new Color(Integer.parseInt("a2c0eb", 16)); // color bg in blue graphics.setColor(blue); graphics.fillRect(0, 0, width, height); // create checkerboard with cyan graphics.setColor(cyan); for(int j = 0; j < height / 2; j++) { for(int i = (j % 2); i < width / 2; i+=2) { graphics.fillRect(i * 2, j * 2, 2, 2); } } // overlay a shade of blue that becomes more solid on the lower right corner GradientPaint paint = new GradientPaint(new Point(0,0), new Color(0, 0, 255, 0), new Point(width, height), new Color(0, 0, 255, 100)); graphics.setPaint(paint); graphics.fillRect(0, 0, width, height); // blue border graphics.setColor(Color.BLUE); graphics.drawRect(0, 0, width - 1, height -1 ); } }