From e818377881dfbadc46ee7f7fd3cd066f8c230ddc Mon Sep 17 00:00:00 2001 From: Melissa Linkert Date: Tue, 23 Jul 2024 16:35:32 -0500 Subject: [PATCH 1/4] Exporter: fix typo when setting Channel.SamplesPerPixel This caused a problem when exporting DICOM with multiple channels from ImageJ, as the DICOM writer strictly requires non-null SamplesPerPixel on every Channel. --- .../bio-formats-plugins/src/loci/plugins/out/Exporter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bio-formats-plugins/src/loci/plugins/out/Exporter.java b/components/bio-formats-plugins/src/loci/plugins/out/Exporter.java index 2a953b3fea7..7395b38fcfd 100644 --- a/components/bio-formats-plugins/src/loci/plugins/out/Exporter.java +++ b/components/bio-formats-plugins/src/loci/plugins/out/Exporter.java @@ -505,7 +505,7 @@ else if (FormatTools.isSigned(originalType)) { String lsid = MetadataTools.createLSID("Channel", 0, c); store.setChannelID(lsid, 0, c); } - store.setChannelSamplesPerPixel(new PositiveInteger(channels), 0, 0); + store.setChannelSamplesPerPixel(new PositiveInteger(channels), 0, c); if (imp instanceof CompositeImage) { luts[c] = ((CompositeImage) imp).getChannelLut(c + 1); From cd22cb9739059edb89d16a0cb12abeb061fadef8 Mon Sep 17 00:00:00 2001 From: Melissa Linkert Date: Tue, 23 Jul 2024 16:36:39 -0500 Subject: [PATCH 2/4] DICOM writer: don't throw NPE if close was already called Shouldn't affect bfconvert, but does affect ImageJ export which calls close() twice. --- components/formats-bsd/src/loci/formats/out/DicomWriter.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/formats-bsd/src/loci/formats/out/DicomWriter.java b/components/formats-bsd/src/loci/formats/out/DicomWriter.java index 23c6921f81a..4b26e2e8dc7 100644 --- a/components/formats-bsd/src/loci/formats/out/DicomWriter.java +++ b/components/formats-bsd/src/loci/formats/out/DicomWriter.java @@ -1383,6 +1383,11 @@ public void close() throws IOException { for (int res=0; res Date: Wed, 11 Sep 2024 11:59:00 -0500 Subject: [PATCH 3/4] Don't try to convert lengths with pixel/referenceframe units to physical units --- .../src/loci/formats/out/DicomWriter.java | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/components/formats-bsd/src/loci/formats/out/DicomWriter.java b/components/formats-bsd/src/loci/formats/out/DicomWriter.java index 4b26e2e8dc7..05d27e26de6 100644 --- a/components/formats-bsd/src/loci/formats/out/DicomWriter.java +++ b/components/formats-bsd/src/loci/formats/out/DicomWriter.java @@ -988,7 +988,7 @@ public void setId(String id) throws FormatException, IOException { opticalSequence.children.add(illuminationTypeCodes); DicomTag wavelength = new DicomTag(ILLUMINATION_WAVELENGTH, FL); - Length wave = r.getChannelEmissionWavelength(pyramid, c); + Length wave = fixUnits(r.getChannelEmissionWavelength(pyramid, c)); wavelength.value = new float[] {wave == null ? 1f : wave.value(UNITS.NM).floatValue()}; opticalSequence.children.add(wavelength); @@ -1019,7 +1019,7 @@ public void setId(String id) throws FormatException, IOException { DicomTag sliceThickness = new DicomTag(SLICE_THICKNESS, DS); DicomTag sliceSpace = new DicomTag(SLICE_SPACING, DS); - Length physicalZ = r.getPixelsPhysicalSizeZ(pyramid); + Length physicalZ = fixUnits(r.getPixelsPhysicalSizeZ(pyramid)); if (physicalZ != null) { sliceThickness.value = padString(String.valueOf(physicalZ.value(UNITS.MM))); } @@ -1032,8 +1032,8 @@ public void setId(String id) throws FormatException, IOException { pixelMeasuresSequence.children.add(sliceSpace); DicomTag pixelSpacing = new DicomTag(PIXEL_SPACING, DS); - Length physicalX = r.getPixelsPhysicalSizeX(pyramid); - Length physicalY = r.getPixelsPhysicalSizeY(pyramid); + Length physicalX = fixUnits(r.getPixelsPhysicalSizeX(pyramid)); + Length physicalY = fixUnits(r.getPixelsPhysicalSizeY(pyramid)); String px = physicalX == null ? "1" : String.valueOf(physicalX.value(UNITS.MM)); String py = physicalY == null ? "1" : String.valueOf(physicalY.value(UNITS.MM)); pixelSpacing.value = padString(px + "\\" + py); @@ -2076,6 +2076,18 @@ private short[] makeShortArray(int v) { return s; } + /** + * Check if the unit for the given Length is "pixel" + * or "referenceframe". These two units cannot be assigned to + * proper physical units (e.g. mm), so need to be handled specially. + */ + private Length fixUnits(Length size) { + if (size == null || size.unit() == UNITS.PIXEL || size.unit() == UNITS.REFERENCEFRAME) { + return null; + } + return size; + } + private TiffRational getPhysicalSize(Length size) { if (size == null || size.value(UNITS.MICROMETER) == null) { return new TiffRational(0, 1000); From c7e916197cafd5820993320198be315a50c1abfb Mon Sep 17 00:00:00 2001 From: Melissa Linkert Date: Thu, 12 Sep 2024 20:45:47 -0500 Subject: [PATCH 4/4] Warn if relative units are encountered for a physical length --- .../formats-bsd/src/loci/formats/out/DicomWriter.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/formats-bsd/src/loci/formats/out/DicomWriter.java b/components/formats-bsd/src/loci/formats/out/DicomWriter.java index 05d27e26de6..808f81ea87b 100644 --- a/components/formats-bsd/src/loci/formats/out/DicomWriter.java +++ b/components/formats-bsd/src/loci/formats/out/DicomWriter.java @@ -2082,7 +2082,12 @@ private short[] makeShortArray(int v) { * proper physical units (e.g. mm), so need to be handled specially. */ private Length fixUnits(Length size) { - if (size == null || size.unit() == UNITS.PIXEL || size.unit() == UNITS.REFERENCEFRAME) { + if (size == null) { + return null; + } + if (size.unit() == UNITS.PIXEL || size.unit() == UNITS.REFERENCEFRAME) { + LOGGER.warn("Found physical length '{}' in relative units '{}'; this value will be lost", + size.value(), size.unit()); return null; } return size;