diff --git a/pom.xml b/pom.xml
index d56dc94..4050877 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,7 +11,7 @@
org.janelia.saalfeldlab
n5-hdf5
- 2.3.0-alpha-4-SNAPSHOT
+ 2.3.0-alpha-4-fix
N5 HDF5 Bindings
Best effort N5 implementation on HDF5 files.
@@ -139,7 +139,7 @@
sign,deploy-to-scijava
- 4.0.0-alpha-4
+ 4.0.0-alpha-6
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 35a085d..d0b3838 100644
--- a/src/main/java/org/janelia/saalfeldlab/n5/hdf5/N5HDF5Writer.java
+++ b/src/main/java/org/janelia/saalfeldlab/n5/hdf5/N5HDF5Writer.java
@@ -552,6 +552,138 @@ public void writeBlock(
}
}
+ @Override
+ public void writeRegion(
+ final String datasetPath,
+ final DatasetAttributes datasetAttributes,
+ final long[] min,
+ final long[] size,
+ final DataBlockSupplier dataBlocks,
+ final boolean writeFully) throws N5Exception {
+
+ // For HDF5 (no sharding support), iterate through blocks in the region
+ // and write each one using writeBlock
+ final int n = min.length;
+ final int[] blockSize = datasetAttributes.getBlockSize();
+
+ // Compute min and max block grid positions
+ final long[] minBlock = new long[n];
+ final long[] maxBlock = new long[n];
+ for (int d = 0; d < n; ++d) {
+ minBlock[d] = min[d] / blockSize[d];
+ maxBlock[d] = (min[d] + size[d] - 1) / blockSize[d];
+ }
+
+ // Iterate through all blocks in the region
+ final long[] gridPosition = minBlock.clone();
+ while (true) {
+ // Check if we need to read existing data for this block
+ final DataBlock existingBlock;
+ if (writeFully) {
+ existingBlock = null;
+ } else {
+ // Check if block is fully contained in the region
+ boolean fullyContained = true;
+ for (int d = 0; d < n; ++d) {
+ final long blockStart = gridPosition[d] * blockSize[d];
+ final long blockEnd = blockStart + blockSize[d];
+ if (blockStart < min[d] || blockEnd > min[d] + size[d]) {
+ fullyContained = false;
+ break;
+ }
+ }
+ @SuppressWarnings("unchecked")
+ final DataBlock readBlockUnchecked = (DataBlock) readBlock(datasetPath, datasetAttributes, gridPosition);
+ existingBlock = fullyContained ? null : readBlockUnchecked;
+ }
+
+ // Get the new block from the supplier
+ final DataBlock dataBlock = dataBlocks.get(gridPosition, existingBlock);
+ if (dataBlock != null) {
+ writeBlock(datasetPath, datasetAttributes, dataBlock);
+ }
+
+ // Increment grid position
+ int d = 0;
+ for (; d < n; ++d) {
+ if (gridPosition[d] < maxBlock[d]) {
+ gridPosition[d]++;
+ break;
+ }
+ gridPosition[d] = minBlock[d];
+ }
+ if (d == n) break; // Done iterating
+ }
+ }
+
+ @Override
+ public void writeRegion(
+ final String datasetPath,
+ final DatasetAttributes datasetAttributes,
+ final long[] min,
+ final long[] size,
+ final DataBlockSupplier dataBlocks,
+ final boolean writeFully,
+ final java.util.concurrent.ExecutorService executor) throws N5Exception {
+
+ // For HDF5 (no sharding support), iterate through blocks in the region
+ // and write each one using writeBlock, parallelized with executor
+ final int n = min.length;
+ final int[] blockSize = datasetAttributes.getBlockSize();
+
+ // Compute min and max block grid positions
+ final long[] minBlock = new long[n];
+ final long[] maxBlock = new long[n];
+ for (int d = 0; d < n; ++d) {
+ minBlock[d] = min[d] / blockSize[d];
+ maxBlock[d] = (min[d] + size[d] - 1) / blockSize[d];
+ }
+
+ // Iterate through all blocks in the region and submit tasks to executor
+ final long[] gridPosition = minBlock.clone();
+ while (true) {
+ final long[] currentGridPosition = gridPosition.clone();
+ executor.submit(() -> {
+ // Check if we need to read existing data for this block
+ final DataBlock existingBlock;
+ if (writeFully) {
+ existingBlock = null;
+ } else {
+ // Check if block is fully contained in the region
+ boolean fullyContained = true;
+ for (int d = 0; d < n; ++d) {
+ final long blockStart = currentGridPosition[d] * blockSize[d];
+ final long blockEnd = blockStart + blockSize[d];
+ if (blockStart < min[d] || blockEnd > min[d] + size[d]) {
+ fullyContained = false;
+ break;
+ }
+ }
+ @SuppressWarnings("unchecked")
+ final DataBlock readBlockUnchecked = (DataBlock) readBlock(datasetPath, datasetAttributes, currentGridPosition);
+ existingBlock = fullyContained ? null : readBlockUnchecked;
+ }
+
+ // Get the new block from the supplier (must be thread-safe)
+ final DataBlock dataBlock = dataBlocks.get(currentGridPosition, existingBlock);
+ if (dataBlock != null) {
+ writeBlock(datasetPath, datasetAttributes, dataBlock);
+ }
+ });
+
+ // Increment grid position
+ int d = 0;
+ for (; d < n; ++d) {
+ if (gridPosition[d] < maxBlock[d]) {
+ gridPosition[d]++;
+ break;
+ }
+ gridPosition[d] = minBlock[d];
+ }
+ if (d == n) break; // Done iterating
+ }
+ }
+
@Override
public boolean deleteBlock(String pathName, final long... gridPosition) throws N5Exception {