/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2014 MangoSystem
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wps.spatialstatistics.ppio;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import org.geoserver.wps.ppio.BinaryPPIO;
import org.geotools.data.collection.ListFeatureCollection;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.map.FeatureLayer;
import org.geotools.map.GridCoverageLayer;
import org.geotools.map.MapContent;
import org.geotools.process.spatialstatistics.core.FeatureTypes;
import org.geotools.process.spatialstatistics.core.MapToImageParam;
import org.geotools.renderer.GTRenderer;
import org.geotools.renderer.lite.StreamingRenderer;
import org.geotools.styling.Style;
import org.geotools.util.logging.Logging;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.GeometryDescriptor;
import org.opengis.filter.Filter;
/**
* A PPIO to generate Image from featurecollection, gridcoverage2d
*
* @author Minpa Lee, MangoSystem
*
* @source $URL$
*/
public class MapImagePPIO extends BinaryPPIO {
protected static final Logger LOGGER = Logging.getLogger(MapImagePPIO.class);
protected MapImagePPIO() {
super(MapToImageParam.class, MapToImageParam.class, "image/png");
}
@Override
public void encode(Object value, OutputStream os) throws Exception {
MapToImageParam info = (MapToImageParam) value;
this.mimeType = info.getFormat();
// prepare map context
MapContent mapContent = new MapContent();
mapContent.getViewport().setCoordinateReferenceSystem(info.getSrs());
Style style = info.getStyle();
if (info.getInputFeatures() == null) {
mapContent.layers().add(new GridCoverageLayer(info.getInputCoverage(), style));
} else {
// convert string type to number type
Filter filter = info.getFilter();
SimpleFeatureCollection sfc = info.getInputFeatures();
if (filter != Filter.INCLUDE && filter != null) {
sfc = retypeCheck(info.getInputFeatures()).subCollection(filter);
}
mapContent.layers().add(new FeatureLayer(sfc, style));
}
mapContent.getViewport().setBounds(info.getMapExtent());
// export map
GTRenderer renderer = new StreamingRenderer();
renderer.setMapContent(mapContent);
RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
renderer.setJava2DHints(hints);
Map<Object, Object> rendererParams = new HashMap<Object, Object>();
rendererParams.put("optimizedDataLoadingEnabled", Boolean.TRUE);
renderer.setRendererHints(rendererParams);
BufferedImage image = new BufferedImage(info.getWidth(), info.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = image.createGraphics();
Rectangle paintArea = new Rectangle(0, 0, info.getWidth(), info.getHeight());
ReferencedEnvelope mapArea = mapContent.getViewport().getBounds();
if (info.getTransparent()) {
renderer.paint(graphics, paintArea, mapArea);
} else {
graphics.setPaint(info.getBackgroundColor());
graphics.fill(paintArea);
renderer.paint(graphics, paintArea, mapArea);
}
// cleanup
graphics.dispose();
mapContent.dispose();
// write image
ImageIO.write(image, getFileExtension(), os);
}
private SimpleFeatureCollection retypeCheck(SimpleFeatureCollection sfc) {
SimpleFeatureType schema = sfc.getSchema();
// 1. check value
Map<String, String> fieldMap = new HashMap<String, String>();
SimpleFeatureIterator featureIter = sfc.features();
try {
while (featureIter.hasNext()) {
SimpleFeature feature = featureIter.next();
for (AttributeDescriptor descriptor : schema.getAttributeDescriptors()) {
if (descriptor instanceof GeometryDescriptor) {
continue;
} else {
final String propertyName = descriptor.getLocalName();
Object val = feature.getAttribute(propertyName);
try {
if (val != null) {
Double.parseDouble(val.toString().trim());
fieldMap.put(propertyName, propertyName);
}
} catch (NumberFormatException e) {
LOGGER.log(Level.FINEST, e.getLocalizedMessage(), e);
}
}
}
break;
}
} finally {
featureIter.close();
}
// 2. if required, retype schema
if (fieldMap.size() > 0) {
SimpleFeatureTypeBuilder sftBuilder = new SimpleFeatureTypeBuilder();
sftBuilder.setNamespaceURI(FeatureTypes.NAMESPACE_URL);
sftBuilder.setName(schema.getName());
sftBuilder.setCRS(schema.getCoordinateReferenceSystem());
for (AttributeDescriptor descriptor : schema.getAttributeDescriptors()) {
if (descriptor instanceof GeometryDescriptor) {
sftBuilder.add(descriptor);
} else {
final String propertyName = descriptor.getLocalName();
if (fieldMap.containsKey(propertyName)) {
sftBuilder.add(propertyName, Number.class);
} else {
sftBuilder.add(descriptor);
}
}
}
// return retyping features
SimpleFeatureType retypeSchema = sftBuilder.buildFeatureType();
ListFeatureCollection featureCollection = new ListFeatureCollection(retypeSchema);
SimpleFeatureBuilder builder = new SimpleFeatureBuilder(retypeSchema);
featureIter = sfc.features();
try {
while (featureIter.hasNext()) {
SimpleFeature feature = featureIter.next();
SimpleFeature newFeature = builder.buildFeature(feature.getID());
for (AttributeDescriptor descriptor : retypeSchema.getAttributeDescriptors()) {
String name = descriptor.getLocalName();
if (descriptor instanceof GeometryDescriptor) {
newFeature.setDefaultGeometry(feature.getDefaultGeometry());
} else {
Object val = feature.getAttribute(name);
if (descriptor.getType().getBinding().isAssignableFrom(Number.class)) {
newFeature.setAttribute(name, Double.parseDouble(val.toString()));
} else {
newFeature.setAttribute(name, val);
}
}
}
featureCollection.add(newFeature);
}
} finally {
featureIter.close();
}
return featureCollection;
}
return sfc;
}
@Override
public Object decode(InputStream input) throws Exception {
// nothing to do
return null;
}
@Override
public String getFileExtension() {
int pos = mimeType.lastIndexOf("/");
return mimeType.substring(pos + 1);
}
}