/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.wms.legendgraphic; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.awt.image.IndexColorModel; import java.awt.image.RenderedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.logging.Logger; import javax.imageio.ImageIO; import javax.media.jai.PlanarImage; import javax.xml.namespace.QName; import org.geoserver.catalog.Catalog; import org.geoserver.catalog.CoverageInfo; import org.geoserver.catalog.FeatureTypeInfo; import org.geoserver.data.test.MockData; import org.geoserver.data.test.SystemTestData; import org.geoserver.wms.GetLegendGraphic; import org.geoserver.wms.GetLegendGraphicRequest; import org.geoserver.wms.GetLegendGraphicRequest.LegendRequest; import org.geoserver.wms.WMSTestSupport; import org.geoserver.wms.legendgraphic.Cell.ColorMapEntryLegendBuilder; import org.geoserver.wms.legendgraphic.Cell.SingleColorMapEntryLegendBuilder; import org.geoserver.wms.map.ImageUtils; import org.geotools.coverage.grid.GridCoverage2D; import org.geotools.data.simple.SimpleFeatureCollection; import org.geotools.factory.CommonFactoryFinder; import org.geotools.feature.NameImpl; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.feature.type.AttributeDescriptorImpl; import org.geotools.feature.type.AttributeTypeImpl; import org.geotools.feature.type.GeometryDescriptorImpl; import org.geotools.feature.type.GeometryTypeImpl; import org.geotools.referencing.CRS; import org.geotools.renderer.lite.RendererUtilities; import org.geotools.resources.coverage.FeatureUtilities; import org.geotools.resources.image.ImageUtilities; import org.geotools.styling.ColorMapEntry; import org.geotools.styling.FeatureTypeStyle; import org.geotools.styling.RasterSymbolizer; import org.geotools.styling.Rule; import org.geotools.styling.SLDParser; import org.geotools.styling.Style; import org.geotools.styling.StyleFactory; import org.geotools.util.logging.Logging; import org.junit.After; import org.junit.Before; import org.opengis.coverage.grid.GridCoverage; import org.opengis.feature.type.AttributeType; import org.opengis.feature.type.FeatureType; import org.opengis.feature.type.GeometryType; import org.opengis.referencing.crs.CoordinateReferenceSystem; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; /** * Tets the functioning of the abstract legend producer for raster formats, which relies on * Geotools' StyledShapePainter. * * @author Gabriel Roldan * @version $Id$ */ public class AbstractLegendGraphicOutputFormatTest extends BaseLegendTest{ /** * Tests that a legend is produced for the explicitly specified rule, when the FeatureTypeStyle * has more than one rule, and one of them is requested by the RULE parameter. */ @org.junit.Test public void testUserSpecifiedRule() throws Exception { // load a style with 3 rules Style multipleRulesStyle = getCatalog().getStyleByName( MockData.ROAD_SEGMENTS.getLocalPart()).getStyle(); assertNotNull(multipleRulesStyle); Rule rule = multipleRulesStyle.getFeatureTypeStyles()[0].getRules()[0]; LOGGER.info("testing single rule " + rule.getName() + " from style " + multipleRulesStyle.getName()); GetLegendGraphicRequest req = new GetLegendGraphicRequest(); FeatureTypeInfo ftInfo = getCatalog().getFeatureTypeByName( MockData.ROAD_SEGMENTS.getNamespaceURI(), MockData.ROAD_SEGMENTS.getLocalPart()); req.setLayer(ftInfo.getFeatureType()); req.setStyle(multipleRulesStyle); req.setRule(rule.getName()); req.setLegendOptions(new HashMap()); final int HEIGHT_HINT = 30; req.setHeight(HEIGHT_HINT); // use default values for the rest of parameters this.legendProducer.buildLegendGraphic(req); BufferedImage image = this.legendProducer.buildLegendGraphic(req); // was the legend painted? assertNotBlank("testUserSpecifiedRule", image, LegendUtils.DEFAULT_BG_COLOR); // was created only one rule? String errMsg = "expected just one legend of height " + HEIGHT_HINT + ", for the rule " + rule.getName(); int resultLegendCount = image.getHeight() / HEIGHT_HINT; assertEquals(errMsg, 1, resultLegendCount); } /** * Tests that a legend is produced for the explicitly specified rule, when the FeatureTypeStyle * has more than one rule, and one of them is requested by the RULE parameter. * */ @org.junit.Test public void testRainfall() throws Exception { // load a style with 3 rules Style multipleRulesStyle = getCatalog().getStyleByName("rainfall").getStyle(); assertNotNull(multipleRulesStyle); GetLegendGraphicRequest req = new GetLegendGraphicRequest(); CoverageInfo cInfo = getCatalog().getCoverageByName("world"); assertNotNull(cInfo); GridCoverage coverage = cInfo.getGridCoverage(null, null); try { SimpleFeatureCollection feature; feature = FeatureUtilities.wrapGridCoverage((GridCoverage2D) coverage); req.setLayer(feature.getSchema()); req.setStyle(multipleRulesStyle); req.setLegendOptions(new HashMap()); final int HEIGHT_HINT = 30; req.setHeight(HEIGHT_HINT); // use default values for the rest of parameters this.legendProducer.buildLegendGraphic(req); BufferedImage image = this.legendProducer.buildLegendGraphic(req); // was the legend painted? assertNotBlank("testRainfall", image, LegendUtils.DEFAULT_BG_COLOR); // was the legend painted? assertNotBlank("testRainfall", image, LegendUtils.DEFAULT_BG_COLOR); } finally { RenderedImage ri = coverage.getRenderedImage(); if(coverage instanceof GridCoverage2D) { ((GridCoverage2D) coverage).dispose(true); } if(ri instanceof PlanarImage) { ImageUtilities.disposePlanarImageChain((PlanarImage) ri); } } } /** * Tests that the legend graphic is still produced when the request's strict parameter is set to * false and a layer is not specified */ @org.junit.Test public void testNoLayerProvidedAndNonStrictRequest() throws Exception { Style style = getCatalog().getStyleByName("rainfall").getStyle(); assertNotNull(style); GetLegendGraphicRequest req = new GetLegendGraphicRequest(); req.setStrict(false); req.setLayer(null); req.setStyle(style); final int HEIGHT_HINT = 30; req.setHeight(HEIGHT_HINT); // use default values for the rest of parameters this.legendProducer.buildLegendGraphic(req); BufferedImage image = this.legendProducer.buildLegendGraphic(req); // was the legend painted? assertNotBlank("testRainfall", image, LegendUtils.DEFAULT_BG_COLOR); // was the legend painted? assertNotBlank("testRainfall", image, LegendUtils.DEFAULT_BG_COLOR); } /** * Tests that the legend graphic is produced for multiple layers */ @org.junit.Test public void testMultipleLayers() throws Exception { GetLegendGraphicRequest req = new GetLegendGraphicRequest(); int titleHeight = getTitleHeight(req); FeatureTypeInfo ftInfo = getCatalog().getFeatureTypeByName( MockData.ROAD_SEGMENTS.getNamespaceURI(), MockData.ROAD_SEGMENTS.getLocalPart()); req.setLayer(ftInfo.getFeatureType()); req.setStyle(getCatalog().getStyleByName(MockData.ROAD_SEGMENTS.getLocalPart()).getStyle()); this.legendProducer.buildLegendGraphic(req); BufferedImage image = this.legendProducer.buildLegendGraphic(req); // was the legend painted? assertNotBlank("testMultipleLayers", image, LegendUtils.DEFAULT_BG_COLOR); int height=image.getHeight(); LegendRequest legend = req.new LegendRequest(ftInfo.getFeatureType()); legend.setStyle(getCatalog().getStyleByName(MockData.ROAD_SEGMENTS.getLocalPart()).getStyle()); req.getLegends().add( legend ); this.legendProducer.buildLegendGraphic(req); image = this.legendProducer.buildLegendGraphic(req); // was the legend painted? assertNotBlank("testMultipleLayers", image, LegendUtils.DEFAULT_BG_COLOR); // with 2 layers we should have a legend at least 2 times taller (title + 2 layers) assertEquals(2*(height+titleHeight),image.getHeight()); // first title assertPixel(image, 1, titleHeight/2, new Color(0,0,0)); // first layer assertPixel(image, 10, 10+titleHeight, new Color(192,160,0)); assertPixel(image, 10, 30+titleHeight, new Color(0,0,0)); assertPixel(image, 10, 50+titleHeight, new Color(224,64,0)); // second title assertPixel(image, 1, 60+titleHeight+titleHeight/2, new Color(0,0,0)); // same colors for the second layer assertPixel(image, 10, 70+titleHeight*2, new Color(192,160,0)); assertPixel(image, 10, 90+titleHeight*2, new Color(0,0,0)); assertPixel(image, 10, 110+titleHeight*2, new Color(224,64,0)); } /** * Tests that with forceTitles option off no title is rendered */ @org.junit.Test public void testForceTitlesOff() throws Exception { Catalog cat = getCatalog(); GetLegendGraphicRequest req = new GetLegendGraphicRequest(); Map<String,String> options = new HashMap<String,String>(); options.put("forceTitles", "off"); req.setLegendOptions(options); FeatureTypeInfo ftInfo = cat.getFeatureTypeByName( MockData.ROAD_SEGMENTS.getNamespaceURI(), MockData.ROAD_SEGMENTS.getLocalPart()); List<FeatureType> layers=new ArrayList<FeatureType>(); req.setLayer(ftInfo.getFeatureType()); req.setStyle(cat.getStyleByName( MockData.ROAD_SEGMENTS.getLocalPart()).getStyle()); this.legendProducer.buildLegendGraphic(req); BufferedImage image = this.legendProducer.buildLegendGraphic(req); // was the legend painted? assertNotBlank("testMultipleLayers", image, LegendUtils.DEFAULT_BG_COLOR); int height=image.getHeight(); LegendRequest legend = req.new LegendRequest(ftInfo.getFeatureType()); legend.setStyle(cat.getStyleByName(MockData.ROAD_SEGMENTS.getLocalPart()).getStyle()); req.getLegends().add(legend); this.legendProducer.buildLegendGraphic(req); image = this.legendProducer.buildLegendGraphic(req); // was the legend painted? assertNotBlank("testForceTitlesOff", image, LegendUtils.DEFAULT_BG_COLOR); assertEquals(2*height,image.getHeight()); // first layer assertPixel(image, 10, 10, new Color(192,160,0)); assertPixel(image, 10, 30, new Color(0,0,0)); assertPixel(image, 10, 50, new Color(224,64,0)); // same colors for the second layer assertPixel(image, 10, 70, new Color(192,160,0)); assertPixel(image, 10, 90, new Color(0,0,0)); assertPixel(image, 10, 110, new Color(224,64,0)); } /** * Tests that the legend graphic is produced for multiple layers * with different style for each layer. */ @org.junit.Test public void testMultipleLayersWithDifferentStyles() throws Exception { GetLegendGraphicRequest req = new GetLegendGraphicRequest(); int titleHeight = getTitleHeight(req); FeatureTypeInfo ftInfo = getCatalog().getFeatureTypeByName( MockData.ROAD_SEGMENTS.getNamespaceURI(), MockData.ROAD_SEGMENTS.getLocalPart()); List<FeatureType> layers=new ArrayList<FeatureType>(); layers.add(ftInfo.getFeatureType()); layers.add(ftInfo.getFeatureType()); req.setLayers(layers); List<Style> styles=new ArrayList<Style>(); Style style1= getCatalog().getStyleByName( MockData.ROAD_SEGMENTS.getLocalPart()).getStyle(); styles.add(style1); Style style2= getCatalog().getStyleByName( MockData.LAKES.getLocalPart()).getStyle(); styles.add(style2); req.setStyles(styles); this.legendProducer.buildLegendGraphic(req); BufferedImage image = this.legendProducer.buildLegendGraphic(req); // first layer assertPixel(image, 10, 10+titleHeight, new Color(192,160,0)); assertPixel(image, 10, 30+titleHeight, new Color(0,0,0)); assertPixel(image, 10, 50+titleHeight, new Color(224,64,0)); // different color (style) for the second layer assertPixel(image, 10, 70+titleHeight*2, new Color(64,64,192)); } /** * Tests that the legend graphic is produced for multiple layers * with vector and coverage layers. */ @org.junit.Test public void testMultipleLayersWithVectorAndCoverage() throws Exception { GetLegendGraphicRequest req = new GetLegendGraphicRequest(); int titleHeight = getTitleHeight(req); FeatureTypeInfo ftInfo = getCatalog().getFeatureTypeByName( MockData.ROAD_SEGMENTS.getNamespaceURI(), MockData.ROAD_SEGMENTS.getLocalPart()); List<FeatureType> layers=new ArrayList<FeatureType>(); layers.add(ftInfo.getFeatureType()); CoverageInfo cInfo = getCatalog().getCoverageByName("world"); assertNotNull(cInfo); GridCoverage coverage = cInfo.getGridCoverage(null, null); try { SimpleFeatureCollection feature; feature = FeatureUtilities.wrapGridCoverage((GridCoverage2D) coverage); layers.add(feature.getSchema()); req.setLayers(layers); List<Style> styles=new ArrayList<Style>(); Style style1= getCatalog().getStyleByName( MockData.ROAD_SEGMENTS.getLocalPart()).getStyle(); styles.add(style1); Style style2= getCatalog().getStyleByName("rainfall").getStyle(); styles.add(style2); req.setStyles(styles); this.legendProducer.buildLegendGraphic(req); BufferedImage image = this.legendProducer.buildLegendGraphic(req); // vector layer assertPixel(image, 10, 10+titleHeight, new Color(192,160,0)); assertPixel(image, 10, 30+titleHeight, new Color(0,0,0)); assertPixel(image, 10, 50+titleHeight, new Color(224,64,0)); // coverage layer assertPixel(image, 10, 70+titleHeight*2, new Color(115,38,0)); } finally { RenderedImage ri = coverage.getRenderedImage(); if(coverage instanceof GridCoverage2D) { ((GridCoverage2D) coverage).dispose(true); } if(ri instanceof PlanarImage) { ImageUtilities.disposePlanarImageChain((PlanarImage) ri); } } } /** * Tests that the legend graphic is produced for multiple layers * with vector and coverage layers, when coverage is not visible * at current scale. */ @org.junit.Test public void testMultipleLayersWithVectorAndInvisibleCoverage() throws Exception { GetLegendGraphicRequest req = new GetLegendGraphicRequest(); req.setScale(1000); int titleHeight = getTitleHeight(req); FeatureTypeInfo ftInfo = getCatalog().getFeatureTypeByName( MockData.ROAD_SEGMENTS.getNamespaceURI(), MockData.ROAD_SEGMENTS.getLocalPart()); List<FeatureType> layers=new ArrayList<FeatureType>(); layers.add(ftInfo.getFeatureType()); CoverageInfo cInfo = getCatalog().getCoverageByName("world"); assertNotNull(cInfo); GridCoverage coverage = cInfo.getGridCoverage(null, null); try { SimpleFeatureCollection feature; feature = FeatureUtilities.wrapGridCoverage((GridCoverage2D) coverage); layers.add(feature.getSchema()); req.setLayers(layers); List<Style> styles=new ArrayList<Style>(); Style style1= getCatalog().getStyleByName( MockData.ROAD_SEGMENTS.getLocalPart()).getStyle(); styles.add(style1); styles.add(readSLD("InvisibleRaster.sld")); req.setStyles(styles); this.legendProducer.buildLegendGraphic(req); BufferedImage image = this.legendProducer.buildLegendGraphic(req); // vector layer assertPixel(image, 10, 10+titleHeight, new Color(192,160,0)); assertPixel(image, 10, 30+titleHeight, new Color(0,0,0)); assertPixel(image, 10, 50+titleHeight, new Color(224,64,0)); // no coverage assertTrue(image.getHeight() < 70+titleHeight*2); } finally { RenderedImage ri = coverage.getRenderedImage(); if(coverage instanceof GridCoverage2D) { ((GridCoverage2D) coverage).dispose(true); } if(ri instanceof PlanarImage) { ImageUtilities.disposePlanarImageChain((PlanarImage) ri); } } } public void testMixedGeometry() throws Exception { GetLegendGraphicRequest req = new GetLegendGraphicRequest(); SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder(); builder.setName("MIXEDGEOMETRY"); builder.setNamespaceURI("test"); builder.setDefaultGeometry("GEOMETRY"); CoordinateReferenceSystem crs = CRS.decode("EPSG:4326"); builder.setCRS(crs); GeometryFactory geometryFactory = new GeometryFactory(); AttributeType at = new AttributeTypeImpl(new NameImpl("ID"), String.class, false, false, Collections.EMPTY_LIST, null, null); builder.add(new AttributeDescriptorImpl(at, new NameImpl("ID"), 0, 1, false, null)); GeometryType gt = new GeometryTypeImpl(new NameImpl("GEOMETRY"), Geometry.class, crs, false, false, Collections.EMPTY_LIST, null, null); builder.add(new GeometryDescriptorImpl(gt, new NameImpl("GEOMETRY"), 0, 1, false, null)); FeatureType fType = builder.buildFeatureType(); List<FeatureType> layers = new ArrayList<FeatureType>(); layers.add(fType); req.setLayers(layers); List<Style> styles = new ArrayList<Style>(); req.setStyles(styles); styles.add(readSLD("MixedGeometry.sld")); this.legendProducer.buildLegendGraphic(req); BufferedImage image = this.legendProducer.buildLegendGraphic(req); assertNotBlank("testMixedGeometry", image, LegendUtils.DEFAULT_BG_COLOR); // LineSymbolizer assertPixel(image, 10, 10, new Color(0,0,0)); // PolygonSymbolizer assertPixel(image, 10, 30, new Color(0,0,255)); // PointSymbolizer assertPixel(image, 10, 50, new Color(255,0,0)); } /** * Tests that symbols are not bigger than the requested icon size. */ @org.junit.Test public void testSymbolContainedInIcon() throws Exception { GetLegendGraphicRequest req = new GetLegendGraphicRequest(); FeatureTypeInfo ftInfo = getCatalog() .getFeatureTypeByName(MockData.MPOINTS.getNamespaceURI(), MockData.MPOINTS.getLocalPart()); req.setLayer(ftInfo.getFeatureType()); req.setStyle(readSLD("BigSymbol.sld")); BufferedImage image = this.legendProducer.buildLegendGraphic(req); assertNotBlank("testSymbolSize", image, LegendUtils.DEFAULT_BG_COLOR); // background at borders assertPixel(image, 1, 1, new Color(255, 255, 255)); // symbol in the center assertPixel(image, 10, 10, new Color(255, 0, 0)); } /** * Tests that symbols are not bigger than the requested icon size, also * if an expression is used for the symbol Size. */ @org.junit.Test public void testSymbolContainedInIconUsingExpression() throws Exception { GetLegendGraphicRequest req = new GetLegendGraphicRequest(); FeatureTypeInfo ftInfo = getCatalog() .getFeatureTypeByName(MockData.MPOINTS.getNamespaceURI(), MockData.MPOINTS.getLocalPart()); req.setLayer(ftInfo.getFeatureType()); req.setStyle(readSLD("SymbolExpression.sld")); BufferedImage image = this.legendProducer.buildLegendGraphic(req); assertNotBlank("testSymbolContainedInIconUsingExpression", image, LegendUtils.DEFAULT_BG_COLOR); // background at borders assertPixel(image, 1, 1, new Color(255, 255, 255)); // symbol in the center assertPixel(image, 10, 10, new Color(255, 0, 0)); } /** * Tests that symbols relative sizes are proportional. */ @org.junit.Test public void testProportionalSymbolSize() throws Exception { GetLegendGraphicRequest req = new GetLegendGraphicRequest(); FeatureTypeInfo ftInfo = getCatalog() .getFeatureTypeByName(MockData.MPOINTS.getNamespaceURI(), MockData.MPOINTS.getLocalPart()); req.setLayer(ftInfo.getFeatureType()); req.setStyle(readSLD("ProportionalSymbols.sld")); BufferedImage image = this.legendProducer.buildLegendGraphic(req); assertNotBlank("testProportionalSymbolSize", image, LegendUtils.DEFAULT_BG_COLOR); // biggest symbol assertPixel(image, 1, 1, new Color(255, 255, 255)); assertPixel(image, 5, 5, new Color(255, 0, 0)); assertPixel(image, 10, 10, new Color(255, 0, 0)); // second symbol assertPixel(image, 1, 21, new Color(255, 255, 255)); assertPixel(image, 5, 25, new Color(255, 255, 255)); assertPixel(image, 7, 27, new Color(255, 0, 0)); assertPixel(image, 10, 30, new Color(255, 0, 0)); // third symbol assertPixel(image, 1, 41, new Color(255, 255, 255)); assertPixel(image, 5, 45, new Color(255, 255, 255)); assertPixel(image, 6, 46, new Color(255, 255, 255)); assertPixel(image, 10, 50, new Color(255, 0, 0)); // smallest symbol assertPixel(image, 1, 61, new Color(255, 255, 255)); assertPixel(image, 6, 68, new Color(255, 255, 255)); assertPixel(image, 10, 70, new Color(255, 0, 0)); } /** * Tests that symbols relative sizes are proportional also if using uoms. */ @org.junit.Test public void testProportionalSymbolSizeUOM() throws Exception { GetLegendGraphicRequest req = new GetLegendGraphicRequest(); FeatureTypeInfo ftInfo = getCatalog() .getFeatureTypeByName(MockData.MPOINTS.getNamespaceURI(), MockData.MPOINTS.getLocalPart()); req.setLayer(ftInfo.getFeatureType()); req.setStyle(readSLD("ProportionalSymbolsUOM.sld")); BufferedImage image = this.legendProducer.buildLegendGraphic(req); assertNotBlank("testProportionalSymbolSize", image, LegendUtils.DEFAULT_BG_COLOR); // biggest symbol assertPixel(image, 1, 1, new Color(255, 255, 255)); assertPixel(image, 5, 5, new Color(255, 0, 0)); assertPixel(image, 10, 10, new Color(255, 0, 0)); // second symbol assertPixel(image, 1, 21, new Color(255, 255, 255)); assertPixel(image, 5, 25, new Color(255, 255, 255)); assertPixel(image, 7, 27, new Color(255, 0, 0)); assertPixel(image, 10, 30, new Color(255, 0, 0)); // third symbol assertPixel(image, 1, 41, new Color(255, 255, 255)); assertPixel(image, 5, 45, new Color(255, 255, 255)); assertPixel(image, 6, 46, new Color(255, 255, 255)); assertPixel(image, 10, 50, new Color(255, 0, 0)); // smallest symbol assertPixel(image, 1, 61, new Color(255, 255, 255)); assertPixel(image, 6, 68, new Color(255, 255, 255)); assertPixel(image, 10, 70, new Color(255, 0, 0)); } /** * Tests that symbols relative sizes are proportional also if using uoms * in some Symbolizer and not using them in others. */ @org.junit.Test public void testProportionalSymbolSizePartialUOM() throws Exception { GetLegendGraphicRequest req = new GetLegendGraphicRequest(); req.setScale(RendererUtilities.calculatePixelsPerMeterRatio(10, Collections.EMPTY_MAP)); FeatureTypeInfo ftInfo = getCatalog() .getFeatureTypeByName(MockData.MPOINTS.getNamespaceURI(), MockData.MPOINTS.getLocalPart()); req.setLayer(ftInfo.getFeatureType()); req.setStyle(readSLD("ProportionalSymbolsPartialUOM.sld")); BufferedImage image = this.legendProducer.buildLegendGraphic(req); assertNotBlank("testProportionalSymbolSize", image, LegendUtils.DEFAULT_BG_COLOR); // UOM symbol assertPixel(image, 1, 1, new Color(255, 255, 255)); assertPixel(image, 5, 5, new Color(255, 0, 0)); assertPixel(image, 10, 10, new Color(255, 0, 0)); // non UOM symbol assertPixel(image, 1, 1, new Color(255, 255, 255)); assertPixel(image, 5, 5, new Color(255, 0, 0)); assertPixel(image, 10, 10, new Color(255, 0, 0)); } /** * Tests that minSymbolSize legend option is respected. */ @org.junit.Test public void testMinSymbolSize() throws Exception { GetLegendGraphicRequest req = new GetLegendGraphicRequest(); FeatureTypeInfo ftInfo = getCatalog() .getFeatureTypeByName(MockData.MPOINTS.getNamespaceURI(), MockData.MPOINTS.getLocalPart()); Map<String,String> options = new HashMap<String,String>(); options.put("minSymbolSize", "10"); req.setLegendOptions(options); req.setLayer(ftInfo.getFeatureType()); req.setStyle(readSLD("ProportionalSymbols.sld")); BufferedImage image = this.legendProducer.buildLegendGraphic(req); assertNotBlank("testProportionalSymbolSize", image, LegendUtils.DEFAULT_BG_COLOR); // biggest symbol assertPixel(image, 1, 1, new Color(255, 255, 255)); assertPixel(image, 5, 5, new Color(255, 0, 0)); assertPixel(image, 10, 10, new Color(255, 0, 0)); // smallest symbol assertPixel(image, 1, 61, new Color(255, 255, 255)); assertPixel(image, 7, 67, new Color(255, 0, 0)); assertPixel(image, 10, 70, new Color(255, 0, 0)); } /** * Tests that minSymbolSize legend option is respected. */ @org.junit.Test public void testInternationalizedLabels() throws Exception { GetLegendGraphicRequest req = new GetLegendGraphicRequest(); Map<String,String> options = new HashMap<String,String>(); options.put("forceLabels", "on"); req.setLegendOptions(options); FeatureTypeInfo ftInfo = getCatalog() .getFeatureTypeByName(MockData.MPOINTS.getNamespaceURI(), MockData.MPOINTS.getLocalPart()); req.setLayer(ftInfo.getFeatureType()); req.setStyle(readSLD("Internationalized.sld")); BufferedImage image = this.legendProducer.buildLegendGraphic(req); int noLocalizedWidth = image.getWidth(); req.setLocale(Locale.ITALIAN); image = this.legendProducer.buildLegendGraphic(req); // test that using localized labels we get a different label than when not using it int itWidth = image.getWidth(); assertTrue(itWidth != noLocalizedWidth); req.setLocale(Locale.ENGLISH); image = this.legendProducer.buildLegendGraphic(req); // test that using localized labels we get a different label than when not using it int enWidth = image.getWidth(); assertTrue(enWidth != noLocalizedWidth); assertTrue(enWidth != itWidth); } /** * Test that the legend is not the same if there is a rendering transformation that * converts the rendered layer from raster to vector */ @org.junit.Test public void testRenderingTransformationRasterVector() throws Exception { Style transformStyle = readSLD("RenderingTransformRasterVector.sld"); GetLegendGraphicRequest req = new GetLegendGraphicRequest(); CoverageInfo cInfo = getCatalog() .getCoverageByName(MockData.TASMANIA_DEM.getNamespaceURI(), MockData.TASMANIA_DEM.getLocalPart()); assertNotNull(cInfo); GridCoverage coverage = cInfo.getGridCoverage(null, null); try { SimpleFeatureCollection feature; feature = FeatureUtilities.wrapGridCoverage((GridCoverage2D) coverage); req.setLayer(feature.getSchema()); req.setStyle(transformStyle); req.setLegendOptions(new HashMap()); this.legendProducer.buildLegendGraphic(req); BufferedImage image = this.legendProducer.buildLegendGraphic(req); // ImageIO.write(image, "PNG", new File("/tmp/rv.png")); assertNotBlank("testRenderingTransform", image, LegendUtils.DEFAULT_BG_COLOR); assertPixel(image, 1, 1, new Color(255, 255, 255)); assertPixel(image, 10, 10, new Color (0, 0, 0)); assertPixel(image, 19, 19, new Color (255, 255, 255)); }catch(Exception e){ fail(e.getMessage()); } finally { RenderedImage ri = coverage.getRenderedImage(); if(coverage instanceof GridCoverage2D) { ((GridCoverage2D) coverage).dispose(true); } if(ri instanceof PlanarImage) { ImageUtilities.disposePlanarImageChain((PlanarImage) ri); } } } /** * Test that the legend is not the same if there is a rendering transformation that * converts the rendered layer from raster to vector */ @org.junit.Test public void testColorMapWithCql() throws Exception { Style style = readSLD("ColorMapWithCql.sld"); assertNotNull(style.featureTypeStyles()); assertEquals(1, style.featureTypeStyles().size()); FeatureTypeStyle fts = style.featureTypeStyles().get(0); assertNotNull(fts.rules()); assertEquals(1, fts.rules().size()); Rule rule = fts.rules().get(0); assertNotNull(rule.symbolizers()); assertEquals(1, rule.symbolizers().size()); assertTrue(rule.symbolizers().get(0) instanceof RasterSymbolizer); RasterSymbolizer symbolizer = (RasterSymbolizer)rule.symbolizers().get(0); assertNotNull(symbolizer.getColorMap()); assertEquals(3, symbolizer.getColorMap().getColorMapEntries().length); ColorMapEntry[] entries = symbolizer.getColorMap().getColorMapEntries(); Color color = LegendUtils.color(entries[0]); int red = color.getRed(); assertEquals(255, red); int green = color.getGreen(); assertEquals(0, green); int blue = color.getBlue(); assertEquals(0, blue); double quantity = LegendUtils.getQuantity(entries[1]); assertEquals(20.0, quantity, 0.0); double opacity = LegendUtils.getOpacity(entries[2]); assertEquals(0.5, opacity, 0.0); GetLegendGraphicRequest req = new GetLegendGraphicRequest(); CoverageInfo cInfo = getCatalog().getCoverageByName("world"); assertNotNull(cInfo); GridCoverage coverage = cInfo.getGridCoverage(null, null); try { SimpleFeatureCollection feature; feature = FeatureUtilities.wrapGridCoverage((GridCoverage2D) coverage); req.setLayer(feature.getSchema()); req.setStyle(style); req.setLegendOptions(new HashMap()); final int HEIGHT_HINT = 30; req.setHeight(HEIGHT_HINT); // use default values for the rest of parameters this.legendProducer.buildLegendGraphic(req); BufferedImage image = this.legendProducer.buildLegendGraphic(req); // was the legend painted? assertNotBlank("testColorMapWithCql", image, LegendUtils.DEFAULT_BG_COLOR); // was the legend painted? assertNotBlank("testColorMapWithCql", image, LegendUtils.DEFAULT_BG_COLOR); } finally { RenderedImage ri = coverage.getRenderedImage(); if(coverage instanceof GridCoverage2D) { ((GridCoverage2D) coverage).dispose(true); } if(ri instanceof PlanarImage) { ImageUtilities.disposePlanarImageChain((PlanarImage) ri); } } } /** * Test that the legend is not the same if there is a rendering transformation that * converts the rendered layer from vector to raster */ @org.junit.Test public void testRenderingTransformationVectorRaster() throws Exception { Style transformStyle = readSLD("RenderingTransformVectorRaster.sld"); GetLegendGraphicRequest req = new GetLegendGraphicRequest(); FeatureTypeInfo ftInfo = getCatalog() .getFeatureTypeByName(MockData.NAMED_PLACES.getNamespaceURI(), MockData.NAMED_PLACES.getLocalPart()); assertNotNull(ftInfo); req.setLayer(ftInfo.getFeatureType()); req.setStyle(transformStyle); req.setLegendOptions(new HashMap()); this.legendProducer.buildLegendGraphic(req); BufferedImage image = this.legendProducer.buildLegendGraphic(req); // ImageIO.write(image, "PNG", new File("/tmp/vr.png")); assertNotBlank("testRenderingTransform", image, LegendUtils.DEFAULT_BG_COLOR); assertPixel(image, 10, 70, new Color(188, 188, 255)); assertPixel(image, 10, 80, new Color (68, 68, 255)); assertPixel(image, 10, 130, new Color (255, 152, 0)); } /** * Tests that a legend containing an ExternalGraphic icon is rendered properly. */ @org.junit.Test public void testExternalGraphic() throws Exception { // load a style with 3 rules Style externalGraphicStyle = readSLD("ExternalGraphicDemo.sld"); assertNotNull(externalGraphicStyle); GetLegendGraphicRequest req = new GetLegendGraphicRequest(); CoverageInfo cInfo = getCatalog().getCoverageByName("world"); assertNotNull(cInfo); GridCoverage coverage = cInfo.getGridCoverage(null, null); try { LegendRequest legend = req.new LegendRequest(); legend.setStyle(externalGraphicStyle); req.getLegends().add( legend ); req.setScale(1.0); final int HEIGHT_HINT = 30; req.setHeight(HEIGHT_HINT); // use default values for the rest of parameters this.legendProducer.buildLegendGraphic(req); BufferedImage image = this.legendProducer.buildLegendGraphic(req); // was our external graphic icon painted? assertPixel(image, 10, HEIGHT_HINT + HEIGHT_HINT/2, Color.YELLOW); } finally { RenderedImage ri = coverage.getRenderedImage(); if(coverage instanceof GridCoverage2D) { ((GridCoverage2D) coverage).dispose(true); } if(ri instanceof PlanarImage) { ImageUtilities.disposePlanarImageChain((PlanarImage) ri); } } } /** * Tests labelMargin legend option */ @org.junit.Test public void testLabelMargin() throws Exception { GetLegendGraphicRequest req = new GetLegendGraphicRequest(); FeatureTypeInfo ftInfo = getCatalog().getFeatureTypeByName( MockData.POINTS.getNamespaceURI(), MockData.POINTS.getLocalPart()); req.setLayer(ftInfo.getFeatureType()); Style externalGraphicStyle = readSLD("ExternalGraphicDemo.sld"); req.setStyle(externalGraphicStyle); final int HEIGHT_HINT = 20; req.setHeight(HEIGHT_HINT); HashMap legendOptions = new HashMap(); legendOptions.put("labelMargin", "10"); req.setLegendOptions(legendOptions); this.legendProducer.buildLegendGraphic(req); BufferedImage image = this.legendProducer.buildLegendGraphic(req); assertEquals(HEIGHT_HINT * 2, image.getHeight()); for(int x = 21; x <= 29; x++) { assertPixel(image, x, HEIGHT_HINT/2, new Color(255, 255, 255)); } legendOptions.put("labelMargin", "20"); req.setLegendOptions(legendOptions); this.legendProducer.buildLegendGraphic(req); image = this.legendProducer.buildLegendGraphic(req); assertEquals(HEIGHT_HINT * 2, image.getHeight()); for(int x = 21; x <= 39; x++) { assertPixel(image, x, HEIGHT_HINT/2, new Color(255, 255, 255)); } } /** * Tests labelMargin legend option */ @org.junit.Test public void testAbsoluteMargins() throws Exception { Style style = readSLD("ColorMapWithLongLabels.sld"); assertNotNull(style.featureTypeStyles()); assertEquals(1, style.featureTypeStyles().size()); FeatureTypeStyle fts = style.featureTypeStyles().get(0); assertNotNull(fts.rules()); assertEquals(1, fts.rules().size()); Rule rule = fts.rules().get(0); assertNotNull(rule.symbolizers()); assertEquals(1, rule.symbolizers().size()); assertTrue(rule.symbolizers().get(0) instanceof RasterSymbolizer); RasterSymbolizer symbolizer = (RasterSymbolizer)rule.symbolizers().get(0); assertNotNull(symbolizer.getColorMap()); assertEquals(3, symbolizer.getColorMap().getColorMapEntries().length); GetLegendGraphicRequest req = new GetLegendGraphicRequest(); CoverageInfo cInfo = getCatalog().getCoverageByName("world"); assertNotNull(cInfo); GridCoverage coverage = cInfo.getGridCoverage(null, null); try { SimpleFeatureCollection feature; feature = FeatureUtilities.wrapGridCoverage((GridCoverage2D) coverage); req.setLayer(feature.getSchema()); req.setStyle(style); HashMap legendOptions = new HashMap(); legendOptions.put("dx", "0.5"); legendOptions.put("dy", "0"); req.setLegendOptions(legendOptions); final int HEIGHT_HINT = 30; req.setHeight(HEIGHT_HINT); // use default values for the rest of parameters this.legendProducer.buildLegendGraphic(req); BufferedImage image = this.legendProducer.buildLegendGraphic(req); int absoluteWidth = image.getWidth(); legendOptions.put("absoluteMargins", "false"); image = this.legendProducer.buildLegendGraphic(req); assertTrue(image.getWidth() > absoluteWidth); } finally { RenderedImage ri = coverage.getRenderedImage(); if(coverage instanceof GridCoverage2D) { ((GridCoverage2D) coverage).dispose(true); } if(ri instanceof PlanarImage) { ImageUtilities.disposePlanarImageChain((PlanarImage) ri); } } } /** * @param sldName * * @throws IOException */ private Style readSLD(String sldName) throws IOException { StyleFactory styleFactory = CommonFactoryFinder.getStyleFactory(null); SLDParser stylereader = new SLDParser(styleFactory, getClass().getResource( sldName)); Style[] readStyles = stylereader.readXML(); Style style = readStyles[0]; return style; } }