/* (c) 2014 - 2015 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.map;
import com.vividsolutions.jts.geom.Envelope;
import org.geoserver.catalog.*;
import org.geoserver.catalog.LayerInfo.WMSInterpolation;
import org.geoserver.catalog.CoverageView.CompositionType;
import org.geoserver.catalog.CoverageView.CoverageBand;
import org.geoserver.catalog.CoverageView.InputCoverageBand;
import org.geoserver.data.test.MockData;
import org.geoserver.data.test.SystemTestData;
import org.geoserver.platform.ServiceException;
import org.geoserver.security.decorators.DecoratingFeatureSource;
import org.geoserver.wms.*;
import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.coverage.grid.io.GridCoverage2DReader;
import org.geotools.data.FeatureSource;
import org.geotools.data.Query;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.factory.FactoryRegistryException;
import org.geotools.feature.IllegalAttributeException;
import org.geotools.feature.SchemaException;
import org.geotools.filter.IllegalFilterException;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.image.test.ImageAssert;
import org.geotools.map.FeatureLayer;
import org.geotools.map.Layer;
import org.geotools.parameter.Parameter;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.renderer.lite.StreamingRenderer;
import org.geotools.resources.coverage.FeatureUtilities;
import org.geotools.styling.ChannelSelection;
import org.geotools.styling.ChannelSelectionImpl;
import org.geotools.styling.RasterSymbolizer;
import org.geotools.styling.SelectedChannelType;
import org.geotools.styling.SelectedChannelTypeImpl;
import org.geotools.styling.Style;
import org.geotools.styling.StyleBuilder;
import org.geotools.util.logging.Logging;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.opengis.parameter.GeneralParameterValue;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.TransformException;
import javax.media.jai.Interpolation;
import javax.media.jai.RenderedOp;
import javax.xml.namespace.QName;
import java.awt.*;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.geoserver.data.test.CiteTestData.STREAMS;
import static org.junit.Assert.*;
public class RenderedImageMapOutputFormatTest extends WMSTestSupport {
private static final Logger LOGGER = org.geotools.util.logging.Logging
.getLogger(RenderedImageMapOutputFormatTest.class.getPackage().getName());
private RenderedImageMapOutputFormat rasterMapProducer;
private String mapFormat = "image/gif";
@Before
public void setRasterMapProducer() throws Exception {
Logging.getLogger("org.geotools.rendering").setLevel(Level.OFF);
this.rasterMapProducer = getProducerInstance();
getTestData().addDefaultRasterLayer(SystemTestData.MULTIBAND, getCatalog());
}
protected RenderedImageMapOutputFormat getProducerInstance() {
return new DummyRasterMapProducer(getWMS());
}
@After
public void unsetRasterMapProducer() throws Exception {
this.rasterMapProducer = null;
}
public String getMapFormat() {
return this.mapFormat;
}
@Test
public void testSimpleGetMapQuery() throws Exception {
Catalog catalog = getCatalog();
final FeatureSource fs = catalog.getFeatureTypeByName(MockData.BASIC_POLYGONS.getPrefix(),
MockData.BASIC_POLYGONS.getLocalPart()).getFeatureSource(null, null);
final Envelope env = fs.getBounds();
LOGGER.info("about to create map ctx for BasicPolygons with bounds " + env);
GetMapRequest request = new GetMapRequest();
final WMSMapContent map = new WMSMapContent();
map.getViewport().setBounds(new ReferencedEnvelope(env, DefaultGeographicCRS.WGS84));
map.setMapWidth(300);
map.setMapHeight(300);
map.setBgColor(Color.red);
map.setTransparent(false);
map.setRequest(request);
StyleInfo styleByName = catalog.getStyleByName("Default");
Style basicStyle = styleByName.getStyle();
map.addLayer(new FeatureLayer(fs, basicStyle));
request.setFormat(getMapFormat());
RenderedImageMap imageMap = this.rasterMapProducer.produceMap(map);
BufferedImage image = (BufferedImage) imageMap.getImage();
imageMap.dispose();
assertNotBlank("testSimpleGetMapQuery", image);
}
/**
* Test to make sure the "direct" raster path and the "nondirect" raster path
* produce matching results. This test was originally created after fixes to GEOS-7270
* where there were issues with images generated during the direct raster path but not
* in the normal path, stemming from not setting the background color the same way
*/
@Test
public void testDirectVsNonDirectRasterRender() throws Exception {
Catalog catalog = getCatalog();
CoverageInfo ci = catalog.getCoverageByName(
SystemTestData.MULTIBAND.getPrefix(), SystemTestData.MULTIBAND.getLocalPart());
final Envelope env = ci.boundingBox();
LOGGER.info("about to create map ctx for BasicPolygons with bounds " + env);
GetMapRequest request = new GetMapRequest();
CoordinateReferenceSystem crs = DefaultGeographicCRS.WGS84;
ReferencedEnvelope bbox = new ReferencedEnvelope(
new Envelope(-116.90673461649858211,
-114.30988665660261461, 32.07093728218402617, 33.89032847348440214), crs);
request.setBbox(bbox);
request.setSRS("urn:x-ogc:def:crs:EPSG:4326");
request.setFormat("image/png");
final WMSMapContent map = new WMSMapContent(request);
map.setMapWidth(300);
map.setMapHeight(300);
map.setBgColor(Color.red);
map.setTransparent(false);
map.getViewport().setBounds(bbox);
StyleBuilder builder = new StyleBuilder();
GridCoverage2DReader reader = (GridCoverage2DReader) ci.getGridCoverageReader(null, null);
reader.getCoordinateReferenceSystem();
Layer l = new CachedGridReaderLayer(
reader,
builder.createStyle(builder.createRasterSymbolizer()));
map.addLayer(l);
RenderedImageMap imageMap = this.rasterMapProducer.produceMap(map);
ImageAssert.assertEquals(new File(
"src/test/resources/org/geoserver/wms/map/direct-raster-expected.tif"), imageMap.getImage(), 0);
imageMap.dispose();
}
@Test
public void testTimeoutOption() throws Exception {
Catalog catalog = getCatalog();
GetMapRequest request = new GetMapRequest();
final WMSMapContent map = new WMSMapContent();
StyleInfo styleByName = catalog.getStyleByName("Default");
Style basicStyle = styleByName.getStyle();
//Build up a complex map so that we can reasonably guarantee a 1 ms timout
SimpleFeatureSource fs = (SimpleFeatureSource) catalog.getFeatureTypeByName(MockData.BASIC_POLYGONS.getPrefix(),
MockData.BASIC_POLYGONS.getLocalPart()).getFeatureSource(null, null);
Envelope env = fs.getBounds();
SimpleFeatureCollection features = fs.getFeatures();
SimpleFeatureCollection delayedCollection = new DelayedFeatureCollection(features, 10);
map.addLayer(new FeatureLayer(delayedCollection, basicStyle));
LOGGER.info("about to create map ctx for "+map.layers().size()+" layers with bounds " + env);
map.getViewport().setBounds(new ReferencedEnvelope(env, DefaultGeographicCRS.WGS84));
map.setMapWidth(1000);
map.setMapHeight(1000);
map.setRequest(request);
request.setFormat(getMapFormat());
Map formatOptions = new HashMap();
//1 ms timeout
formatOptions.put("timeout", 1);
request.setFormatOptions(formatOptions);
try {
RenderedImageMap imageMap = this.rasterMapProducer.produceMap(map);
fail("Timeout was not reached");
} catch (ServiceException e) {
assertTrue(e.getMessage().startsWith("This request used more time than allowed"));
}
//Test partial image exception format
Map rawKvp = new HashMap();
rawKvp.put("EXCEPTIONS", "PARTIALMAP");
request.setRawKvp(rawKvp);
try {
RenderedImageMap imageMap = this.rasterMapProducer.produceMap(map);
fail("Timeout was not reached");
} catch (ServiceException e) {
assertTrue(e instanceof WMSPartialMapException);
assertTrue(e.getCause().getMessage().startsWith("This request used more time than allowed"));
RenderedImageMap partialMap = (RenderedImageMap) ((WMSPartialMapException)e).getMap();
assertNotNull(partialMap);
assertNotNull(partialMap.getImage());
}
}
@Test
public void testDefaultStyle() throws Exception {
List<org.geoserver.catalog.FeatureTypeInfo> typeInfos = getCatalog().getFeatureTypes();
for (org.geoserver.catalog.FeatureTypeInfo info : typeInfos) {
if (info.getQualifiedName().getNamespaceURI().equals(MockData.CITE_URI)
&& info.getFeatureType().getGeometryDescriptor() != null)
testDefaultStyle(info.getFeatureSource(null, null));
}
}
@Test
public void testBlueLake() throws IOException, IllegalFilterException, Exception {
final Catalog catalog = getCatalog();
org.geoserver.catalog.FeatureTypeInfo typeInfo = catalog.getFeatureTypeByName(
MockData.LAKES.getNamespaceURI(), MockData.LAKES.getLocalPart());
Envelope env = typeInfo.getFeatureSource(null, null).getBounds();
double shift = env.getWidth() / 6;
env = new Envelope(env.getMinX() - shift, env.getMaxX() + shift, env.getMinY() - shift,
env.getMaxY() + shift);
GetMapRequest request = new GetMapRequest();
final WMSMapContent map = new WMSMapContent();
int w = 400;
int h = (int) Math.round((env.getHeight() * w) / env.getWidth());
map.setMapWidth(w);
map.setMapHeight(h);
map.setBgColor(BG_COLOR);
map.setTransparent(true);
map.setRequest(request);
addToMap(map, MockData.FORESTS);
addToMap(map, MockData.LAKES);
addToMap(map, MockData.STREAMS);
addToMap(map, MockData.NAMED_PLACES);
addToMap(map, MockData.ROAD_SEGMENTS);
addToMap(map, MockData.PONDS);
addToMap(map, MockData.BUILDINGS);
addToMap(map, MockData.DIVIDED_ROUTES);
addToMap(map, MockData.BRIDGES);
addToMap(map, MockData.MAP_NEATLINE);
map.getViewport().setBounds(new ReferencedEnvelope(env, DefaultGeographicCRS.WGS84));
request.setFormat(getMapFormat());
RenderedImageMap imageMap = this.rasterMapProducer.produceMap(map);
BufferedImage image = (BufferedImage) imageMap.getImage();
imageMap.dispose();
assertNotBlank("testBlueLake", image);
}
@Override
protected void onSetUp(SystemTestData testData) throws Exception {
super.onSetUp(testData);
testData.addDefaultRasterLayer(MockData.TASMANIA_DEM, getCatalog());
}
@Test
public void testInterpolations() throws IOException, IllegalFilterException, Exception {
final Catalog catalog = getCatalog();
CoverageInfo coverageInfo = catalog.getCoverageByName(MockData.TASMANIA_DEM.getNamespaceURI(),
MockData.TASMANIA_DEM.getLocalPart());
Envelope env = coverageInfo.boundingBox();
double shift = env.getWidth() / 6;
env = new Envelope(env.getMinX() - shift, env.getMaxX() + shift, env.getMinY() - shift,
env.getMaxY() + shift);
GetMapRequest request = new GetMapRequest();
WMSMapContent map = new WMSMapContent();
int w = 400;
int h = (int) Math.round((env.getHeight() * w) / env.getWidth());
map.setMapWidth(w);
map.setMapHeight(h);
map.setBgColor(BG_COLOR);
map.setTransparent(true);
map.setRequest(request);
addRasterToMap(map, MockData.TASMANIA_DEM);
map.getViewport().setBounds(new ReferencedEnvelope(env, DefaultGeographicCRS.WGS84));
request.setInterpolations(Arrays.asList(Interpolation
.getInstance(Interpolation.INTERP_NEAREST)));
request.setFormat(getMapFormat());
RenderedImageMap imageMap = this.rasterMapProducer.produceMap(map);
RenderedOp op = (RenderedOp)imageMap.getImage();
BufferedImage imageNearest = op.getAsBufferedImage();
imageMap.dispose();
assertNotBlank("testInterpolationsNearest", imageNearest);
request = new GetMapRequest();
map = new WMSMapContent();
map.setMapWidth(w);
map.setMapHeight(h);
map.setBgColor(BG_COLOR);
map.setTransparent(true);
map.setRequest(request);
addRasterToMap(map, MockData.TASMANIA_DEM);
map.getViewport().setBounds(new ReferencedEnvelope(env, DefaultGeographicCRS.WGS84));
request.setInterpolations(Arrays.asList(Interpolation
.getInstance(Interpolation.INTERP_BICUBIC)));
request.setFormat(getMapFormat());
imageMap = this.rasterMapProducer.produceMap(map);
op = (RenderedOp)imageMap.getImage();
BufferedImage imageBicubic = op.getAsBufferedImage();
imageMap.dispose();
assertNotBlank("testInterpolationsBicubic", imageBicubic);
// test some sample pixels to check rendering is different using different interpolations
assertNotEquals(getPixelColor(imageNearest, 200, 200).getRGB(),
getPixelColor(imageBicubic, 200, 200).getRGB());
assertNotEquals(getPixelColor(imageNearest, 300, 300).getRGB(),
getPixelColor(imageBicubic, 300, 300).getRGB());
}
@Test
public void testInterpolationFromLayerConfig() throws IOException, IllegalFilterException, Exception {
final Catalog catalog = getCatalog();
LayerInfo layerInfo = catalog.getLayerByName(MockData.TASMANIA_DEM.getLocalPart());
MapLayerInfo mapLayer = new MapLayerInfo(layerInfo);
assertNull(layerInfo.getDefaultWMSInterpolationMethod());
Envelope env = layerInfo.getResource().boundingBox();
double shift = env.getWidth() / 6;
env = new Envelope(env.getMinX() - shift, env.getMaxX() + shift, env.getMinY() - shift,
env.getMaxY() + shift);
// set Nearest Neighbor interpolation on layer
GetMapRequest request = new GetMapRequest();
request.setFormat(getMapFormat());
request.setLayers(Arrays.asList(mapLayer));
layerInfo.setDefaultWMSInterpolationMethod(WMSInterpolation.Nearest);
assertEquals(WMSInterpolation.Nearest,
request.getLayers().get(0).getLayerInfo().getDefaultWMSInterpolationMethod());
assertTrue(request.getInterpolations().isEmpty());
WMSMapContent map = createWMSMap(env);
map.setRequest(request);
RenderedImageMap imageMap = this.rasterMapProducer.produceMap(map);
RenderedOp op = (RenderedOp)imageMap.getImage();
BufferedImage imageNearest = op.getAsBufferedImage();
imageMap.dispose();
assertNotBlank("testInterpolationsNearest", imageNearest);
// set Bicubic interpolation on layer
request = new GetMapRequest();
request.setFormat(getMapFormat());
request.setLayers(Arrays.asList(mapLayer));
layerInfo.setDefaultWMSInterpolationMethod(WMSInterpolation.Bicubic);
assertEquals(WMSInterpolation.Bicubic,
request.getLayers().get(0).getLayerInfo().getDefaultWMSInterpolationMethod());
assertTrue(request.getInterpolations().isEmpty());
map = createWMSMap(env);
map.setRequest(request);
imageMap = this.rasterMapProducer.produceMap(map);
op = (RenderedOp)imageMap.getImage();
BufferedImage imageBicubic = op.getAsBufferedImage();
imageMap.dispose();
assertNotBlank("testInterpolationsBicubic", imageBicubic);
// test some sample pixels to check rendering is different using different interpolations
assertNotEquals(getPixelColor(imageNearest, 200, 200).getRGB(),
getPixelColor(imageBicubic, 200, 200).getRGB());
assertNotEquals(getPixelColor(imageNearest, 300, 300).getRGB(),
getPixelColor(imageBicubic, 300, 300).getRGB());
// check also the *non* direct raster render path
request = new GetMapRequest();
request.setFormat(getMapFormat());
// adding layer twice on purpose to disable direct raster render
request.setLayers(Arrays.asList(mapLayer, mapLayer));
layerInfo.setDefaultWMSInterpolationMethod(WMSInterpolation.Bicubic);
assertEquals(WMSInterpolation.Bicubic,
request.getLayers().get(0).getLayerInfo().getDefaultWMSInterpolationMethod());
assertTrue(request.getInterpolations().isEmpty());
map = createWMSMap(env);
map.setRequest(request);
// adding layer twice on purpose to disable direct raster render
addRasterToMap(map, MockData.TASMANIA_DEM);
imageMap = this.rasterMapProducer.produceMap(map);
checkByLayerInterpolation(imageMap, Interpolation.getInstance(Interpolation.INTERP_BICUBIC));
// interpolation method specified in the request overrides service and layer configuration
request = new GetMapRequest();
// request says "Bicubic"
request.setInterpolations(
Arrays.asList(Interpolation.getInstance(Interpolation.INTERP_BICUBIC)));
request.setFormat(getMapFormat());
// adding layer twice on purpose to disable direct raster render
request.setLayers(Arrays.asList(mapLayer, mapLayer));
// layer config says "Bilinear"
layerInfo.setDefaultWMSInterpolationMethod(WMSInterpolation.Bilinear);
assertEquals(WMSInterpolation.Bilinear,
request.getLayers().get(0).getLayerInfo().getDefaultWMSInterpolationMethod());
// service config says "Nearest"
assertEquals(WMSInfo.WMSInterpolation.Nearest, getWMS().getServiceInfo().getInterpolation());
map = createWMSMap(env);
map.setRequest(request);
// adding layer twice on purpose to disable direct raster render
addRasterToMap(map, MockData.TASMANIA_DEM);
imageMap = this.rasterMapProducer.produceMap(map);
checkByLayerInterpolation(imageMap, Interpolation.getInstance(Interpolation.INTERP_BICUBIC));
// if default interpolation method is not specified, service default is used
request = new GetMapRequest();
request.setFormat(getMapFormat());
request.setLayers(Arrays.asList(mapLayer));
layerInfo.setDefaultWMSInterpolationMethod(null);
assertEquals(null,
request.getLayers().get(0).getLayerInfo().getDefaultWMSInterpolationMethod());
assertTrue(request.getInterpolations().isEmpty());
assertEquals(WMSInfo.WMSInterpolation.Nearest, getWMS().getServiceInfo().getInterpolation());
map = createWMSMap(env);
map.setRequest(request);
imageMap = this.rasterMapProducer.produceMap(map);
op = (RenderedOp)imageMap.getImage();
BufferedImage imageServiceDefault = op.getAsBufferedImage();
imageMap.dispose();
assertNotBlank("testInterpolationServiceDefault", imageServiceDefault);
// test produced image is equal to imageNearest
assertEquals(getPixelColor(imageNearest, 200, 200).getRGB(),
getPixelColor(imageServiceDefault, 200, 200).getRGB());
assertEquals(getPixelColor(imageNearest, 300, 300).getRGB(),
getPixelColor(imageServiceDefault, 300, 300).getRGB());
assertEquals(getPixelColor(imageNearest, 250, 250).getRGB(),
getPixelColor(imageServiceDefault, 250, 250).getRGB());
assertEquals(getPixelColor(imageNearest, 150, 150).getRGB(),
getPixelColor(imageServiceDefault, 150, 150).getRGB());
}
/*
* NOTE: this check is valid only if the direct raster render path is *not* taken
*/
private void checkByLayerInterpolation(RenderedImageMap imageMap, Interpolation expected) {
Layer layer = imageMap.getMapContext().layers().get(0);
Interpolation actual = (Interpolation) layer.getUserData().get(StreamingRenderer.BYLAYER_INTERPOLATION);
assertEquals(expected, actual);
}
private WMSMapContent createWMSMap(Envelope bounds) throws Exception {
WMSMapContent map = new WMSMapContent();
int w = 400;
int h = (int) Math.round((bounds.getHeight() * w) /bounds.getWidth());
map.setMapWidth(w);
map.setMapHeight(h);
map.setBgColor(BG_COLOR);
map.setTransparent(true);
addRasterToMap(map, MockData.TASMANIA_DEM);
map.getViewport().setBounds(new ReferencedEnvelope(bounds, DefaultGeographicCRS.WGS84));
return map;
}
private void addRasterToMap(final WMSMapContent map, final QName typeName) throws IOException, FactoryRegistryException, TransformException, SchemaException {
final CoverageInfo coverageInfo = getCatalog().getCoverageByName(typeName.getNamespaceURI(),
typeName.getLocalPart());
List<LayerInfo> layers = getCatalog().getLayers(coverageInfo);
StyleInfo defaultStyle = layers.get(0).getDefaultStyle();
Style style = defaultStyle.getStyle();
SimpleFeatureCollection fc = FeatureUtilities.wrapGridCoverageReader(
(GridCoverage2DReader)coverageInfo.getGridCoverageReader(null, null), new GeneralParameterValue[] {});
map.addLayer(new FeatureLayer(fc, style));
}
private void addToMap(final WMSMapContent map, final QName typeName) throws IOException {
final FeatureTypeInfo ftInfo = getCatalog().getFeatureTypeByName(
typeName.getNamespaceURI(), typeName.getLocalPart());
List<LayerInfo> layers = getCatalog().getLayers(ftInfo);
StyleInfo defaultStyle = layers.get(0).getDefaultStyle();
Style style = defaultStyle.getStyle();
map.addLayer(new FeatureLayer(ftInfo.getFeatureSource(null, null), style));
}
private void testDefaultStyle(FeatureSource fSource) throws Exception {
Catalog catalog = getCatalog();
Style style = catalog.getStyleByName("Default").getStyle();
FeatureTypeInfo typeInfo = catalog.getFeatureTypeByName(MockData.LAKES.getNamespaceURI(),
MockData.LAKES.getLocalPart());
Envelope env = typeInfo.getFeatureSource(null, null).getBounds();
env.expandToInclude(fSource.getBounds());
int w = 400;
int h = (int) Math.round((env.getHeight() * w) / env.getWidth());
double shift = env.getWidth() / 6;
env = new Envelope(env.getMinX() - shift, env.getMaxX() + shift, env.getMinY() - shift,
env.getMaxY() + shift);
WMSMapContent map = new WMSMapContent();
GetMapRequest request = new GetMapRequest();
map.setRequest(request);
map.addLayer(new FeatureLayer(fSource, style));
map.getViewport().setBounds(new ReferencedEnvelope(env, DefaultGeographicCRS.WGS84));
map.setMapWidth(w);
map.setMapHeight(h);
map.setBgColor(BG_COLOR);
map.setTransparent(false);
// this.rasterMapProducer.setOutputFormat(getMapFormat());
// this.rasterMapProducer.setMapContext(map);
// this.rasterMapProducer.produceMap();
request.setFormat(getMapFormat());
RenderedImageMap imageMap = this.rasterMapProducer.produceMap(map);
RenderedImage image = imageMap.getImage();
imageMap.dispose();
assertNotNull(image);
String typeName = fSource.getSchema().getName().getLocalPart();
assertNotBlank("testDefaultStyle " + typeName, (BufferedImage) image);
}
/**
* Checks {@link RenderedImageMapOutputFormat} makes good use of {@link RenderExceptionStrategy}
*/
@SuppressWarnings("deprecation")
@Test
public void testRenderingErrorsHandling() throws Exception {
// the ones that are ignorable by the renderer
assertNotNull(forceRenderingError(new TransformException("fake transform exception")));
assertNotNull(forceRenderingError(new NoninvertibleTransformException(
"fake non invertible exception")));
assertNotNull(forceRenderingError(new IllegalAttributeException(
"non illegal attribute exception")));
assertNotNull(forceRenderingError(new FactoryException("fake factory exception")));
// any other one should make the map producer fail
try {
forceRenderingError(new RuntimeException("fake runtime exception"));
fail("Expected WMSException");
} catch (ServiceException e) {
assertTrue(true);
}
try {
forceRenderingError(new IOException("fake IO exception"));
fail("Expected WMSException");
} catch (ServiceException e) {
assertTrue(true);
}
try {
forceRenderingError(new IllegalArgumentException("fake IAE exception"));
fail("Expected WMSException");
} catch (ServiceException e) {
assertTrue(true);
}
}
/**
* Test to check if we can successfully create a direct rendered image by using
* a coverage view as a source, and a symbolizer defining which three bands of the
* input coverage view can be used for RGB coloring, and with what order.
*/
@Test
public void testStyleUsingChannelsFromCoverageView() throws Exception {
GetMapRequest request = new GetMapRequest();
CoordinateReferenceSystem crs = DefaultGeographicCRS.WGS84;
ReferencedEnvelope bbox = new ReferencedEnvelope(
new Envelope(-116.90673461649858211,
-114.30988665660261461, 32.07093728218402617, 33.89032847348440214), crs);
request.setBbox(bbox);
request.setSRS("urn:x-ogc:def:crs:EPSG:4326");
request.setFormat("image/png");
final WMSMapContent map = new WMSMapContent(request);
map.setMapWidth(300);
map.setMapHeight(300);
map.setTransparent(false);
map.getViewport().setBounds(bbox);
StyleBuilder styleBuilder = new StyleBuilder();
Catalog catalog = getCatalog();
// Source image
CoverageInfo ci = catalog.getCoverageByName(
SystemTestData.MULTIBAND.getPrefix(), SystemTestData.MULTIBAND.getLocalPart());
GridCoverage2DReader reader = (GridCoverage2DReader) ci.getGridCoverageReader(null, null);
reader.getCoordinateReferenceSystem();
Layer sl = new CachedGridReaderLayer(
reader,
styleBuilder.createStyle(styleBuilder.createRasterSymbolizer()));
map.addLayer(sl);
RenderedImageMap srcImageMap = this.rasterMapProducer.produceMap(map);
RenderedImage srcImage = srcImageMap.getImage();
// CoverageView band creation. We create a coverage view with 6 bands, using
// the original bands from the multiband coverage
//Note that first three bands are int reverse order of the bands of the source coverage
final InputCoverageBand ib0 = new InputCoverageBand("multiband", "2");
final CoverageBand b0 = new CoverageBand(Collections.singletonList(ib0), "multiband@2",
0, CompositionType.BAND_SELECT);
final InputCoverageBand ib1 = new InputCoverageBand("multiband", "1");
final CoverageBand b1 = new CoverageBand(Collections.singletonList(ib1), "multiband@1",
1, CompositionType.BAND_SELECT);
final InputCoverageBand ib2 = new InputCoverageBand("multiband", "0");
final CoverageBand b2 = new CoverageBand(Collections.singletonList(ib2), "multiband@0",
2, CompositionType.BAND_SELECT);
final InputCoverageBand ib3 = new InputCoverageBand("multiband", "0");
final CoverageBand b3 = new CoverageBand(Collections.singletonList(ib3), "multiband@0",
0, CompositionType.BAND_SELECT);
final InputCoverageBand ib4 = new InputCoverageBand("multiband", "1");
final CoverageBand b4 = new CoverageBand(Collections.singletonList(ib4), "multiband@1",
1, CompositionType.BAND_SELECT);
final InputCoverageBand ib5 = new InputCoverageBand("multiband", "2");
final CoverageBand b5 = new CoverageBand(Collections.singletonList(ib5), "multiband@2",
2, CompositionType.BAND_SELECT);
final List<CoverageBand> coverageBands = new ArrayList<CoverageBand>(1);
coverageBands.add(b0);
coverageBands.add(b1);
coverageBands.add(b2);
coverageBands.add(b3);
coverageBands.add(b4);
coverageBands.add(b5);
CoverageView multiBandCoverageView = new CoverageView("multiband_select", coverageBands);
CoverageStoreInfo storeInfo = catalog.getCoverageStoreByName("multiband");
CatalogBuilder builder = new CatalogBuilder(catalog);
// Reordered bands coverage
CoverageInfo coverageInfo = multiBandCoverageView.createCoverageInfo("multiband_select",
storeInfo, builder);
coverageInfo.getParameters().put("USE_JAI_IMAGEREAD", "false");
catalog.add(coverageInfo);
final LayerInfo layerInfoView = builder.buildLayer(coverageInfo);
catalog.add(layerInfoView);
final Envelope env = ci.boundingBox();
LOGGER.info("about to create map ctx for BasicPolygons with bounds " + env);
RasterSymbolizer symbolizer = styleBuilder.createRasterSymbolizer();
ChannelSelection cs = new ChannelSelectionImpl();
SelectedChannelType red = new SelectedChannelTypeImpl();
SelectedChannelType green = new SelectedChannelTypeImpl();
SelectedChannelType blue = new SelectedChannelTypeImpl();
// We want to create an image where the RGB channels are in reverse order
// regarding the band order of the input coverage view
// Note that channel names start with index "1"
red.setChannelName("3");
green.setChannelName("2");
blue.setChannelName("1");
cs.setRGBChannels(new SelectedChannelType[]{red, green, blue});
symbolizer.setChannelSelection(cs);
reader = (GridCoverage2DReader) coverageInfo.getGridCoverageReader(null, null);
reader.getCoordinateReferenceSystem();
Layer dl = new CachedGridReaderLayer(
reader,
styleBuilder.createStyle(symbolizer));
map.removeLayer(sl);
map.addLayer(dl);
RenderedImageMap dstImageMap = this.rasterMapProducer.produceMap(map);
RenderedImage destImage = dstImageMap.getImage();
int dWidth = destImage.getWidth();
int dHeight = destImage.getHeight();
int[] destImageRowBand0 = new int[dWidth*dHeight];
int[] destImageRowBand1 = new int[destImageRowBand0.length];
int[] destImageRowBand2 = new int[destImageRowBand0.length];
destImage.getData().getSamples(0, 0, dWidth, dHeight, 0, destImageRowBand0);
destImage.getData().getSamples(0, 0, dWidth, dHeight, 1, destImageRowBand1);
destImage.getData().getSamples(0, 0, dWidth, dHeight, 2, destImageRowBand2);
int sWidth = srcImage.getWidth();
int sHeight = srcImage.getHeight();
int[] srcImageRowBand0 = new int[sWidth*sHeight];
int[] srcImageRowBand2 = new int[srcImageRowBand0.length];
srcImage.getData().getSamples(0, 0, sWidth, sHeight, 0, srcImageRowBand0);
// Source and result image first bands should be the same. We have reversed the order
// of the three first bands of the source coverage and then we re-reversed the three
// first bands using channel selection on the raster symbolizer used for rendering.
Assert.assertTrue(Arrays.equals(destImageRowBand0,srcImageRowBand0));
//Result band 0 should not be equal to source image band 2
Assert.assertFalse(Arrays.equals(destImageRowBand0,srcImageRowBand2));
srcImageMap.dispose();
dstImageMap.dispose();
map.dispose();
}
/**
* Test to check the case where a {@link org.geotools.coverage.grid.io.AbstractGridFormat#BANDS}
* reading parameter is passed to a coverage reader that does not support it. Reader should
* ignore it, resulting coverage should not be affected.
*/
@Test
public void testBandSelectionToNormalCoverage() throws Exception {
GetMapRequest request = new GetMapRequest();
CoordinateReferenceSystem crs = DefaultGeographicCRS.WGS84;
ReferencedEnvelope bbox = new ReferencedEnvelope(
new Envelope(-116.90673461649858211,
-114.30988665660261461, 32.07093728218402617, 33.89032847348440214), crs);
request.setBbox(bbox);
request.setSRS("urn:x-ogc:def:crs:EPSG:4326");
request.setFormat("image/png");
final WMSMapContent map = new WMSMapContent(request);
map.setMapWidth(300);
map.setMapHeight(300);
map.setBgColor(Color.red);
map.setTransparent(false);
map.getViewport().setBounds(bbox);
StyleBuilder styleBuilder = new StyleBuilder();
Catalog catalog = getCatalog();
CoverageInfo ci = catalog.getCoverageByName(
SystemTestData.MULTIBAND.getPrefix(), SystemTestData.MULTIBAND.getLocalPart());
GridCoverage2DReader reader = (GridCoverage2DReader) ci.getGridCoverageReader(null, null);
reader.getCoordinateReferenceSystem();
final Envelope env = ci.boundingBox();
final int[] bandIndices = new int[]{1,2,0,2,1};
//Inject bandIndices read param
Parameter<int[]> bandIndicesParam =
(Parameter<int[]>) AbstractGridFormat.BANDS.createValue();
bandIndicesParam.setValue(bandIndices);
List<GeneralParameterValue> paramList = new ArrayList<GeneralParameterValue>();
paramList.add(bandIndicesParam);
GeneralParameterValue[] readParams = paramList.toArray(new GeneralParameterValue[paramList.size()]);
Layer sl = new CachedGridReaderLayer(
reader,
styleBuilder.createStyle(styleBuilder.createRasterSymbolizer()),
readParams
);
map.addLayer(sl);
RenderedImageMap imageMap = this.rasterMapProducer.produceMap(map);
ImageAssert.assertEquals(new File(
"src/test/resources/org/geoserver/wms/map/direct-raster-expected.tif"), imageMap.getImage(), 0);
imageMap.dispose();
}
/**
* Sets up a rendering loop and throws {@code renderExceptionToThrow} wrapped to a
* RuntimeException when the renderer tries to get a Feature to render.
* <p>
* If the rendering succeeded returns the image, which is going to be a blank one but means the
* renderer didn't complain about the exception caught. Otherwise throws back the exception
* thrown by {@link RenderedImageMapOutputFormat#produceMap()}
* </p>
*/
@SuppressWarnings("unchecked")
private RenderedImage forceRenderingError(final Exception renderExceptionToThrow)
throws Exception {
GetMapRequest request = new GetMapRequest();
final WMSMapContent map = new WMSMapContent();
map.setMapWidth(100);
map.setMapHeight(100);
map.setRequest(request);
final ReferencedEnvelope bounds = new ReferencedEnvelope(-180, 180, -90, 90,
DefaultGeographicCRS.WGS84);
map.getViewport().setBounds(bounds);
final FeatureTypeInfo ftInfo = getCatalog().getFeatureTypeByName(STREAMS.getNamespaceURI(),
STREAMS.getLocalPart());
final SimpleFeatureSource featureSource = (SimpleFeatureSource) ftInfo.getFeatureSource(
null, null);
DecoratingFeatureSource source;
// This source should make the renderer fail when asking for the features
source = new DecoratingFeatureSource(featureSource) {
@Override
public SimpleFeatureCollection getFeatures(Query query) throws IOException {
throw new RuntimeException(renderExceptionToThrow);
// return delegate.getFeatures(query);
}
};
StyleInfo someStyle = getCatalog().getStyleByName("line");
map.addLayer(new FeatureLayer(source, someStyle.getStyle()));
request.setFormat(getMapFormat());
RenderedImageMap imageMap = this.rasterMapProducer.produceMap(map);
BufferedImage image = (BufferedImage) imageMap.getImage();
imageMap.dispose();
return image;
}
/**
* This dummy producer adds no functionality to DefaultRasterMapOutputFormat, just implements a
* void formatImageOutputStream to have a concrete class over which test that
* DefaultRasterMapOutputFormat correctly generates the BufferedImage.
*
* @author Gabriel Roldan
* @version $Id: DefaultRasterMapOutputFormatTest.java 6797 2007-05-16 10:23:50Z aaime $
*/
static class DummyRasterMapProducer extends RenderedImageMapOutputFormat {
public DummyRasterMapProducer(WMS wms) {
super("image/gif", new String[] { "image/gif" }, wms);
}
}
}