source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/RenderingHelper.java@ 12964

Last change on this file since 12964 was 12964, checked in by bastiK, 7 years ago

see #15273 - more straightforward way to set up the styles for rendering

File size: 6.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Dimension;
7import java.awt.Graphics2D;
8import java.awt.Point;
9import java.awt.image.BufferedImage;
10import java.io.File;
11import java.io.IOException;
12import java.util.Collection;
13import java.util.HashMap;
14import java.util.Map;
15import java.util.Optional;
16
17import javax.imageio.ImageIO;
18
19import org.openstreetmap.josm.Main;
20import org.openstreetmap.josm.data.Bounds;
21import org.openstreetmap.josm.data.ProjectionBounds;
22import org.openstreetmap.josm.data.osm.DataSet;
23import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
24import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer;
25import org.openstreetmap.josm.data.projection.Projection;
26import org.openstreetmap.josm.gui.NavigatableComponent;
27import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
28import org.openstreetmap.josm.io.IllegalDataException;
29import org.openstreetmap.josm.tools.CheckParameterUtil;
30import org.openstreetmap.josm.tools.Logging;
31
32/**
33 * Class to render osm data to a file.
34 * @since 12963
35 */
36public class RenderingHelper {
37
38 private final DataSet ds;
39 private final Bounds bounds;
40 private final ProjectionBounds projBounds;
41 private final double scale;
42 private final Collection<StyleData> styles;
43 private String outputFile;
44
45 /**
46 * Data class to save style settings along with the corresponding style URL.
47 */
48 public static class StyleData {
49 public String styleUrl;
50 public Map<String, String> settings = new HashMap<>();
51 }
52
53 /**
54 * Construct a new {@code RenderingHelper}.
55 * @param ds the dataset to render
56 * @param bounds the bounds of the are to render
57 * @param scale the scale to render at (east/north units per pixel)
58 * @param styles the styles to use for rendering
59 */
60 public RenderingHelper(DataSet ds, Bounds bounds, double scale, Collection<StyleData> styles) {
61 CheckParameterUtil.ensureParameterNotNull(ds, "ds");
62 CheckParameterUtil.ensureParameterNotNull(bounds, "bounds");
63 CheckParameterUtil.ensureParameterNotNull(styles, "styles");
64 this.ds = ds;
65 this.bounds = bounds;
66 this.scale = scale;
67 this.styles = styles;
68 Projection proj = Main.getProjection();
69 projBounds = new ProjectionBounds();
70 projBounds.extend(proj.latlon2eastNorth(bounds.getMin()));
71 projBounds.extend(proj.latlon2eastNorth(bounds.getMax()));
72 }
73
74 /**
75 * Set the output file for rendering.
76 *
77 * Default is {@code out.png}.
78 * @param outputFile the output file for rendering
79 */
80 public void setOutputFile(String outputFile) {
81 this.outputFile = outputFile;
82 }
83
84 Dimension getImageSize() {
85 double widthEn = projBounds.maxEast - projBounds.minEast;
86 double heightEn = projBounds.maxNorth - projBounds.minNorth;
87 int widthPx = (int) Math.round(widthEn / scale);
88 int heightPx = (int) Math.round(heightEn / scale);
89 return new Dimension(widthPx, heightPx);
90 }
91
92 /**
93 * Invoke the renderer.
94 *
95 * @throws IOException in case of an IOException
96 * @throws IllegalDataException when illegal data is encountered (style has errors, etc.)
97 */
98 public void render() throws IOException, IllegalDataException {
99 // load the styles
100 ElemStyles elemStyles = new ElemStyles();
101 MapCSSStyleSource.STYLE_SOURCE_LOCK.writeLock().lock();
102 try {
103 for (StyleData sd : styles) {
104 MapCSSStyleSource source = new MapCSSStyleSource(sd.styleUrl, "cliRenderingStyle", "cli rendering style '" + sd.styleUrl + "'");
105 source.loadStyleSource();
106 elemStyles.add(source);
107 if (!source.getErrors().isEmpty()) {
108 throw new IllegalDataException("Failed to load style file. Errors: " + source.getErrors());
109 }
110 for (String key : sd.settings.keySet()) {
111 StyleSetting.BooleanStyleSetting match = source.settings.stream()
112 .filter(s -> s instanceof StyleSetting.BooleanStyleSetting)
113 .map(s -> (StyleSetting.BooleanStyleSetting) s)
114 .filter(bs -> bs.prefKey.endsWith(":" + key))
115 .findFirst().orElse(null);
116 if (match == null) {
117 Logging.warn(tr("Style setting not found: ''{0}''", key));
118 } else {
119 boolean value = Boolean.parseBoolean(sd.settings.get(key));
120 Logging.trace("setting applied: ''{0}:{1}''", key, value);
121 match.setValue(value);
122 }
123 }
124 if (!sd.settings.isEmpty()) {
125 source.loadStyleSource(); // reload to apply settings
126 }
127 }
128 } finally {
129 MapCSSStyleSource.STYLE_SOURCE_LOCK.writeLock().unlock();
130 }
131
132 Dimension imgDimPx = getImageSize();
133 NavigatableComponent nc = new NavigatableComponent() {
134 {
135 setBounds(0, 0, imgDimPx.width, imgDimPx.height);
136 updateLocationState();
137 }
138
139 @Override
140 protected boolean isVisibleOnScreen() {
141 return true;
142 }
143
144 @Override
145 public Point getLocationOnScreen() {
146 return new Point(0, 0);
147 }
148 };
149 nc.zoomTo(projBounds.getCenter(), scale);
150
151 // render the data
152 BufferedImage image = new BufferedImage(imgDimPx.width, imgDimPx.height, BufferedImage.TYPE_INT_ARGB);
153 Graphics2D g = image.createGraphics();
154 g.setColor(PaintColors.getBackgroundColor());
155 g.fillRect(0, 0, imgDimPx.width, imgDimPx.height);
156 StyledMapRenderer smr = new StyledMapRenderer(g, nc, false);
157 smr.setStyles(elemStyles);
158 smr.render(ds, false, bounds);
159
160 // write to file
161 String output = Optional.ofNullable(outputFile).orElse("out.png");
162 ImageIO.write(image, "png", new File(output));
163 }
164
165}
Note: See TracBrowser for help on using the repository browser.