private void styleBuilderExample() throws Exception { // styleBuilderExample start // // We are using the GeoTools StyleBuilder that is helpful for quickly making things StyleBuilder builder = new StyleBuilder(); FilterFactory2 ff = builder.getFilterFactory(); // RULE 1 // first rule to draw cities // define a point symbolizer representing a city Graphic city = builder.createGraphic(); city.setSize(ff.literal(10)); city.graphicalSymbols().add(builder.createExternalGraphic("file:city.svg", "svg")); // svg // preferred city.graphicalSymbols().add(builder.createExternalGraphic("file:city.png", "png")); // png next city.graphicalSymbols() .add(builder.createMark(StyleBuilder.MARK_CIRCLE, Color.BLUE, Color.BLACK, 1)); PointSymbolizer pointSymbolizer = builder.createPointSymbolizer(city, "the_geom"); Rule rule1 = builder.createRule(pointSymbolizer); rule1.setName("rule1"); rule1.getDescription().setTitle("City"); rule1.getDescription().setAbstract("Rule for drawing cities"); rule1.setFilter(ff.less(ff.property("POPULATION"), ff.literal(50000))); // // RULE 2 Default Graphic dotGraphic = builder.createGraphic(null, builder.createMark(StyleBuilder.MARK_CIRCLE), null); PointSymbolizer dotSymbolize = builder.createPointSymbolizer(dotGraphic); Rule rule2 = builder.createRule(dotSymbolize); rule2.setIsElseFilter(true); // // define feature type styles used to actually define how features are rendered Rule rules[] = new Rule[] {rule1, rule2}; FeatureTypeStyle featureTypeStyle = builder.createFeatureTypeStyle("Feature", rules); // // create a "user defined" style Style style = builder.createStyle(); style.setName("style"); style.getDescription().setTitle("User Style"); style.getDescription().setAbstract("Definition of Style"); style.featureTypeStyles().add(featureTypeStyle); // styleBuilderExample end }
/** * Receives a list of <code>BufferedImages</code> and produces a new one which holds all the * images in <code>imageStack</code> one above the other, handling labels. * * @param imageStack the list of BufferedImages, one for each applicable Rule * @param rules The applicable rules, one for each image in the stack (if not null it's used to * compute labels) * @param request The request. * @param forceLabelsOn true for force labels on also with a single image. * @param forceLabelsOff true for force labels off also with more than one rule. * @return the stack image with all the images on the argument list. * @throws IllegalArgumentException if the list is empty */ private BufferedImage mergeLegends( List<RenderedImage> imageStack, Rule[] rules, GetLegendGraphicRequest req, boolean forceLabelsOn, boolean forceLabelsOff) { Font labelFont = LegendUtils.getLabelFont(req); boolean useAA = LegendUtils.isFontAntiAliasing(req); if (imageStack.size() == 0) { return null; } final BufferedImage finalLegend; if (imageStack.size() == 1 && (!forceLabelsOn || rules == null)) { finalLegend = (BufferedImage) imageStack.get(0); } else { final int imgCount = imageStack.size(); final String[] labels = new String[imgCount]; BufferedImage img = ((BufferedImage) imageStack.get(0)); int totalHeight = 0; int totalWidth = 0; int[] rowHeights = new int[imgCount]; BufferedImage labelsGraphics[] = new BufferedImage[imgCount]; for (int i = 0; i < imgCount; i++) { img = (BufferedImage) imageStack.get(i); if (forceLabelsOff || rules == null) { totalWidth = (int) Math.ceil(Math.max(img.getWidth(), totalWidth)); rowHeights[i] = img.getHeight(); totalHeight += img.getHeight(); } else { Rule rule = rules[i]; // What's the label on this rule? We prefer to use // the 'title' if it's available, but fall-back to 'name' final Description description = rule.getDescription(); Locale locale = req.getLocale(); if (description != null && description.getTitle() != null) { final InternationalString title = description.getTitle(); if (locale != null) { labels[i] = title.toString(locale); } else { labels[i] = title.toString(); } } else if (rule.getName() != null) { labels[i] = rule.getName(); } else { labels[i] = ""; } if (labels[i] != null && labels[i].length() > 0) { final BufferedImage renderedLabel = getRenderedLabel(img, labels[i], req); labelsGraphics[i] = renderedLabel; final Rectangle2D bounds = new Rectangle2D.Double(0, 0, renderedLabel.getWidth(), renderedLabel.getHeight()); totalWidth = (int) Math.ceil(Math.max(img.getWidth() + bounds.getWidth(), totalWidth)); rowHeights[i] = (int) Math.ceil(Math.max(img.getHeight(), bounds.getHeight())); } else { totalWidth = (int) Math.ceil(Math.max(img.getWidth(), totalWidth)); rowHeights[i] = (int) Math.ceil(img.getHeight()); labelsGraphics[i] = null; } totalHeight += rowHeights[i]; } } // buffer the width a bit totalWidth += 2; final boolean transparent = req.isTransparent(); final Color backgroundColor = LegendUtils.getBackgroundColor(req); final Map<RenderingHints.Key, Object> hintsMap = new HashMap<RenderingHints.Key, Object>(); // create the final image finalLegend = ImageUtils.createImage(totalWidth, totalHeight, (IndexColorModel) null, transparent); Graphics2D finalGraphics = ImageUtils.prepareTransparency(transparent, backgroundColor, finalLegend, hintsMap); int topOfRow = 0; for (int i = 0; i < imgCount; i++) { img = (BufferedImage) imageStack.get(i); // draw the image int y = topOfRow; if (img.getHeight() < rowHeights[i]) { // move the image to the center of the row y += (int) ((rowHeights[i] - img.getHeight()) / 2d); } finalGraphics.drawImage(img, 0, y, null); if (forceLabelsOff || rules == null) { topOfRow += rowHeights[i]; continue; } finalGraphics.setFont(labelFont); if (useAA) { finalGraphics.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); } else { finalGraphics.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); } // draw the label if (labels[i] != null && labels[i].length() > 0) { // first create the actual overall label image. final BufferedImage renderedLabel = labelsGraphics[i]; y = topOfRow; if (renderedLabel.getHeight() < rowHeights[i]) { y += (int) ((rowHeights[i] - renderedLabel.getHeight()) / 2d); } finalGraphics.drawImage(renderedLabel, img.getWidth(), y, null); // cleanup renderedLabel.flush(); labelsGraphics[i] = null; } topOfRow += rowHeights[i]; } finalGraphics.dispose(); } return finalLegend; }
private void styleFactoryExample() throws Exception { // styleFactoryExample start // // We are using the GeoTools styleFactory that allows access to get/set methods org.geotools.styling.StyleFactory sf = CommonFactoryFinder.getStyleFactory(); FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(); StyledLayerDescriptor sld = sf.createStyledLayerDescriptor(); sld.setName("sld"); sld.setTitle("Example"); sld.setAbstract("Example Style Layer Descriptor"); UserLayer layer = sf.createUserLayer(); layer.setName("layer"); // // define constraint limited what features the sld applies to FeatureTypeConstraint constraint = sf.createFeatureTypeConstraint("Feature", Filter.INCLUDE, null); layer.layerFeatureConstraints().add(constraint); // // create a "user defined" style Style style = sf.createStyle(); style.setName("style"); style.getDescription().setTitle("User Style"); style.getDescription().setAbstract("Definition of Style"); // // define feature type styles used to actually define how features are rendered FeatureTypeStyle featureTypeStyle = sf.createFeatureTypeStyle(); // RULE 1 // first rule to draw cities Rule rule1 = sf.createRule(); rule1.setName("rule1"); rule1.getDescription().setTitle("City"); rule1.getDescription().setAbstract("Rule for drawing cities"); rule1.setFilter(ff.less(ff.property("POPULATION"), ff.literal(50000))); // // create the graphical mark used to represent a city Stroke stroke = sf.stroke(ff.literal("#000000"), null, null, null, null, null, null); Fill fill = sf.fill(null, ff.literal(Color.BLUE), ff.literal(1.0)); // OnLineResource implemented by gt-metadata - so no factory! OnLineResourceImpl svg = new OnLineResourceImpl(new URI("file:city.svg")); svg.freeze(); // freeze to prevent modification at runtime OnLineResourceImpl png = new OnLineResourceImpl(new URI("file:city.png")); png.freeze(); // freeze to prevent modification at runtime // // List of symbols is considered in order with the rendering engine choosing // the first one it can handle. Allowing for svg, png, mark order List<GraphicalSymbol> symbols = new ArrayList<GraphicalSymbol>(); symbols.add(sf.externalGraphic(svg, "svg", null)); // svg preferred symbols.add(sf.externalGraphic(png, "png", null)); // png preferred symbols.add(sf.mark(ff.literal("circle"), fill, stroke)); // simple circle backup plan Expression opacity = null; // use default Expression size = ff.literal(10); Expression rotation = null; // use default AnchorPoint anchor = null; // use default Displacement displacement = null; // use default // define a point symbolizer of a small circle Graphic city = sf.graphic(symbols, opacity, size, rotation, anchor, displacement); PointSymbolizer pointSymbolizer = sf.pointSymbolizer("point", ff.property("the_geom"), null, null, city); rule1.symbolizers().add(pointSymbolizer); featureTypeStyle.rules().add(rule1); // // RULE 2 Default List<GraphicalSymbol> dotSymbols = new ArrayList<GraphicalSymbol>(); dotSymbols.add(sf.mark(ff.literal("circle"), null, null)); Graphic dotGraphic = sf.graphic(dotSymbols, null, ff.literal(3), null, null, null); PointSymbolizer dotSymbolizer = sf.pointSymbolizer("dot", null, null, null, dotGraphic); List<org.opengis.style.Symbolizer> symbolizers = new ArrayList<org.opengis.style.Symbolizer>(); symbolizers.add(dotSymbolizer); Filter other = null; // null will mark this rule as "other" accepting all remaining features Rule rule2 = sf.rule("default", null, null, Double.MIN_VALUE, Double.MAX_VALUE, symbolizers, other); featureTypeStyle.rules().add(rule2); style.featureTypeStyles().add(featureTypeStyle); layer.userStyles().add(style); sld.layers().add(layer); // styleFactoryExample end }