use of org.geotools.styling.visitor.DpiRescaleStyleVisitor in project sldeditor by robward-scisys.
the class SLDEditorBufferedImageLegendGraphicBuilder method buildLegendGraphic.
/**
* Takes a GetLegendGraphicRequest and produces a BufferedImage that then can be used by a
* subclass to encode it to the appropriate output format.
*
* @param request the "parsed" request, where "parsed" means that it's values are already
* validated so this method must not take care of verifying the requested layer exists
* and the like.
*
* @throws ServiceException if there are problems creating a "sample" feature instance for the
* FeatureType <code>request</code> returns as the required layer (which should not
* occur).
*/
public BufferedImage buildLegendGraphic(GetLegendGraphicRequest request) throws ServiceException {
// list of images to be rendered for the layers (more than one if
// a layer group is given)
List<RenderedImage> layersImages = new ArrayList<RenderedImage>();
List<LegendRequest> layers = request.getLegends();
boolean forceLabelsOn = false;
boolean forceLabelsOff = false;
if (request.getLegendOptions().get("forceLabels") instanceof String) {
String forceLabelsOpt = (String) request.getLegendOptions().get("forceLabels");
if (forceLabelsOpt.equalsIgnoreCase("on")) {
forceLabelsOn = true;
} else if (forceLabelsOpt.equalsIgnoreCase("off")) {
forceLabelsOff = true;
}
}
boolean forceTitlesOff = false;
if (request.getLegendOptions().get("forceTitles") instanceof String) {
String forceTitlesOpt = (String) request.getLegendOptions().get("forceTitles");
if (forceTitlesOpt.equalsIgnoreCase("off")) {
forceTitlesOff = true;
}
}
double imageSizeFactor = 1.0;
if (request.getLegendOptions().get("imageSizeFactor") instanceof String) {
String imageSizeFactorOpt = (String) request.getLegendOptions().get("imageSizeFactor");
imageSizeFactor = Double.valueOf(imageSizeFactorOpt);
}
FeatureCountProcessor countProcessor = null;
if (Boolean.TRUE.equals(request.getLegendOption(GetLegendGraphicRequest.COUNT_MATCHED_KEY, Boolean.class))) {
countProcessor = new FeatureCountProcessor(request);
}
for (LegendRequest legend : layers) {
FeatureType layer = legend.getFeatureType();
// style and rule to use for the current layer
Style gt2Style = legend.getStyle();
if (gt2Style == null) {
throw new NullPointerException("request.getStyle()");
}
// get rule corresponding to the layer index
// normalize to null for NO RULE
// was null
String ruleName = legend.getRule();
// width and height, we might have to rescale those in case of DPI usage
int w = request.getWidth();
int h = request.getHeight();
// apply dpi rescale
double dpi = RendererUtilities.getDpi(request.getLegendOptions());
double standardDpi = RendererUtilities.getDpi(Collections.emptyMap());
if (dpi != standardDpi) {
double scaleFactor = dpi / standardDpi;
w = (int) Math.round(w * scaleFactor);
h = (int) Math.round(h * scaleFactor);
DpiRescaleStyleVisitor dpiVisitor = new DpiRescaleStyleVisitor(scaleFactor);
dpiVisitor.visit(gt2Style);
gt2Style = (Style) dpiVisitor.getCopy();
}
// apply UOM rescaling if we have a scale
if (request.getScale() > 0) {
double pixelsPerMeters = RendererUtilities.calculatePixelsPerMeterRatio(request.getScale(), request.getLegendOptions());
UomRescaleStyleVisitor rescaleVisitor = new UomRescaleStyleVisitor(pixelsPerMeters);
rescaleVisitor.visit(gt2Style);
gt2Style = (Style) rescaleVisitor.getCopy();
}
boolean strict = request.isStrict();
final boolean transparent = request.isTransparent();
RenderedImage titleImage = null;
// if we have more than one layer, we put a title on top of each layer legend
if (layers.size() > 1 && !forceTitlesOff) {
titleImage = getLayerTitle(legend, w, h, transparent, request);
}
// Check for rendering transformation
boolean hasVectorTransformation = false;
boolean hasRasterTransformation = false;
List<FeatureTypeStyle> ftsList = gt2Style.featureTypeStyles();
for (int i = 0; i < ftsList.size(); i++) {
FeatureTypeStyle fts = ftsList.get(i);
Expression exp = fts.getTransformation();
if (exp != null) {
ProcessFunction processFunction = (ProcessFunction) exp;
Name processName = processFunction.getProcessName();
Map<String, Parameter<?>> outputs = Processors.getResultInfo(processName, null);
if (outputs.isEmpty()) {
continue;
}
// we assume there is
Parameter<?> output = outputs.values().iterator().next();
// only one output
if (SimpleFeatureCollection.class.isAssignableFrom(output.getType())) {
hasVectorTransformation = true;
break;
} else if (GridCoverage2D.class.isAssignableFrom(output.getType())) {
hasRasterTransformation = true;
break;
}
}
}
final boolean buildRasterLegend = (!strict && layer == null && LegendUtils.checkRasterSymbolizer(gt2Style)) || (LegendUtils.checkGridLayer(layer) && !hasVectorTransformation) || hasRasterTransformation;
// Just checks LegendInfo currently, should check gtStyle
final boolean useProvidedLegend = layer != null && legend.getLayerInfo() != null;
RenderedImage legendImage = null;
if (useProvidedLegend) {
legendImage = getLayerLegend(legend, w, h, transparent, request);
}
if (buildRasterLegend) {
final RasterLayerLegendHelper rasterLegendHelper = new RasterLayerLegendHelper(request, gt2Style, ruleName);
final BufferedImage image = rasterLegendHelper.getLegend();
if (image != null) {
if (titleImage != null) {
layersImages.add(titleImage);
}
layersImages.add(image);
}
} else if (useProvidedLegend && legendImage != null) {
if (titleImage != null) {
layersImages.add(titleImage);
}
layersImages.add(legendImage);
} else {
final Feature sampleFeature;
if (layer == null || hasVectorTransformation) {
sampleFeature = createSampleFeature();
} else {
sampleFeature = createSampleFeature(layer);
}
final FeatureTypeStyle[] ftStyles = gt2Style.featureTypeStyles().toArray(new FeatureTypeStyle[0]);
final double scaleDenominator = request.getScale();
Rule[] applicableRules;
if (ruleName != null) {
Rule rule = LegendUtils.getRule(ftStyles, ruleName);
if (rule == null) {
throw new ServiceException("Specified style does not contains a rule named " + ruleName);
}
applicableRules = new Rule[] { rule };
} else {
applicableRules = LegendUtils.getApplicableRules(ftStyles, scaleDenominator);
}
// do we have to alter the style to do context sensitive feature counts?
if (countProcessor != null && !forceLabelsOff) {
applicableRules = updateRuleTitles(countProcessor, legend, applicableRules);
}
final NumberRange<Double> scaleRange = NumberRange.create(scaleDenominator, scaleDenominator);
final int ruleCount = applicableRules.length;
/**
* A legend graphic is produced for each applicable rule. They're being held here
* until the process is done and then painted on a "stack" like legend.
*/
final List<RenderedImage> legendsStack = new ArrayList<RenderedImage>(ruleCount);
final SLDStyleFactory styleFactory = new SLDStyleFactory();
double minimumSymbolSize = MINIMUM_SYMBOL_SIZE;
// get minSymbolSize from LEGEND_OPTIONS, if defined
if (request.getLegendOptions().get("minSymbolSize") instanceof String) {
String minSymbolSizeOpt = (String) request.getLegendOptions().get("minSymbolSize");
try {
minimumSymbolSize = Double.parseDouble(minSymbolSizeOpt);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid minSymbolSize value: should be a number");
}
}
// calculate the symbols rescaling factor necessary for them to be
// drawn inside the icon box
double symbolScale = calcSymbolScale(w, h, layer, sampleFeature, applicableRules, minimumSymbolSize);
for (int i = 0; i < ruleCount; i++) {
final RenderedImage image = ImageUtils.createImage(w, h, (IndexColorModel) null, transparent);
final Map<RenderingHints.Key, Object> hintsMap = new HashMap<RenderingHints.Key, Object>();
final Graphics2D graphics = ImageUtils.prepareTransparency(transparent, LegendUtils.getBackgroundColor(request), image, hintsMap);
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Feature sample = getSampleFeatureForRule(layer, sampleFeature, applicableRules[i]);
FilterFactory ff = CommonFactoryFinder.getFilterFactory();
final Symbolizer[] symbolizers = applicableRules[i].getSymbolizers();
final GraphicLegend graphic = applicableRules[i].getLegend();
// If this rule has a legend graphic defined in the SLD, use it
if (graphic != null) {
if (this.samplePoint == null) {
Coordinate coord = new Coordinate(w / 2, h / 2);
try {
this.samplePoint = new LiteShape2(geomFac.createPoint(coord), null, null, false);
} catch (Exception e) {
this.samplePoint = null;
}
}
shapePainter.paint(graphics, this.samplePoint, graphic, scaleDenominator, false);
} else {
for (int sIdx = 0; sIdx < symbolizers.length; sIdx++) {
Symbolizer symbolizer = symbolizers[sIdx];
if (symbolizer instanceof RasterSymbolizer) {
// skip it
} else {
// rescale symbols if needed
if (symbolScale > 1.0 && symbolizer instanceof PointSymbolizer) {
PointSymbolizer pointSymbolizer = (PointSymbolizer) cloneSymbolizer(symbolizer);
if (pointSymbolizer.getGraphic() != null) {
double size = getGraphicSize(sample, pointSymbolizer.getGraphic(), Math.min(w, h) - 4);
pointSymbolizer.getGraphic().setSize(ff.literal(size / symbolScale + minimumSymbolSize));
symbolizer = pointSymbolizer;
}
}
if (!(Math.abs(imageSizeFactor - 1.0) < 0.0001)) {
if (symbolizer instanceof PointSymbolizer) {
PointSymbolizer pointSymbolizer2 = (PointSymbolizer) cloneSymbolizer(symbolizer);
if (pointSymbolizer2.getGraphic() != null) {
double size = getGraphicSize(sample, pointSymbolizer2.getGraphic(), Math.min(w, h) - 4);
pointSymbolizer2.getGraphic().setSize(ff.literal(size * imageSizeFactor + minimumSymbolSize));
symbolizer = pointSymbolizer2;
}
} else if (symbolizer instanceof PolygonSymbolizer) {
PolygonSymbolizer polygonSymbolizer2 = (PolygonSymbolizer) cloneSymbolizer(symbolizer);
if (polygonSymbolizer2.getFill() != null) {
// Fill
double size = 0.0;
if (polygonSymbolizer2.getFill().getGraphicFill() != null) {
size = getGraphicSize(sample, polygonSymbolizer2.getFill().getGraphicFill(), Math.min(w, h) - 4);
polygonSymbolizer2.getFill().getGraphicFill().setSize(ff.literal(size * imageSizeFactor + minimumSymbolSize));
}
}
if (polygonSymbolizer2.getStroke() != null) {
// Stroke
double size = getGraphicSize(sample, polygonSymbolizer2.getStroke().getGraphicFill(), Math.min(w, h) - 4);
polygonSymbolizer2.getStroke().getGraphicFill().setSize(ff.literal(size * imageSizeFactor + minimumSymbolSize));
if (polygonSymbolizer2.getStroke().getGraphicStroke() != null) {
size = getGraphicSize(sample, polygonSymbolizer2.getStroke().getGraphicStroke(), Math.min(w, h) - 4);
polygonSymbolizer2.getStroke().getGraphicStroke().setSize(ff.literal(size * imageSizeFactor + minimumSymbolSize));
}
}
symbolizer = polygonSymbolizer2;
} else if (symbolizer instanceof LineSymbolizer) {
LineSymbolizer lineSymbolizer2 = (LineSymbolizer) cloneSymbolizer(symbolizer);
if (lineSymbolizer2.getStroke() != null) {
// Stroke
double size = 0.0;
if (lineSymbolizer2.getStroke().getGraphicFill() != null) {
size = getGraphicSize(sample, lineSymbolizer2.getStroke().getGraphicFill(), Math.min(w, h) - 4);
lineSymbolizer2.getStroke().getGraphicFill().setSize(ff.literal(size * imageSizeFactor + minimumSymbolSize));
}
if (lineSymbolizer2.getStroke().getGraphicStroke() != null) {
size = getGraphicSize(sample, lineSymbolizer2.getStroke().getGraphicStroke(), Math.min(w, h) - 4);
lineSymbolizer2.getStroke().getGraphicStroke().setSize(ff.literal(size * imageSizeFactor + minimumSymbolSize));
}
if (lineSymbolizer2.getStroke().getWidth() != null) {
size = getWidthSize(sample, lineSymbolizer2.getStroke().getWidth(), 1);
lineSymbolizer2.getStroke().setWidth(ff.literal(size * imageSizeFactor));
}
}
symbolizer = lineSymbolizer2;
}
}
}
Style2D style2d = styleFactory.createStyle(sample, symbolizer, scaleRange);
LiteShape2 shape = getSampleShape(symbolizer, w, h);
if (style2d != null) {
shapePainter.paint(graphics, shape, style2d, scaleDenominator);
}
}
}
if (image != null && titleImage != null) {
layersImages.add(titleImage);
titleImage = null;
}
legendsStack.add(image);
graphics.dispose();
}
int labelMargin = 3;
if (!StringUtils.isEmpty(request.getLegendOptions().get("labelMargin"))) {
labelMargin = Integer.parseInt(request.getLegendOptions().get("labelMargin").toString());
}
LegendMerger.MergeOptions options = LegendMerger.MergeOptions.createFromRequest(legendsStack, 0, 0, 0, labelMargin, request, forceLabelsOn, forceLabelsOff, forceTitlesOff);
if (ruleCount > 0) {
BufferedImage image = LegendMerger.mergeLegends(applicableRules, request, options);
if (image != null) {
layersImages.add(image);
}
}
}
}
// all legend graphics are merged if we have a layer group
BufferedImage finalLegend = mergeGroups(layersImages, null, request, forceLabelsOn, forceLabelsOff, forceTitlesOff);
if (finalLegend == null) {
throw new IllegalArgumentException("no legend passed");
}
return finalLegend;
}
Aggregations