# HG changeset patch # User Sebastien Jodogne # Date 1610472750 -3600 # Node ID 7ffcce8ec94c7e9e248f4bf54be0017d135d7f8e # Parent ef3f8c5126a47533fd6964f0eb88c7d80078fe27 Fix issue #145 (support of Concatenation UID) diff -r ef3f8c5126a4 -r 7ffcce8ec94c Framework/Outputs/DicomPyramidWriter.cpp --- 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; { diff -r ef3f8c5126a4 -r 7ffcce8ec94c Framework/Outputs/MultiframeDicomWriter.cpp --- 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 // For std::unique_ptr +#include +#include #include -#include #include #include @@ -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(instanceNumber); - std::unique_ptr 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(instanceNumber)); DicomToolbox::SetStringTag(*dicom->getDataset(), DCM_NumberOfFrames, boost::lexical_cast(framesCount_)); + if (isConcatenation_) + { + DicomToolbox::SetUint32Tag(*dicom->getDataset(), DCM_ConcatenationFrameOffsetNumber, firstFrameInInstance_); + DicomToolbox::SetUint16Tag(*dicom->getDataset(), DCM_InConcatenationNumber, countInstances_); + } + switch (compression_) { case ImageCompression_None: diff -r ef3f8c5126a4 -r 7ffcce8ec94c Framework/Outputs/MultiframeDicomWriter.h --- 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 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 diff -r ef3f8c5126a4 -r 7ffcce8ec94c NEWS --- 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