From b87cfc4025c569b36779d0bab3a1a35b136f118e Mon Sep 17 00:00:00 2001 From: John Bogovic Date: Mon, 23 Mar 2026 14:43:58 -0400 Subject: [PATCH] fix: add writeRegion * bump n5 dependency (no longer has default implementation) * add generic type to readBlock --- pom.xml | 2 +- .../saalfeldlab/n5/hdf5/N5HDF5Reader.java | 7 +-- .../saalfeldlab/n5/hdf5/N5HDF5Writer.java | 49 +++++++++++++++++++ 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 1933a63..fbbd19b 100644 --- a/pom.xml +++ b/pom.xml @@ -139,7 +139,7 @@ sign,deploy-to-scijava - 4.0.0-alpha-9 + 4.0.0-alpha-12-SNAPSHOT diff --git a/src/main/java/org/janelia/saalfeldlab/n5/hdf5/N5HDF5Reader.java b/src/main/java/org/janelia/saalfeldlab/n5/hdf5/N5HDF5Reader.java index e19a23e..84ff01e 100644 --- a/src/main/java/org/janelia/saalfeldlab/n5/hdf5/N5HDF5Reader.java +++ b/src/main/java/org/janelia/saalfeldlab/n5/hdf5/N5HDF5Reader.java @@ -688,8 +688,9 @@ public DatasetAttributes getDatasetAttributes(String pathName) { new RawCompression()); } + @SuppressWarnings("unchecked") @Override - public DataBlock readBlock( + public DataBlock readBlock( String pathName, final DatasetAttributes datasetAttributes, final long... gridPosition) throws N5Exception { @@ -713,7 +714,7 @@ public DataBlock readBlock( if (datasetAttributes.getDataType() == DataType.STRING) { final int[] intHdf5CroppedBlockSize = Arrays.stream(hdf5CroppedBlockSize).mapToInt(i -> (int)i).toArray(); MDArray data = reader.string().readMDArrayBlockWithOffset(normalizedPathName, intHdf5CroppedBlockSize, hdf5Offset); - return new StringDataBlock(croppedBlockSize, gridPosition, data.getAsFlatArray()); + return (DataBlock)new StringDataBlock(croppedBlockSize, gridPosition, data.getAsFlatArray()); } final DataType dataType = datasetAttributes.getDataType(); @@ -733,7 +734,7 @@ public DataBlock readBlock( H5Sclose(fileSpaceId); H5Sclose(memorySpaceId); } - return block; + return (DataBlock)block; } @Override diff --git a/src/main/java/org/janelia/saalfeldlab/n5/hdf5/N5HDF5Writer.java b/src/main/java/org/janelia/saalfeldlab/n5/hdf5/N5HDF5Writer.java index 9997ccc..148ef5b 100644 --- a/src/main/java/org/janelia/saalfeldlab/n5/hdf5/N5HDF5Writer.java +++ b/src/main/java/org/janelia/saalfeldlab/n5/hdf5/N5HDF5Writer.java @@ -47,6 +47,9 @@ import org.janelia.saalfeldlab.n5.N5Writer; import org.janelia.saalfeldlab.n5.RawCompression; import org.janelia.saalfeldlab.n5.hdf5.N5HDF5Util.OpenDataSetCache.OpenDataSet; +import org.janelia.saalfeldlab.n5.shard.Region; +import org.janelia.saalfeldlab.n5.shard.Nesting.NestedGrid; +import org.janelia.saalfeldlab.n5.shard.Nesting.NestedPosition; import java.io.File; import java.io.IOException; @@ -55,6 +58,8 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; import static hdf.hdf5lib.H5.H5Dget_space; import static hdf.hdf5lib.H5.H5Dwrite; @@ -564,6 +569,50 @@ public void writeShard( writeBlock(pathName, datasetAttributes, dataBlock); } + @Override + public void writeRegion( + String datasetPath, + DatasetAttributes datasetAttributes, + long[] min, + long[] size, + DataBlockSupplier dataBlocks, + boolean writeFully) throws N5Exception { + + final NestedGrid grid = datasetAttributes.getNestedBlockGrid(); + final Region region = new Region(min, size, grid); + for (long[] key : Region.gridPositions(region.minPos().key(), region.maxPos().key())) { + final NestedPosition pos = grid.nestedPosition(key, 0); // HDF5 is never nested, get level 0 + final long[] gridPosition = pos.absolute(0); + final DataBlock existingDataBlock = writeFully || region.fullyContains(pos) + ? null + : readBlock(datasetPath, datasetAttributes, gridPosition); + final DataBlock dataBlock = dataBlocks.get(gridPosition, existingDataBlock); + // null blocks may be provided when they contain only the fill value + // and only non-empty blocks should be written, for example + if (dataBlock == null) { + deleteBlock(datasetPath, datasetAttributes, gridPosition); + } else { + writeBlock(datasetPath, datasetAttributes, dataBlock); + } + } + + } + + public void writeRegion( + String datasetPath, + DatasetAttributes datasetAttributes, + long[] min, + long[] size, + DataBlockSupplier dataBlocks, + boolean writeFully, + ExecutorService exec) throws N5Exception, InterruptedException, ExecutionException { + + // block until the write is complete + exec.submit(() -> { + writeRegion(datasetPath, datasetAttributes, min, size, dataBlocks, writeFully); + }).get(); + } + @Override public boolean deleteBlock(String pathName, final long... gridPosition) throws N5Exception {