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 8043b8130f1b8394fa951fe11d8d42b552b27458 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Fri Oct 27 15:00:19 2023 +0200 Rearrange the GeoTIFF internal classes in some subpackages in order to provide at least a partial separation between reader and writer classes. --- .../org/apache/sis/storage/geotiff/DataCube.java | 7 +- .../org/apache/sis/storage/geotiff/DataSubset.java | 3 +- .../apache/sis/storage/geotiff/DeferredEntry.java | 2 + .../apache/sis/storage/geotiff/GeoTiffStore.java | 95 ++++++++++++---------- .../sis/storage/geotiff/GeoTiffStoreProvider.java | 8 +- .../storage/geotiff/{GeoTIFF.java => IOBase.java} | 52 +++--------- .../sis/storage/geotiff/ImageFileDirectory.java | 40 ++++++--- .../apache/sis/storage/geotiff/NativeMetadata.java | 15 ++-- .../org/apache/sis/storage/geotiff/Reader.java | 22 ++++- .../org/apache/sis/storage/geotiff/Writer.java | 79 +++++++++--------- .../geotiff/{internal => base}/Compression.java | 2 +- .../sis/storage/geotiff/{ => base}/GeoCodes.java | 33 +++++++- .../sis/storage/geotiff/{ => base}/GeoKeys.java | 19 +---- .../geotiff/{internal => base}/Predictor.java | 2 +- .../geotiff/{internal => base}/Resources.java | 2 +- .../{internal => base}/Resources.properties | 0 .../geotiff/{internal => base}/Resources_en.java | 2 +- .../geotiff/{internal => base}/Resources_fr.java | 2 +- .../{internal => base}/Resources_fr.properties | 0 .../sis/storage/geotiff/{ => base}/Tags.java | 8 +- .../sis/storage/geotiff/{ => base}/UnitKey.java | 16 ++-- .../geotiff/{internal => base}/package-info.java | 4 +- .../geotiff/inflater/CompressionChannel.java | 2 +- .../sis/storage/geotiff/inflater/Inflater.java | 6 +- .../apache/sis/storage/geotiff/inflater/LZW.java | 2 +- .../storage/geotiff/inflater/PredictorChannel.java | 2 +- .../storage/geotiff/{ => reader}/CRSBuilder.java | 50 ++++++++---- .../geotiff/{ => reader}/GeoKeysLoader.java | 34 +++----- .../geotiff/{ => reader}/GridGeometryBuilder.java | 38 +++++---- .../geotiff/{ => reader}/ImageMetadataBuilder.java | 46 ++++------- .../storage/geotiff/{ => reader}/Localization.java | 2 +- .../geotiff/{ => reader}/ReversedBitsChannel.java | 9 +- .../sis/storage/geotiff/{ => reader}/Type.java | 8 +- .../storage/geotiff/{ => reader}/XMLMetadata.java | 39 +++++---- .../geotiff/{internal => reader}/package-info.java | 10 ++- .../{GeoKeysWriter.java => writer/GeoEncoder.java} | 76 +++++++++-------- .../geotiff/{ => writer}/ReformattedImage.java | 22 ++--- .../{TagValueWriter.java => writer/TagValue.java} | 52 ++++++++++-- .../TileMatrix.java} | 22 ++--- .../geotiff/{internal => writer}/package-info.java | 10 ++- .../org/apache/sis/storage/geotiff/WriterTest.java | 11 +-- .../{internal => base}/CompressionTest.java | 2 +- .../storage/geotiff/{ => base}/GeoCodesTest.java | 2 +- .../storage/geotiff/{ => base}/GeoIdentifiers.java | 2 +- .../storage/geotiff/{ => base}/GeoKeysTest.java | 6 +- .../sis/storage/geotiff/{ => base}/TagsTest.java | 2 +- .../geotiff/{ => reader}/CRSBuilderTest.java | 2 +- .../sis/storage/geotiff/{ => reader}/TypeTest.java | 2 +- .../geotiff/{ => reader}/XMLMetadataTest.java | 2 +- .../apache/sis/storage/base/MetadataFetcher.java | 4 +- 50 files changed, 485 insertions(+), 393 deletions(-) diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataCube.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataCube.java index eff8a80e3e..43980dd29e 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataCube.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataCube.java @@ -28,9 +28,10 @@ import org.apache.sis.storage.DataStoreContentException; import org.apache.sis.storage.event.StoreListeners; import org.apache.sis.coverage.grid.GridCoverage; import org.apache.sis.coverage.grid.GridGeometry; -import org.apache.sis.storage.geotiff.internal.Resources; -import org.apache.sis.storage.geotiff.internal.Predictor; -import org.apache.sis.storage.geotiff.internal.Compression; +import org.apache.sis.storage.geotiff.base.Tags; +import org.apache.sis.storage.geotiff.base.Resources; +import org.apache.sis.storage.geotiff.base.Predictor; +import org.apache.sis.storage.geotiff.base.Compression; import org.apache.sis.storage.base.TiledGridResource; import org.apache.sis.storage.base.ResourceOnFileSystem; import org.apache.sis.storage.base.StoreResource; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataSubset.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataSubset.java index def938762b..e58172a29d 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataSubset.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataSubset.java @@ -42,7 +42,8 @@ import org.apache.sis.storage.base.TiledGridResource; import org.apache.sis.coverage.grid.j2d.TilePlaceholder; import org.apache.sis.coverage.grid.j2d.ImageUtilities; import org.apache.sis.coverage.grid.j2d.RasterFactory; -import org.apache.sis.storage.geotiff.internal.Resources; +import org.apache.sis.storage.geotiff.base.Resources; +import org.apache.sis.storage.geotiff.reader.ReversedBitsChannel; import org.apache.sis.util.resources.Errors; import org.apache.sis.math.Vector; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DeferredEntry.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DeferredEntry.java index 7b4c5d9396..b6f719b76f 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DeferredEntry.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DeferredEntry.java @@ -16,6 +16,8 @@ */ package org.apache.sis.storage.geotiff; +import org.apache.sis.storage.geotiff.reader.Type; + /** * Offset to a TIFF tag entry that has not yet been read. diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStore.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStore.java index e6ef201639..b787aac7b2 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStore.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStore.java @@ -19,8 +19,10 @@ package org.apache.sis.storage.geotiff; import java.util.Set; import java.util.List; import java.util.Locale; +import java.util.TimeZone; import java.util.Optional; -import java.util.logging.LogRecord; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.net.URI; import java.io.IOException; import java.nio.charset.Charset; @@ -107,6 +109,18 @@ public class GeoTiffStore extends DataStore implements Aggregate { */ final Locale dataLocale; + /** + * The timezone for the date and time parsing, or {@code null} for the default. + */ + private final TimeZone timezone; + + /** + * The object to use for parsing and formatting dates. Created when first needed. + * + * @see #getDateFormat() + */ + private transient DateFormat dateFormat; + /** * The {@link GeoTiffStoreProvider#LOCATION} parameter value, or {@code null} if none. * This is used for information purpose only, not for actual reading operations. @@ -227,6 +241,7 @@ public class GeoTiffStore extends DataStore implements Aggregate { this.encoding = (encoding != null) ? encoding : StandardCharsets.US_ASCII; dataLocale = connector.getOption(OptionKey.LOCALE); + timezone = connector.getOption(OptionKey.TIMEZONE); location = connector.getStorageAs(URI.class); path = connector.getStorageAs(Path.class); try { @@ -284,8 +299,6 @@ public class GeoTiffStore extends DataStore implements Aggregate { /** * Opens access to listeners for {@link ImageFileDirectory}. - * - * @see #warning(LogRecord) */ final StoreListeners listeners() { return listeners; @@ -424,21 +437,16 @@ public class GeoTiffStore extends DataStore implements Aggregate { } /** - * Returns the exception to throw when an I/O error occurred. - * This method wraps the exception with a {@literal "Cannot read <filename>"} message. + * {@return the object to use for parsing and formatting dates}. */ - final DataStoreException errorIO(final IOException e) { - return new DataStoreException(errors().getString(Errors.Keys.CanNotRead_1, getDisplayName()), e); - } - - /** - * Returns a localized error message saying that this data store has been opened in read-only or write-only mode. - * - * @param mode 0 for read-only, or 1 for write-only. - * @return localized error message. - */ - final String readOrWriteOnly(final int mode) { - return errors().getString(Errors.Keys.OpenedReadOrWriteOnly_2, mode, getDisplayName()); + final DateFormat getDateFormat() { + if (dateFormat == null) { + dateFormat = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss", Locale.US); + if (timezone != null) { + dateFormat.setTimeZone(timezone); + } + } + return dateFormat; } /** @@ -707,6 +715,31 @@ public class GeoTiffStore extends DataStore implements Aggregate { } } + /** + * Returns the error resources in the current locale. + */ + private Errors errors() { + return Errors.getResources(getLocale()); + } + + /** + * Returns the exception to throw when an I/O error occurred. + * This method wraps the exception with a {@literal "Cannot read <filename>"} message. + */ + final DataStoreException errorIO(final IOException e) { + return new DataStoreException(errors().getString(Errors.Keys.CanNotRead_1, getDisplayName()), e); + } + + /** + * Returns a localized error message saying that this data store has been opened in read-only or write-only mode. + * + * @param mode 0 for read-only, or 1 for write-only. + * @return localized error message. + */ + final String readOrWriteOnly(final int mode) { + return errors().getString(Errors.Keys.OpenedReadOrWriteOnly_2, mode, getDisplayName()); + } + /** * Closes this GeoTIFF store and releases any underlying resources. * This method can be invoked asynchronously for interrupting a long reading process. @@ -734,32 +767,4 @@ public class GeoTiffStore extends DataStore implements Aggregate { } } } - - /** - * Returns the error resources in the current locale. - */ - final Errors errors() { - return Errors.getResources(getLocale()); - } - - /** - * Reports a warning contained in the given {@link LogRecord}. - * Note that the given record will not necessarily be sent to the logging framework; - * if the user has registered at least one listener, then the record will be sent to the listeners instead. - * - * <p>This method sets the {@linkplain LogRecord#setSourceClassName(String) source class name} and - * {@linkplain LogRecord#setSourceMethodName(String) source method name} to hard-coded values. - * Those values assume that the warnings occurred indirectly from a call to {@link #getMetadata()} - * in this class. We do not report private classes or methods as the source of warnings.</p> - * - * @param record the warning to report. - * - * @see #listeners() - */ - final void warning(final LogRecord record) { - // Logger name will be set by listeners.warning(record). - record.setSourceClassName(GeoTiffStore.class.getName()); - record.setSourceMethodName("getMetadata"); - listeners.warning(record); - } } diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStoreProvider.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStoreProvider.java index 1c130998e6..b7a5c5d723 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStoreProvider.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStoreProvider.java @@ -135,11 +135,11 @@ public class GeoTiffStoreProvider extends DataStoreProvider { return ProbeResult.INSUFFICIENT_BYTES; } switch (buffer.getShort()) { - case GeoTIFF.LITTLE_ENDIAN: buffer.order(ByteOrder.LITTLE_ENDIAN); // Fall through - case GeoTIFF.BIG_ENDIAN: { // Default buffer order is big endian. + case IOBase.LITTLE_ENDIAN: buffer.order(ByteOrder.LITTLE_ENDIAN); // Fall through + case IOBase.BIG_ENDIAN: { // Default buffer order is big endian. switch (buffer.getShort()) { - case GeoTIFF.CLASSIC: - case GeoTIFF.BIG_TIFF: return new ProbeResult(true, MIME_TYPE, VERSION); + case IOBase.CLASSIC: + case IOBase.BIG_TIFF: return new ProbeResult(true, MIME_TYPE, VERSION); } } } diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTIFF.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/IOBase.java similarity index 57% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTIFF.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/IOBase.java index 493acb1bc5..49d611cccd 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTIFF.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/IOBase.java @@ -17,13 +17,9 @@ package org.apache.sis.storage.geotiff; import java.util.Set; -import java.util.Locale; -import java.util.TimeZone; import java.io.Closeable; -import java.text.DateFormat; -import java.text.SimpleDateFormat; import org.apache.sis.util.resources.Errors; -import org.apache.sis.storage.geotiff.internal.Resources; +import org.apache.sis.storage.geotiff.base.Resources; /** @@ -36,44 +32,29 @@ import org.apache.sis.storage.geotiff.internal.Resources; * @author Johann Sorel (Geomatys) * @author Martin Desruisseaux (Geomatys) */ -abstract class GeoTIFF implements Closeable { - /** - * The timezone for the date and time parsing, or {@code null} for the default. - * This is not yet configurable, but may become in a future version. - */ - private static final TimeZone TIMEZONE = null; - - /** - * The locale to use for parsers or formatter. This is <strong>not</strong> the locale - * for warnings or other messages emitted to the users. - */ - private static final Locale LOCALE = Locale.US; - +abstract class IOBase implements Closeable { /** * The magic number for big-endian TIFF files or little-endian TIFF files. */ - static final short BIG_ENDIAN = 0x4D4D, LITTLE_ENDIAN = 0x4949; + protected static final short BIG_ENDIAN = 0x4D4D, LITTLE_ENDIAN = 0x4949; /** * The magic number for classic (32 bits) or big TIFF (64 bits) files. */ - static final short CLASSIC = 42, BIG_TIFF= 43; + protected static final short CLASSIC = 42, BIG_TIFF= 43; /** * The store which created this reader or writer. * This is also the synchronization lock. */ - final GeoTiffStore store; - - /** - * The object to use for parsing and formatting dates. Created when first needed. - */ - private transient DateFormat dateFormat; + public final GeoTiffStore store; /** * For subclass constructors. + * + * @param store the store which created this reader or writer. */ - GeoTIFF(final GeoTiffStore store) { + protected IOBase(final GeoTiffStore store) { this.store = store; } @@ -85,29 +66,16 @@ abstract class GeoTIFF implements Closeable { public abstract Set<GeoTiffOption> getOptions(); /** - * Returns the resources to use for formatting error messages. + * {@return the resources to use for formatting error messages}. */ final Errors errors() { return Errors.getResources(store.getLocale()); } /** - * Returns the GeoTIFF-specific resource for error messages and warnings. + * {@return the GeoTIFF-specific resource for error messages and warnings}. */ final Resources resources() { return Resources.forLocale(store.getLocale()); } - - /** - * Returns the object to use for parsing and formatting dates. - */ - final DateFormat getDateFormat() { - if (dateFormat == null) { - dateFormat = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss", LOCALE); - if (TIMEZONE != null) { - dateFormat.setTimeZone(TIMEZONE); - } - } - return dateFormat; - } } 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 c24065bca3..a0540b2b90 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 @@ -38,10 +38,13 @@ import org.opengis.referencing.operation.TransformException; import org.apache.sis.referencing.operation.transform.MathTransforms; import org.apache.sis.storage.DataStoreException; import org.apache.sis.storage.DataStoreContentException; -import org.apache.sis.storage.geotiff.internal.Resources; -import org.apache.sis.storage.geotiff.internal.Predictor; -import org.apache.sis.storage.geotiff.internal.Compression; -import org.apache.sis.storage.base.MetadataBuilder; +import org.apache.sis.storage.geotiff.base.Tags; +import org.apache.sis.storage.geotiff.base.Resources; +import org.apache.sis.storage.geotiff.base.Predictor; +import org.apache.sis.storage.geotiff.base.Compression; +import org.apache.sis.storage.geotiff.reader.Type; +import org.apache.sis.storage.geotiff.reader.GridGeometryBuilder; +import org.apache.sis.storage.geotiff.reader.ImageMetadataBuilder; import org.apache.sis.io.stream.ChannelDataInput; import org.apache.sis.coverage.SampleDimension; import org.apache.sis.coverage.grid.GridGeometry; @@ -50,6 +53,7 @@ import org.apache.sis.coverage.grid.j2d.ColorModelFactory; 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.internal.UnmodifiableArrayList; import org.apache.sis.util.internal.Numerics; import org.apache.sis.util.internal.Strings; @@ -460,7 +464,7 @@ final class ImageFileDirectory extends DataCube { /** * Returns the image index used in the default identifier. */ - final String getImageIndex() { + private String getImageIndex() { return String.valueOf(index + 1); } @@ -1007,8 +1011,8 @@ final class ImageFileDirectory extends DataCube { */ case TAG_DATE_TIME: { for (final String value : type.readAsStrings(input(), count, encoding())) { - metadata.addCitationDate(reader.getDateFormat().parse(value), - DateType.CREATION, MetadataBuilder.Scope.RESOURCE); + metadata.addCitationDate(reader.store.getDateFormat().parse(value), + DateType.CREATION, ImageMetadataBuilder.Scope.RESOURCE); } break; } @@ -1126,7 +1130,7 @@ final class ImageFileDirectory extends DataCube { case Tags.GEO_METADATA: case Tags.GDAL_METADATA: { - metadata.addXML(new XMLMetadata(reader, type, count, tag)); + metadata.addXML(reader.readXML(type, count, tag)); break; } case Tags.GDAL_NODATA: { @@ -1373,6 +1377,11 @@ final class ImageFileDirectory extends DataCube { return super.createMetadata(); } this.metadata = null; // Clear now in case an exception happens. + getIdentifier().ifPresent((id) -> { + if (!getImageIndex().equals(id.tip().toString())) { + metadata.addTitle(id.toString()); + } + }); /* * Add information about sample dimensions. * @@ -1404,10 +1413,21 @@ final class ImageFileDirectory extends DataCube { } referencing.completeMetadata(gridGeometry, metadata); } + /* + * Add information about the file format. + * + * Destination: metadata/identificationInfo/resourceFormat + */ + if (reader.store.hidden) { + reader.store.setFormatInfo(metadata); // Should be before `addCompression(…)`. + } + if (compression != null) { + metadata.addCompression(CharSequences.upperCaseToSentence(compression.name())); + } /* * End of metadata construction from TIFF tags. */ - metadata.finish(this, listeners); + metadata.finish(reader.store, listeners); final DefaultMetadata md = metadata.build(); if (isIndexValid) { final Metadata c = reader.store.customizer.customize(index, md); @@ -1458,7 +1478,7 @@ final class ImageFileDirectory extends DataCube { synchronized (getSynchronizationLock()) { if (gridGeometry == null) { if (referencing != null) try { - gridGeometry = referencing.build(reader, imageWidth, imageHeight); + gridGeometry = referencing.build(reader.store.listeners(), imageWidth, imageHeight); } catch (FactoryException e) { throw new DataStoreContentException(reader.resources().getString(Resources.Keys.CanNotComputeGridGeometry_1, filename()), e); } else { diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/NativeMetadata.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/NativeMetadata.java index 8bb2de1fed..bbbaeaadb3 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/NativeMetadata.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/NativeMetadata.java @@ -30,8 +30,13 @@ import org.apache.sis.util.collection.TreeTable; import org.apache.sis.util.collection.TableColumn; import org.apache.sis.util.collection.DefaultTreeTable; import org.apache.sis.io.stream.ChannelDataInput; -import org.apache.sis.storage.geotiff.internal.Compression; -import org.apache.sis.storage.geotiff.internal.Predictor; +import org.apache.sis.storage.geotiff.base.Compression; +import org.apache.sis.storage.geotiff.base.Predictor; +import org.apache.sis.storage.geotiff.base.GeoKeys; +import org.apache.sis.storage.geotiff.base.Tags; +import org.apache.sis.storage.geotiff.reader.Type; +import org.apache.sis.storage.geotiff.reader.GeoKeysLoader; +import org.apache.sis.storage.geotiff.reader.XMLMetadata; import static java.lang.Math.addExact; import static javax.imageio.plugins.tiff.GeoTIFFTagSet.*; @@ -62,12 +67,12 @@ final class NativeMetadata extends GeoKeysLoader { * Column for the name associated to the tag. * Value may be null if the name is unknown. */ - static final TableColumn<CharSequence> NAME = TableColumn.NAME; + private static final TableColumn<CharSequence> NAME = TableColumn.NAME; /** * Column for the value associated to the tag. */ - static final TableColumn<Object> VALUE = TableColumn.VALUE; + private static final TableColumn<Object> VALUE = TableColumn.VALUE; /** * The stream from which to read the data. @@ -174,7 +179,7 @@ final class NativeMetadata extends GeoKeysLoader { } case Tags.GDAL_METADATA: case Tags.GEO_METADATA: { - children = new XMLMetadata(reader, type, count, tag); + children = reader.readXML(type, count, tag); if (children.isEmpty()) { // Fallback on showing array of numerical values. value = type.readAsVector(input, count); diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Reader.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Reader.java index 4901c84c7d..3dda195317 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Reader.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Reader.java @@ -30,7 +30,10 @@ import org.apache.sis.storage.GridCoverageResource; import org.apache.sis.storage.DataStoreException; import org.apache.sis.storage.DataStoreContentException; import org.apache.sis.storage.InternalDataStoreException; -import org.apache.sis.storage.geotiff.internal.Resources; +import org.apache.sis.storage.geotiff.base.Resources; +import org.apache.sis.storage.geotiff.base.Tags; +import org.apache.sis.storage.geotiff.reader.Type; +import org.apache.sis.storage.geotiff.reader.XMLMetadata; import org.apache.sis.util.iso.DefaultNameFactory; import org.apache.sis.util.resources.Errors; @@ -51,7 +54,7 @@ import org.apache.sis.util.resources.Errors; * @author Johann Sorel (Geomatys) * @author Martin Desruisseaux (Geomatys) */ -final class Reader extends GeoTIFF { +final class Reader extends IOBase { /** * The stream from which to read the data. */ @@ -190,7 +193,7 @@ final class Reader extends GeoTIFF { } } // Do not invoke this.errors() yet because GeoTiffStore construction may not be finished. Owner.error() is okay. - throw new DataStoreContentException(store.errors().getString(Errors.Keys.UnexpectedFileFormat_2, "TIFF", input.filename)); + throw new DataStoreContentException(errors().getString(Errors.Keys.UnexpectedFileFormat_2, "TIFF", input.filename)); } /** @@ -443,6 +446,19 @@ final class Reader extends GeoTIFF { return image; } + /** + * Reads metadata that embedded in some TIFF files as XML document. + * + * @param type type of the metadata tag to read. + * @param count number of bytes or characters in the value to read. + * @param tag the tag where the metadata was stored. + * @return the metadata embedded in a XML document. + * @throws IOException if an error occurred while reading the TIFF tag content. + */ + final XMLMetadata readXML(final Type type, final long count, final short tag) throws IOException { + return new XMLMetadata(input, store.encoding, store.listeners(), type, count, tag); + } + /** * Logs a warning about a tag that cannot be read, but does not interrupt the TIFF reading. * diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Writer.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Writer.java index 91b733ceeb..d8dc3aca6b 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Writer.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Writer.java @@ -48,6 +48,10 @@ import org.apache.sis.util.resources.Errors; import org.apache.sis.util.CharSequences; import org.apache.sis.util.ArraysExt; import org.apache.sis.math.Fraction; +import org.apache.sis.storage.geotiff.writer.TagValue; +import org.apache.sis.storage.geotiff.writer.TileMatrix; +import org.apache.sis.storage.geotiff.writer.GeoEncoder; +import org.apache.sis.storage.geotiff.writer.ReformattedImage; import static javax.imageio.plugins.tiff.BaselineTIFFTagSet.*; import static javax.imageio.plugins.tiff.GeoTIFFTagSet.*; @@ -69,7 +73,7 @@ import static javax.imageio.plugins.tiff.GeoTIFFTagSet.*; * @author Erwan Roussel (Geomatys) * @author Martin Desruisseaux (Geomatys) */ -final class Writer extends GeoTIFF implements Flushable { +final class Writer extends IOBase implements Flushable { /** * BigTIFF code for unsigned 64-bits integer type. * @@ -147,7 +151,7 @@ final class Writer extends GeoTIFF implements Flushable { * Write operations for tag having data too large for fitting inside a IFD tag entry. * The writing of those data need to be delayed somewhere after the sequence of entries. */ - private final Queue<TagValueWriter> largeTagData = new ArrayDeque<>(); + private final Queue<TagValue> largeTagData = new ArrayDeque<>(); /** * Number of TIFF tag entries in the image being written. @@ -238,7 +242,7 @@ final class Writer extends GeoTIFF implements Flushable { * {@return the processor to use for reformatting the image before to write it}. * The processor is created only when this method is first invoked. */ - final ImageProcessor processor() { + private ImageProcessor processor() { if (processor == null) { processor = new ImageProcessor(); } @@ -262,9 +266,9 @@ final class Writer extends GeoTIFF implements Flushable { public final long append(final RenderedImage image, final GridGeometry grid, final Metadata metadata) throws IOException, DataStoreException { - final TileMatrixWriter tiles; + final TileMatrix tiles; try { - tiles = writeImageFileDirectory(new ReformattedImage(this, image), grid, metadata, false); + tiles = writeImageFileDirectory(new ReformattedImage(image, this::processor), grid, metadata, false); } finally { largeTagData.clear(); // For making sure that there is no memory retention. } @@ -309,7 +313,7 @@ final class Writer extends GeoTIFF implements Flushable { * @throws DataStoreException if the given {@code image} has a property * which is not supported by TIFF specification or by this writer. */ - private TileMatrixWriter writeImageFileDirectory(final ReformattedImage image, final GridGeometry grid, final Metadata metadata, + private TileMatrix writeImageFileDirectory(final ReformattedImage image, final GridGeometry grid, final Metadata metadata, final boolean overview) throws IOException, DataStoreException { /* @@ -342,14 +346,14 @@ final class Writer extends GeoTIFF implements Flushable { final double[][] statistics = image.statistics(numBands); final short[][] shortStats = toShorts(statistics, sampleFormat); final MetadataFetcher<String> mf = new MetadataFetcher<>(store.dataLocale) { - @Override protected String parseDate(final Date date) { - return getDateFormat().format(date); + @Override protected String convertDate(final Date date) { + return store.getDateFormat().format(date); } }; mf.accept(metadata); - GeoKeysWriter geoKeys = null; + GeoEncoder geoKeys = null; if (grid != null && grid.isDefined(GridGeometry.GRID_TO_CRS)) try { - geoKeys = new GeoKeysWriter(store); + geoKeys = new GeoEncoder(store.listeners()); geoKeys.write(grid, mf); } catch (FactoryException | IncommensurableException | RuntimeException e) { throw new DataStoreReferencingException(e); @@ -395,7 +399,7 @@ final class Writer extends GeoTIFF implements Flushable { if (colorInterpretation == PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR) { writeColorPalette((IndexColorModel) image.visibleBands.getColorModel(), 1L << bitsPerSample[0]); } - final var tiling = new TileMatrixWriter(image.visibleBands, numPlanes, bitsPerSample, offsetIFD); + final var tiling = new TileMatrix(image.visibleBands, numPlanes, bitsPerSample, offsetIFD); writeTag((short) TAG_TILE_WIDTH, (short) TIFFTag.TIFF_LONG, tiling.tileWidth); writeTag((short) TAG_TILE_LENGTH, (short) TIFFTag.TIFF_LONG, tiling.tileHeight); tiling.offsetsTag = writeTag((short) TAG_TILE_OFFSETS, tiling.offsets); @@ -416,11 +420,9 @@ final class Writer extends GeoTIFF implements Flushable { tagCountWriter.setAsLong(numberOfTags); writeOrQueue(tagCountWriter); nextIFD = writeOffset(0); - for (final TagValueWriter tag : largeTagData) { - final UpdatableWrite<?> offset = tag.offset; - offset.setAsLong(output.getStreamPosition()); - writeOrQueue(offset); - tag.write(output); + for (final TagValue tag : largeTagData) { + UpdatableWrite<?> offset = tag.writeHere(output); + if (offset != null) deferredWrites.add(offset); } return tiling; } @@ -509,7 +511,7 @@ final class Writer extends GeoTIFF implements Flushable { buffer.putInt((int) count); return Integer.BYTES; } else { - throw new ArithmeticException(store.errors().getString(Errors.Keys.IntegerOverflow_1, Integer.SIZE)); + throw new ArithmeticException(errors().getString(Errors.Keys.IntegerOverflow_1, Integer.SIZE)); } } @@ -522,14 +524,13 @@ final class Writer extends GeoTIFF implements Flushable { * @throws IOException if an error occurred while writing to the output. * @throws ArithmeticException if the count is too large for the TIFF format in use. */ - private TagValueWriter writeLargeTag(final short tag, final short type, final long count, final TagValueWriter deferred) throws IOException { + private TagValue writeLargeTag(final short tag, final short type, final long count, final TagValue deferred) throws IOException { final long r = writeTagHeader(tag, type, count) - TYPE_SIZES[type] * count; if (r >= 0) { - deferred.offset = UpdatableWrite.of(output); // Record only the position. - deferred.write(output); + deferred.markAndWrite(output); output.repeat(r, (byte) 0); } else { - deferred.offset = writeOffset(0); + deferred.mark(writeOffset(0)); largeTagData.add(deferred); } return deferred; @@ -544,8 +545,8 @@ final class Writer extends GeoTIFF implements Flushable { */ private void writeColorPalette(final IndexColorModel cm, final long count) throws IOException { final int numBands = 3; - writeLargeTag((short) TAG_COLOR_MAP, (short) TIFFTag.TIFF_SHORT, count * numBands, new TagValueWriter() { - @Override void write(final ChannelDataOutput output) throws IOException { + writeLargeTag((short) TAG_COLOR_MAP, (short) TIFFTag.TIFF_SHORT, count * numBands, new TagValue() { + @Override protected void write(final ChannelDataOutput output) throws IOException { final int n = (int) Math.min(cm.getMapSize(), count); for (int band=0; band < numBands; band++) { for (int i=0; i<n; i++) { @@ -595,8 +596,8 @@ final class Writer extends GeoTIFF implements Flushable { } } if (count != 0) { - writeLargeTag(tag, (short) TIFFTag.TIFF_ASCII, count, new TagValueWriter() { - @Override void write(final ChannelDataOutput output) throws IOException { + writeLargeTag(tag, (short) TIFFTag.TIFF_ASCII, count, new TagValue() { + @Override protected void write(final ChannelDataOutput output) throws IOException { for (final byte[] c : chars) { if (c != null) { output.write(c); @@ -623,8 +624,8 @@ final class Writer extends GeoTIFF implements Flushable { if (value == null) { return; } - writeLargeTag(tag, (short) TIFFTag.TIFF_RATIONAL, 1, new TagValueWriter() { - @Override void write(final ChannelDataOutput output) throws IOException { + writeLargeTag(tag, (short) TIFFTag.TIFF_RATIONAL, 1, new TagValue() { + @Override protected void write(final ChannelDataOutput output) throws IOException { output.writeInt(value.numerator); output.writeInt(value.denominator); } @@ -641,12 +642,12 @@ final class Writer extends GeoTIFF implements Flushable { * @return a handler for rewriting the data if the array content changes. * @throws IOException if an error occurred while writing to the output. */ - private TagValueWriter writeTag(final short tag, final short type, final double[] values) throws IOException { + private TagValue writeTag(final short tag, final short type, final double[] values) throws IOException { if (values == null || values.length == 0) { return null; } - return writeLargeTag(tag, type, values.length, new TagValueWriter() { - @Override void write(final ChannelDataOutput output) throws IOException { + return writeLargeTag(tag, type, values.length, new TagValue() { + @Override protected void write(final ChannelDataOutput output) throws IOException { switch (type) { default: throw new AssertionError(type); case TIFFTag.TIFF_DOUBLE: output.writeDoubles(values); break; @@ -670,13 +671,13 @@ final class Writer extends GeoTIFF implements Flushable { * @return a handler for rewriting the data if the array content changes. * @throws IOException if an error occurred while writing to the output. */ - private TagValueWriter writeTag(final short tag, final long[] values) throws IOException { + private TagValue writeTag(final short tag, final long[] values) throws IOException { if (values == null || values.length == 0) { return null; } final short type = isBigTIFF ? TIFF_ULONG : TIFFTag.TIFF_LONG; - return writeLargeTag(tag, type, values.length, new TagValueWriter() { - @Override void write(final ChannelDataOutput output) throws IOException { + return writeLargeTag(tag, type, values.length, new TagValue() { + @Override protected void write(final ChannelDataOutput output) throws IOException { switch (type) { default: throw new AssertionError(type); case TIFF_ULONG: output.writeLongs(values); break; @@ -699,12 +700,12 @@ final class Writer extends GeoTIFF implements Flushable { * @return a handler for rewriting the data if the array content changes. * @throws IOException if an error occurred while writing to the output. */ - private TagValueWriter writeTag(final short tag, final short[] values) throws IOException { + private TagValue writeTag(final short tag, final short[] values) throws IOException { if (values == null || values.length == 0) { return null; } - return writeLargeTag(tag, (short) TIFFTag.TIFF_SHORT, values.length, new TagValueWriter() { - @Override void write(final ChannelDataOutput output) throws IOException { + return writeLargeTag(tag, (short) TIFFTag.TIFF_SHORT, values.length, new TagValue() { + @Override protected void write(final ChannelDataOutput output) throws IOException { output.writeShorts(values); } }); @@ -720,12 +721,12 @@ final class Writer extends GeoTIFF implements Flushable { * @return a handler for rewriting the data if the array content changes. * @throws IOException if an error occurred while writing to the output. */ - private TagValueWriter writeTag(final short tag, final short type, final int[] values) throws IOException { + private TagValue writeTag(final short tag, final short type, final int[] values) throws IOException { if (values == null || values.length == 0) { return null; } - return writeLargeTag(tag, type, values.length, new TagValueWriter() { - @Override void write(final ChannelDataOutput output) throws IOException { + return writeLargeTag(tag, type, values.length, new TagValue() { + @Override protected void write(final ChannelDataOutput output) throws IOException { switch (type) { default: throw new AssertionError(type); case TIFFTag.TIFF_LONG: output.writeInts(values); break; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/Compression.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Compression.java similarity index 99% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/Compression.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Compression.java index f11c10881a..17f0b0ab49 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/Compression.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Compression.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff.internal; +package org.apache.sis.storage.geotiff.base; import static javax.imageio.plugins.tiff.BaselineTIFFTagSet.*; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoCodes.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/GeoCodes.java similarity index 74% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoCodes.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/GeoCodes.java index 80d3e06ba0..e99029508b 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoCodes.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/GeoCodes.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.base; /** @@ -24,7 +24,7 @@ package org.apache.sis.storage.geotiff; * @author Rémi Maréchal (Geomatys) * @author Martin Desruisseaux (Geomatys) */ -final class GeoCodes { +public final class GeoCodes { /** * Do not allow instantiation of this class. */ @@ -45,7 +45,7 @@ final class GeoCodes { * An alternative code for {@link #undefined} found in some GeoTIFF file. * This is not a standard value. This is used only in some methods implemented defensively. */ - static final short missing = -1; + public static final short missing = -1; /* * 6.3.1.1 Model Type Codes @@ -85,4 +85,31 @@ final class GeoCodes { * This is handled as a special case for distinguishing between variants. */ public static final short PolarStereographic = 15; + + /** + * Number of GeoTIFF keys. + * This value is verified by the {@code GeoKeysTest.verifyNumKeys()} test. + * + * <p>This field should be part of {@link GeoKeys}, but is declared here because we + * need to avoid public constants that are not GeoKey names in {@code GeoKeys}.</p> + */ + public static final int NUM_GEOKEYS = 46; + + /** + * Number of GeoTIFF key associated to values of type {@code double}. + * + * <p>This field should be part of {@link GeoKeys}, but is declared here because we + * need to avoid public constants that are not GeoKey names in {@code GeoKeys}.</p> + */ + public static final int NUM_DOUBLE_GEOKEYS = 25; + + /** + * Number of {@code short} values in each GeoKey entry. + */ + public static final int ENTRY_LENGTH = 4; + + /** + * The character used as a separator in {@link String} multi-values. + */ + public static final char STRING_SEPARATOR = '|'; } diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoKeys.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/GeoKeys.java similarity index 93% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoKeys.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/GeoKeys.java index 2762793adc..6abbd6919a 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoKeys.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/GeoKeys.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.base; import java.lang.reflect.Field; import org.opengis.referencing.crs.CoordinateReferenceSystem; @@ -43,7 +43,7 @@ import org.opengis.referencing.operation.MathTransform; * @author Rémi Maréchal (Geomatys) * @author Martin Desruisseaux (Geomatys) */ -final class GeoKeys { +public final class GeoKeys { /** * Do not allow instantiation of this class. */ @@ -105,24 +105,11 @@ final class GeoKeys { /** For user-defined CRS. */ public static final short VerticalDatum = 4098; /** For vertical axis. */ public static final short VerticalUnits = 4099; - /** - * Number of keys. Because keys cannot be repeated, this is the maximal - * number of entries that {@link GeoKeysWriter#keyDirectory} can contain. - * This value is verified by the {@code GeoKeysTest.verifyNumKeys()}. - */ - static final int NUM_KEYS = 46; - - /** - * Number of parameters that are of type {@code double}. - * This is the maximal length of {@link GeoKeysWriter#doubleParams}. - */ - static final int NUM_DOUBLES = 25; - /** * Returns the name of the given key. Implementation of this method is inefficient, * but it should rarely be invoked (mostly for formatting error messages). */ - static String name(final short key) { + public static String name(final short key) { try { for (final Field field : GeoKeys.class.getFields()) { if (field.getType() == Short.TYPE) { diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/Predictor.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Predictor.java similarity index 97% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/Predictor.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Predictor.java index c97846e2be..834169505e 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/Predictor.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Predictor.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff.internal; +package org.apache.sis.storage.geotiff.base; import static javax.imageio.plugins.tiff.BaselineTIFFTagSet.*; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/Resources.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources.java similarity index 99% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/Resources.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources.java index 832cc46ce8..8fc671e7f4 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/Resources.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff.internal; +package org.apache.sis.storage.geotiff.base; import java.io.InputStream; import java.util.Locale; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/Resources.properties b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources.properties similarity index 100% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/Resources.properties rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources.properties diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/Resources_en.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources_en.java similarity index 95% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/Resources_en.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources_en.java index a09db44680..d92caeb33b 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/Resources_en.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources_en.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff.internal; +package org.apache.sis.storage.geotiff.base; /** diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/Resources_fr.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources_fr.java similarity index 95% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/Resources_fr.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources_fr.java index 28ed9111cc..17693ea012 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/Resources_fr.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources_fr.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff.internal; +package org.apache.sis.storage.geotiff.base; /** diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/Resources_fr.properties b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources_fr.properties similarity index 100% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/Resources_fr.properties rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources_fr.properties diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Tags.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Tags.java similarity index 96% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Tags.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Tags.java index b4c38827e7..f301a7a166 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Tags.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Tags.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.base; import java.lang.reflect.Field; import java.util.function.Supplier; @@ -34,7 +34,7 @@ import javax.imageio.plugins.tiff.TIFFTagSet; * * @author Johann Sorel (Geomatys) */ -final class Tags { +public final class Tags { /** * XML packet containing metadata such as descriptions, titles, keywords, author and copyright information. * @@ -92,10 +92,10 @@ final class Tags { } /** - * Returns the name of the given tag. + * {@return the name of the given tag}. * This method should be rarely invoked (mostly for formatting error messages). */ - static String name(final short tag) { + public static String name(final short tag) { final int ti = Short.toUnsignedInt(tag); for (final Supplier<TIFFTagSet> s : TAG_SETS) { final TIFFTag t = s.get().getTag(ti); diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/UnitKey.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/UnitKey.java similarity index 95% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/UnitKey.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/UnitKey.java index 4aacfb1064..b8c4e16c3c 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/UnitKey.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/UnitKey.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.base; import javax.measure.Unit; import org.apache.sis.measure.Units; @@ -27,7 +27,7 @@ import org.apache.sis.util.Workaround; * * @author Martin Desruisseaux (Geomatys) */ -enum UnitKey { +public enum UnitKey { /** * Linear unit in geodetic CRS. Used for * the axes in user-defined geocentric Cartesian CRSs, @@ -84,17 +84,17 @@ enum UnitKey { /** * The {@link GeoKeys} for a unit of measurement defined by an EPSG code, or 0 if none. */ - final short codeKey; + public final short codeKey; /** * The {@link GeoKeys} for a unit of measurement defined by a scale applied on a base unit, or 0 if none. */ - final short scaleKey; + public final short scaleKey; /** * Whether the unit may be associated to coordinate system axes. */ - final boolean isAxis; + public final boolean isAxis; /** * Whether the key accepts linear, angular or scalar units. @@ -129,7 +129,7 @@ enum UnitKey { * @return the unit of measurement of the map projection parameter, or {@link #LINEAR} or {@link #NULL} * if the given parameter is not a map projection parameter. */ - static UnitKey ofProjectionParameter(final short key) { + public static UnitKey ofProjectionParameter(final short key) { switch (key) { case GeoKeys.SemiMajorAxis: case GeoKeys.SemiMinorAxis: return LINEAR; @@ -160,7 +160,7 @@ enum UnitKey { * @param unit unit of measurement of an axis of a geodetic CRS. * @return the key to use for the specified unit, or {@code null} if none. */ - UnitKey validate(final Unit<?> unit) { + public UnitKey validate(final Unit<?> unit) { if ((linear && Units.isLinear (unit)) || (angular && Units.isAngular(unit)) || (scalar && Units.isScale (unit))) @@ -177,7 +177,7 @@ enum UnitKey { /** * {@return the default unit of measurement, or {@code null} if none}. */ - Unit<?> defaultUnit() { + public Unit<?> defaultUnit() { if (linear) return Units.METRE; if (angular) return Units.DEGREE; if (scalar) return Units.UNITY; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/package-info.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/package-info.java similarity index 89% copy from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/package-info.java copy to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/package-info.java index 156321c438..d789ea14da 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/package-info.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/package-info.java @@ -16,7 +16,7 @@ */ /** - * Utility classes for the implementation of GeoTIFF reader and writer. + * Shared classes for the implementation of GeoTIFF reader and writer. * * <STRONG>Do not use!</STRONG> * @@ -25,4 +25,4 @@ * * @author Martin Desruisseaux (Geomatys) */ -package org.apache.sis.storage.geotiff.internal; +package org.apache.sis.storage.geotiff.base; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/CompressionChannel.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/CompressionChannel.java index 08d03c0f2f..87ff92d9fd 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/CompressionChannel.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/CompressionChannel.java @@ -22,7 +22,7 @@ import java.nio.ByteBuffer; import org.apache.sis.math.MathFunctions; import org.apache.sis.util.internal.Numerics; import org.apache.sis.storage.StorageConnector; -import org.apache.sis.storage.geotiff.internal.Resources; +import org.apache.sis.storage.geotiff.base.Resources; import org.apache.sis.io.stream.ChannelDataInput; import org.apache.sis.storage.event.StoreListeners; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/Inflater.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/Inflater.java index 3adadb067f..25dfb9f396 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/Inflater.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/Inflater.java @@ -25,9 +25,9 @@ import org.apache.sis.math.MathFunctions; import org.apache.sis.util.ArgumentChecks; import org.apache.sis.util.internal.Numerics; import org.apache.sis.storage.UnsupportedEncodingException; -import org.apache.sis.storage.geotiff.internal.Compression; -import org.apache.sis.storage.geotiff.internal.Predictor; -import org.apache.sis.storage.geotiff.internal.Resources; +import org.apache.sis.storage.geotiff.base.Compression; +import org.apache.sis.storage.geotiff.base.Predictor; +import org.apache.sis.storage.geotiff.base.Resources; import org.apache.sis.io.stream.ChannelDataInput; import org.apache.sis.storage.event.StoreListeners; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/LZW.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/LZW.java index 7e309ec153..7524ffa147 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/LZW.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/LZW.java @@ -20,7 +20,7 @@ import java.util.Arrays; import java.io.IOException; import java.io.EOFException; import java.nio.ByteBuffer; -import org.apache.sis.storage.geotiff.internal.Resources; +import org.apache.sis.storage.geotiff.base.Resources; import org.apache.sis.io.stream.ChannelDataInput; import org.apache.sis.storage.event.StoreListeners; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/PredictorChannel.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/PredictorChannel.java index c110210883..7624f5e269 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/PredictorChannel.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/PredictorChannel.java @@ -19,7 +19,7 @@ package org.apache.sis.storage.geotiff.inflater; import java.io.IOException; import java.nio.ByteBuffer; import org.apache.sis.util.ArraysExt; -import org.apache.sis.storage.geotiff.internal.Predictor; +import org.apache.sis.storage.geotiff.base.Predictor; import org.apache.sis.pending.jdk.JDK17; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/CRSBuilder.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/CRSBuilder.java similarity index 97% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/CRSBuilder.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/CRSBuilder.java index e3643d7088..1350c57d0b 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/CRSBuilder.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/CRSBuilder.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.reader; import java.util.Arrays; import java.util.Set; @@ -82,7 +82,12 @@ import org.apache.sis.util.resources.Errors; import org.apache.sis.math.Vector; import org.apache.sis.measure.Units; import org.apache.sis.metadata.iso.citation.Citations; -import org.apache.sis.storage.geotiff.internal.Resources; +import org.apache.sis.storage.event.StoreListeners; +import org.apache.sis.storage.geotiff.GeoTiffStore; +import org.apache.sis.storage.geotiff.base.Resources; +import org.apache.sis.storage.geotiff.base.GeoCodes; +import org.apache.sis.storage.geotiff.base.GeoKeys; +import org.apache.sis.storage.geotiff.base.UnitKey; import static org.apache.sis.util.Utilities.equalsIgnoreMetadata; @@ -97,7 +102,7 @@ import static org.apache.sis.util.Utilities.equalsIgnoreMetadata; * @see GeoKeys * @see GeoKeysLoader */ -final class CRSBuilder extends ReferencingFactoryContainer { +public final class CRSBuilder extends ReferencingFactoryContainer { /** * Index where to store the name of the geodetic CRS, the datum, the ellipsoid and the prime meridian. * The GeoTIFF specification has only one key, {@link GeoKeys#GeodeticCitation}, for the geographic CRS @@ -134,10 +139,9 @@ final class CRSBuilder extends ReferencingFactoryContainer { private static final int MIN_KEY_LENGTH = 5; /** - * The reader for which we will create coordinate reference systems. - * This is used for reporting warnings. + * The listeners where to report warnings. */ - private final Reader reader; + private final StoreListeners listeners; /** * Version of the set of keys declared in the {@code GeoKeyDirectory} header. @@ -189,16 +193,23 @@ final class CRSBuilder extends ReferencingFactoryContainer { /** * Creates a new builder of coordinate reference systems. * - * @param reader where to report warnings if any. + * @param listeners the listeners where to report warnings. */ - CRSBuilder(final Reader reader) { - this.reader = reader; + public CRSBuilder(final StoreListeners listeners) { + this.listeners = listeners; geoKeys = new HashMap<>(32); missingGeoKeys = new HashSet<>(); } /** * Reports a warning with a message built from the given resource keys and arguments. + * Note that the record will not necessarily be sent to the logging framework. + * If the user has registered at least one listener, then the record will be sent to the listeners instead. + * + * <p>This method sets the {@linkplain LogRecord#setSourceClassName(String) source class name} and + * {@linkplain LogRecord#setSourceMethodName(String) source method name} to hard-coded values. + * Those values assume that the warnings occurred indirectly from a call to {@link #getMetadata()} + * in this class. We do not report private classes or methods as the source of warnings.</p> * * @param key one of the {@link Resources.Keys} constants. * @param args arguments for the log message. @@ -207,8 +218,11 @@ final class CRSBuilder extends ReferencingFactoryContainer { * @see GeoKeysLoader#warning(short, Object...) */ final void warning(final short key, final Object... args) { - final LogRecord r = reader.resources().getLogRecord(Level.WARNING, key, args); - reader.store.warning(r); + LogRecord record = Resources.forLocale(listeners.getLocale()).getLogRecord(Level.WARNING, key, args); + // Logger name will be set by listeners.warning(record). + record.setSourceClassName(GeoTiffStore.class.getName()); + record.setSourceMethodName("getMetadata"); + listeners.warning(record); } /** @@ -456,7 +470,7 @@ final class CRSBuilder extends ReferencingFactoryContainer { try { expected = Integer.parseInt(id.getCode()); } catch (NumberFormatException e) { - reader.store.listeners().warning(e); // Should not happen. + listeners.warning(e); // Should not happen. return; } if (code != expected) { @@ -578,7 +592,7 @@ final class CRSBuilder extends ReferencingFactoryContainer { if (epsg != null) try { return getCSAuthorityFactory().createCartesianCS(epsg.toString()); } catch (NoSuchAuthorityCodeException e) { - reader.store.listeners().warning(e); + listeners.warning(e); } return (CartesianCS) CoordinateSystems.replaceLinearUnit(cs, unit); } @@ -596,7 +610,7 @@ final class CRSBuilder extends ReferencingFactoryContainer { if (epsg != null) try { return getCSAuthorityFactory().createEllipsoidalCS(epsg.toString()); } catch (NoSuchAuthorityCodeException e) { - reader.store.listeners().warning(e); + listeners.warning(e); } return (EllipsoidalCS) CoordinateSystems.replaceAngularUnit(cs, unit); } @@ -950,7 +964,7 @@ final class CRSBuilder extends ReferencingFactoryContainer { */ static String[] splitName(final String name) { final String[] names = new String[GCRS + 1]; - final String[] components = (String[]) CharSequences.split(name, GeoKeysLoader.SEPARATOR); + final String[] components = (String[]) CharSequences.split(name, GeoCodes.STRING_SEPARATOR); switch (components.length) { case 0: break; case 1: names[GCRS] = name; break; @@ -1404,8 +1418,8 @@ final class CRSBuilder extends ReferencingFactoryContainer { String paramName = toNames.get(Short.toUnsignedInt(key)); if (paramName == null) { paramName = GeoKeys.name(key); - throw new ParameterNotFoundException(reader.errors().getString( - Errors.Keys.UnexpectedParameter_1, paramName), paramName); + throw new ParameterNotFoundException(Errors.getResources(listeners.getLocale()) + .getString(Errors.Keys.UnexpectedParameter_1, paramName), paramName); } final Number value = paramValues.get(key); final Number actual = paramValues.putIfAbsent(paramName, value); @@ -1574,7 +1588,7 @@ final class CRSBuilder extends ReferencingFactoryContainer { @Override public final String toString() { final StringBuilder buffer = new StringBuilder("GeoTIFF keys ").append(majorRevision).append('.') - .append(minorRevision).append(" in ").append(reader.input.filename).append(System.lineSeparator()); + .append(minorRevision).append(" in ").append(listeners.getSourceName()).append(System.lineSeparator()); final TableAppender table = new TableAppender(buffer, " "); for (Map.Entry<Short,Object> entry : geoKeys.entrySet()) { final short key = entry.getKey(); diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoKeysLoader.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/GeoKeysLoader.java similarity index 94% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoKeysLoader.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/GeoKeysLoader.java index 2a62e2a816..869a69c8ba 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoKeysLoader.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/GeoKeysLoader.java @@ -14,12 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.reader; import java.util.Map; import org.apache.sis.math.Vector; import org.apache.sis.util.CharSequences; -import org.apache.sis.storage.geotiff.internal.Resources; +import org.apache.sis.storage.geotiff.base.GeoKeys; +import org.apache.sis.storage.geotiff.base.GeoCodes; +import org.apache.sis.storage.geotiff.base.Resources; import static javax.imageio.plugins.tiff.GeoTIFFTagSet.*; @@ -67,17 +69,7 @@ import static javax.imageio.plugins.tiff.GeoTIFFTagSet.*; * @author Rémi Maréchal (Geomatys) * @author Martin Desruisseaux (Geomatys) */ -class GeoKeysLoader { - /** - * Number of {@code short} values in each GeoKey entry. - */ - static final int ENTRY_LENGTH = 4; - - /** - * The character used as a separator in {@link String} multi-values. - */ - static final char SEPARATOR = '|'; - +public class GeoKeysLoader { /** * References the {@link GeoKeys} needed for building the Coordinate Reference System. * Cannot be null when invoking {@link #load(Map)}. @@ -96,7 +88,7 @@ class GeoKeysLoader { * * @see #setAsciiParameters(String[]) */ - public String asciiParameters; + String asciiParameters; /** * Version of the set of keys declared in the {@code GeoKeyDirectory} header. @@ -114,13 +106,13 @@ class GeoKeysLoader { * Creates a new GeoTIFF keys loader. The {@link #keyDirectory}, {@link #numericParameters} * {@link #asciiParameters} and {@link #logger} fields must be initialized by the caller. */ - GeoKeysLoader() { + protected GeoKeysLoader() { } /** * Sets the value of {@link #asciiParameters} from {@code GeoAsciiParams} value. */ - final void setAsciiParameters(final String[] values) { + public final void setAsciiParameters(final String[] values) { switch (values.length) { case 0: break; case 1: asciiParameters = values[0]; break; @@ -134,10 +126,10 @@ class GeoKeysLoader { * @param geoKeys where to write GeoKeys. * @return whether the operation succeed. */ - final boolean load(final Map<Short,Object> geoKeys) { + protected final boolean load(final Map<Short,Object> geoKeys) { final int numberOfKeys; final int directoryLength = keyDirectory.size(); - if (directoryLength >= ENTRY_LENGTH) { + if (directoryLength >= GeoCodes.ENTRY_LENGTH) { final int version = keyDirectory.intValue(0); if (version != 1) { warning(Resources.Keys.UnsupportedGeoKeyDirectory_1, version); @@ -156,7 +148,7 @@ class GeoKeysLoader { * * (number of key + head) * 4 --- 1 entry = 4 short values. */ - final int expectedLength = (numberOfKeys + 1) * ENTRY_LENGTH; + final int expectedLength = (numberOfKeys + 1) * GeoCodes.ENTRY_LENGTH; if (directoryLength < expectedLength) { warning(Resources.Keys.ListTooShort_3, "GeoKeyDirectory", expectedLength, directoryLength); return false; @@ -168,7 +160,7 @@ class GeoKeysLoader { * because the CRS creation may use them out of order. */ for (int i=1; i <= numberOfKeys; i++) { - final int p = i * ENTRY_LENGTH; + final int p = i * GeoCodes.ENTRY_LENGTH; final short key = keyDirectory.shortValue(p); final int tagLocation = keyDirectory.intValue(p+1); final int count = keyDirectory.intValue(p+2); @@ -254,7 +246,7 @@ class GeoKeysLoader { continue; } upper = CharSequences.skipTrailingWhitespaces(asciiParameters, valueOffset, upper); - while (upper > valueOffset && asciiParameters.charAt(upper - 1) == SEPARATOR) { + while (upper > valueOffset && asciiParameters.charAt(upper - 1) == GeoCodes.STRING_SEPARATOR) { upper--; // Skip trailing pipe, interpreted as C/C++ NUL character. } // Use String.trim() for skipping C/C++ NUL character in addition of whitespaces. diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GridGeometryBuilder.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/GridGeometryBuilder.java similarity index 93% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GridGeometryBuilder.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/GridGeometryBuilder.java index 154496ca06..0afa81fa06 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GridGeometryBuilder.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/GridGeometryBuilder.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.reader; import java.util.NoSuchElementException; import org.opengis.util.FactoryException; @@ -33,7 +33,8 @@ import org.apache.sis.referencing.operation.matrix.MatrixSIS; import org.apache.sis.referencing.operation.matrix.Matrices; import org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory; import org.apache.sis.storage.base.MetadataBuilder; -import org.apache.sis.storage.geotiff.internal.Resources; +import org.apache.sis.storage.event.StoreListeners; +import org.apache.sis.storage.geotiff.base.Resources; import org.apache.sis.util.internal.DoubleDouble; import org.apache.sis.coverage.grid.GridGeometry; import org.apache.sis.coverage.grid.GridExtent; @@ -74,7 +75,7 @@ import org.apache.sis.math.Vector; * * @author Martin Desruisseaux (Geomatys) */ -final class GridGeometryBuilder extends GeoKeysLoader { +public final class GridGeometryBuilder extends GeoKeysLoader { //////////////////////////////////////////////////////////////////////////////////////// //// //// @@ -164,21 +165,21 @@ final class GridGeometryBuilder extends GeoKeysLoader { /** * Suggested value for a general description of the transformation form grid coordinates to "real world" coordinates. - * This information is obtained as a side-effect of {@link #build(Reader, long, long)} call. + * This information is obtained as a side-effect of {@link #build(StoreListeners, long, long)} call. */ private String description; /** * {@code POINT} if {@link GeoKeys#RasterType} is {@link GeoCodes#RasterPixelIsPoint}, * {@code AREA} if it is {@link GeoCodes#RasterPixelIsArea}, or null if unspecified. - * This information is obtained as a side-effect of {@link #build(Reader, long, long)} call. + * This information is obtained as a side-effect of {@link #build(StoreListeners, long, long)} call. */ private CellGeometry cellGeometry; /** * Creates a new builder. */ - GridGeometryBuilder() { + public GridGeometryBuilder() { } /** @@ -249,16 +250,17 @@ final class GridGeometryBuilder extends GeoKeysLoader { * After this method call (if successful), the returned value is guaranteed non-null * and can be used as a flag for determining that the build has been completed. * - * @param width the image width in pixels. - * @param height the image height in pixels. + * @param listeners the listeners where to report warnings. + * @param width the image width in pixels. + * @param height the image height in pixels. * @return the grid geometry, guaranteed non-null. * @throws FactoryException if an error occurred while creating a CRS or a transform. */ @SuppressWarnings("fallthrough") - public GridGeometry build(final Reader reader, final long width, final long height) throws FactoryException { + public GridGeometry build(final StoreListeners listeners, final long width, final long height) throws FactoryException { CoordinateReferenceSystem crs = null; if (keyDirectory != null) { - final CRSBuilder helper = new CRSBuilder(reader); + final CRSBuilder helper = new CRSBuilder(listeners); try { crs = helper.build(this); description = helper.description; @@ -268,10 +270,10 @@ final class GridGeometryBuilder extends GeoKeysLoader { if (e instanceof NoSuchAuthorityCodeException) { key = Resources.Keys.UnknownCRS_1; } - reader.store.listeners().warning(reader.resources().getString(key, reader.store.getDisplayName()), e); + listeners.warning(Resources.forLocale(listeners.getLocale()).getString(key, listeners.getSourceName()), e); } catch (IllegalArgumentException | NoSuchElementException | ClassCastException e) { if (!helper.alreadyReported) { - canNotCreate(reader, e); + canNotCreate(listeners, e); } } } @@ -310,7 +312,7 @@ final class GridGeometryBuilder extends GeoKeysLoader { envelope.setToNaN(); } gridGeometry = new GridGeometry(extent, envelope, GridOrientation.HOMOTHETY); - canNotCreate(reader, e); + canNotCreate(listeners, e); /* * Note: we catch TransformExceptions because they may be caused by erroneous data in the GeoTIFF file, * but let FactoryExceptions propagate because they are more likely to be a SIS configuration problem. @@ -329,7 +331,7 @@ final class GridGeometryBuilder extends GeoKeysLoader { * * <h4>Prerequisite</h4> * <ul> - * <li>{@link #build(Reader, long, long)} must have been invoked successfully before this method.</li> + * <li>{@link #build(StoreListeners, long, long)} must have been invoked successfully before this method.</li> * <li>{@link ImageFileDirectory} must have filled its part of metadata before to invoke this method.</li> * </ul> * @@ -343,7 +345,7 @@ final class GridGeometryBuilder extends GeoKeysLoader { * <li>{@code metadata/referenceSystemInfo}</li> * </ul> * - * @param gridGeometry the grid geometry computed by {@link #build(Reader, long, long)}. + * @param gridGeometry the grid geometry computed by {@link #build(StoreListeners, long, long)}. * @param metadata the helper class where to write metadata values. * @throws NumberFormatException if a numeric value was stored as a string and cannot be parsed. */ @@ -373,8 +375,8 @@ final class GridGeometryBuilder extends GeoKeysLoader { /** * Logs a warning telling that we cannot create a grid geometry for the given reason. */ - private static void canNotCreate(final Reader reader, final Exception e) { - reader.store.listeners().warning(reader.resources().getString( - Resources.Keys.CanNotComputeGridGeometry_1, reader.input.filename), e); + private static void canNotCreate(final StoreListeners listeners, final Exception e) { + listeners.warning(Resources.forLocale(listeners.getLocale()).getString( + Resources.Keys.CanNotComputeGridGeometry_1, listeners.getSourceName()), e); } } diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageMetadataBuilder.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/ImageMetadataBuilder.java similarity index 85% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageMetadataBuilder.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/ImageMetadataBuilder.java index aeaae5d361..b36a14a3c2 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageMetadataBuilder.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/ImageMetadataBuilder.java @@ -14,16 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.reader; import javax.measure.Unit; import javax.measure.quantity.Length; import org.apache.sis.storage.DataStoreException; -import org.apache.sis.storage.geotiff.internal.Resources; -import org.apache.sis.storage.geotiff.internal.Compression; +import org.apache.sis.storage.geotiff.GeoTiffStore; +import org.apache.sis.storage.geotiff.base.Resources; import org.apache.sis.storage.base.MetadataBuilder; import org.apache.sis.storage.event.StoreListeners; -import org.apache.sis.util.CharSequences; import org.apache.sis.util.resources.Errors; import org.apache.sis.measure.Units; @@ -42,7 +41,7 @@ import static javax.imageio.plugins.tiff.BaselineTIFFTagSet.*; * * @author Martin Desruisseaux (Geomatys) */ -final class ImageMetadataBuilder extends MetadataBuilder { +public final class ImageMetadataBuilder extends MetadataBuilder { /** * The number of pixels per {@link #resolutionUnit} in the image width and Height directions, * or {@link Double#NaN} if unspecified. Since ISO 19115 does not have separated resolution @@ -78,7 +77,7 @@ final class ImageMetadataBuilder extends MetadataBuilder { /** * Creates an initially empty metadata builder. */ - ImageMetadataBuilder() { + public ImageMetadataBuilder() { } /** @@ -95,7 +94,7 @@ final class ImageMetadataBuilder extends MetadataBuilder { * @return {@code null} on success, or the given value if not recognized. */ @SuppressWarnings("fallthrough") - Integer setThreshholding(final int value) { + public Integer setThreshholding(final int value) { switch (value) { default: return value; // Cause a warning to be reported by the caller. case THRESHHOLDING_ORDERED_DITHER: { @@ -118,15 +117,17 @@ final class ImageMetadataBuilder extends MetadataBuilder { * @param size the new size. * @param w {@code true} for setting cell width, or {@code false} for setting cell height. */ - void setCellSize(final short size, final boolean w) { + public void setCellSize(final short size, final boolean w) { if (w) cellWidth = size; else cellHeight = size; } /** * Sets the resolution to the maximal of current value and given value. + * + * @param r the resolution. */ - void setResolution(final double r) { + public void setResolution(final double r) { if (Double.isNaN(resolution) || r > resolution) { resolution = r; } @@ -145,7 +146,7 @@ final class ImageMetadataBuilder extends MetadataBuilder { * @param value the threshholding value. * @return {@code null} on success, or the given value if not recognized. */ - Integer setResolutionUnit(final int unit) { + public Integer setResolutionUnit(final int unit) { switch (unit) { case 1: resolutionUnit = null; break; case 2: resolutionUnit = Units.INCH; break; @@ -159,7 +160,7 @@ final class ImageMetadataBuilder extends MetadataBuilder { * Adds metadata in XML format. Those metadata are defined * in {@code GEO_METADATA} or {@code GDAL_METADATA} tags. */ - void addXML(final XMLMetadata xml) { + public void addXML(final XMLMetadata xml) { if (complement == null) { complement = xml; } else { @@ -174,25 +175,7 @@ final class ImageMetadataBuilder extends MetadataBuilder { * * @throws DataStoreException if an error occurred while reading metadata from the data store. */ - void finish(final ImageFileDirectory image, final StoreListeners listeners) throws DataStoreException { - image.getIdentifier().ifPresent((id) -> { - if (!image.getImageIndex().equals(id.tip().toString())) { - addTitle(id.toString()); - } - }); - /* - * Add information about the file format. - * - * Destination: metadata/identificationInfo/resourceFormat - */ - final GeoTiffStore store = image.reader.store; - if (store.hidden) { - store.setFormatInfo(this); // Should be before `addCompression(…)`. - } - final Compression compression = image.getCompression(); - if (compression != null) { - addCompression(CharSequences.upperCaseToSentence(compression.name())); - } + public void finish(final GeoTiffStore store, final StoreListeners listeners) throws DataStoreException { /* * Add the resolution into the metadata. Our current ISO 19115 implementation restricts * the resolution unit to metres, but it may be relaxed in a future SIS version. @@ -238,7 +221,8 @@ final class ImageMetadataBuilder extends MetadataBuilder { while (complement != null) try { complement = complement.appendTo(this); } catch (Exception ex) { - listeners.warning(image.reader.errors().getString(Errors.Keys.CanNotSetPropertyValue_1, complement.tag()), ex); + listeners.warning(Errors.getResources(listeners.getLocale()) + .getString(Errors.Keys.CanNotSetPropertyValue_1, complement.tag()), ex); } } } diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Localization.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/Localization.java similarity index 99% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Localization.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/Localization.java index 234279002d..82974b59c1 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Localization.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/Localization.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.reader; import java.util.Arrays; import java.util.Set; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ReversedBitsChannel.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/ReversedBitsChannel.java similarity index 93% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ReversedBitsChannel.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/ReversedBitsChannel.java index f8dec2fd9a..2b87e5722c 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ReversedBitsChannel.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/ReversedBitsChannel.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.reader; import java.io.IOException; import java.nio.ByteBuffer; @@ -32,7 +32,7 @@ import org.apache.sis.util.resources.Errors; * @author Rémi Maréchal (Geomatys) * @author Martin Desruisseaux (Geomatys) */ -final class ReversedBitsChannel implements ReadableByteChannel, SeekableByteChannel { +public final class ReversedBitsChannel implements ReadableByteChannel, SeekableByteChannel { /** * Lookup table for reversing the order of bits in a byte. */ @@ -61,8 +61,11 @@ final class ReversedBitsChannel implements ReadableByteChannel, SeekableByteChan * but with bits order reversed in every byte. The new channel uses a temporary buffer of relatively * small size because invoking {@link #read(ByteBuffer)} is presumed not too costly for this class, * and because a new buffer is created for each strip or tile to read. + * + * @param input the channel to wrap. + * @return a channel with other of bits reversed. */ - static ChannelDataInput wrap(final ChannelDataInput input) throws IOException { + public static ChannelDataInput wrap(final ChannelDataInput input) throws IOException { final var buffer = ByteBuffer.allocate(2048).order(input.buffer.order()); return new ChannelDataInput(input, new ReversedBitsChannel(input), buffer); } diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Type.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/Type.java similarity index 99% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Type.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/Type.java index 019844d311..b97b204dc6 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Type.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/Type.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.reader; import java.util.Arrays; import java.io.IOException; @@ -39,7 +39,7 @@ import org.apache.sis.util.resources.Errors; * * @author Martin Desruisseaux (Geomatys) */ -enum Type { +public enum Type { /** * An 8-bits byte that may contain anything, depending on the definition of the field. * <ul> @@ -396,7 +396,7 @@ enum Type { /** * The size of this type, in number of bytes. */ - final int size; + public final int size; /** * Whether this type is an unsigned integer. @@ -430,7 +430,7 @@ enum Type { * @param code the GeoTIFF numerical code. * @return the enumeration value that represent the given type, or {@code null} if unknown. */ - static Type valueOf(final int code) { + public static Type valueOf(final int code) { return (code >= 0 && code < FROM_CODES.length) ? FROM_CODES[code] : null; } diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/XMLMetadata.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/XMLMetadata.java similarity index 92% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/XMLMetadata.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/XMLMetadata.java index 6b8910c98a..06464ba596 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/XMLMetadata.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/XMLMetadata.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.reader; import java.util.Locale; import java.util.Iterator; @@ -26,6 +26,7 @@ import java.io.IOException; import java.io.StringReader; import java.io.ByteArrayInputStream; import java.nio.ByteBuffer; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.time.Instant; import javax.xml.stream.XMLEventReader; @@ -38,9 +39,11 @@ import javax.xml.stream.events.StartElement; import javax.xml.transform.stax.StAXSource; import javax.xml.namespace.QName; import jakarta.xml.bind.JAXBException; +import org.apache.sis.io.stream.ChannelDataInput; import org.apache.sis.util.internal.StandardDateFormat; import org.apache.sis.storage.base.MetadataBuilder; import org.apache.sis.storage.event.StoreListeners; +import org.apache.sis.storage.geotiff.base.Tags; import org.apache.sis.util.collection.TreeTable; import org.apache.sis.util.collection.DefaultTreeTable; import org.apache.sis.util.collection.TableColumn; @@ -67,7 +70,7 @@ import static org.apache.sis.metadata.internal.TemporalUtilities.toDate; * * @see <a href="https://www.dgiwg.org/dgiwg-standards">DGIWG Standards</a> */ -final class XMLMetadata implements Filter { +public final class XMLMetadata implements Filter { /** * The {@value} string, used in GDAL metadata. */ @@ -126,17 +129,22 @@ final class XMLMetadata implements Filter { /** * Creates new metadata which will decode the given vector of bytes. * - * @param reader the TIFF reader. - * @param type type of the metadata tag to read. - * @param count number of bytes or characters in the value to read. - * @param tag the tag where the metadata was stored. + * @param input the input channel from which to read the tag. + * @param encoding the encoding of characters (usually US ASCII). + * @param listeners where to report warnings. + * @param type type of the metadata tag to read. + * @param count number of bytes or characters in the value to read. + * @param tag the tag where the metadata was stored. + * @throws IOException if an error occurred while reading the TIFF tag content. */ - XMLMetadata(final Reader reader, final Type type, final long count, final short tag) throws IOException { + public XMLMetadata(final ChannelDataInput input, final Charset encoding, final StoreListeners listeners, + final Type type, final long count, final short tag) throws IOException + { + this.listeners = listeners; isGDAL = (tag == Tags.GDAL_METADATA); - listeners = reader.store.listeners(); switch (type) { case ASCII: { - final String[] cs = type.readAsStrings(reader.input, count, reader.store.encoding); + final String[] cs = type.readAsStrings(input, count, encoding); switch (cs.length) { case 0: break; case 1: string = cs[0]; break; // Usual case. @@ -150,7 +158,7 @@ final class XMLMetadata implements Filter { * NoSuchElementException, ClassCastException and UnsupportedOperationException * should never happen here because we verified that the vector type is byte. */ - bytes = ((ByteBuffer) type.readAsVector(reader.input, count).buffer().get()).array(); + bytes = ((ByteBuffer) type.readAsVector(input, count).buffer().get()).array(); break; } } @@ -189,6 +197,7 @@ final class XMLMetadata implements Filter { /** * Returns the XML document as a character string, or {@code null} if the document could not be read. */ + @Override public String toString() { if (string == null) { if (bytes == null) { @@ -218,7 +227,7 @@ final class XMLMetadata implements Filter { * The root node contains the XML document as a {@linkplain #getUserObject() user object}. * It allows JavaFX application to support the "copy to clipboard" operation. */ - static final class Root extends DefaultTreeTable.Node { + public static final class Root extends DefaultTreeTable.Node { /** * For cross-version compatibility. */ @@ -226,13 +235,15 @@ final class XMLMetadata implements Filter { /** * Column for the name associated to the element. + * Should be same as {@code NativeMetadata.NAME}. */ - private static final TableColumn<CharSequence> NAME = NativeMetadata.NAME; + private static final TableColumn<CharSequence> NAME = TableColumn.NAME; /** * Column for the value associated to the element. + * Should be same as {@code NativeMetadata.VALUE}. */ - private static final TableColumn<Object> VALUE = NativeMetadata.VALUE; + private static final TableColumn<Object> VALUE = TableColumn.VALUE; /** * A string representation of the XML document. @@ -264,7 +275,7 @@ final class XMLMetadata implements Filter { * @param name name to assign to this root node. * @return {@code true} on success, or {@code false} if the XML document could not be decoded. */ - Root(final XMLMetadata source, final DefaultTreeTable.Node parent, final String name) { + public Root(final XMLMetadata source, final DefaultTreeTable.Node parent, final String name) { super(parent); xml = source.toString(); source.currentElement = name; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/package-info.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/package-info.java similarity index 81% copy from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/package-info.java copy to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/package-info.java index 156321c438..32ae036bf1 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/package-info.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/package-info.java @@ -16,13 +16,15 @@ */ /** - * Utility classes for the implementation of GeoTIFF reader and writer. - * - * <STRONG>Do not use!</STRONG> + * Helper classes for the GeoTIFF reader. + * This package does not contain all reader code. + * The main reader class is in the parent package. * * This package is for internal use by SIS only. Classes in this package * may change in incompatible ways in any future version without notice. * * @author Martin Desruisseaux (Geomatys) + * + * @see org.apache.sis.storage.geotiff.Reader */ -package org.apache.sis.storage.geotiff.internal; +package org.apache.sis.storage.geotiff.reader; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoKeysWriter.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/GeoEncoder.java similarity index 93% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoKeysWriter.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/GeoEncoder.java index 38f00f0067..b4f8e3c212 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoKeysWriter.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/GeoEncoder.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.writer; import java.util.List; import java.util.EnumMap; @@ -61,7 +61,11 @@ import org.apache.sis.referencing.util.WKTKeywords; import org.apache.sis.coverage.grid.GridGeometry; import org.apache.sis.coverage.grid.IncompleteGridGeometryException; import org.apache.sis.storage.base.MetadataFetcher; -import org.apache.sis.storage.geotiff.internal.Resources; +import org.apache.sis.storage.geotiff.base.UnitKey; +import org.apache.sis.storage.geotiff.base.GeoKeys; +import org.apache.sis.storage.geotiff.base.GeoCodes; +import org.apache.sis.storage.geotiff.base.Resources; +import org.apache.sis.storage.event.StoreListeners; import org.apache.sis.metadata.iso.citation.Citations; @@ -73,7 +77,7 @@ import org.apache.sis.metadata.iso.citation.Citations; * * @author Martin Desruisseaux (Geomatys) */ -final class GeoKeysWriter { +public final class GeoEncoder { /** * Size of the model transformation matrix, in number of rows and columns. * This size is fixed by the GeoTIFF specification. @@ -81,10 +85,9 @@ final class GeoKeysWriter { private static final int MATRIX_SIZE = 4; /** - * The store for which we are writing GeoTIFF keys. - * Used for logging warnings. + * The listeners where to report warnings. */ - private final GeoTiffStore store; + private final StoreListeners listeners; /** * Overall configuration of the GeoTIFF file, or {@code null} if none. @@ -128,7 +131,7 @@ final class GeoKeysWriter { /** * The key directory, including the header. - * Each entry is a record of {@value GeoKeysLoader#ENTRY_LENGTH} values. + * Each entry is a record of {@value GeoCodes#ENTRY_LENGTH} values. * The first record is a header of the same length. * * @see #keyCount @@ -156,7 +159,7 @@ final class GeoKeysWriter { /** * Parameters to encode as ASCII character strings. - * Strings are separated by the {@value GeoKeysLoader#SEPARATOR} character. + * Strings are separated by the {@value GeoCodes#STRING_SEPARATOR} character. * * @see #asciiParams() */ @@ -185,14 +188,14 @@ final class GeoKeysWriter { * Prepares information for writing GeoTIFF tags for the given grid geometry. * Caller shall invoke {@link #write(GridGeometry, MetadataFetcher)} exactly once after construction. * - * @param store the store for which to write GeoTIFF keys. + * @param listeners the listeners where to report warnings. */ - GeoKeysWriter(final GeoTiffStore store) { - this.store = store; + public GeoEncoder(final StoreListeners listeners) { + this.listeners = listeners; units = new EnumMap<>(UnitKey.class); asciiParams = new StringBuilder(100); - doubleParams = new double[GeoKeys.NUM_DOUBLES]; - keyDirectory = new short[(GeoKeys.NUM_KEYS + 1) * GeoKeysLoader.ENTRY_LENGTH]; + doubleParams = new double[GeoCodes.NUM_DOUBLE_GEOKEYS]; + keyDirectory = new short[(GeoCodes.NUM_GEOKEYS + 1) * GeoCodes.ENTRY_LENGTH]; keyDirectory[0] = 1; // Directory version. keyDirectory[1] = 1; // Revision major number. We implement GeoTIFF 1.1. keyDirectory[2] = 1; // Revision minor number. We implement GeoTIFF 1.1. @@ -210,7 +213,7 @@ final class GeoKeysWriter { * @throws IncommensurableException if a measure uses an unexpected unit of measurement. * @throws IncompleteGridGeometryException if the grid geometry is incomplete. */ - final void write(final GridGeometry grid, final MetadataFetcher<?> metadata) + public void write(final GridGeometry grid, final MetadataFetcher<?> metadata) throws FactoryException, IncommensurableException { citation = CollectionsExt.first(metadata.transformationDimension); @@ -422,7 +425,7 @@ final class GeoKeysWriter { if (type != null) { final Unit<?> previous = units.putIfAbsent(type, unit); if (previous != null && !previous.equals(unit)) { - warning(store.errors().getString(Errors.Keys.HeterogynousUnitsIn_1, name(cs)), null); + warning(errors().getString(Errors.Keys.HeterogynousUnitsIn_1, name(cs)), null); } } else { cannotEncode(2, unit.toString(), null); @@ -465,7 +468,7 @@ final class GeoKeysWriter { } writeString(key, name); citationMainKey = type; - citationLengthIndex = keyCount * GeoKeysLoader.ENTRY_LENGTH + 2; // Length is the field #2. + citationLengthIndex = keyCount * GeoCodes.ENTRY_LENGTH + 2; // Length is the field #2. } /** @@ -489,7 +492,7 @@ final class GeoKeysWriter { length += value.length(); citationMainKey = null; } - final String value = GeoKeysLoader.SEPARATOR + type + '=' + name; + final String value = GeoCodes.STRING_SEPARATOR + type + '=' + name; asciiParams.insert(offset + length, value); keyDirectory[i] = toShort(length += value.length()); /* @@ -499,10 +502,10 @@ final class GeoKeysWriter { * after citation, but we keep it in case a future GeoTIFF version adds more ASCII entries. */ final int shift = length - start; - final int limit = keyCount * GeoKeysLoader.ENTRY_LENGTH; // Inclusive. + final int limit = keyCount * GeoCodes.ENTRY_LENGTH; // Inclusive. i++; // Offset is the field after length. while (i < limit) { - i += GeoKeysLoader.ENTRY_LENGTH; // Really after (i < limit) test. + i += GeoCodes.ENTRY_LENGTH; // Really after (i < limit) test. if (keyDirectory[i-2] == (short) TAG_GEO_ASCII_PARAMS) { offset = Short.toUnsignedInt(keyDirectory[i]); keyDirectory[i] = toShort(offset + shift); @@ -527,7 +530,7 @@ final class GeoKeysWriter { if (id != null) try { return Short.parseShort(id.getCode()); } catch (NumberFormatException e) { - warning(store.errors().getString(Errors.Keys.CanNotParse_1, IdentifiedObjects.toString(id)), e); + warning(errors().getString(Errors.Keys.CanNotParse_1, IdentifiedObjects.toString(id)), e); } return GeoCodes.userDefined; } @@ -586,7 +589,7 @@ final class GeoKeysWriter { * @param value the value to store. */ private void writeShort(final short key, final short value) { - int i = ++keyCount * GeoKeysLoader.ENTRY_LENGTH; + int i = ++keyCount * GeoCodes.ENTRY_LENGTH; keyDirectory[i++] = key; // Key identifier. keyDirectory[++i] = 1; // Number of values in this key. keyDirectory[++i] = value; // Value offset. In this particular case, contains directly the value. @@ -599,7 +602,7 @@ final class GeoKeysWriter { * @param value the value to store. */ private void writeDouble(final short key, final double value) { - int i = ++keyCount * GeoKeysLoader.ENTRY_LENGTH; + int i = ++keyCount * GeoCodes.ENTRY_LENGTH; keyDirectory[i++] = key; // Key identifier. keyDirectory[i++] = (short) TAG_GEO_DOUBLE_PARAMS; // TIFF tag location. keyDirectory[i++] = 1; // Number of values in this key. @@ -614,12 +617,12 @@ final class GeoKeysWriter { * @param value the value to store. */ private void writeString(final short key, final String value) { - int i = ++keyCount * GeoKeysLoader.ENTRY_LENGTH; + int i = ++keyCount * GeoCodes.ENTRY_LENGTH; keyDirectory[i++] = key; // Key identifier. keyDirectory[i++] = (short) TAG_GEO_ASCII_PARAMS; // TIFF tag location. keyDirectory[i++] = toShort(value.length()); // Number of values in this key. keyDirectory[i ] = toShort(asciiParams.length()); // Offset of the first character. - asciiParams.append(value).append(GeoKeysLoader.SEPARATOR); + asciiParams.append(value).append(GeoCodes.STRING_SEPARATOR); } /** @@ -641,16 +644,16 @@ final class GeoKeysWriter { /** * {@return the values to write in the "GeoTIFF keys directory" tag}. */ - final short[] keyDirectory() { + public short[] keyDirectory() { if (keyCount == 0) return null; - keyDirectory[GeoKeysLoader.ENTRY_LENGTH - 1] = (short) keyCount; - return ArraysExt.resize(keyDirectory, (keyCount + 1) * GeoKeysLoader.ENTRY_LENGTH); + keyDirectory[GeoCodes.ENTRY_LENGTH - 1] = (short) keyCount; + return ArraysExt.resize(keyDirectory, (keyCount + 1) * GeoCodes.ENTRY_LENGTH); } /** * {@return the values to write in the "GeoTIFF double-precision parameters" tag}. */ - final double[] doubleParams() { + public double[] doubleParams() { if (doubleCount == 0) return null; return ArraysExt.resize(doubleParams, doubleCount); } @@ -658,7 +661,7 @@ final class GeoKeysWriter { /** * {@return the values to write in the "GeoTIFF ASCII strings" tag}. */ - final List<String> asciiParams() { + public List<String> asciiParams() { if (asciiParams.length() == 0) return null; // TODO: replace by isEmpty() with JDK15. return List.of(asciiParams.toString()); } @@ -668,7 +671,7 @@ final class GeoKeysWriter { * Array length is fixed to 16 elements, for a 4×4 matrix in row-major order. * Axis order is fixed to (longitude, latitude, height). */ - final double[] modelTransformation() { + public double[] modelTransformation() { if (gridToCRS == null) { return null; } @@ -728,14 +731,21 @@ final class GeoKeysWriter { * @return the object name. */ private String name(final IdentifiedObject object) { - return IdentifiedObjects.getDisplayName(object, store.getLocale()); + return IdentifiedObjects.getDisplayName(object, listeners.getLocale()); + } + + /** + * {@return the resources for error messages in the current locale}. + */ + private Errors errors() { + return Errors.getResources(listeners.getLocale()); } /** * {@return the resources in the current locale}. */ private Resources resources() { - return Resources.forLocale(store.getLocale()); + return Resources.forLocale(listeners.getLocale()); } /** @@ -775,7 +785,7 @@ final class GeoKeysWriter { * @param cause the reason why a warning occurred, or {@code null} if none. */ private void warning(final String message, final Exception cause) { - store.listeners().warning(message, cause); + listeners.warning(message, cause); } /** diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ReformattedImage.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/ReformattedImage.java similarity index 88% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ReformattedImage.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/ReformattedImage.java index 9bb0cf275f..a7008d005e 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ReformattedImage.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/ReformattedImage.java @@ -14,8 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.writer; +import java.util.function.Supplier; import java.awt.color.ColorSpace; import java.awt.image.ColorModel; import java.awt.image.IndexColorModel; @@ -25,6 +26,7 @@ import static javax.imageio.plugins.tiff.BaselineTIFFTagSet.*; import org.apache.sis.util.ArraysExt; import org.apache.sis.math.Statistics; import org.apache.sis.image.PlanarImage; +import org.apache.sis.image.ImageProcessor; import org.apache.sis.coverage.grid.j2d.ImageUtilities; import org.apache.sis.storage.IncompatibleResourceException; @@ -37,11 +39,11 @@ import org.apache.sis.storage.IncompatibleResourceException; * * @author Martin Desruisseaux (Geomatys) */ -final class ReformattedImage { +public final class ReformattedImage { /** * The main image with visible bands. */ - final RenderedImage visibleBands; + public final RenderedImage visibleBands; /* * TODO: alpha and extra bands not yet stored. @@ -53,10 +55,10 @@ final class ReformattedImage { * The visible image will have at most 3 bands and should have no alpha channel. * If no change is needed, then the given image is used unchanged. * - * @param writer the writer for which to separate in image. - * @param image the image to separate into visible, alpha and extra bands. + * @param image the image to separate into visible, alpha and extra bands. + * @param processor supplier of the image processor to use if the image must be transformed. */ - ReformattedImage(final Writer writer, final RenderedImage image) { + public ReformattedImage(final RenderedImage image, final Supplier<ImageProcessor> processor) { final int numBands = ImageUtilities.getNumBands(image); select: if (numBands > 1) { final int[] bands; @@ -73,7 +75,7 @@ select: if (numBands > 1) { } bands = ArraysExt.range(0, max); } - visibleBands = writer.processor().selectBands(image, bands); + visibleBands = processor.get().selectBands(image, bands); return; } visibleBands = image; @@ -87,7 +89,7 @@ select: if (numBands > 1) { * @return statistics in an array of length 2, with minimums first then maximums. * Array elements may be {@code null} if there is no statistics. */ - final double[][] statistics(final int numBands) { + public double[][] statistics(final int numBands) { final Object property = visibleBands.getProperty(PlanarImage.STATISTICS_KEY); found: if (property instanceof Statistics[]) { final var stats = (Statistics[]) property; @@ -109,7 +111,7 @@ found: if (property instanceof Statistics[]) { * * @return One of {@code SAMPLE_FORMAT_*} constants. */ - final int getSampleFormat() { + public int getSampleFormat() { final SampleModel sm = visibleBands.getSampleModel(); if (ImageUtilities.isUnsignedType(sm)) return SAMPLE_FORMAT_UNSIGNED_INTEGER; if (ImageUtilities.isIntegerType(sm)) return SAMPLE_FORMAT_SIGNED_INTEGER; @@ -122,7 +124,7 @@ found: if (property instanceof Statistics[]) { * @return One of {@code PHOTOMETRIC_INTERPRETATION_*} constants. * @throws IncompatibleResourceException if the color model is not supported. */ - final int getColorInterpretation() throws IncompatibleResourceException { + public int getColorInterpretation() throws IncompatibleResourceException { final ColorModel cm = visibleBands.getColorModel(); if (cm instanceof IndexColorModel) { final var icm = (IndexColorModel) cm; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/TagValueWriter.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/TagValue.java similarity index 56% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/TagValueWriter.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/TagValue.java index f46e6fffb1..07136c568c 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/TagValueWriter.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/TagValue.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.writer; import java.io.IOException; import org.apache.sis.io.stream.UpdatableWrite; @@ -28,26 +28,62 @@ import org.apache.sis.io.stream.ChannelDataOutput; * * @author Martin Desruisseaux (Geomatys) */ -abstract class TagValueWriter { +public abstract class TagValue { /** * A handler for writing the position of tag values when this position will become known. - * This is initialized by {@link Writer#writeLargeTag(short, short, long, TagValueWriter)}. + * This is initialized by {@link Writer#writeLargeTag(short, short, long, TagValue)}. */ - UpdatableWrite<?> offset; + private UpdatableWrite<?> offset; /** * Creates a new container for the values of a tag. */ - TagValueWriter() { + public TagValue() { } /** * Writes the values of the tag at the current position of the given output stream. * - * @param output the {@link Writer#output} value, provided for convenience. + * @param output the stream where to write tag values. + * @throws IOException if an error occurred while writing the tag values. + */ + protected abstract void write(ChannelDataOutput output) throws IOException; + + /** + * Remembers the position where the tag will be written. + * + * @param offset a handler for writing the position. + */ + public final void mark(final UpdatableWrite<?> offset) { + this.offset = offset; + } + + /** + * Remembers the current stream position, then writes the values of the tag. + * + * @param output the stream where to write tag values. * @throws IOException if an error occurred while writing the tag values. */ - abstract void write(ChannelDataOutput output) throws IOException; + public final void markAndWrite(final ChannelDataOutput output) throws IOException { + offset = UpdatableWrite.of(output); // Record only the position. + write(output); + } + + /** + * Writes at the current position and update the pointer to that position. + * If the pointer can be updated immediately, this method returns {@code null}. + * Otherwise this method returns a handler for updating the pointer later. + * + * @param output the stream where to write tag values. + * @return a handler for updating the position if it couldn't be written now. + * @throws IOException if an error occurred while writing the tag values. + */ + public final UpdatableWrite<?> writeHere(final ChannelDataOutput output) throws IOException { + offset.setAsLong(output.getStreamPosition()); + boolean done = offset.tryUpdateBuffer(output); + write(output); + return done ? null : offset; + } /** * Writes again the values at the same offset than previously. @@ -56,7 +92,7 @@ abstract class TagValueWriter { * @param output the stream where to write tag values. * @throws IOException if an error occurred while writing the tag values. * - * @see TileMatrixWriter#isLengthChanged() + * @see TileMatrix#isLengthChanged() */ final void rewrite(final ChannelDataOutput output) throws IOException { /* diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/TileMatrixWriter.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/TileMatrix.java similarity index 93% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/TileMatrixWriter.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/TileMatrix.java index 9843019ba6..ed080fb0ef 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/TileMatrixWriter.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/TileMatrix.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.writer; import java.util.Arrays; import java.io.IOException; @@ -44,11 +44,11 @@ import org.apache.sis.io.stream.HyperRectangleWriter; * * @author Martin Desruisseaux (Geomatys) */ -final class TileMatrixWriter { +public final class TileMatrix { /** * Offset in {@link ChannelDataOutput} where the IFD starts. */ - final long offsetIFD; + public final long offsetIFD; /** * The images to write. @@ -73,7 +73,7 @@ final class TileMatrixWriter { /** * Size of each tile. */ - final int tileWidth, tileHeight; + public final int tileWidth, tileHeight; /** * Uncompressed size of tiles in number of bytes, as an unsigned integer. @@ -83,17 +83,17 @@ final class TileMatrixWriter { /** * Compressed size of each tile in number of bytes, as unsigned integers. */ - final int[] lengths; + public final int[] lengths; /** * Offsets to each tiles. Not necessarily in increasing order (it depends on tile order). */ - final long[] offsets; + public final long[] offsets; /** * Tags where are stored offsets and lengths. */ - TagValueWriter offsetsTag, lengthsTag; + public TagValue offsetsTag, lengthsTag; /** * Creates a new set of information about tiles to write. @@ -104,8 +104,8 @@ final class TileMatrixWriter { * @param isPlanar whether the planar configuration is to store bands in separated planes. * @param offsetIFD offset in {@link ChannelDataOutput} where the IFD starts. */ - TileMatrixWriter(final RenderedImage image, final int numPlanes, final int[] bitsPerSample, - final long offsetIFD) + public TileMatrix(final RenderedImage image, final int numPlanes, final int[] bitsPerSample, + final long offsetIFD) { final int pixelSize, numArrays; this.offsetIFD = offsetIFD; @@ -131,7 +131,7 @@ final class TileMatrixWriter { * * @throws IOException if an error occurred while writing to the output stream. */ - final void writeOffsetsAndLengths(final ChannelDataOutput output) throws IOException { + public void writeOffsetsAndLengths(final ChannelDataOutput output) throws IOException { offsetsTag.rewrite(output); for (int value : lengths) { if (value != tileSize) { @@ -149,7 +149,7 @@ final class TileMatrixWriter { * @param output where to write the tiles data. * @throws IOException if an error occurred while writing to the given output. */ - final void writeRasters(final ChannelDataOutput output) throws IOException { + public void writeRasters(final ChannelDataOutput output) throws IOException { SampleModel sm = null; int[] bankIndices = null; HyperRectangleWriter rect = null; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/package-info.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/package-info.java similarity index 81% rename from endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/package-info.java rename to endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/package-info.java index 156321c438..d0625e6a05 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/internal/package-info.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/package-info.java @@ -16,13 +16,15 @@ */ /** - * Utility classes for the implementation of GeoTIFF reader and writer. - * - * <STRONG>Do not use!</STRONG> + * Helper classes for the GeoTIFF writer. + * This package does not contain all writer code. + * The main writer class is in the parent package. * * This package is for internal use by SIS only. Classes in this package * may change in incompatible ways in any future version without notice. * * @author Martin Desruisseaux (Geomatys) + * + * @see org.apache.sis.storage.geotiff.Writer */ -package org.apache.sis.storage.geotiff.internal; +package org.apache.sis.storage.geotiff.writer; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/WriterTest.java b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/WriterTest.java index 8481ec8d0e..a6e235f514 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/WriterTest.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/WriterTest.java @@ -37,6 +37,7 @@ import org.apache.sis.io.stream.ByteArrayChannel; import org.apache.sis.io.stream.ChannelDataOutput; import org.apache.sis.storage.DataStoreException; import org.apache.sis.storage.StorageConnector; +import org.apache.sis.storage.geotiff.base.Tags; import org.apache.sis.coverage.grid.GridExtent; import org.apache.sis.coverage.grid.GridGeometry; import org.apache.sis.coverage.grid.GridOrientation; @@ -182,7 +183,7 @@ public final class WriterTest extends TestCase { public void testUntiledGrayScale() throws IOException, DataStoreException { initialize(DataType.BYTE, ByteOrder.BIG_ENDIAN, false, 1, 1, 1); writeImage(); - verifyHeader(false, GeoTIFF.BIG_ENDIAN); + verifyHeader(false, IOBase.BIG_ENDIAN); verifyImageFileDirectory(Writer.MINIMAL_NUMBER_OF_TAGS, PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO, new short[] {Byte.SIZE}); verifySampleValues(1); @@ -199,7 +200,7 @@ public final class WriterTest extends TestCase { public void testUntiledBigTIFF() throws IOException, DataStoreException { initialize(DataType.BYTE, ByteOrder.LITTLE_ENDIAN, false, 1, 1, 1, GeoTiffOption.BIG_TIFF); writeImage(); - verifyHeader(true, GeoTIFF.LITTLE_ENDIAN); + verifyHeader(true, IOBase.LITTLE_ENDIAN); verifyImageFileDirectory(Writer.MINIMAL_NUMBER_OF_TAGS, PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO, new short[] {Byte.SIZE}); verifySampleValues(1); @@ -217,7 +218,7 @@ public final class WriterTest extends TestCase { public void testTiledGrayScale() throws IOException, DataStoreException { initialize(DataType.BYTE, ByteOrder.LITTLE_ENDIAN, false, 1, 3, 4); writeImage(); - verifyHeader(false, GeoTIFF.LITTLE_ENDIAN); + verifyHeader(false, IOBase.LITTLE_ENDIAN); verifyImageFileDirectory(Writer.MINIMAL_NUMBER_OF_TAGS, PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO, new short[] {Byte.SIZE}); verifySampleValues(1); @@ -235,7 +236,7 @@ public final class WriterTest extends TestCase { initialize(DataType.BYTE, ByteOrder.LITTLE_ENDIAN, false, 3, 1, 1); image.setColorModel(ColorModelFactory.createRGB(image.getSampleModel())); writeImage(); - verifyHeader(false, GeoTIFF.LITTLE_ENDIAN); + verifyHeader(false, IOBase.LITTLE_ENDIAN); verifyImageFileDirectory(Writer.MINIMAL_NUMBER_OF_TAGS, PHOTOMETRIC_INTERPRETATION_RGB, new short[] {Byte.SIZE, Byte.SIZE, Byte.SIZE}); verifySampleValues(3); @@ -253,7 +254,7 @@ public final class WriterTest extends TestCase { initialize(DataType.BYTE, ByteOrder.LITTLE_ENDIAN, false, 1, 1, 1); createGridGeometry(); writeImage(); - verifyHeader(false, GeoTIFF.LITTLE_ENDIAN); + verifyHeader(false, IOBase.LITTLE_ENDIAN); verifyImageFileDirectory(Writer.MINIMAL_NUMBER_OF_TAGS + 3, // GeoTIFF adds 3 tags. PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO, new short[] {Byte.SIZE}); verifySampleValues(1); diff --git a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/internal/CompressionTest.java b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/base/CompressionTest.java similarity index 96% rename from endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/internal/CompressionTest.java rename to endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/base/CompressionTest.java index 59b8d1837d..9191f906e0 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/internal/CompressionTest.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/base/CompressionTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff.internal; +package org.apache.sis.storage.geotiff.base; // Test dependencies import org.junit.Test; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/GeoCodesTest.java b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/base/GeoCodesTest.java similarity index 98% rename from endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/GeoCodesTest.java rename to endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/base/GeoCodesTest.java index dc7d67b151..a89cc35885 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/GeoCodesTest.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/base/GeoCodesTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.base; import org.opengis.util.FactoryException; import org.opengis.parameter.ParameterDescriptorGroup; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/GeoIdentifiers.java b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/base/GeoIdentifiers.java similarity index 99% rename from endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/GeoIdentifiers.java rename to endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/base/GeoIdentifiers.java index d357f1cd05..a009f2d86b 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/GeoIdentifiers.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/base/GeoIdentifiers.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.base; import java.lang.reflect.Field; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/GeoKeysTest.java b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/base/GeoKeysTest.java similarity index 97% rename from endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/GeoKeysTest.java rename to endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/base/GeoKeysTest.java index ef149eede8..955a15831c 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/GeoKeysTest.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/base/GeoKeysTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.base; import java.util.Set; import java.lang.reflect.Field; @@ -129,11 +129,11 @@ public final class GeoKeysTest extends TestCase { } /** - * Verifies the value of {@link GeoKeys#NUM_KEYS}. + * Verifies the value of {@link GeoCodes#NUM_GEOKEYS}. */ @Test public void verifyNumKeys() { final Field[] fields = GeoKeys.class.getFields(); // Include only public fields. - assertEquals(fields.length, GeoKeys.NUM_KEYS); + assertEquals(fields.length, GeoCodes.NUM_GEOKEYS); } } diff --git a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/TagsTest.java b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/base/TagsTest.java similarity index 97% rename from endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/TagsTest.java rename to endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/base/TagsTest.java index b89acd17ef..2f3ba3797e 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/TagsTest.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/base/TagsTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.base; // Test dependencies import org.junit.Test; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/CRSBuilderTest.java b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/reader/CRSBuilderTest.java similarity index 98% rename from endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/CRSBuilderTest.java rename to endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/reader/CRSBuilderTest.java index 6f431df2e7..a4789b2b6a 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/CRSBuilderTest.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/reader/CRSBuilderTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.reader; // Test dependencies import org.junit.Test; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/TypeTest.java b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/reader/TypeTest.java similarity index 98% rename from endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/TypeTest.java rename to endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/reader/TypeTest.java index 695e052905..2d98989c87 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/TypeTest.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/reader/TypeTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.reader; import org.apache.sis.io.stream.ChannelDataInput; diff --git a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/XMLMetadataTest.java b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/reader/XMLMetadataTest.java similarity index 99% rename from endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/XMLMetadataTest.java rename to endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/reader/XMLMetadataTest.java index 8be6dcd852..e3c2f05aab 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/XMLMetadataTest.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/reader/XMLMetadataTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.storage.geotiff; +package org.apache.sis.storage.geotiff.reader; import org.apache.sis.metadata.iso.DefaultMetadata; import org.apache.sis.storage.base.MetadataBuilder; diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataFetcher.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataFetcher.java index 0784362639..d02ccefe7c 100644 --- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataFetcher.java +++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataFetcher.java @@ -219,7 +219,7 @@ public abstract class MetadataFetcher<T> { protected boolean accept(final CitationDate info) { if (creationDate == null) { if (DateType.CREATION.equals(info.getDateType())) { - creationDate = List.of(parseDate(info.getDate())); + creationDate = List.of(convertDate(info.getDate())); } else { return false; // Search another date. } @@ -391,5 +391,5 @@ public abstract class MetadataFetcher<T> { * @param date the date to convert. * @return subclass-dependent object representing the given date. */ - protected abstract T parseDate(final Date date); + protected abstract T convertDate(final Date date); }