/* (c) 2014 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.kml.icons;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.net.MalformedURLException;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Icon;
import org.geotools.data.memory.MemoryFeatureCollection;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.factory.CommonFactoryFinder;
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.MapContent;
import org.geotools.renderer.lite.StreamingRenderer;
import org.geotools.renderer.style.DynamicSymbolFactoryFinder;
import org.geotools.renderer.style.ExternalGraphicFactory;
import org.geotools.styling.ExternalGraphic;
import org.geotools.styling.FeatureTypeStyle;
import org.geotools.styling.Graphic;
import org.geotools.styling.Mark;
import org.geotools.styling.PointSymbolizer;
import org.geotools.styling.Rule;
import org.geotools.styling.Style;
import org.geotools.styling.Symbolizer;
import org.opengis.feature.Feature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.expression.Expression;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;
/**
* Utility to render a point symbol as a stand alone icon.
*
* @author David Winslow, OpenGeo
* @author Kevin Smith, OpenGeo
*
*/
public final class IconRenderer {
private final static ReferencedEnvelope sampleArea = new ReferencedEnvelope(-1, 1, -1, 1, null);
private final static SimpleFeatureCollection sampleData;
static Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geoserver.kml.icons");
static {
SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
typeBuilder.setName("example");
typeBuilder.setNamespaceURI("http://example.com/");
typeBuilder.setSRS("EPSG:4326");
typeBuilder.add("the_geom", Point.class);
GeometryFactory geomFactory = new GeometryFactory();
SimpleFeatureType featureType = typeBuilder.buildFeatureType();
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);
featureBuilder.set("the_geom", geomFactory.createPoint(new Coordinate(0, 0)));
MemoryFeatureCollection temp = new MemoryFeatureCollection(featureType);
temp.add(featureBuilder.buildFeature(null));
sampleData = temp;
}
/**
* Render a point icon for the given style. This operation will fail if any
* style properties in the given style are dynamic. This method is intended
* to work with styles that have been preprocessed by IconPropertyExtractor
* and IconPropertyInjector.
*
* @param style
*
*/
public static BufferedImage renderIcon(Style style) {
int size = findIconSize(style)+2; // size is an int because icons are always square
MapContent mapContent = new MapContent();
mapContent.addLayer(new FeatureLayer(sampleData, style));
BufferedImage image = new BufferedImage(size * Icons.RENDER_SCALE_FACTOR,
size * Icons.RENDER_SCALE_FACTOR, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = image.createGraphics();
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.scale(Icons.RENDER_SCALE_FACTOR, Icons.RENDER_SCALE_FACTOR);
StreamingRenderer renderer = new StreamingRenderer();
renderer.setMapContent(mapContent);
try {
try {
renderer.paint(graphics, new Rectangle(size, size), sampleArea);
} finally {
graphics.dispose();
}
} finally {
mapContent.dispose();
}
return image;
}
private static int findIconSize(Style style) {
int size = 0;
if (style.featureTypeStyles().isEmpty()) throw new IllegalArgumentException("Feature type style list was empty");
for (FeatureTypeStyle ftStyle : style.featureTypeStyles()) {
if (ftStyle.rules().isEmpty()) throw new IllegalArgumentException("Rule list was empty");
for (Rule rule : ftStyle.rules()) {
if (rule.symbolizers().isEmpty()) throw new IllegalArgumentException("Symbolizer list was empty");
for (Symbolizer symbolizer : rule.symbolizers()) {
if (symbolizer instanceof PointSymbolizer) {
Graphic g = ((PointSymbolizer) symbolizer).getGraphic();
if (g != null) {
Double rotation = g.getRotation() != null ? g.getRotation().evaluate(null, Double.class) : null;
size = Math.max(size, getGraphicSize(g, rotation));
}
} else {
throw new IllegalArgumentException("IconRenderer only supports PointSymbolizer");
}
}
}
}
return size;
}
private static int getGraphicSize(Graphic g, Double rotation) {
Double result = Icons.graphicSize(g, rotation, null);
if(result==null) {
return (int) Icons.DEFAULT_SYMBOL_SIZE;
} else {
return (int) Math.ceil(result);
}
}
}