Skip to content

Commit

Permalink
Multiscale metadata
Browse files Browse the repository at this point in the history
By listing pyramids in the group attributes which contain
the pyramids, clients can lookup the number of resolutions
without needing to know beforehand or perform a directory
listing.

see: zarr-developers/zarr-specs#50
  • Loading branch information
joshmoore committed Apr 23, 2020
1 parent 9968023 commit 33fad84
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 0 deletions.
41 changes: 41 additions & 0 deletions src/main/java/com/glencoesoftware/bioformats2raw/Converter.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
Expand Down Expand Up @@ -848,10 +851,14 @@ public void saveResolutions(int series)
Compression compression = N5Compression.getCompressor(compressionType,
compressionParameter);

// fileset level metadata
final String pyramidPath = outputPath.resolve(pyramidName).toString();
final N5Writer n5 = fileType.writer(pyramidPath);
n5.setAttribute("/", "bioformats2raw.layout", LAYOUT);

// series level metadata
setSeriesLevelMetadata(series, resolutions, n5);

for (int resCounter=0; resCounter<resolutions; resCounter++) {
final int resolution = resCounter;
int scale = (int) Math.pow(PYRAMID_SCALE, resolution);
Expand All @@ -870,6 +877,9 @@ public void saveResolutions(int series)
activeTileHeight = scaledHeight;
}

String resolutionString = "/" + String.format(
scaleFormatString, getScaleFormatStringArgs(series, resolution));

n5.createDataset(
"/" + String.format(
scaleFormatString, getScaleFormatStringArgs(series, resolution)),
Expand Down Expand Up @@ -928,6 +938,37 @@ scaleFormatString, getScaleFormatStringArgs(series, resolution)),

}

/**
* Use {@link N5Writer#setAttribute(String, String, Object)} to attach the multiscales
* metadata to the group containing the pyramids.
*
* @param series
* @param resolutions
* @param n5
* @throws IOException
*/
private void setSeriesLevelMetadata(int series, int resolutions, N5Writer n5) throws IOException {
String resolutionString = "/" + String.format(
scaleFormatString, getScaleFormatStringArgs(series, 0));
String seriesString = resolutionString.substring(0,
resolutionString.lastIndexOf('/'));
List<Map<String, Object>> multiscales =
new ArrayList<Map<String, Object>>();
Map<String, Object> multiscale = new HashMap<String, Object>();
multiscale.put("version", "0.1");
multiscales.add(multiscale);
List<Map<String, String>> datasets = new ArrayList<Map<String, String>>();
for (int r = 0; r < resolutions; r++) {
resolutionString = "/" + String.format(
scaleFormatString, getScaleFormatStringArgs(series, r));
String lastPath = resolutionString.substring(resolutionString.lastIndexOf('/'+1));
datasets.add(Collections.singletonMap("path", lastPath));
}
multiscale.put("datasets", datasets);
n5.createGroup(seriesString);
n5.setAttribute(seriesString, "multiscales", multiscales);
}

/**
* Takes exception from asynchronous execution and re-throw known exception
* types. If the end is reached with no known exception detected, either the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,27 @@ public void testDefaultLayoutIsSet() throws Exception {
Assert.assertEquals(Converter.LAYOUT, layout);
}

/**
* Test that multiscales metadata is present.
*/
@Test
public void testMultiscalesMetadata() throws Exception {
input = fake();
assertTool();
N5ZarrReader z =
new N5ZarrReader(output.resolve("data.zarr").toString());
//
List<Map<String, Object>> multiscales =
z.getAttribute("/0", "multiscales", List.class);
Assert.assertEquals(1, multiscales.size());
Map<String, Object> multiscale = multiscales.get(0);
Assert.assertEquals("0.1", multiscale.get("version"));
List<Map<String, Object>> datasets =
(List<Map<String, Object>>) multiscale.get("datasets");
Assert.assertTrue(datasets.size() > 0);
Assert.assertEquals("0", datasets.get(0).get("path"));
}

/**
* Test alternative dimension order.
*/
Expand Down

0 comments on commit 33fad84

Please sign in to comment.