Changeset 14635 in josm for trunk/scripts
- Timestamp:
- 2019-01-04T21:41:56+01:00 (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/scripts/TagInfoExtract.java
r14634 r14635 89 89 * java -cp dist/josm-custom.jar TagInfoExtract --type external_presets 90 90 */ 91 class TagInfoExtract { 91 public class TagInfoExtract { 92 92 93 93 /** … … 97 97 TagInfoExtract script = new TagInfoExtract(); 98 98 script.parseCommandLineArguments(args); 99 script.init(); 99 100 switch (script.options.mode) { 100 101 case MAPPAINT: 101 script. runStyleSheet();102 script.new StyleSheet().run(); 102 103 break; 103 104 case PRESETS: 104 script. runPresets();105 script.new Presets().run(); 105 106 break; 106 107 case EXTERNAL_PRESETS: 107 script. runExternalPresets();108 script.new ExternalPresets().run(); 108 109 break; 109 110 default: … … 120 121 121 122 private final Options options = new Options(); 122 private MapCSSStyleSource styleSource;123 123 124 124 /** … … 200 200 noexit = true; 201 201 } 202 } 203 private void runPresets() throws IOException, SAXException { 204 init(); 205 try (BufferedReader reader = options.inputFile.getContentReader()) { 206 Collection<TaggingPreset> presets = TaggingPresetReader.readAll(reader, true); 207 List<TagInfoTag> tags = convertPresets(presets, "", true); 208 writeJson("JOSM main presets", "Tags supported by the default presets in the OSM editor JOSM", tags); 209 } 210 } 211 212 private List<TagInfoTag> convertPresets(Iterable<TaggingPreset> presets, String descriptionPrefix, boolean addImages) { 213 final List<TagInfoTag> tags = new ArrayList<>(); 214 for (TaggingPreset preset : presets) { 215 for (KeyedItem item : Utils.filteredCollection(preset.data, KeyedItem.class)) { 216 final Iterable<String> values = item.isKeyRequired() 217 ? item.getValues() 218 : Collections.emptyList(); 219 for (String value : values) { 220 final Set<TagInfoTag.Type> types = preset.types.stream() 221 .map(it -> it.equals(TaggingPresetType.CLOSEDWAY) ? TagInfoTag.Type.AREA : it.equals(TaggingPresetType.MULTIPOLYGON) ? TagInfoTag.Type.RELATION : TagInfoTag.Type.valueOf(it.toString())) 222 .collect(Collectors.toCollection(() -> EnumSet.noneOf(TagInfoTag.Type.class))); 223 tags.add(new TagInfoTag(descriptionPrefix + preset.getName(), item.key, value, types, 224 addImages && preset.iconName != null ? findImageUrl(preset.iconName) : null)); 225 } 226 } 227 } 228 229 return tags; 230 } 231 232 private void runExternalPresets() throws IOException, OsmTransferException, SAXException { 233 init(); 234 TaggingPresetReader.setLoadIcons(false); 235 final Collection<ExtendedSourceEntry> sources = new TaggingPresetPreference.TaggingPresetSourceEditor().loadAndGetAvailableSources(); 236 final List<TagInfoTag> tags = new ArrayList<>(); 237 for (SourceEntry source : sources) { 238 if (source.url.startsWith("resource")) { 239 // default presets 240 continue; 241 } 242 try { 243 System.out.println("Loading " + source.url); 244 Collection<TaggingPreset> presets = TaggingPresetReader.readAll(source.url, false); 245 final List<TagInfoTag> t = convertPresets(presets, source.title + " ", false); 246 System.out.println("Converting " + t.size() + " presets of " + source.title); 247 tags.addAll(t); 248 } catch (Exception ex) { 249 System.err.println("Skipping " + source.url + " due to error"); 250 ex.printStackTrace(); 251 } 252 253 } 254 255 writeJson("JOSM user presets", "Tags supported by the user contributed presets in the OSM editor JOSM", tags); 256 } 257 258 private void runStyleSheet() throws IOException, ParseException { 259 init(); 260 parseStyleSheet(); 261 final List<TagInfoTag> tags = convertStyleSheet(); 262 writeJson("JOSM main mappaint style", "Tags supported by the main mappaint style in the OSM editor JOSM", tags); 263 } 264 202 203 /** 204 * Determine full image url (can refer to JOSM or OSM repository). 205 * @param path the image path 206 */ 207 private String findImageUrl(String path) { 208 final Path f = baseDir.resolve("images").resolve(path); 209 if (Files.exists(f)) { 210 return "https://josm.openstreetmap.de/export/" + josmSvnRevision + "/josm/trunk/images/" + path; 211 } 212 throw new IllegalStateException("Cannot find image url for " + path); 213 } 214 } 215 216 private abstract class Extractor { 217 abstract void run() throws Exception; 218 219 void writeJson(String name, String description, Iterable<TagInfoTag> tags) throws IOException { 220 try (Writer writer = options.outputFile != null ? Files.newBufferedWriter(options.outputFile) : new StringWriter(); 221 JsonWriter json = Json 222 .createWriterFactory(Collections.singletonMap(JsonGenerator.PRETTY_PRINTING, true)) 223 .createWriter(writer)) { 224 JsonObjectBuilder project = Json.createObjectBuilder() 225 .add("name", name) 226 .add("description", description) 227 .add("project_url", "https://josm.openstreetmap.de/") 228 .add("icon_url", "https://josm.openstreetmap.de/export/7770/josm/trunk/images/logo_16x16x8.png") 229 .add("contact_name", "JOSM developer team") 230 .add("contact_email", "josm-dev@openstreetmap.org"); 231 final JsonArrayBuilder jsonTags = Json.createArrayBuilder(); 232 for (TagInfoTag t : tags) { 233 jsonTags.add(t.toJson()); 234 } 235 json.writeObject(Json.createObjectBuilder() 236 .add("data_format", 1) 237 .add("data_updated", DateTimeFormatter.ofPattern("yyyyMMdd'T'hhmmss'Z'").withZone(ZoneId.of("Z")).format(Instant.now())) 238 .add("project", project) 239 .add("tags", jsonTags) 240 .build()); 241 if (options.outputFile == null) { 242 System.out.println(writer.toString()); 243 } 244 } 245 } 246 247 } 248 249 private class Presets extends Extractor { 250 251 @Override 252 void run() throws IOException, OsmTransferException, SAXException { 253 try (BufferedReader reader = options.inputFile.getContentReader()) { 254 Collection<TaggingPreset> presets = TaggingPresetReader.readAll(reader, true); 255 List<TagInfoTag> tags = convertPresets(presets, "", true); 256 writeJson("JOSM main presets", "Tags supported by the default presets in the OSM editor JOSM", tags); 257 } 258 } 259 260 List<TagInfoTag> convertPresets(Iterable<TaggingPreset> presets, String descriptionPrefix, boolean addImages) { 261 final List<TagInfoTag> tags = new ArrayList<>(); 262 for (TaggingPreset preset : presets) { 263 for (KeyedItem item : Utils.filteredCollection(preset.data, KeyedItem.class)) { 264 final Iterable<String> values = item.isKeyRequired() 265 ? item.getValues() 266 : Collections.emptyList(); 267 for (String value : values) { 268 final Set<TagInfoTag.Type> types = preset.types == null ? Collections.emptySet() : preset.types.stream() 269 .map(it -> TaggingPresetType.CLOSEDWAY.equals(it) 270 ? TagInfoTag.Type.AREA 271 : TaggingPresetType.MULTIPOLYGON.equals(it) 272 ? TagInfoTag.Type.RELATION 273 : TagInfoTag.Type.valueOf(it.toString())) 274 .collect(Collectors.toCollection(() -> EnumSet.noneOf(TagInfoTag.Type.class))); 275 tags.add(new TagInfoTag(descriptionPrefix + preset.getName(), item.key, value, types, 276 addImages && preset.iconName != null ? options.findImageUrl(preset.iconName) : null)); 277 } 278 } 279 } 280 return tags; 281 } 282 283 } 284 285 private class ExternalPresets extends Presets { 286 287 @Override 288 void run() throws IOException, OsmTransferException, SAXException { 289 TaggingPresetReader.setLoadIcons(false); 290 final Collection<ExtendedSourceEntry> sources = new TaggingPresetPreference.TaggingPresetSourceEditor().loadAndGetAvailableSources(); 291 final List<TagInfoTag> tags = new ArrayList<>(); 292 for (SourceEntry source : sources) { 293 if (source.url.startsWith("resource")) { 294 // default presets 295 continue; 296 } 297 try { 298 System.out.println("Loading " + source.url); 299 Collection<TaggingPreset> presets = TaggingPresetReader.readAll(source.url, false); 300 final List<TagInfoTag> t = convertPresets(presets, source.title + " ", false); 301 System.out.println("Converting " + t.size() + " presets of " + source.title); 302 tags.addAll(t); 303 } catch (Exception ex) { 304 System.err.println("Skipping " + source.url + " due to error"); 305 ex.printStackTrace(); 306 } 307 308 } 309 writeJson("JOSM user presets", "Tags supported by the user contributed presets in the OSM editor JOSM", tags); 310 } 311 } 312 313 private class StyleSheet extends Extractor { 314 private MapCSSStyleSource styleSource; 315 316 @Override 317 void run() throws IOException, ParseException { 318 init(); 319 parseStyleSheet(); 320 final List<TagInfoTag> tags = convertStyleSheet(); 321 writeJson("JOSM main mappaint style", "Tags supported by the main mappaint style in the OSM editor JOSM", tags); 322 } 323 324 /** 325 * Read the style sheet file and parse the MapCSS code. 326 */ 327 private void parseStyleSheet() throws IOException, ParseException { 328 try (InputStream stream = options.inputFile.getInputStream()) { 329 MapCSSParser parser = new MapCSSParser(stream, "UTF-8", MapCSSParser.LexicalState.DEFAULT); 330 styleSource = new MapCSSStyleSource(""); 331 styleSource.url = ""; 332 parser.sheet(styleSource); 333 } 334 } 335 336 /** 337 * Collect all the tag from the style sheet. 338 */ 339 private List<TagInfoTag> convertStyleSheet() { 340 return styleSource.rules.stream() 341 .map(rule -> rule.selector) 342 .filter(Selector.GeneralSelector.class::isInstance) 343 .map(Selector.GeneralSelector.class::cast) 344 .map(Selector.AbstractSelector::getConditions) 345 .flatMap(Collection::stream) 346 .filter(ConditionFactory.SimpleKeyValueCondition.class::isInstance) 347 .map(ConditionFactory.SimpleKeyValueCondition.class::cast) 348 .map(condition -> condition.asTag(null)) 349 .distinct() 350 .map(tag -> { 351 String iconUrl = null; 352 final EnumSet<TagInfoTag.Type> types = EnumSet.noneOf(TagInfoTag.Type.class); 353 Optional<String> nodeUrl = new NodeChecker(tag).findUrl(true); 354 if (nodeUrl.isPresent()) { 355 iconUrl = nodeUrl.get(); 356 types.add(TagInfoTag.Type.NODE); 357 } 358 Optional<String> wayUrl = new WayChecker(tag).findUrl(iconUrl == null); 359 if (wayUrl.isPresent()) { 360 if (iconUrl == null) { 361 iconUrl = wayUrl.get(); 362 } 363 types.add(TagInfoTag.Type.WAY); 364 } 365 Optional<String> areaUrl = new AreaChecker(tag).findUrl(iconUrl == null); 366 if (areaUrl.isPresent()) { 367 if (iconUrl == null) { 368 iconUrl = areaUrl.get(); 369 } 370 types.add(TagInfoTag.Type.AREA); 371 } 372 return new TagInfoTag(null, tag.getKey(), tag.getValue(), types, iconUrl); 373 }) 374 .collect(Collectors.toList()); 375 } 376 377 /** 378 * Check if a certain tag is supported by the style as node / way / area. 379 */ 380 private abstract class Checker { 381 Checker(Tag tag) { 382 this.tag = tag; 383 } 384 385 Environment applyStylesheet(OsmPrimitive osm) { 386 osm.put(tag); 387 MultiCascade mc = new MultiCascade(); 388 389 Environment env = new Environment(osm, mc, null, styleSource); 390 for (MapCSSRule r : styleSource.rules) { 391 env.clearSelectorMatchingInformation(); 392 if (r.selector.matches(env)) { 393 // ignore selector range 394 if (env.layer == null) { 395 env.layer = "default"; 396 } 397 r.execute(env); 398 } 399 } 400 env.layer = "default"; 401 return env; 402 } 403 404 /** 405 * Create image file from StyleElement. 406 * 407 * @return the URL 408 */ 409 String createImage(StyleElement elem_style, final String type, NavigatableComponent nc) { 410 BufferedImage img = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB); 411 Graphics2D g = img.createGraphics(); 412 g.setClip(0, 0, 16, 16); 413 StyledMapRenderer renderer = new StyledMapRenderer(g, nc, false); 414 renderer.getSettings(false); 415 elem_style.paintPrimitive(osm, MapPaintSettings.INSTANCE, renderer, false, false, false); 416 final String imageName = type + "_" + tag + ".png"; 417 try (OutputStream out = Files.newOutputStream(options.imageDir.resolve(imageName))) { 418 ImageIO.write(img, "png", out); 419 } catch (IOException e) { 420 throw new UncheckedIOException(e); 421 } 422 final String baseUrl = options.imageUrlPrefix != null ? options.imageUrlPrefix : options.imageDir.toString(); 423 return baseUrl + "/" + imageName; 424 } 425 426 /** 427 * Checks, if tag is supported and find URL for image icon in this case. 428 * 429 * @param generateImage if true, create or find a suitable image icon and return URL, 430 * if false, just check if tag is supported and return true or false 431 */ 432 abstract Optional<String> findUrl(boolean generateImage); 433 434 protected Tag tag; 435 protected OsmPrimitive osm; 436 } 437 438 private class NodeChecker extends Checker { 439 NodeChecker(Tag tag) { 440 super(tag); 441 } 442 443 @Override 444 Optional<String> findUrl(boolean generateImage) { 445 this.osm = new Node(LatLon.ZERO); 446 Environment env = applyStylesheet(osm); 447 Cascade c = env.mc.getCascade("default"); 448 Object image = c.get("icon-image"); 449 if (image instanceof MapPaintStyles.IconReference && !((MapPaintStyles.IconReference) image).isDeprecatedIcon()) { 450 return Optional.of(options.findImageUrl(((MapPaintStyles.IconReference) image).iconName)); 451 } 452 return Optional.empty(); 453 } 454 455 } 456 457 private class WayChecker extends Checker { 458 WayChecker(Tag tag) { 459 super(tag); 460 } 461 462 @Override 463 Optional<String> findUrl(boolean generateImage) { 464 this.osm = new Way(); 465 NavigatableComponent nc = new NavigatableComponent(); 466 Node n1 = new Node(nc.getLatLon(2, 8)); 467 Node n2 = new Node(nc.getLatLon(14, 8)); 468 ((Way) osm).addNode(n1); 469 ((Way) osm).addNode(n2); 470 Environment env = applyStylesheet(osm); 471 LineElement les = LineElement.createLine(env); 472 if (les != null) { 473 if (!generateImage) return Optional.of(""); 474 return Optional.of(createImage(les, "way", nc)); 475 } 476 return Optional.empty(); 477 } 478 479 } 480 481 private class AreaChecker extends Checker { 482 AreaChecker(Tag tag) { 483 super(tag); 484 } 485 486 @Override 487 Optional<String> findUrl(boolean generateImage) { 488 this.osm = new Way(); 489 NavigatableComponent nc = new NavigatableComponent(); 490 Node n1 = new Node(nc.getLatLon(2, 2)); 491 Node n2 = new Node(nc.getLatLon(14, 2)); 492 Node n3 = new Node(nc.getLatLon(14, 14)); 493 Node n4 = new Node(nc.getLatLon(2, 14)); 494 ((Way) osm).addNode(n1); 495 ((Way) osm).addNode(n2); 496 ((Way) osm).addNode(n3); 497 ((Way) osm).addNode(n4); 498 ((Way) osm).addNode(n1); 499 Environment env = applyStylesheet(osm); 500 AreaElement aes = AreaElement.create(env); 501 if (aes != null) { 502 if (!generateImage) return Optional.of(""); 503 return Optional.of(createImage(aes, "area", nc)); 504 } 505 return Optional.empty(); 506 } 507 } 508 } 509 510 /** 511 * POJO representing a <a href="https://wiki.openstreetmap.org/wiki/Taginfo/Projects">Taginfo tag</a>. 512 */ 265 513 private static class TagInfoTag { 266 514 final String description; … … 298 546 enum Type { 299 547 NODE, WAY, AREA, RELATION 300 }301 }302 303 private void writeJson(String name, String description, Iterable<TagInfoTag> tags) throws IOException {304 try (Writer writer = options.outputFile != null ? Files.newBufferedWriter(options.outputFile) : new StringWriter();305 JsonWriter json = Json306 .createWriterFactory(Collections.singletonMap(JsonGenerator.PRETTY_PRINTING, true))307 .createWriter(writer)) {308 JsonObjectBuilder project = Json.createObjectBuilder()309 .add("name", name)310 .add("description", description)311 .add("project_url", "https://josm.openstreetmap.de/")312 .add("icon_url", "https://josm.openstreetmap.de/export/7770/josm/trunk/images/logo_16x16x8.png")313 .add("contact_name", "JOSM developer team")314 .add("contact_email", "josm-dev@openstreetmap.org");315 final JsonArrayBuilder jsonTags = Json.createArrayBuilder();316 for (TagInfoTag t : tags) {317 jsonTags.add(t.toJson());318 }319 json.writeObject(Json.createObjectBuilder()320 .add("data_format", 1)321 .add("data_updated", DateTimeFormatter.ofPattern("yyyyMMdd'T'hhmmss'Z'").withZone(ZoneId.of("Z")).format(Instant.now()))322 .add("project", project)323 .add("tags", jsonTags)324 .build());325 if (options.outputFile == null) {326 System.out.println(writer.toString());327 }328 548 } 329 549 } … … 346 566 RightAndLefthandTraffic.initialize(); 347 567 } 348 349 /**350 * Determine full image url (can refer to JOSM or OSM repository).351 */352 private String findImageUrl(String path) {353 final Path f = options.baseDir.resolve("images").resolve(path);354 if (Files.exists(f)) {355 return "https://josm.openstreetmap.de/export/" + options.josmSvnRevision + "/josm/trunk/images/" + path;356 }357 throw new IllegalStateException("Cannot find image url for " + path);358 }359 360 /**361 * Read the style sheet file and parse the MapCSS code.362 */363 private void parseStyleSheet() throws IOException, ParseException {364 try (InputStream stream = options.inputFile.getInputStream()) {365 MapCSSParser parser = new MapCSSParser(stream, "UTF-8", MapCSSParser.LexicalState.DEFAULT);366 styleSource = new MapCSSStyleSource("");367 styleSource.url = "";368 parser.sheet(styleSource);369 }370 }371 372 /**373 * Collect all the tag from the style sheet.374 */375 private List<TagInfoTag> convertStyleSheet() {376 return styleSource.rules.stream()377 .map(rule -> rule.selector)378 .filter(Selector.GeneralSelector.class::isInstance)379 .map(Selector.GeneralSelector.class::cast)380 .map(Selector.AbstractSelector::getConditions)381 .flatMap(Collection::stream)382 .filter(ConditionFactory.SimpleKeyValueCondition.class::isInstance)383 .map(ConditionFactory.SimpleKeyValueCondition.class::cast)384 .map(condition -> condition.asTag(null))385 .distinct()386 .map(tag -> {387 String iconUrl = null;388 final EnumSet<TagInfoTag.Type> types = EnumSet.noneOf(TagInfoTag.Type.class);389 Optional<String> nodeUrl = new NodeChecker(tag).findUrl(true);390 if (nodeUrl.isPresent()) {391 iconUrl = nodeUrl.get();392 types.add(TagInfoTag.Type.NODE);393 }394 Optional<String> wayUrl = new WayChecker(tag).findUrl(iconUrl == null);395 if (wayUrl.isPresent()) {396 if (iconUrl == null) {397 iconUrl = wayUrl.get();398 }399 types.add(TagInfoTag.Type.WAY);400 }401 Optional<String> areaUrl = new AreaChecker(tag).findUrl(iconUrl == null);402 if (areaUrl.isPresent()) {403 if (iconUrl == null) {404 iconUrl = areaUrl.get();405 }406 types.add(TagInfoTag.Type.AREA);407 }408 return new TagInfoTag(null, tag.getKey(), tag.getValue(), types, iconUrl);409 })410 .collect(Collectors.toList());411 }412 413 /**414 * Check if a certain tag is supported by the style as node / way / area.415 */416 private abstract class Checker {417 Checker(Tag tag) {418 this.tag = tag;419 }420 421 Environment applyStylesheet(OsmPrimitive osm) {422 osm.put(tag);423 MultiCascade mc = new MultiCascade();424 425 Environment env = new Environment(osm, mc, null, styleSource);426 for (MapCSSRule r : styleSource.rules) {427 env.clearSelectorMatchingInformation();428 if (r.selector.matches(env)) {429 // ignore selector range430 if (env.layer == null) {431 env.layer = "default";432 }433 r.execute(env);434 }435 }436 env.layer = "default";437 return env;438 }439 440 /**441 * Create image file from StyleElement.442 *443 * @return the URL444 */445 String createImage(StyleElement elem_style, final String type, NavigatableComponent nc) {446 BufferedImage img = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);447 Graphics2D g = img.createGraphics();448 g.setClip(0, 0, 16, 16);449 StyledMapRenderer renderer = new StyledMapRenderer(g, nc, false);450 renderer.getSettings(false);451 elem_style.paintPrimitive(osm, MapPaintSettings.INSTANCE, renderer, false, false, false);452 final String imageName = type + "_" + tag + ".png";453 try (OutputStream out = Files.newOutputStream(options.imageDir.resolve(imageName))) {454 ImageIO.write(img, "png", out);455 } catch (IOException e) {456 throw new UncheckedIOException(e);457 }458 final String baseUrl = options.imageUrlPrefix != null ? options.imageUrlPrefix : options.imageDir.toString();459 return baseUrl + "/" + imageName;460 }461 462 /**463 * Checks, if tag is supported and find URL for image icon in this case.464 *465 * @param generateImage if true, create or find a suitable image icon and return URL,466 * if false, just check if tag is supported and return true or false467 */468 abstract Optional<String> findUrl(boolean generateImage);469 470 protected Tag tag;471 protected OsmPrimitive osm;472 }473 474 private class NodeChecker extends Checker {475 NodeChecker(Tag tag) {476 super(tag);477 }478 479 @Override480 Optional<String> findUrl(boolean generateImage) {481 this.osm = new Node(LatLon.ZERO);482 Environment env = applyStylesheet(osm);483 Cascade c = env.mc.getCascade("default");484 Object image = c.get("icon-image");485 if (image instanceof MapPaintStyles.IconReference && !((MapPaintStyles.IconReference) image).isDeprecatedIcon()) {486 return Optional.of(findImageUrl(((MapPaintStyles.IconReference) image).iconName));487 }488 return Optional.empty();489 }490 491 }492 493 private class WayChecker extends Checker {494 WayChecker(Tag tag) {495 super(tag);496 }497 498 @Override499 Optional<String> findUrl(boolean generateImage) {500 this.osm = new Way();501 NavigatableComponent nc = new NavigatableComponent();502 Node n1 = new Node(nc.getLatLon(2, 8));503 Node n2 = new Node(nc.getLatLon(14, 8));504 ((Way) osm).addNode(n1);505 ((Way) osm).addNode(n2);506 Environment env = applyStylesheet(osm);507 LineElement les = LineElement.createLine(env);508 if (les != null) {509 if (!generateImage) return Optional.of("");510 return Optional.of(createImage(les, "way", nc));511 }512 return Optional.empty();513 }514 515 }516 517 private class AreaChecker extends Checker {518 AreaChecker(Tag tag) {519 super(tag);520 }521 522 @Override523 Optional<String> findUrl(boolean generateImage) {524 this.osm = new Way();525 NavigatableComponent nc = new NavigatableComponent();526 Node n1 = new Node(nc.getLatLon(2, 2));527 Node n2 = new Node(nc.getLatLon(14, 2));528 Node n3 = new Node(nc.getLatLon(14, 14));529 Node n4 = new Node(nc.getLatLon(2, 14));530 ((Way) osm).addNode(n1);531 ((Way) osm).addNode(n2);532 ((Way) osm).addNode(n3);533 ((Way) osm).addNode(n4);534 ((Way) osm).addNode(n1);535 Environment env = applyStylesheet(osm);536 AreaElement aes = AreaElement.create(env);537 if (aes != null) {538 if (!generateImage) return Optional.of("");539 return Optional.of(createImage(aes, "area", nc));540 }541 return Optional.empty();542 }543 544 }545 568 }
Note:
See TracChangeset
for help on using the changeset viewer.