From 475a9aafadb0609aba0fa8e8e289bf427779ae38 Mon Sep 17 00:00:00 2001 From: Melissa Linkert Date: Mon, 13 Dec 2021 17:19:58 -0600 Subject: [PATCH 1/5] Store dimension order using new "axes" spec See https://github.com/ome/ngff/pull/57 --- .../bioformats2raw/Converter.java | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/glencoesoftware/bioformats2raw/Converter.java b/src/main/java/com/glencoesoftware/bioformats2raw/Converter.java index f22e0568..0321c50c 100644 --- a/src/main/java/com/glencoesoftware/bioformats2raw/Converter.java +++ b/src/main/java/com/glencoesoftware/bioformats2raw/Converter.java @@ -1206,7 +1206,8 @@ public void saveResolutions(int series) .nested(nested) .compressor(CompressorFactory.create( compressionType.toString(), compressionProperties)); - ZarrArray.create(getRootPath().resolve(resolutionString), arrayParams); + ZarrArray.create(getRootPath().resolve(resolutionString), + arrayParams, getArrayAttributes()); nTile = new AtomicInteger(0); tileCount = (int) Math.ceil((double) scaledWidth / tileWidth) @@ -1497,6 +1498,27 @@ private void setSeriesLevelMetadata(int series, int resolutions) datasets.add(Collections.singletonMap("path", lastPath)); } multiscale.put("datasets", datasets); + + if (dimensionOrder != null) { + List> axes = new ArrayList>(); + String axisOrder = dimensionOrder.toString(); + for (int i=axisOrder.length()-1; i>=0; i--) { + String axis = axisOrder.substring(i, i + 1).toLowerCase(); + String type = "space"; + if (axis.equals("t")) { + type = "time"; + } + else if (axis.equals("c")) { + type = "channel"; + } + Map thisAxis = new HashMap(); + thisAxis.put("name", axis); + thisAxis.put("type", type); + axes.add(thisAxis); + } + multiscale.put("axes", axes); + } + Path subGroupPath = getRootPath().resolve(seriesString); LOGGER.debug(" creating subgroup {}", subGroupPath); ZarrGroup subGroup = ZarrGroup.create(subGroupPath); @@ -1744,6 +1766,16 @@ private Class getBaseReaderClass() throws FormatException, IOException { } } + private Map getArrayAttributes() { + Map attrs = new HashMap(); + if (dimensionOrder != null) { + String order = dimensionOrder.toString().toLowerCase(); + String[] axes = new StringBuilder(order).reverse().toString().split(""); + attrs.put("_ARRAY_DIMENSIONS", axes); + } + return attrs; + } + private static Slf4JStopWatch stopWatch() { return new Slf4JStopWatch(LOGGER, Slf4JStopWatch.DEBUG_LEVEL); } From 990b688a31d758c2da6efe48cb406fcc39986cd7 Mon Sep 17 00:00:00 2001 From: Melissa Linkert Date: Tue, 14 Dec 2021 17:46:52 -0600 Subject: [PATCH 2/5] Check "axes" metadata in existing multiscales/dimension order tests --- .../bioformats2raw/test/ZarrTest.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/test/java/com/glencoesoftware/bioformats2raw/test/ZarrTest.java b/src/test/java/com/glencoesoftware/bioformats2raw/test/ZarrTest.java index b7de5334..d0621cec 100644 --- a/src/test/java/com/glencoesoftware/bioformats2raw/test/ZarrTest.java +++ b/src/test/java/com/glencoesoftware/bioformats2raw/test/ZarrTest.java @@ -249,6 +249,10 @@ public void testMultiscalesMetadata() throws Exception { (List>) multiscale.get("datasets"); assertTrue(datasets.size() > 0); assertEquals("0", datasets.get(0).get("path")); + + List> axes = + (List>) multiscale.get("axes"); + checkAxes(axes, "TCZYX"); } /** @@ -273,6 +277,15 @@ public void testSetXYCZTDimensionOrder() throws Exception { ZarrGroup z = ZarrGroup.open(output.toString()); ZarrArray array = z.openArray("0/0"); assertArrayEquals(new int[] {1, 1, 2, 512, 512}, array.getShape()); + + z = ZarrGroup.open(output.resolve("0").toString()); + List> multiscales = (List>) + z.getAttributes().get("multiscales"); + assertEquals(1, multiscales.size()); + Map multiscale = multiscales.get(0); + List> axes = + (List>) multiscale.get("axes"); + checkAxes(axes, "TZCYX"); } /** @@ -1257,6 +1270,15 @@ private void checkWell(ZarrGroup wellGroup, int fieldCount) } } + private void checkAxes(List> axes, String order) { + assertEquals(axes.size(), order.length()); + for (int i=0; i Date: Wed, 2 Feb 2022 14:17:29 -0600 Subject: [PATCH 3/5] Fix axes metadata when dimensionOrder is null dimensionOrder is only null if "--dimension-order original" was specified. --- .../bioformats2raw/Converter.java | 65 +++++++++++++------ 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/glencoesoftware/bioformats2raw/Converter.java b/src/main/java/com/glencoesoftware/bioformats2raw/Converter.java index 20b641f6..b05099c9 100644 --- a/src/main/java/com/glencoesoftware/bioformats2raw/Converter.java +++ b/src/main/java/com/glencoesoftware/bioformats2raw/Converter.java @@ -1473,9 +1473,10 @@ private void saveHCSMetadata(IMetadata meta) throws IOException { * @param resolutions Total number of resolutions from which * names will be generated. * @throws IOException + * @throws InterruptedException */ private void setSeriesLevelMetadata(int series, int resolutions) - throws IOException + throws IOException, InterruptedException { LOGGER.debug("setSeriesLevelMetadata({}, {})", series, resolutions); String resolutionString = String.format( @@ -1516,25 +1517,35 @@ private void setSeriesLevelMetadata(int series, int resolutions) } multiscale.put("datasets", datasets); + String axisOrder = null; if (dimensionOrder != null) { - List> axes = new ArrayList>(); - String axisOrder = dimensionOrder.toString(); - for (int i=axisOrder.length()-1; i>=0; i--) { - String axis = axisOrder.substring(i, i + 1).toLowerCase(); - String type = "space"; - if (axis.equals("t")) { - type = "time"; - } - else if (axis.equals("c")) { - type = "channel"; - } - Map thisAxis = new HashMap(); - thisAxis.put("name", axis); - thisAxis.put("type", type); - axes.add(thisAxis); + axisOrder = dimensionOrder.toString(); + } + else { + IFormatReader reader = readers.take(); + try { + axisOrder = reader.getDimensionOrder(); + } + finally { + readers.put(reader); + } + } + List> axes = new ArrayList>(); + for (int i=axisOrder.length()-1; i>=0; i--) { + String axis = axisOrder.substring(i, i + 1).toLowerCase(); + String type = "space"; + if (axis.equals("t")) { + type = "time"; + } + else if (axis.equals("c")) { + type = "channel"; } - multiscale.put("axes", axes); + Map thisAxis = new HashMap(); + thisAxis.put("name", axis); + thisAxis.put("type", type); + axes.add(thisAxis); } + multiscale.put("axes", axes); Path subGroupPath = getRootPath().resolve(seriesString); LOGGER.debug(" creating subgroup {}", subGroupPath); @@ -1783,13 +1794,25 @@ private Class getBaseReaderClass() throws FormatException, IOException { } } - private Map getArrayAttributes() { + private Map getArrayAttributes() throws InterruptedException { Map attrs = new HashMap(); + String order = null; if (dimensionOrder != null) { - String order = dimensionOrder.toString().toLowerCase(); - String[] axes = new StringBuilder(order).reverse().toString().split(""); - attrs.put("_ARRAY_DIMENSIONS", axes); + order = dimensionOrder.toString(); + } + else { + IFormatReader reader = readers.take(); + try { + order = reader.getDimensionOrder(); + } + finally { + readers.put(reader); + } } + + String[] axes = + new StringBuilder(order.toLowerCase()).reverse().toString().split(""); + attrs.put("_ARRAY_DIMENSIONS", axes); return attrs; } From fa6dd0599e63da280565a5f6c7a62fb33f9df4db Mon Sep 17 00:00:00 2001 From: Melissa Linkert Date: Thu, 3 Feb 2022 20:08:08 -0600 Subject: [PATCH 4/5] Add test for axes metadata when using "--dimension-order original" --- .../glencoesoftware/bioformats2raw/test/ZarrTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/test/java/com/glencoesoftware/bioformats2raw/test/ZarrTest.java b/src/test/java/com/glencoesoftware/bioformats2raw/test/ZarrTest.java index 598b9993..1a166ef1 100644 --- a/src/test/java/com/glencoesoftware/bioformats2raw/test/ZarrTest.java +++ b/src/test/java/com/glencoesoftware/bioformats2raw/test/ZarrTest.java @@ -309,6 +309,15 @@ public void testSetOriginalDimensionOrder() throws Exception { ZarrGroup z = ZarrGroup.open(output.toString()); ZarrArray array = z.openArray("0/0"); assertArrayEquals(new int[] {1, 1, 2, 512, 512}, array.getShape()); + + z = ZarrGroup.open(output.resolve("0").toString()); + List> multiscales = (List>) + z.getAttributes().get("multiscales"); + assertEquals(1, multiscales.size()); + Map multiscale = multiscales.get(0); + List> axes = + (List>) multiscale.get("axes"); + checkAxes(axes, "TZCYX"); } /** From 8f430e2615e9d7803e20466298dabd54cab9e51c Mon Sep 17 00:00:00 2001 From: Melissa Linkert Date: Tue, 8 Feb 2022 08:54:56 -0600 Subject: [PATCH 5/5] Don't set _ARRAY_DIMENSIONS attribute --- .../bioformats2raw/Converter.java | 25 +------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/src/main/java/com/glencoesoftware/bioformats2raw/Converter.java b/src/main/java/com/glencoesoftware/bioformats2raw/Converter.java index b05099c9..ae0f4674 100644 --- a/src/main/java/com/glencoesoftware/bioformats2raw/Converter.java +++ b/src/main/java/com/glencoesoftware/bioformats2raw/Converter.java @@ -1220,8 +1220,7 @@ public void saveResolutions(int series) .nested(nested) .compressor(CompressorFactory.create( compressionType.toString(), compressionProperties)); - ZarrArray.create(getRootPath().resolve(resolutionString), - arrayParams, getArrayAttributes()); + ZarrArray.create(getRootPath().resolve(resolutionString), arrayParams); nTile = new AtomicInteger(0); tileCount = (int) Math.ceil((double) scaledWidth / tileWidth) @@ -1794,28 +1793,6 @@ private Class getBaseReaderClass() throws FormatException, IOException { } } - private Map getArrayAttributes() throws InterruptedException { - Map attrs = new HashMap(); - String order = null; - if (dimensionOrder != null) { - order = dimensionOrder.toString(); - } - else { - IFormatReader reader = readers.take(); - try { - order = reader.getDimensionOrder(); - } - finally { - readers.put(reader); - } - } - - String[] axes = - new StringBuilder(order.toLowerCase()).reverse().toString().split(""); - attrs.put("_ARRAY_DIMENSIONS", axes); - return attrs; - } - /** * Check if the given metadata object contains at least one plate * with at least one well that links to an image.