changeset 5129:16138d6d568d

fix decoding of RLE images for which the "Planar Configuration" tag (0028,0006) equals 1
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 22 Dec 2022 15:28:14 +0100
parents ede035d48b8e
children e107ff622e6d
files NEWS OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.cpp
diffstat 2 files changed, 61 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Mon Dec 19 20:00:21 2022 +0100
+++ b/NEWS	Thu Dec 22 15:28:14 2022 +0100
@@ -32,7 +32,12 @@
 Common plugins code (C++)
 -------------------------
 
-* Added a 'header' argument to all OrthancPeers::DoPost, DoPut, ... 
+* Added a 'header' argument to all OrthancPeers::DoPost, DoPut, ...
+
+Maintenance
+-----------
+
+* Fix decoding of RLE images for which the "Planar Configuration" tag (0028,0006) equals 1
 
 
 version 1.11.2 (2022-08-30)
--- a/OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.cpp	Mon Dec 19 20:00:21 2022 +0100
+++ b/OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.cpp	Thu Dec 22 15:28:14 2022 +0100
@@ -644,6 +644,51 @@
   }
 
 
+  static ImageAccessor* DecodePlanarConfiguration(const ImageAccessor& source)
+  {
+    /**
+     * This function will interleave the RGB channels, if the source
+     * DICOM image has the "Planar Configuration" (0028,0006) tag that
+     * equals 1. This process was not applied to images using the RLE
+     * codec, which led to the following issue:
+     * https://groups.google.com/g/orthanc-users/c/CSVWfRasSR0/m/y1XDRXVnAgAJ
+     **/
+
+    const unsigned int height = source.GetHeight();
+    const unsigned int width = source.GetWidth();
+    const size_t size = static_cast<size_t>(height) * static_cast<size_t>(width);
+
+    if (source.GetFormat() != PixelFormat_RGB24 ||
+        3 * width != source.GetPitch())
+    {
+      throw OrthancException(ErrorCode_NotImplemented);
+    }
+
+    std::unique_ptr<ImageAccessor> target(new Image(PixelFormat_RGB24, width, height, false));
+
+    const uint8_t* red = reinterpret_cast<const uint8_t*>(source.GetConstBuffer());
+    const uint8_t* green = red + size;
+    const uint8_t* blue = red + 2 * size;
+
+    for (unsigned int y = 0; y < height; y++)
+    {
+      uint8_t* interleaved = reinterpret_cast<uint8_t*>(target->GetRow(y));
+      for (unsigned int x = 0; x < width; x++)
+      {
+        interleaved[0] = *red;
+        interleaved[1] = *green;
+        interleaved[2] = *blue;
+        interleaved += 3;
+        red++;
+        green++;
+        blue++;
+      }
+    }
+
+    return target.release();
+  }
+
+
   ImageAccessor* DicomImageDecoder::ApplyCodec
   (const DcmCodec& codec,
    const DcmCodecParameter& parameters,
@@ -700,7 +745,16 @@
                                "Cannot decode a non-palette image");
       }
 
-      return target.release();
+      if (target->GetFormat() == PixelFormat_RGB24 &&
+          Orthanc::Toolbox::StripSpaces(decompressedColorModel.c_str()) == "RGB" &&
+          info.IsPlanar())
+      {
+        return DecodePlanarConfiguration(*target);
+      }
+      else
+      {
+        return target.release();
+      }
     }
   }