This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
commit 18eff4603a64538e3a1fc10e32bfe814e8fd5053 Author: Martin Desruisseaux <[email protected]> AuthorDate: Wed Nov 29 15:30:21 2023 +0100 Add an `info` sub-command to the SIS command-line for showing the grid geometry of a file. --- .../main/org/apache/sis/console/CRSCommand.java | 2 +- .../main/org/apache/sis/console/Command.java | 1 + .../org/apache/sis/console/Commands.properties | 3 +- .../org/apache/sis/console/Commands_fr.properties | 3 +- .../apache/sis/console/FormattedOutputCommand.java | 11 +- .../main/org/apache/sis/console/InfoCommand.java | 153 +++++++++++++++++++++ .../org/apache/sis/console/MetadataCommand.java | 5 +- .../sis/storage/geotiff/ImageFileDirectory.java | 22 ++- .../org/apache/sis/util/collection/TreeTables.java | 26 +++- 9 files changed, 210 insertions(+), 16 deletions(-) diff --git a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/CRSCommand.java b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/CRSCommand.java index d0c5a76eec..0b2238708e 100644 --- a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/CRSCommand.java +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/CRSCommand.java @@ -36,7 +36,7 @@ final class CRSCommand extends FormattedOutputCommand { } /** - * Prints metadata or CRS information. + * Prints CRS information. * * @return 0 on success, or an exit code if the command failed for a reason other than an uncaught Java exception. */ diff --git a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Command.java b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Command.java index 6a6f4c9111..adf3405508 100644 --- a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Command.java +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Command.java @@ -155,6 +155,7 @@ public final class Command { case "mime-type": command = new MimeTypeCommand (commandIndex, args); break; case "metadata": command = new MetadataCommand (commandIndex, args); break; case "crs": command = new CRSCommand (commandIndex, args); break; + case "info": command = new InfoCommand (commandIndex, args); break; case "identifier": command = new IdentifierCommand(commandIndex, args); break; case "transform": command = new TransformCommand (commandIndex, args); break; case "translate": command = new TranslateCommand (commandIndex, args); break; diff --git a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Commands.properties b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Commands.properties index 14e23b348f..09d6e5534c 100644 --- a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Commands.properties +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Commands.properties @@ -6,7 +6,8 @@ Usage=Usage: sis <command> [options] [files] help=Show a help overview. about=Show information about Apache SIS and system configuration. mime-type=Show MIME type for the given file. -metadata=Show metadata information for the given file. +info=Show information about the content of the given file. +metadata=Show ISO 19115 metadata information for the given file. crs=Show Coordinate Reference System (CRS) information for the given file. identifier=Show identifiers for metadata and referencing systems in the given file. transform=Convert or transform coordinates from given source CRS to target CRS. diff --git a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Commands_fr.properties b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Commands_fr.properties index 65747e839d..c91847685a 100644 --- a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Commands_fr.properties +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Commands_fr.properties @@ -6,7 +6,8 @@ Usage=Usage: sis <commande> [options] [fichiers] help=Affiche un \u00e9cran d\u2019aide. about=Affiche des informations \u00e0 propos de Apache SIS et de la configuration du syst\u00e8me. mime-type=Affiche le type MIME du fichier sp\u00e9cifi\u00e9. -metadata=Affiche les m\u00e9ta-donn\u00e9es du fichier sp\u00e9cifi\u00e9. +info=Affiche des informations \u00e0 propos du contenu du fichier sp\u00e9cifi\u00e9. +metadata=Affiche les m\u00e9ta-donn\u00e9es ISO 19115 du fichier sp\u00e9cifi\u00e9. crs=Affiche le syst\u00e8me de r\u00e9f\u00e9rence des coordonn\u00e9es du fichier sp\u00e9cifi\u00e9. identifier=Affiche les identifiants des m\u00e9ta-donn\u00e9es et des syst\u00e8mes de r\u00e9f\u00e9rences du fichier sp\u00e9cifi\u00e9. transform=Transforme des coordonn\u00e9es du syst\u00e8me de r\u00e9f\u00e9rence source vers le syst\u00e8me destination donn\u00e9. diff --git a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/FormattedOutputCommand.java b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/FormattedOutputCommand.java index 504a66ce43..fab233f71c 100644 --- a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/FormattedOutputCommand.java +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/FormattedOutputCommand.java @@ -88,7 +88,6 @@ abstract class FormattedOutputCommand extends CommandRunner { /** * Creates a new sub-command with the given command-line arguments. - * This constructor is for {@code MetadataCommand} subclasses. * * @param commandIndex index of the {@code arguments} element containing the sub-command name, or -1 if none. * @param arguments the command-line arguments provided by the user. @@ -217,7 +216,7 @@ abstract class FormattedOutputCommand extends CommandRunner { final TreeTable tree = MetadataStandard.ISO_19115.asTreeTable(object, (object instanceof Metadata) ? Metadata.class : null, ValueExistencePolicy.COMPACT); - final TreeTableFormat tf = new TreeTableFormat(locale, timezone); + final var tf = new TreeTableFormat(locale, timezone); tf.setColumns(TableColumn.NAME, TableColumn.VALUE); tf.setNodeFilter(getNodeFilter()); tf.format(tree, out); @@ -225,7 +224,7 @@ abstract class FormattedOutputCommand extends CommandRunner { } case WKT: { - final WKTFormat f = new WKTFormat(locale, timezone); + final var f = new WKTFormat(locale, timezone); if (convention != null) { f.setConvention(convention); } @@ -238,7 +237,7 @@ abstract class FormattedOutputCommand extends CommandRunner { } case XML: { - final MarshallerPool pool = new MarshallerPool(null); + final var pool = new MarshallerPool(null); final Marshaller marshaller = pool.acquireMarshaller(); marshaller.setProperty(XML.LOCALE, locale); marshaller.setProperty(XML.TIMEZONE, timezone); @@ -254,7 +253,7 @@ abstract class FormattedOutputCommand extends CommandRunner { } default: { - final StorageConnector connector = new StorageConnector(out); + final var connector = new StorageConnector(out); connector.setOption(OptionKey.TIMEZONE, timezone); connector.setOption(OptionKey.LOCALE, locale); connector.setOption(OptionKey.ENCODING, encoding); @@ -266,7 +265,7 @@ abstract class FormattedOutputCommand extends CommandRunner { * Note: after such generalization is done, revert the xml-store dependency * scope in pom.xml from "compile" to "runtime". */ - final org.apache.sis.storage.gpx.WritableStore fs = (org.apache.sis.storage.gpx.WritableStore) store; + final var fs = (org.apache.sis.storage.gpx.WritableStore) store; if (version != null) { fs.setVersion(version); } diff --git a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/InfoCommand.java b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/InfoCommand.java new file mode 100644 index 0000000000..4ed829c9b0 --- /dev/null +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/InfoCommand.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sis.console; + +import java.util.EnumSet; +import org.apache.sis.coverage.Category; +import org.apache.sis.coverage.SampleDimension; +import org.apache.sis.storage.DataStore; +import org.apache.sis.storage.DataStores; +import org.apache.sis.storage.Resource; +import org.apache.sis.storage.Aggregate; +import org.apache.sis.storage.DataStoreException; +import org.apache.sis.storage.GridCoverageResource; +import org.apache.sis.coverage.grid.GridGeometry; +import org.apache.sis.measure.RangeFormat; +import org.apache.sis.util.collection.TreeTable; +import org.apache.sis.util.collection.TreeTables; +import org.apache.sis.util.collection.TableColumn; +import org.apache.sis.util.collection.TreeTableFormat; +import org.apache.sis.util.collection.DefaultTreeTable; +import org.apache.sis.util.collection.BackingStoreException; +import org.apache.sis.util.resources.Vocabulary; + + +/** + * The "info" sub-command. + * The content varies depending on the resource type. + * For grid coverage, it contains the grid geometry. + * + * @author Martin Desruisseaux (Geomatys) + */ +final class InfoCommand extends FormattedOutputCommand { + /** + * Returns valid options for the {@code "metadata"} command. + */ + static EnumSet<Option> options() { + return EnumSet.of(Option.LOCALE, Option.TIMEZONE, Option.COLORS, Option.VERBOSE, Option.HELP, Option.DEBUG); + } + + /** + * The bit mask of information to request from a grid geometry. + */ + private int gridBitMask; + + /** + * Creates the {@code "info"} sub-command. + * + * @param commandIndex index of the {@code arguments} element containing the {@code "info"} command name, or -1 if none. + * @param arguments the command-line arguments provided by the user. + * @throws InvalidOptionException if an illegal option has been provided, or the option has an illegal value. + */ + InfoCommand(final int commandIndex, final String... arguments) throws InvalidOptionException { + super(commandIndex, arguments, options(), OutputFormat.TEXT); + gridBitMask = GridGeometry.EXTENT | GridGeometry.GEOGRAPHIC_EXTENT | GridGeometry.TEMPORAL_EXTENT + | GridGeometry.CRS | GridGeometry.RESOLUTION; + if (options.containsKey(Option.VERBOSE)) { + gridBitMask |= GridGeometry.ENVELOPE | GridGeometry.GRID_TO_CRS; + } + } + + /** + * Prints resource information. + * + * @return 0 on success, or an exit code if the command failed for a reason other than an uncaught Java exception. + */ + @Override + public int run() throws Exception { + final Object input; + final String name; + if (useStandardInput()) { + input = System.in; + name = "stdin"; + } else { + if (hasUnexpectedFileCount = hasUnexpectedFileCount(1, 1)) { + return Command.INVALID_ARGUMENT_EXIT_CODE; + } + input = name = files.get(0); + } + final var tree = new DefaultTreeTable(TableColumn.VALUE_AS_TEXT); + try (DataStore store = DataStores.open(input)) { + define(tree.getRoot(), store); + } catch (BackingStoreException e) { + throw e.unwrapOrRethrow(DataStoreException.class); + } + final var tf = new TreeTableFormat(locale, timezone); + tf.format(tree, out); + return 0; + } + + /** + * Sets the values of the given node using information in the given resource. + * + * @param target the tree node to define. + * @param source the resource from which to get the information. + * @throws DataStoreException if an error occurred while reading the resource. + */ + private void define(final TreeTable.Node target, final Resource source) throws DataStoreException { + String name = source.getIdentifier().map((id) -> id.toInternationalString().toString(locale)) + .orElseGet(() -> Vocabulary.getResources(locale).getString(Vocabulary.Keys.Unnamed)); + target.setValue(TableColumn.VALUE_AS_TEXT, name); + if (source instanceof GridCoverageResource) { + final var grid = (GridCoverageResource) source; + TreeTable.Node root = grid.getGridGeometry().toTree(locale, gridBitMask).getRoot(); + TreeTables.moveChildren(root, target); + toTree(grid.getSampleDimensions(), target.newChild(), TableColumn.VALUE_AS_TEXT); + } else if (source instanceof Aggregate) { + for (Resource component : ((Aggregate) source).components()) { + define(target.newChild(), component); + } + } + } + + /** + * Appends information about the sample dimensions in a tree. + * + * @param bands the sample dimensions to format. + * @param target where to format the sample dimensions. + * @param column the column where to write the texts. + */ + private void toTree(final Iterable<SampleDimension> bands, final TreeTable.Node target, + final TableColumn<? super String> column) + { + target.setValue(column, Vocabulary.getResources(locale).getString(Vocabulary.Keys.SampleDimensions)); + final var rf = new RangeFormat(locale, timezone); + final var sb = new StringBuffer(); + for (SampleDimension band : bands) { + band = band.forConvertedValues(true); + final TreeTable.Node bn = target.newChild(); + bn.setValue(column, band.getName().toInternationalString().toString(locale)); + for (final Category category : band.getCategories()) { + final TreeTable.Node cn = bn.newChild(); + sb.append(category.getName().toString(locale)).append(" ("); + rf.format(category.getSampleRange(), sb, null).append(')'); + cn.setValue(column, sb.toString()); + sb.setLength(0); + } + } + } +} diff --git a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/MetadataCommand.java b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/MetadataCommand.java index 9e22472a51..61c64bbaad 100644 --- a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/MetadataCommand.java +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/MetadataCommand.java @@ -28,6 +28,7 @@ import org.apache.sis.util.collection.TreeTable; /** * The "metadata" sub-command. + * This command shows ISO 19115 metadata for the content of a file. * * @author Martin Desruisseaux (Geomatys) */ @@ -52,7 +53,7 @@ final class MetadataCommand extends FormattedOutputCommand { } /** - * Prints metadata or CRS information. + * Prints metadata. * * @return 0 on success, or an exit code if the command failed for a reason other than an uncaught Java exception. */ @@ -68,7 +69,7 @@ final class MetadataCommand extends FormattedOutputCommand { } if (metadata != null) { if (!(metadata instanceof Metadata)) { - final DefaultMetadata md = new DefaultMetadata(); + final var md = new DefaultMetadata(); md.setReferenceSystemInfo(Set.of((ReferenceSystem) metadata)); metadata = md; } diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java index 52a0dca631..0477b3cfc4 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java @@ -56,6 +56,7 @@ import org.apache.sis.coverage.grid.j2d.SampleModelFactory; import org.apache.sis.util.ArraysExt; import org.apache.sis.util.Numbers; import org.apache.sis.util.CharSequences; +import org.apache.sis.util.resources.Vocabulary; import org.apache.sis.util.internal.UnmodifiableArrayList; import org.apache.sis.util.internal.Numerics; import org.apache.sis.util.internal.Strings; @@ -1519,7 +1520,26 @@ final class ImageFileDirectory extends DataCube { minValues.get(Math.min(band, minValues.size()-1)), true, maxValues.get(Math.min(band, maxValues.size()-1)), true); } - builder.setName(band + 1).setBackground(getFillValue(true)); + short nameKey = 0; + switch (photometricInterpretation) { + case PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO: + case PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO: nameKey = Vocabulary.Keys.Grayscale; break; + case PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR: nameKey = Vocabulary.Keys.ColorIndex; break; + case PHOTOMETRIC_INTERPRETATION_RGB: { + switch (band) { + case 0: nameKey = Vocabulary.Keys.Red; break; + case 1: nameKey = Vocabulary.Keys.Green; break; + case 2: nameKey = Vocabulary.Keys.Blue; break; + } + break; + } + } + if (nameKey != 0) { + builder.setName(Vocabulary.formatInternational(nameKey)); + } else { + builder.setName(band + 1); + } + builder.setBackground(getFillValue(true)); final SampleDimension sd; if (isIndexValid) { sd = reader.store.customizer.customize(index, band, sampleRange, builder); diff --git a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/collection/TreeTables.java b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/collection/TreeTables.java index dd212c1d1b..6d176b35d6 100644 --- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/collection/TreeTables.java +++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/collection/TreeTables.java @@ -16,6 +16,8 @@ */ package org.apache.sis.util.collection; +import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -34,9 +36,6 @@ import org.apache.sis.util.ArgumentChecks; * This class provides methods for some tasks considered generic enough, * and example codes for more specialized tasks that developers can customize. * - * <p>The remaining of this class javadoc contains example codes placed in public domain. - * Developers can copy and adapt those examples as they see fit.</p> - * * <h2>Example 1: Reduce the depth of a tree</h2> * For every branch containing exactly one child, the following method concatenates in-place * that branch and its child together. This method can be used for simplifying depth trees into @@ -99,7 +98,7 @@ import org.apache.sis.util.ArgumentChecks; * } * * @author Martin Desruisseaux - * @version 0.3 + * @version 1.5 * * @see TreeTable * @@ -254,6 +253,25 @@ public final class TreeTables extends Static { return changes; } + /** + * Removes all children of the given source, then adds them to the given target. + * Children need to be removed first because they cannot have two parents. + * Caller should ensure that the two tables use the same columns. + * + * @param source source from which to remove children. + * @param target where to add the children. + * + * @since 1.5 + */ + public static void moveChildren(final TreeTable.Node source, final TreeTable.Node target) { + ArgumentChecks.ensureNonNull("source", source); + ArgumentChecks.ensureNonNull("target", target); + final Collection<TreeTable.Node> children = source.getChildren(); + final TreeTable.Node[] array = children.toArray(TreeTable.Node[]::new); + children.clear(); + target.getChildren().addAll(Arrays.asList(array)); + } + /** * Returns a string representation of the given tree table. * The current implementation uses a shared instance of {@link TreeTableFormat}.
