This is an automated email from the ASF dual-hosted git repository. asf-gitbox-commits pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
commit 35d0e9d06ea9996369c5b449ef4063d8c61ad679 Author: jsorel <[email protected]> AuthorDate: Wed Jun 3 15:27:39 2026 +0200 feat(GeoHeif): support auxilary prj and hfw files --- .../sis/storage/geoheif/CoverageBuilder.java | 74 ++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/CoverageBuilder.java b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/CoverageBuilder.java index ab53ba7e16..46c18e7320 100644 --- a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/CoverageBuilder.java +++ b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/CoverageBuilder.java @@ -32,6 +32,12 @@ import java.awt.Dimension; import java.awt.image.ColorModel; import java.awt.image.SampleModel; import java.awt.image.RasterFormatException; +import java.io.EOFException; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; import javax.imageio.ImageTypeSpecifier; import org.opengis.util.GenericName; import org.opengis.referencing.crs.CoordinateReferenceSystem; @@ -44,6 +50,7 @@ import org.apache.sis.coverage.SampleDimension; import org.apache.sis.coverage.grid.GridExtent; import org.apache.sis.coverage.grid.GridGeometry; import org.apache.sis.coverage.grid.PixelInCell; +import org.apache.sis.io.stream.IOUtilities; import org.apache.sis.storage.DataStoreException; import org.apache.sis.storage.metadata.MetadataBuilder; import org.apache.sis.storage.modifier.CoverageModifier; @@ -66,8 +73,14 @@ import org.apache.sis.util.collection.Containers; import org.apache.sis.util.internal.shared.Numerics; import org.apache.sis.util.resources.Errors; import org.apache.sis.pending.jdk.JDK18; +import org.apache.sis.referencing.CRS; +import org.apache.sis.referencing.internal.shared.AffineTransform2D; +import org.apache.sis.storage.*; +import org.apache.sis.storage.base.AuxiliaryContent; import org.apache.sis.storage.isobmff.mpeg.CompressedUnitsItemInfo; import org.apache.sis.storage.isobmff.mpeg.CompressionConfiguration; +import org.apache.sis.util.CharSequences; +import org.opengis.util.FactoryException; /** @@ -713,10 +726,25 @@ final class CoverageBuilder implements Emptiable { MathTransform gridToCRS = null; if (affine != null) { gridToCRS = affine.toMathTransform(); + } else { + try { + gridToCRS = readWorldFile("hfw"); + } catch (URISyntaxException | IOException ex) { + throw new DataStoreException(ex); + } } CoordinateReferenceSystem crs = null; if (crsDefinition != null) { crs = crsDefinition.toCRS(store.listeners()); // May stil be null. + } else { + try { + AuxiliaryContent aux = store.readAuxiliaryPath("prj"); + crs = CRS.fromWKT(aux.toString()); + } catch (NoSuchFileException e) { + //no file + } catch (URISyntaxException | IOException | FactoryException ex) { + throw new DataStoreException(ex); + } } var gridGeometry = new GridGeometry(extent, PixelInCell.CELL_CORNER, gridToCRS, crs); metadata().addSpatialRepresentation(null, gridGeometry, false); @@ -726,4 +754,50 @@ final class CoverageBuilder implements Emptiable { var source = new CoverageModifier.Source(store, imageIndex, dataType); return store.customizer.customize(source, gridGeometry); } + + /** + * Reads the "World file" by parsing an auxiliary file with the given suffix. + * + * @param wld suffix of the auxiliary file. + * @return the "World file" content as an affine transform, or {@code null} if none was found. + * @throws URISyntaxException if an error occurred while normalizing the URI. + * @throws IOException if an I/O error occurred. + * @throws DataStoreException if the file content cannot be parsed. + */ + private AffineTransform2D readWorldFile(final String wld) + throws URISyntaxException, IOException, DataStoreException + { + final AuxiliaryContent content; + try { + content = store.readAuxiliaryPath(wld); + } catch (NoSuchFileException e) { + return null; + } + if (content == null) { + return null; + } + final String filename = content.getFilename(); + final CharSequence[] lines = CharSequences.splitOnEOL(content); + final int expected = 6; // Expected number of elements. + int count = 0; // Actual number of elements. + final double[] elements = new double[expected]; + for (int i=0; i<expected; i++) { + final String line = lines[i].toString().trim(); + if (!line.isEmpty() && line.charAt(0) != '#') { + if (count >= expected) { + throw new DataStoreContentException(Errors.forLocale(store.getLocale()).getString(Errors.Keys.TooManyOccurrences_2, expected, "coefficient")); + } + try { + elements[count++] = Double.parseDouble(line); + } catch (NumberFormatException e) { + throw new DataStoreContentException(Errors.forLocale(store.getLocale()).getString(Errors.Keys.ErrorInFileAtLine_2, filename, i), e); + } + } + } + if (count != expected) { + throw new EOFException(Errors.forLocale(store.getLocale()).getString(Errors.Keys.UnexpectedEndOfFile_1, filename)); + } + return new AffineTransform2D(elements); + } + }
