source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/RenderingCLI.java

Last change on this file was 18494, checked in by taylor.smock, 4 years ago

Fix #22115: Extract methods from LatLon into ILatLon where they are generally applicable

This also removes calls to Node#getCoor where possible, which reduces
the number of memory allocations in SearchCompiler#match, and overall
allocations due to Node#getCoor

File size: 26.4 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.image.BufferedImage;
8import java.io.File;
9import java.io.FileNotFoundException;
10import java.io.IOException;
11import java.io.InputStream;
12import java.nio.file.NoSuchFileException;
13import java.nio.file.Paths;
14import java.util.ArrayList;
15import java.util.Arrays;
16import java.util.List;
17import java.util.Locale;
18import java.util.Optional;
19import java.util.function.DoubleSupplier;
20import java.util.logging.Level;
21
22import javax.imageio.ImageIO;
23
24import org.openstreetmap.gui.jmapviewer.OsmMercator;
25import org.openstreetmap.josm.cli.CLIModule;
26import org.openstreetmap.josm.data.Bounds;
27import org.openstreetmap.josm.data.ProjectionBounds;
28import org.openstreetmap.josm.data.coor.EastNorth;
29import org.openstreetmap.josm.data.coor.ILatLon;
30import org.openstreetmap.josm.data.coor.LatLon;
31import org.openstreetmap.josm.data.coor.conversion.LatLonParser;
32import org.openstreetmap.josm.data.osm.DataSet;
33import org.openstreetmap.josm.data.preferences.JosmBaseDirectories;
34import org.openstreetmap.josm.data.preferences.JosmUrls;
35import org.openstreetmap.josm.data.projection.Projection;
36import org.openstreetmap.josm.data.projection.ProjectionRegistry;
37import org.openstreetmap.josm.data.projection.Projections;
38import org.openstreetmap.josm.gui.mappaint.RenderingHelper.StyleData;
39import org.openstreetmap.josm.io.Compression;
40import org.openstreetmap.josm.io.IllegalDataException;
41import org.openstreetmap.josm.io.OsmReader;
42import org.openstreetmap.josm.spi.lifecycle.Lifecycle;
43import org.openstreetmap.josm.spi.preferences.Config;
44import org.openstreetmap.josm.spi.preferences.MemoryPreferences;
45import org.openstreetmap.josm.tools.Http1Client;
46import org.openstreetmap.josm.tools.HttpClient;
47import org.openstreetmap.josm.tools.JosmDecimalFormatSymbolsProvider;
48import org.openstreetmap.josm.tools.Logging;
49import org.openstreetmap.josm.tools.OptionParser;
50import org.openstreetmap.josm.tools.OptionParser.OptionCount;
51import org.openstreetmap.josm.tools.OptionParser.OptionParseException;
52import org.openstreetmap.josm.tools.Stopwatch;
53import org.openstreetmap.josm.tools.Territories;
54
55/**
56 * Command line interface for rendering osm data to an image file.
57 *
58 * @since 12906
59 */
60public class RenderingCLI implements CLIModule {
61
62 /**
63 * The singleton instance of this class.
64 */
65 public static final RenderingCLI INSTANCE = new RenderingCLI();
66
67 private static final double PIXEL_PER_METER = 96 / 2.54 * 100; // standard value of 96 dpi display resolution
68 private static final int DEFAULT_MAX_IMAGE_SIZE = 20000;
69
70 private boolean argDebug;
71 private boolean argTrace;
72 private String argInput;
73 private String argOutput;
74 private List<StyleData> argStyles;
75 private Integer argZoom;
76 private Double argScale;
77 private Bounds argBounds;
78 private LatLon argAnchor;
79 private Double argWidthM;
80 private Double argHeightM;
81 private Integer argWidthPx;
82 private Integer argHeightPx;
83 private String argProjection;
84 private Integer argMaxImageSize;
85
86 private StyleData argCurrentStyle;
87
88 private enum Option {
89 HELP(false, 'h'),
90 DEBUG(false, '*'),
91 TRACE(false, '*'),
92 INPUT(true, 'i'),
93 STYLE(true, 's'),
94 SETTING(true, '*'),
95 OUTPUT(true, 'o'),
96 ZOOM(true, 'z'),
97 SCALE(true, '*'),
98 BOUNDS(true, 'b'),
99 ANCHOR(true, '*'),
100 WIDTH_M(true, '*'),
101 HEIGHT_M(true, '*'),
102 WIDTH_PX(true, '*'),
103 HEIGHT_PX(true, '*'),
104 PROJECTION(true, '*'),
105 MAX_IMAGE_SIZE(true, '*');
106
107 private final String name;
108 private final boolean requiresArg;
109 private final char shortOption;
110
111 Option(boolean requiresArgument, char shortOption) {
112 this.name = name().toLowerCase(Locale.US).replace('_', '-');
113 this.requiresArg = requiresArgument;
114 this.shortOption = shortOption;
115 }
116
117 /**
118 * Replies the option name
119 * @return The option name, in lowercase
120 */
121 public String getName() {
122 return name;
123 }
124
125 /**
126 * Determines if this option requires an argument.
127 * @return {@code true} if this option requires an argument, {@code false} otherwise
128 */
129 public boolean requiresArgument() {
130 return requiresArg;
131 }
132
133 /**
134 * Replies the short option (single letter) associated with this option.
135 * @return the short option or '*' if there is no short option
136 */
137 public char getShortOption() {
138 return shortOption;
139 }
140 }
141
142 /**
143 * Data class to hold return values for {@link #determineRenderingArea(DataSet)}.
144 *
145 * Package private access for unit tests.
146 */
147 static class RenderingArea {
148 public Bounds bounds;
149 public double scale; // in east-north units per pixel (unlike the --scale option, which is in meter per meter)
150 }
151
152 RenderingCLI() {
153 // hide constructor (package private access for unit tests)
154 }
155
156 @Override
157 public String getActionKeyword() {
158 return "render";
159 }
160
161 @Override
162 public void processArguments(String[] argArray) {
163 try {
164 parseArguments(argArray);
165 initialize();
166 Stopwatch stopwatch = Stopwatch.createStarted();
167 String task = tr("Rendering {0} to {1}", argInput, argOutput);
168 System.err.println(task);
169 DataSet ds = loadDataset();
170 RenderingArea area = determineRenderingArea(ds);
171 RenderingHelper rh = new RenderingHelper(ds, area.bounds, area.scale, argStyles);
172 checkPreconditions(rh);
173 BufferedImage image = rh.render();
174 writeImageToFile(image);
175 System.err.println(stopwatch.toString(task));
176 } catch (FileNotFoundException | NoSuchFileException e) {
177 if (Logging.isDebugEnabled()) {
178 e.printStackTrace();
179 }
180 System.err.println(tr("Error - file not found: ''{0}''", e.getMessage()));
181 Lifecycle.exitJosm(true, 1);
182 } catch (IllegalArgumentException | IllegalDataException | IOException e) {
183 if (Logging.isDebugEnabled()) {
184 e.printStackTrace();
185 }
186 if (e.getMessage() != null) {
187 System.err.println(tr("Error: {0}", e.getMessage()));
188 }
189 Lifecycle.exitJosm(true, 1);
190 }
191 Lifecycle.exitJosm(true, 0);
192 }
193
194 /**
195 * Parse command line arguments and do some low-level error checking.
196 * @param argArray the arguments array
197 */
198 void parseArguments(String[] argArray) {
199 Logging.setLogLevel(Level.INFO);
200
201 OptionParser parser = new OptionParser("JOSM rendering");
202 for (Option o : Option.values()) {
203 if (o.requiresArgument()) {
204 parser.addArgumentParameter(o.getName(),
205 o == Option.SETTING ? OptionCount.MULTIPLE : OptionCount.OPTIONAL,
206 arg -> handleOption(o, arg));
207 } else {
208 parser.addFlagParameter(o.getName(), () -> handleOption(o));
209 }
210 if (o.getShortOption() != '*') {
211 parser.addShortAlias(o.getName(), Character.toString(o.getShortOption()));
212 }
213 }
214
215 argCurrentStyle = new StyleData();
216 argStyles = new ArrayList<>();
217
218 parser.parseOptionsOrExit(Arrays.asList(argArray));
219
220 if (argCurrentStyle.styleUrl != null) {
221 argStyles.add(argCurrentStyle);
222 } else if (argStyles.isEmpty()) {
223 argCurrentStyle.styleUrl = "resource://styles/standard/elemstyles.mapcss";
224 argStyles.add(argCurrentStyle);
225 }
226 }
227
228 private void handleOption(Option o) {
229 switch (o) {
230 case HELP:
231 showHelp();
232 Lifecycle.exitJosm(true, 0);
233 break;
234 case DEBUG:
235 argDebug = true;
236 break;
237 case TRACE:
238 argTrace = true;
239 break;
240 default:
241 throw new AssertionError("Unexpected option index: " + o);
242 }
243 }
244
245 private void handleOption(Option o, String arg) {
246 switch (o) {
247 case INPUT:
248 argInput = arg;
249 break;
250 case STYLE:
251 if (argCurrentStyle.styleUrl != null) {
252 argStyles.add(argCurrentStyle);
253 argCurrentStyle = new StyleData();
254 }
255 argCurrentStyle.styleUrl = arg;
256 break;
257 case OUTPUT:
258 argOutput = arg;
259 break;
260 case ZOOM:
261 try {
262 argZoom = Integer.valueOf(arg);
263 } catch (NumberFormatException nfe) {
264 throw new OptionParseException(
265 tr("Expected integer number for option {0}, but got ''{1}''", "--zoom", arg), nfe);
266 }
267 if (argZoom < 0) {
268 throw new OptionParseException(
269 tr("Expected integer number >= 0 for option {0}, but got ''{1}''", "--zoom", arg));
270 }
271 break;
272 case BOUNDS:
273 if (!"auto".equals(arg)) {
274 try {
275 argBounds = new Bounds(arg, ",", Bounds.ParseMethod.LEFT_BOTTOM_RIGHT_TOP, false);
276 } catch (IllegalArgumentException iae) { // NOPMD
277 throw new OptionParseException(
278 tr("Unable to parse {0} parameter: {1}", "--bounds", iae.getMessage()), iae);
279 }
280 }
281 break;
282
283 case SETTING:
284 String keyval = arg;
285 String[] comp = keyval.split(":", 2);
286 if (comp.length != 2) {
287 throw new OptionParseException(
288 tr("Expected key and value, separated by '':'' character for option {0}, but got ''{1}''",
289 "--setting", arg));
290 }
291 argCurrentStyle.settings.put(comp[0].trim(), comp[1].trim());
292 break;
293 case SCALE:
294 try {
295 argScale = JosmDecimalFormatSymbolsProvider.parseDouble(arg);
296 } catch (NumberFormatException nfe) {
297 throw new OptionParseException(
298 tr("Expected floating point number for option {0}, but got ''{1}''", "--scale", arg), nfe);
299 }
300 break;
301 case ANCHOR:
302 String[] parts = arg.split(",", -1);
303 if (parts.length != 2)
304 throw new OptionParseException(
305 tr("Expected two coordinates, separated by comma, for option {0}, but got ''{1}''", "--anchor",
306 arg));
307 try {
308 double lon = LatLonParser.parseCoordinate(parts[0]);
309 double lat = LatLonParser.parseCoordinate(parts[1]);
310 argAnchor = new LatLon(lat, lon);
311 } catch (IllegalArgumentException iae) { // NOPMD
312 throw new OptionParseException(tr("In option {0}: {1}", "--anchor", iae.getMessage()), iae);
313 }
314 break;
315 case WIDTH_M:
316 try {
317 argWidthM = JosmDecimalFormatSymbolsProvider.parseDouble(arg);
318 } catch (NumberFormatException nfe) {
319 throw new OptionParseException(
320 tr("Expected floating point number for option {0}, but got ''{1}''", "--width-m", arg), nfe);
321 }
322 if (argWidthM <= 0)
323 throw new OptionParseException(
324 tr("Expected floating point number > 0 for option {0}, but got ''{1}''", "--width-m", arg));
325 break;
326 case HEIGHT_M:
327 try {
328 argHeightM = JosmDecimalFormatSymbolsProvider.parseDouble(arg);
329 } catch (NumberFormatException nfe) {
330 throw new OptionParseException(
331 tr("Expected floating point number for option {0}, but got ''{1}''", "--height-m", arg), nfe);
332 }
333 if (argHeightM <= 0)
334 throw new OptionParseException(
335 tr("Expected floating point number > 0 for option {0}, but got ''{1}''", "--width-m", arg));
336 break;
337 case WIDTH_PX:
338 try {
339 argWidthPx = Integer.valueOf(arg);
340 } catch (NumberFormatException nfe) {
341 throw new OptionParseException(
342 tr("Expected integer number for option {0}, but got ''{1}''", "--width-px", arg), nfe);
343 }
344 if (argWidthPx <= 0)
345 throw new OptionParseException(
346 tr("Expected integer number > 0 for option {0}, but got ''{1}''", "--width-px", arg));
347 break;
348 case HEIGHT_PX:
349 try {
350 argHeightPx = Integer.valueOf(arg);
351 } catch (NumberFormatException nfe) {
352 throw new OptionParseException(
353 tr("Expected integer number for option {0}, but got ''{1}''", "--height-px", arg), nfe);
354 }
355 if (argHeightPx <= 0) {
356 throw new OptionParseException(
357 tr("Expected integer number > 0 for option {0}, but got ''{1}''", "--height-px", arg));
358 }
359 break;
360 case PROJECTION:
361 argProjection = arg;
362 break;
363 case MAX_IMAGE_SIZE:
364 try {
365 argMaxImageSize = Integer.valueOf(arg);
366 } catch (NumberFormatException nfe) {
367 throw new OptionParseException(
368 tr("Expected integer number for option {0}, but got ''{1}''", "--max-image-size", arg), nfe);
369 }
370 if (argMaxImageSize < 0) {
371 throw new OptionParseException(
372 tr("Expected integer number >= 0 for option {0}, but got ''{1}''", "--max-image-size", arg));
373 }
374 break;
375 default:
376 throw new AssertionError("Unexpected option index: " + o);
377 }
378 }
379
380 /**
381 * Displays help on the console
382 */
383 public static void showHelp() {
384 System.out.println(getHelp());
385 }
386
387 private static String getHelp() {
388 return tr("JOSM rendering command line interface")+"\n\n"+
389 tr("Usage")+":\n"+
390 "\tjava -jar josm.jar render <options>\n\n"+
391 tr("Description")+":\n"+
392 tr("Renders data and saves the result to an image file.")+"\n\n"+
393 tr("Options")+":\n"+
394 "\t--help|-h "+tr("Show this help")+"\n"+
395 "\t--input|-i <file> "+tr("Input data file name (.osm)")+"\n"+
396 "\t--output|-o <file> "+tr("Output image file name (.png); defaults to ''{0}''", "out.png")+"\n"+
397 "\t--style|-s <file> "+tr("Style file to use for rendering (.mapcss or .zip)")+"\n"+
398 "\t "+tr("This option can be repeated to load multiple styles.")+"\n"+
399 "\t--setting <key>:<value> "+tr("Style setting (in JOSM accessible in the style list dialog right click menu)")+"\n"+
400 "\t "+tr("Applies to the last style loaded with the {0} option.", "--style")+"\n"+
401 "\t--zoom|-z <lvl> "+tr("Select zoom level to render. (integer value, 0=entire earth, 18=street level)")+"\n"+
402 "\t--scale <scale> "+tr("Select the map scale")+"\n"+
403 "\t "+tr("A value of 10000 denotes a scale of 1:10000 (1 cm on the map equals 100 m on the ground; "
404 + "display resolution: 96 dpi)")+"\n"+
405 "\t "+tr("Options {0} and {1} are mutually exclusive.", "--zoom", "--scale")+"\n"+
406 "\t--bounds|-b auto|<min_lon>,<min_lat>,<max_lon>,<max_lat>\n"+
407 "\t "+tr("Area to render, default value is ''{0}''", "auto")+"\n"+
408 "\t "+tr("With keyword ''{0}'', the downloaded area in the .osm input file will be used (if recorded).",
409 "auto")+"\n"+
410 "\t--anchor <lon>,<lat> "+tr("Specify bottom left corner of the rendering area")+"\n"+
411 "\t "+tr("Used in combination with width and height options to determine the area to render.")+"\n"+
412 "\t--width-m <number> "+tr("Width of the rendered area, in meter")+"\n"+
413 "\t--height-m <number> "+tr("Height of the rendered area, in meter")+"\n"+
414 "\t--width-px <number> "+tr("Width of the target image, in pixel")+"\n"+
415 "\t--height-px <number> "+tr("Height of the target image, in pixel")+"\n"+
416 "\t--projection <code> "+tr("Projection to use, default value ''{0}'' (web-Mercator)", "epsg:3857")+"\n"+
417 "\t--max-image-size <number> "+tr("Maximum image width/height in pixel (''{0}'' means no limit), default value: {1}",
418 0, Integer.toString(DEFAULT_MAX_IMAGE_SIZE))+"\n"+
419 "\n"+
420 tr("To specify the rendered area and scale, the options can be combined in various ways")+":\n"+
421 " * --bounds (--zoom|--scale|--width-px|--height-px)\n"+
422 " * --anchor (--width-m|--width-px) (--height-m|--height-px) (--zoom|--scale)\n"+
423 " * --anchor --width-m --height-m (--width-px|--height-px)\n"+
424 " * --anchor --width-px --height-px (--width-m|--height-m)\n"+
425 tr("If neither ''{0}'' nor ''{1}'' is given, the default value {2} takes effect "
426 + "and the bounds of the download area in the .osm input file are used.",
427 "bounds", "anchor", "--bounds=auto")+"\n\n"+
428 tr("Examples")+":\n"+
429 " java -jar josm.jar render -i data.osm -s style.mapcss -z 16\n"+
430 " josm render -i data.osm -s style.mapcss --scale 5000\n"+
431 " josm render -i data.osm -s style.mapcss -z 16 -o image.png\n"+
432 " josm render -i data.osm -s elemstyles.mapcss --setting hide_icons:false -z 16\n"+
433 " josm render -i data.osm -s style.mapcss -s another_style.mapcss -z 16 -o image.png\n"+
434 " josm render -i data.osm -s style.mapcss --bounds 21.151,51.401,21.152,51.402 -z 16\n"+
435 " josm render -i data.osm -s style.mapcss --anchor 21.151,51.401 --width-m 500 --height-m 300 -z 16\n"+
436 " josm render -i data.osm -s style.mapcss --anchor 21.151,51.401 --width-m 500 --height-m 300 --width-px 1800\n"+
437 " josm render -i data.osm -s style.mapcss --scale 5000 --projection epsg:4326\n";
438 }
439
440 /**
441 * Initialization.
442 *
443 * Requires arguments to be parsed already ({@link #parseArguments(java.lang.String[])}).
444 */
445 void initialize() {
446 Logging.setLogLevel(getLogLevel());
447 HttpClient.setFactory(Http1Client::new);
448
449 Config.setBaseDirectoriesProvider(JosmBaseDirectories.getInstance()); // for right-left-hand traffic cache file
450 Config.setPreferencesInstance(new MemoryPreferences());
451 Config.setUrlsProvider(JosmUrls.getInstance());
452 Config.getPref().putBoolean("mappaint.auto_reload_local_styles", false); // unnecessary to listen for external changes
453 String projCode = Optional.ofNullable(argProjection).orElse("epsg:3857");
454 ProjectionRegistry.setProjection(Projections.getProjectionByCode(projCode.toUpperCase(Locale.US)));
455
456 Territories.initializeInternalData();
457 }
458
459 private Level getLogLevel() {
460 if (argTrace) {
461 return Logging.LEVEL_TRACE;
462 } else if (argDebug) {
463 return Logging.LEVEL_DEBUG;
464 } else {
465 return Logging.LEVEL_INFO;
466 }
467 }
468
469 /**
470 * Find the area to render and the scale, given certain command line options and the dataset.
471 * @param ds the dataset
472 * @return area to render and the scale
473 */
474 RenderingArea determineRenderingArea(DataSet ds) {
475
476 Projection proj = ProjectionRegistry.getProjection();
477 Double scale = null; // scale in east-north units per pixel
478 if (argZoom != null) {
479 scale = OsmMercator.EARTH_RADIUS * Math.PI * 2 / Math.pow(2, argZoom) / OsmMercator.DEFAUL_TILE_SIZE
480 / proj.getMetersPerUnit();
481 }
482 Bounds bounds = argBounds;
483 ProjectionBounds pb = null;
484
485 if (bounds == null) {
486 if (argAnchor != null) {
487 EastNorth projAnchor = proj.latlon2eastNorth(argAnchor);
488
489 double enPerMeter = Double.NaN;
490 DoubleSupplier getEnPerMeter = () -> {
491 double shiftMeter = 10;
492 EastNorth projAnchorShifted = projAnchor.add(shiftMeter / proj.getMetersPerUnit(),
493 shiftMeter / proj.getMetersPerUnit());
494 ILatLon anchorShifted = proj.eastNorth2latlon(projAnchorShifted);
495 return projAnchor.distance(projAnchorShifted) / argAnchor.greatCircleDistance(anchorShifted);
496 };
497
498 if (scale == null) {
499 if (argScale != null) {
500 enPerMeter = getEnPerMeter.getAsDouble();
501 scale = argScale * enPerMeter / PIXEL_PER_METER;
502 } else if (argWidthM != null && argWidthPx != null) {
503 enPerMeter = getEnPerMeter.getAsDouble();
504 scale = argWidthM / argWidthPx * enPerMeter;
505 } else if (argHeightM != null && argHeightPx != null) {
506 enPerMeter = getEnPerMeter.getAsDouble();
507 scale = argHeightM / argHeightPx * enPerMeter;
508 } else {
509 throw new IllegalArgumentException(
510 tr("Argument {0} given, but scale cannot be determined from remaining arguments",
511 "--anchor"));
512 }
513 }
514
515 double widthEn;
516 if (argWidthM != null) {
517 if (Double.isNaN(enPerMeter)) {
518 enPerMeter = getEnPerMeter.getAsDouble();
519 }
520 widthEn = argWidthM * enPerMeter;
521 } else if (argWidthPx != null) {
522 widthEn = argWidthPx * scale;
523 } else {
524 throw new IllegalArgumentException(
525 tr("Argument {0} given, expected {1} or {2}", "--anchor", "--width-m", "--width-px"));
526 }
527
528 double heightEn;
529 if (argHeightM != null) {
530 if (Double.isNaN(enPerMeter)) {
531 enPerMeter = getEnPerMeter.getAsDouble();
532 }
533 heightEn = argHeightM * enPerMeter;
534 } else if (argHeightPx != null) {
535 heightEn = argHeightPx * scale;
536 } else {
537 throw new IllegalArgumentException(
538 tr("Argument {0} given, expected {1} or {2}", "--anchor", "--height-m", "--height-px"));
539 }
540 pb = new ProjectionBounds(projAnchor);
541 pb.extend(new EastNorth(projAnchor.east() + widthEn, projAnchor.north() + heightEn));
542 bounds = new Bounds(proj.eastNorth2latlon(pb.getMin()), false);
543 bounds.extend(proj.eastNorth2latlon(pb.getMax()));
544 } else {
545 if (ds.getDataSourceBounds().isEmpty()) {
546 throw new IllegalArgumentException(
547 tr("{0} mode, but no bounds found in osm data input file", "--bounds=auto"));
548 }
549 bounds = ds.getDataSourceBounds().get(0);
550 }
551 }
552
553 if (pb == null) {
554 pb = new ProjectionBounds();
555 pb.extend(proj.latlon2eastNorth(bounds.getMin()));
556 pb.extend(proj.latlon2eastNorth(bounds.getMax()));
557 }
558
559 if (scale == null) {
560 if (argScale != null) {
561 double enPerMeter = pb.getMin().distance(pb.getMax())
562 / bounds.getMin().greatCircleDistance((ILatLon) bounds.getMax());
563 scale = argScale * enPerMeter / PIXEL_PER_METER;
564 } else if (argWidthPx != null) {
565 scale = (pb.maxEast - pb.minEast) / argWidthPx;
566 } else if (argHeightPx != null) {
567 scale = (pb.maxNorth - pb.minNorth) / argHeightPx;
568 } else {
569 throw new IllegalArgumentException(
570 tr("Unable to determine scale, one of the options {0}, {1}, {2} or {3} expected", "--zoom",
571 "--scale", "--width-px", "--height-px"));
572 }
573 }
574
575 RenderingArea ra = new RenderingArea();
576 ra.bounds = bounds;
577 ra.scale = scale;
578 return ra;
579 }
580
581 private DataSet loadDataset() throws IOException, IllegalDataException {
582 if (argInput == null) {
583 throw new IllegalArgumentException(tr("Missing argument - input data file ({0})", "--input|-i"));
584 }
585 try (InputStream inputStream = Compression.getUncompressedFileInputStream(Paths.get(argInput))) {
586 return OsmReader.parseDataSet(inputStream, null);
587 } catch (IllegalDataException e) {
588 throw new IllegalDataException(tr("In .osm data file ''{0}'' - ", argInput) + e.getMessage(), e);
589 }
590 }
591
592 private void checkPreconditions(RenderingHelper rh) {
593 Dimension imgSize = rh.getImageSize();
594 Logging.debug("image size (px): {0}x{1}", imgSize.width, imgSize.height);
595 int maxSize = Optional.ofNullable(argMaxImageSize).orElse(DEFAULT_MAX_IMAGE_SIZE);
596 if (maxSize != 0 && (imgSize.width > maxSize || imgSize.height > maxSize)) {
597 throw new IllegalArgumentException(
598 tr("Image dimensions ({0}x{1}) exceeds maximum image size {2} (use option {3} to change limit)",
599 imgSize.width, imgSize.height, maxSize, "--max-image-size"));
600 }
601 }
602
603 private void writeImageToFile(BufferedImage image) throws IOException {
604 String output = Optional.ofNullable(argOutput).orElse("out.png");
605 ImageIO.write(image, "png", new File(output));
606 }
607}
Note: See TracBrowser for help on using the repository browser.