diff OrthancFramework/Sources/DicomFormat/DicomImageInformation.cpp @ 4827:4cfd96732076

Support decoding of black-and-white images (with 1 bit per pixel), notably DICOM SEG
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 25 Nov 2021 15:52:54 +0100
parents d9473bd5ed43
children 7053502fbf97
line wrap: on
line diff
--- a/OrthancFramework/Sources/DicomFormat/DicomImageInformation.cpp	Thu Nov 25 13:58:10 2021 +0100
+++ b/OrthancFramework/Sources/DicomFormat/DicomImageInformation.cpp	Thu Nov 25 15:52:54 2021 +0100
@@ -124,6 +124,11 @@
         bitsStored_ = bitsAllocated_;
       }
 
+      if (bitsStored_ > bitsAllocated_)
+      {
+        throw OrthancException(ErrorCode_BadFileFormat);
+      }
+
       if (!values.ParseUnsignedInteger32(highBit_, DICOM_TAG_HIGH_BIT))
       {
         highBit_ = bitsStored_ - 1;
@@ -168,7 +173,8 @@
     }
 
     if (bitsAllocated_ != 8 && bitsAllocated_ != 16 &&
-        bitsAllocated_ != 24 && bitsAllocated_ != 32)
+        bitsAllocated_ != 24 && bitsAllocated_ != 32 &&
+        bitsAllocated_ != 1 /* new in Orthanc 1.9.8 */)
     {
       throw OrthancException(ErrorCode_IncompatibleImageFormat, "Image not supported: " + boost::lexical_cast<std::string>(bitsAllocated_) + " bits allocated");
     }
@@ -186,7 +192,26 @@
       throw OrthancException(ErrorCode_IncompatibleImageFormat, "Image not supported: samples per pixel is 0");
     }
 
-    bytesPerValue_ = bitsAllocated_ / 8;
+    if (bitsStored_ == 1)
+    {
+      // This is the case of DICOM SEG, new in Orthanc 1.9.8
+      if (bitsAllocated_ != 1)
+      {
+        throw OrthancException(ErrorCode_BadFileFormat);
+      }
+      else if (width_ % 8 != 0)
+      {
+        throw OrthancException(ErrorCode_BadFileFormat, "Bad number of columns for a black-and-white image");
+      }
+      else
+      {
+        bytesPerValue_ = 0;  // Arbitrary initialization
+      }
+    }
+    else
+    {
+      bytesPerValue_ = bitsAllocated_ / 8;
+    }
 
     isPlanar_ = (planarConfiguration != 0 ? true : false);
     isSigned_ = (pixelRepresentation != 0 ? true : false);
@@ -237,7 +262,16 @@
 
   size_t DicomImageInformation::GetBytesPerValue() const
   {
-    return bytesPerValue_;
+    if (bitsStored_ == 1)
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls,
+                             "This call is incompatible with black-and-white images");
+    }
+    else
+    {
+      assert(bitsAllocated_ >= 8);
+      return bytesPerValue_;
+    }
   }
 
   bool DicomImageInformation::IsSigned() const
@@ -315,6 +349,13 @@
         format = PixelFormat_Grayscale32;
         return true;
       }
+
+      if (GetBitsStored() == 1 && GetChannelCount() == 1 && !IsSigned())
+      {
+        // This is the case of DICOM SEG, new in Orthanc 1.9.8
+        format = PixelFormat_Grayscale8;
+        return true;
+      }
     }
 
     if (GetBitsStored() == 8 &&
@@ -332,10 +373,27 @@
 
   size_t DicomImageInformation::GetFrameSize() const
   {
-    return (GetHeight() *
-            GetWidth() *
-            GetBytesPerValue() *
-            GetChannelCount());
+    if (bitsStored_ == 1)
+    {
+      assert(GetWidth() % 8 == 0);
+      
+      if (GetChannelCount() == 1)
+      {
+        return GetHeight() * GetWidth() / 8;
+      }
+      else
+      {
+        throw OrthancException(ErrorCode_IncompatibleImageFormat,
+                               "Image not supported (multi-channel black-and-image image)");
+      }
+    }
+    else
+    {
+      return (GetHeight() *
+              GetWidth() *
+              GetBytesPerValue() *
+              GetChannelCount());
+    }
   }