changeset 220:7ffcce8ec94c

Fix issue #145 (support of Concatenation UID)
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 12 Jan 2021 18:32:30 +0100
parents ef3f8c5126a4
children dbcf9ad44a70
files Framework/Outputs/DicomPyramidWriter.cpp Framework/Outputs/MultiframeDicomWriter.cpp Framework/Outputs/MultiframeDicomWriter.h NEWS
diffstat 4 files changed, 54 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/Framework/Outputs/DicomPyramidWriter.cpp	Tue Jan 12 17:09:57 2021 +0100
+++ b/Framework/Outputs/DicomPyramidWriter.cpp	Tue Jan 12 18:32:30 2021 +0100
@@ -138,9 +138,10 @@
 
       if (writer == NULL)
       {
+        const bool isConcatenation = (maxSize_ != 0);
         writer = new MultiframeDicomWriter
           (dataset_, GetImageCompression(), GetPixelFormat(), level.width_, level.height_, 
-           GetTileWidth(), GetTileHeight(), photometric_);
+           GetTileWidth(), GetTileHeight(), photometric_, isConcatenation);
         writers_[z] = writer;
 
         {
--- a/Framework/Outputs/MultiframeDicomWriter.cpp	Tue Jan 12 17:09:57 2021 +0100
+++ b/Framework/Outputs/MultiframeDicomWriter.cpp	Tue Jan 12 18:32:30 2021 +0100
@@ -25,8 +25,9 @@
 #include "../DicomToolbox.h"
 
 #include <Compatibility.h>  // For std::unique_ptr
+#include <DicomParsing/FromDcmtkBridge.h>
+#include <Logging.h>
 #include <OrthancException.h>
-#include <Logging.h>
 
 #include <dcmtk/dcmdata/dcuid.h>
 #include <dcmtk/dcmdata/dcdeftag.h>
@@ -98,6 +99,9 @@
       offsetList_.reset(new DcmOffsetList);
     }
 
+    firstFrameInInstance_ += framesCount_;
+    countInstances_ ++;
+
     writtenSize_ = 0;
     framesCount_ = 0;
   }
@@ -150,10 +154,15 @@
                                                unsigned int height,
                                                unsigned int tileWidth,
                                                unsigned int tileHeight,
-                                               Orthanc::PhotometricInterpretation photometric) :
+                                               Orthanc::PhotometricInterpretation photometric,
+                                               bool isConcatenation) :
     compression_(compression),
+    framesCount_(0),
     width_(width),
-    height_(height)
+    height_(height),
+    isConcatenation_(isConcatenation),
+    countInstances_(0),
+    firstFrameInInstance_(0)
   {
     switch (compression)
     {
@@ -208,6 +217,28 @@
         throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
 
+    if (isConcatenation)
+    {
+      /**
+       * Generate a shared SOP Instance UID that corresponds to the
+       * main instance containing all the instances. This main
+       * instance is purely "virtual", as it is never generated.
+       * https://bugs.orthanc-server.com/show_bug.cgi?id=145
+       * http://dicom.nema.org/medical/dicom/2020d/output/chtml/part03/figures/PS3.3_C.7.6.16-1a.svg
+       **/
+      DicomToolbox::SetStringTag(sharedTags_, DCM_SOPInstanceUIDOfConcatenationSource,
+                                 Orthanc::FromDcmtkBridge::GenerateUniqueIdentifier(Orthanc::ResourceType_Instance));
+
+      /**
+       * Similarly, we generate one random UID to identify the
+       * concatenation. As we never generate two different
+       * concatenations of the "main" instance, this UID is shared by
+       * all the instances of the concatenation.
+       **/
+      DicomToolbox::SetStringTag(sharedTags_, DCM_ConcatenationUID,
+                                 Orthanc::FromDcmtkBridge::GenerateUniqueIdentifier(Orthanc::ResourceType_Instance));
+    }
+
     ResetImage();
   }
 
@@ -259,23 +290,27 @@
       throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
 
-    std::string tmp = boost::lexical_cast<std::string>(instanceNumber);
-
     std::unique_ptr<DcmFileFormat> dicom(new DcmFileFormat);
 
-    char uid[100];
-    dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT);
-
+    const std::string uid = Orthanc::FromDcmtkBridge::GenerateUniqueIdentifier(Orthanc::ResourceType_Instance);
+    
     if (!dicom->getDataset()->copyFrom(sharedTags_).good() ||
         !dicom->getDataset()->insert(perFrameFunctionalGroups_.release(), false, false).good() ||
-        !dicom->getDataset()->putAndInsertString(DCM_SOPInstanceUID, uid).good() ||
-        !dicom->getDataset()->putAndInsertString(DCM_InstanceNumber, tmp.c_str()).good())
+        !dicom->getDataset()->putAndInsertString(DCM_SOPInstanceUID, uid.c_str()).good())
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
     }
 
+    // The two tags below have "IS" (integer string) value representation
+    DicomToolbox::SetStringTag(*dicom->getDataset(), DCM_InstanceNumber, boost::lexical_cast<std::string>(instanceNumber));
     DicomToolbox::SetStringTag(*dicom->getDataset(), DCM_NumberOfFrames, boost::lexical_cast<std::string>(framesCount_));
 
+    if (isConcatenation_)
+    {
+      DicomToolbox::SetUint32Tag(*dicom->getDataset(), DCM_ConcatenationFrameOffsetNumber, firstFrameInInstance_);
+      DicomToolbox::SetUint16Tag(*dicom->getDataset(), DCM_InConcatenationNumber, countInstances_);
+    }
+
     switch (compression_)
     {
       case ImageCompression_None:
--- a/Framework/Outputs/MultiframeDicomWriter.h	Tue Jan 12 17:09:57 2021 +0100
+++ b/Framework/Outputs/MultiframeDicomWriter.h	Tue Jan 12 18:32:30 2021 +0100
@@ -54,6 +54,10 @@
     DcmPixelItem*                      offsetTable_;
     std::unique_ptr<DcmOffsetList>       offsetList_;
 
+    bool             isConcatenation_;
+    unsigned int     countInstances_;
+    unsigned int     firstFrameInInstance_;
+    
     void ResetImage();
 
     void InjectUncompressedPixelData(DcmFileFormat& dicom);
@@ -66,7 +70,8 @@
                           unsigned int height,
                           unsigned int tileWidth,
                           unsigned int tileHeight,
-                          Orthanc::PhotometricInterpretation photometric);
+                          Orthanc::PhotometricInterpretation photometric,
+                          bool isConcatenation);
 
     void AddFrame(const std::string& frame,
                   DcmItem* functionalGroup);   // This takes the ownership
--- a/NEWS	Tue Jan 12 17:09:57 2021 +0100
+++ b/NEWS	Tue Jan 12 18:32:30 2021 +0100
@@ -6,6 +6,7 @@
 * Better handling of PhotometricInterpretation in viewer
 * Fix colorspace of TIFF containing JPEG with RGB photometric interpretation (not YCbCr)
 * Don't display the thumbnail/overview instances in the Web viewer
+* Fix issue #145 (support of Concatenation UID)
 * Support of dynamic linking against the system-wide Orthanc framework library