From bbd161722d58ef614a57bcd884a0ce7223fcd0a6 Mon Sep 17 00:00:00 2001 From: Melissa Linkert Date: Tue, 7 Jan 2025 13:42:34 -0600 Subject: [PATCH 01/14] Add option for specifying image file that provides metadata --- .../pyramid/PyramidFromDirectoryWriter.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java index f25dbea..ed3bf85 100755 --- a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java +++ b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java @@ -40,8 +40,10 @@ import loci.common.services.ServiceFactory; import loci.formats.FormatException; import loci.formats.FormatTools; +import loci.formats.ImageReader; import loci.formats.MetadataTools; import loci.formats.codec.CodecOptions; +import loci.formats.meta.IMetadata; import loci.formats.ome.OMEPyramidStore; import loci.formats.services.OMEXMLService; import loci.formats.tiff.IFD; @@ -138,6 +140,8 @@ public class PyramidFromDirectoryWriter implements Callable { boolean splitBySeries = false; boolean splitByPlane = false; + String imageFile = null; + private ZarrGroup reader = null; /** Writer metadata. */ @@ -352,6 +356,25 @@ public void setSplitSinglePlaneTIFFs(boolean split) { splitByPlane = split; } + /** + * Set an alternate file to use for obtaining OME-XML metadata + * If the expected "OME/METADATA.ome.xml" file is not found, then + * the provided file will be read using Bio-Formats. + * This file is expected to be an original image file, with dimensions + * that match the input Zarr. + * + * @param file path to image file + */ + @Option( + names = {"--image-file", "-f"}, + description = + "Image file from which read metadata, if METADATA.ome.xml not found", + defaultValue = "" + ) + public void setImageFile(String file) { + imageFile = file; + } + /** * Set the maximum number of workers to use for converting tiles. * Defaults to 4 or the number of detected CPUs, whichever is smaller. @@ -483,6 +506,14 @@ public boolean getSplitSinglePlaneTIFFs() { return splitByPlane; } + /** + * @return path to image file from which metadata is read, + * if METADATA.ome.xml not present + */ + public String getImageFile() { + return imageFile; + } + /** * @return maximum number of worker threads */ @@ -931,6 +962,17 @@ else if (layoutVersion != 3) { if (omexml != null && Files.exists(omexml)) { xml = DataTools.readFile(omexml.toString()); } + else if (imageFile != null && !imageFile.isEmpty()) { + try (ImageReader imageReader = new ImageReader()) { + IMetadata srcMetadata = service.createOMEXMLMetadata(); + imageReader.setMetadataStore(srcMetadata); + imageReader.setId(imageFile); + xml = service.getOMEXML(srcMetadata); + } + catch (ServiceException e) { + throw new FormatException("Could not get OME-XML from image file", e); + } + } try { if (xml != null) { metadata = (OMEPyramidStore) service.createOMEXMLMetadata(xml); From e1740fcca86c541d4062d289f95cf10a75406fff Mon Sep 17 00:00:00 2001 From: Melissa Linkert Date: Tue, 7 Jan 2025 13:42:51 -0600 Subject: [PATCH 02/14] Allow input Zarr to be a single series (e.g. one label image) --- .../pyramid/PyramidFromDirectoryWriter.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java index ed3bf85..c257e7c 100755 --- a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java +++ b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java @@ -999,8 +999,11 @@ else if (imageFile != null && !imageFile.isEmpty()) { int seriesCount = getSeriesCount(); + boolean flatHierarchy = false; if (seriesCount < 1) { - throw new FormatException("Found no images to convert. Corrupt input?"); + LOG.warn("Series missing from hierarchy, assuming single pyramid"); + seriesCount = 1; + flatHierarchy = true; } if (seriesCount > 1 && legacy) { @@ -1032,7 +1035,7 @@ else if (imageFile != null && !imageFile.isEmpty()) { for (int seriesIndex=0; seriesIndex Date: Thu, 9 Jan 2025 16:28:18 -0600 Subject: [PATCH 03/14] Fix failing test --- .../pyramid/PyramidFromDirectoryWriter.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java index c257e7c..570c948 100755 --- a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java +++ b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java @@ -1035,7 +1035,19 @@ else if (imageFile != null && !imageFile.isEmpty()) { for (int seriesIndex=0; seriesIndex Date: Thu, 9 Jan 2025 16:44:55 -0600 Subject: [PATCH 04/14] Remove file length limit in checkstyle config --- config/checkstyle/checkstyle.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 2be1917..d805a9a 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -37,7 +37,6 @@ - From 2dfdc8a75fe8d76eacabec0e9bcfc48ca0272d79 Mon Sep 17 00:00:00 2001 From: Melissa Linkert Date: Fri, 10 Jan 2025 12:20:57 -0600 Subject: [PATCH 05/14] Throw an exception if OME-XML and Zarr dimensions do not match --- .../pyramid/PyramidFromDirectoryWriter.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java index 570c948..8dbb080 100755 --- a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java +++ b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java @@ -1061,9 +1061,26 @@ else if (imageFile != null && !imageFile.isEmpty()) { } findNumberOfResolutions(s); + int x = metadata.getPixelsSizeX(seriesIndex).getNumberValue().intValue(); + int y = metadata.getPixelsSizeY(seriesIndex).getNumberValue().intValue(); + s.z = metadata.getPixelsSizeZ(seriesIndex).getNumberValue().intValue(); s.c = metadata.getPixelsSizeC(seriesIndex).getNumberValue().intValue(); s.t = metadata.getPixelsSizeT(seriesIndex).getNumberValue().intValue(); + + // make sure that OME-XML and first resolution array have same dimensions + ZarrGroup imgGroup = getZarrGroup(s.path); + ZarrArray imgArray = imgGroup.openArray("0"); + int[] dims = imgArray.getShape(); + int[] metadataDims = new int[] {s.t, s.c, s.z, y, x}; + for (int d=0; d Date: Fri, 10 Jan 2025 12:52:43 -0600 Subject: [PATCH 06/14] Add basic tests for label image and `-f` --- .../raw2ometiff/test/ConversionTest.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/test/java/com/glencoesoftware/raw2ometiff/test/ConversionTest.java b/src/test/java/com/glencoesoftware/raw2ometiff/test/ConversionTest.java index 45b173f..aa184db 100644 --- a/src/test/java/com/glencoesoftware/raw2ometiff/test/ConversionTest.java +++ b/src/test/java/com/glencoesoftware/raw2ometiff/test/ConversionTest.java @@ -834,6 +834,37 @@ public void testVersionOnly() throws Exception { new PyramidFromDirectoryWriter(), new String[] {"--version"}); } + /** + * Test conversion of a single multiscales, similar to a label image. + */ + @Test + public void testLabelImage() throws Exception { + input = fake("sizeX", "2000", "sizeY", "1500"); + assertBioFormats2Raw(); + output = output.resolve("0"); + assertTool("-f", input.toString()); + iteratePixels(); + } + + /** + * Test conversion of a single multiscales (similar to label image), + * but intentionally provide incorrect image metadata. + */ + @Test + public void testLabelImageWrongSize() throws Exception { + input = fake("sizeX", "2000", "sizeY", "1500"); + assertBioFormats2Raw(); + output = output.resolve("0"); + try { + assertTool("-f", "test.fake"); + } + catch (ExecutionException e) { + // First cause is RuntimeException wrapping the checked FormatException + Assert.assertEquals( + FormatException.class, e.getCause().getCause().getClass()); + } + } + private void checkRGBIFDs() throws FormatException, IOException { try (TiffParser parser = new TiffParser(outputOmeTiff.toString())) { IFDList mainIFDs = parser.getMainIFDs(); From 2cbb9049a30b7f677cb67623b535be745a0b34c5 Mon Sep 17 00:00:00 2001 From: Melissa Linkert Date: Wed, 15 Jan 2025 16:06:46 -0600 Subject: [PATCH 07/14] Fix typo in dimension mismatch exception --- .../com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java index 8dbb080..19ff321 100755 --- a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java +++ b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java @@ -1076,7 +1076,7 @@ else if (imageFile != null && !imageFile.isEmpty()) { for (int d=0; d Date: Thu, 16 Jan 2025 16:26:16 -0600 Subject: [PATCH 08/14] Better handling of channel, pixel type, and endianness mismatches --- .../pyramid/PyramidFromDirectoryWriter.java | 130 +++++++++++------- .../raw2ometiff/test/ConversionTest.java | 54 ++++++++ 2 files changed, 135 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java index 19ff321..b7d5e51 100755 --- a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java +++ b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java @@ -38,9 +38,9 @@ import loci.common.services.DependencyException; import loci.common.services.ServiceException; import loci.common.services.ServiceFactory; +import loci.formats.ChannelSeparator; import loci.formats.FormatException; import loci.formats.FormatTools; -import loci.formats.ImageReader; import loci.formats.MetadataTools; import loci.formats.codec.CodecOptions; import loci.formats.meta.IMetadata; @@ -963,7 +963,7 @@ else if (layoutVersion != 3) { xml = DataTools.readFile(omexml.toString()); } else if (imageFile != null && !imageFile.isEmpty()) { - try (ImageReader imageReader = new ImageReader()) { + try (ChannelSeparator imageReader = new ChannelSeparator()) { IMetadata srcMetadata = service.createOMEXMLMetadata(); imageReader.setMetadataStore(srcMetadata); imageReader.setId(imageFile); @@ -1072,7 +1072,8 @@ else if (imageFile != null && !imageFile.isEmpty()) { ZarrGroup imgGroup = getZarrGroup(s.path); ZarrArray imgArray = imgGroup.openArray("0"); int[] dims = imgArray.getShape(); - int[] metadataDims = new int[] {s.t, s.c, s.z, y, x}; + // allow mismatch in channel count... + int[] metadataDims = new int[] {s.t, dims[1], s.z, y, x}; for (int d=0; d dims[1]) { + mergeChannels(seriesIndex, s.c, false); + s.c = dims[1]; + } + else if (s.c < dims[1]) { + for (int channel=s.c; channel 0 && s.littleEndian != series.get(0).littleEndian) { // always warn on endian mismatches @@ -1121,48 +1145,7 @@ else if (imageFile != null && !imageFile.isEmpty()) { LOG.debug("Merging {} original channels into {} RGB channels", s.c, effectiveChannels); - OMEXMLMetadataRoot root = (OMEXMLMetadataRoot) metadata.getRoot(); - Pixels pixels = root.getImage(seriesIndex).getPixels(); - for (int index=pixels.sizeOfChannelList()-1; index>0; index--) { - if (index % rgbChannels == 0) { - continue; - } - Channel ch = pixels.getChannel(index); - pixels.removeChannel(ch); - } - for (int index=0; index0; index--) { + if (index % rgbChannels == 0) { + continue; + } + Channel ch = pixels.getChannel(index); + pixels.removeChannel(ch); + } + for (int index=0; index Date: Fri, 17 Jan 2025 14:08:06 -0600 Subject: [PATCH 09/14] Read input files with unflattened resolutions (i.e. keep pyramid hierarchy) This better matches what bioformats2raw would have produced. --- .../com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java index b7d5e51..8041e28 100755 --- a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java +++ b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java @@ -965,6 +965,7 @@ else if (layoutVersion != 3) { else if (imageFile != null && !imageFile.isEmpty()) { try (ChannelSeparator imageReader = new ChannelSeparator()) { IMetadata srcMetadata = service.createOMEXMLMetadata(); + imageReader.setFlattenedResolutions(false); imageReader.setMetadataStore(srcMetadata); imageReader.setId(imageFile); xml = service.getOMEXML(srcMetadata); From b15c8b339e6c2b2c3c4579cfd6d479665c265068 Mon Sep 17 00:00:00 2001 From: Melissa Linkert Date: Tue, 21 Jan 2025 12:30:26 -0600 Subject: [PATCH 10/14] Update src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Besson --- .../com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java index 8041e28..4ff74f6 100755 --- a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java +++ b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java @@ -360,7 +360,7 @@ public void setSplitSinglePlaneTIFFs(boolean split) { * Set an alternate file to use for obtaining OME-XML metadata * If the expected "OME/METADATA.ome.xml" file is not found, then * the provided file will be read using Bio-Formats. - * This file is expected to be an original image file, with dimensions + * This file is expected to be an original image file, with XYZT dimensions * that match the input Zarr. * * @param file path to image file From 8a5553dca2c865763e4fa1745705b8c4c4ce25b4 Mon Sep 17 00:00:00 2001 From: Melissa Linkert Date: Tue, 21 Jan 2025 13:53:49 -0600 Subject: [PATCH 11/14] Log when endianness, pixel type, and channel counts mismatch --- .../pyramid/PyramidFromDirectoryWriter.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java index 4ff74f6..b6e455f 100755 --- a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java +++ b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java @@ -1084,10 +1084,15 @@ else if (imageFile != null && !imageFile.isEmpty()) { } // ...but if the channel count mismatches, metadata needs to be corrected if (s.c > dims[1]) { + LOG.debug("OME-XML has {} channels; using {} Zarr channels instead", + s.c, dims[1]); mergeChannels(seriesIndex, s.c, false); s.c = dims[1]; } else if (s.c < dims[1]) { + LOG.debug( + "OME-XML has {} channels; adding {} to match {} Zarr channels", + s.c, dims[1] - s.c + 1, dims[1]); for (int channel=s.c; channel Date: Tue, 21 Jan 2025 14:28:54 -0600 Subject: [PATCH 12/14] Add Z and T mismatch tests, and refactor exception check --- .../raw2ometiff/test/ConversionTest.java | 63 ++++++++++++++++--- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/src/test/java/com/glencoesoftware/raw2ometiff/test/ConversionTest.java b/src/test/java/com/glencoesoftware/raw2ometiff/test/ConversionTest.java index 605d635..c9ff6e6 100644 --- a/src/test/java/com/glencoesoftware/raw2ometiff/test/ConversionTest.java +++ b/src/test/java/com/glencoesoftware/raw2ometiff/test/ConversionTest.java @@ -349,9 +349,7 @@ public void testSeriesCountCheck() throws Exception { assertTool(); } catch (ExecutionException e) { - // First cause is RuntimeException wrapping the checked FormatException - Assert.assertEquals( - FormatException.class, e.getCause().getCause().getClass()); + testException(FormatException.class, e); return; } Assert.fail("Did not throw exception on invalid data"); @@ -850,7 +848,8 @@ public void testLabelImage() throws Exception { /** * Test conversion of a single multiscales (similar to label image), - * but intentionally provide incorrect image metadata. + * but intentionally provide incorrect XY metadata. + * Conversion is expected to fail in this case. */ @Test public void testLabelImageWrongSize() throws Exception { @@ -861,9 +860,47 @@ public void testLabelImageWrongSize() throws Exception { assertTool("-f", "test.fake"); } catch (ExecutionException e) { - // First cause is RuntimeException wrapping the checked FormatException - Assert.assertEquals( - FormatException.class, e.getCause().getCause().getClass()); + testException(FormatException.class, e); + return; + } + Assert.fail("Did not throw exception on invalid data"); + } + + /** + * Test conversion of a single multiscales (similar to label image), + * but intentionally provide incorrect T metadata. + * Conversion is expected to fail in this case. + */ + @Test + public void testLabelImageWrongT() throws Exception { + input = fake(); + assertBioFormats2Raw(); + output = output.resolve("0"); + try { + assertTool("-f", fake("sizeT", "5").toString()); + } + catch (ExecutionException e) { + testException(FormatException.class, e); + return; + } + Assert.fail("Did not throw exception on invalid data"); + } + + /** + * Test conversion of a single multiscales (similar to label image), + * but intentionally provide incorrect Z metadata. + * Conversion is expected to fail in this case. + */ + @Test + public void testLabelImageWrongZ() throws Exception { + input = fake(); + assertBioFormats2Raw(); + output = output.resolve("0"); + try { + assertTool("-f", fake("sizeZ", "4").toString()); + } + catch (ExecutionException e) { + testException(FormatException.class, e); return; } Assert.fail("Did not throw exception on invalid data"); @@ -935,4 +972,16 @@ private void checkRGBIFDs() throws FormatException, IOException { } } + /** + * Check that the underlying cause of an exception matches the given class. + * This is used to check that e.g. RuntimeException wraps an underlying + * FormatException as expected. + * + * @param cause Class of expected underlying exception + * @param e exception that was thrown + */ + private void testException(Class cause, Exception e) { + Assert.assertEquals(cause, e.getCause().getCause().getClass()); + } + } From 07263e3cb5a10b8e9917df7e1d926377d752420a Mon Sep 17 00:00:00 2001 From: Melissa Linkert Date: Tue, 21 Jan 2025 17:45:03 -0600 Subject: [PATCH 13/14] Add RGB label image tests and refactor RGB channel testing --- .../raw2ometiff/test/ConversionTest.java | 105 ++++++++++++------ 1 file changed, 69 insertions(+), 36 deletions(-) diff --git a/src/test/java/com/glencoesoftware/raw2ometiff/test/ConversionTest.java b/src/test/java/com/glencoesoftware/raw2ometiff/test/ConversionTest.java index c9ff6e6..93863c3 100644 --- a/src/test/java/com/glencoesoftware/raw2ometiff/test/ConversionTest.java +++ b/src/test/java/com/glencoesoftware/raw2ometiff/test/ConversionTest.java @@ -477,12 +477,8 @@ public void testRGBMultiT() throws Exception { Assert.assertEquals( 3, metadata.getPixelsSizeC(0).getNumberValue()); Assert.assertEquals(1, metadata.getChannelCount(0)); - Assert.assertEquals( - 3, metadata.getChannelSamplesPerPixel(0, 0).getNumberValue()); - Assert.assertNull(metadata.getChannelColor(0, 0)); - Assert.assertNull(metadata.getChannelEmissionWavelength(0, 0)); - Assert.assertNull(metadata.getChannelExcitationWavelength(0, 0)); - Assert.assertNull(metadata.getChannelName(0, 0)); + + checkRGBChannel(metadata, 0, 0); } checkRGBIFDs(); } @@ -506,30 +502,10 @@ public void testRGBMultiC() throws Exception { Assert.assertEquals( 12, metadata.getPixelsSizeC(0).getNumberValue()); Assert.assertEquals(4, metadata.getChannelCount(0)); - Assert.assertEquals( - 3, metadata.getChannelSamplesPerPixel(0, 0).getNumberValue()); - Assert.assertNull(metadata.getChannelColor(0, 0)); - Assert.assertNull(metadata.getChannelEmissionWavelength(0, 0)); - Assert.assertNull(metadata.getChannelExcitationWavelength(0, 0)); - Assert.assertNull(metadata.getChannelName(0, 0)); - Assert.assertEquals( - 3, metadata.getChannelSamplesPerPixel(0, 1).getNumberValue()); - Assert.assertNull(metadata.getChannelColor(0, 1)); - Assert.assertNull(metadata.getChannelEmissionWavelength(0, 1)); - Assert.assertNull(metadata.getChannelExcitationWavelength(0, 1)); - Assert.assertNull(metadata.getChannelName(0, 1)); - Assert.assertEquals( - 3, metadata.getChannelSamplesPerPixel(0, 2).getNumberValue()); - Assert.assertNull(metadata.getChannelColor(0, 2)); - Assert.assertNull(metadata.getChannelEmissionWavelength(0, 2)); - Assert.assertNull(metadata.getChannelExcitationWavelength(0, 2)); - Assert.assertNull(metadata.getChannelName(0, 2)); - Assert.assertEquals( - 3, metadata.getChannelSamplesPerPixel(0, 3).getNumberValue()); - Assert.assertNull(metadata.getChannelColor(0, 3)); - Assert.assertNull(metadata.getChannelEmissionWavelength(0, 3)); - Assert.assertNull(metadata.getChannelExcitationWavelength(0, 3)); - Assert.assertNull(metadata.getChannelName(0, 3)); + + for (int c=0; c Date: Tue, 21 Jan 2025 17:45:25 -0600 Subject: [PATCH 14/14] Fix RGB label image test --- .../pyramid/PyramidFromDirectoryWriter.java | 60 +++++++++++++++---- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java index b6e455f..3c450ee 100755 --- a/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java +++ b/src/main/java/com/glencoesoftware/pyramid/PyramidFromDirectoryWriter.java @@ -1069,17 +1069,62 @@ else if (imageFile != null && !imageFile.isEmpty()) { s.c = metadata.getPixelsSizeC(seriesIndex).getNumberValue().intValue(); s.t = metadata.getPixelsSizeT(seriesIndex).getNumberValue().intValue(); + // trust the OME-XML dimension order if it's coming from + // OME/METADATA.ome.xml, as that implies that it can be trusted to match + // the Zarr dimension order - usually it will be the default XYZCT anyway + // + // don't trust the OME-XML dimension order if an external file is + // providing the OME-XML metadata (e.g. label image) + // this only makes a real difference if the Zarr has multiple planes, + // but protects against e.g. RGB input data with an XYCZT order vs. + // Zarr data with an XYZCT order + if (getImageFile() == null) { + s.dimensionOrder = + metadata.getPixelsDimensionOrder(seriesIndex).toString(); + LOG.debug("No image file; set dimension order to {}", + s.dimensionOrder); + } + else { + s.dimensionOrder = "XYZCT"; + LOG.debug("Image file has dimension order {}; using default {}", + metadata.getPixelsDimensionOrder(seriesIndex), s.dimensionOrder); + } + + s.dimensionLengths[s.dimensionOrder.indexOf("Z") - 2] = s.z; + s.dimensionLengths[s.dimensionOrder.indexOf("T") - 2] = s.t; + s.dimensionLengths[s.dimensionOrder.indexOf("C") - 2] = s.c; + // make sure that OME-XML and first resolution array have same dimensions ZarrGroup imgGroup = getZarrGroup(s.path); ZarrArray imgArray = imgGroup.openArray("0"); int[] dims = imgArray.getShape(); // allow mismatch in channel count... - int[] metadataDims = new int[] {s.t, dims[1], s.z, y, x}; for (int d=0; d