# HG changeset patch # User Sebastien Jodogne # Date 1584114613 -3600 # Node ID ca36e3f1112c474880516ef2ab09395e11d864eb # Parent 7b6058f8f7aa8fd747965b5364609f98879637ef transcoding to uncompressed transfer syntaxes diff -r 7b6058f8f7aa -r ca36e3f1112c Core/DicomParsing/FromDcmtkBridge.cpp --- a/Core/DicomParsing/FromDcmtkBridge.cpp Fri Mar 13 08:32:13 2020 +0100 +++ b/Core/DicomParsing/FromDcmtkBridge.cpp Fri Mar 13 16:50:13 2020 +0100 @@ -120,6 +120,12 @@ #endif +#include +#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 +# include +#endif + + namespace Orthanc { static bool IsBinaryTag(const DcmTag& key) @@ -1197,6 +1203,52 @@ } } + + + static bool SaveToMemoryBufferInternal(std::string& buffer, + DcmFileFormat& dicom, + E_TransferSyntax xfer) + { + E_EncodingType encodingType = /*opt_sequenceType*/ EET_ExplicitLength; + + // Create a memory buffer with the proper size + { + const uint32_t estimatedSize = dicom.calcElementLength(xfer, encodingType); // (*) + buffer.resize(estimatedSize); + } + + DcmOutputBufferStream ob(&buffer[0], buffer.size()); + + // Fill the memory buffer with the meta-header and the dataset + dicom.transferInit(); + OFCondition c = dicom.write(ob, xfer, encodingType, NULL, + /*opt_groupLength*/ EGL_recalcGL, + /*opt_paddingType*/ EPD_withoutPadding); + dicom.transferEnd(); + + if (c.good()) + { + // The DICOM file is successfully written, truncate the target + // buffer if its size was overestimated by (*) + ob.flush(); + + size_t effectiveSize = static_cast(ob.tell()); + if (effectiveSize < buffer.size()) + { + buffer.resize(effectiveSize); + } + + return true; + } + else + { + // Error + buffer.clear(); + return false; + } + } + + bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer, DcmDataset& dataSet) { @@ -1221,47 +1273,51 @@ xfer = EXS_LittleEndianExplicit; } - E_EncodingType encodingType = /*opt_sequenceType*/ EET_ExplicitLength; - // Create the meta-header information DcmFileFormat ff(&dataSet); ff.validateMetaInfo(xfer); ff.removeInvalidGroups(); - // Create a memory buffer with the proper size + return SaveToMemoryBufferInternal(buffer, ff, xfer); + } + + + bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer, + DcmFileFormat& dicom) + { + E_TransferSyntax xfer = dicom.getDataset()->getOriginalXfer(); + if (xfer == EXS_Unknown) { - const uint32_t estimatedSize = ff.calcElementLength(xfer, encodingType); // (*) - buffer.resize(estimatedSize); + throw OrthancException(ErrorCode_InternalError, + "Cannot write a DICOM instance with unknown transfer syntax"); } - - DcmOutputBufferStream ob(&buffer[0], buffer.size()); - - // Fill the memory buffer with the meta-header and the dataset - ff.transferInit(); - OFCondition c = ff.write(ob, xfer, encodingType, NULL, - /*opt_groupLength*/ EGL_recalcGL, - /*opt_paddingType*/ EPD_withoutPadding); - ff.transferEnd(); - - if (c.good()) + else if (!dicom.validateMetaInfo(xfer).good()) { - // The DICOM file is successfully written, truncate the target - // buffer if its size was overestimated by (*) - ob.flush(); - - size_t effectiveSize = static_cast(ob.tell()); - if (effectiveSize < buffer.size()) - { - buffer.resize(effectiveSize); - } - - return true; + throw OrthancException(ErrorCode_InternalError, + "Cannot setup the transfer syntax to write a DICOM instance"); } else { - // Error - buffer.clear(); - return false; + return SaveToMemoryBufferInternal(buffer, dicom, xfer); + } + } + + + bool FromDcmtkBridge::Transcode(std::string& buffer, + DcmFileFormat& dicom, + DicomTransferSyntax syntax, + const DcmRepresentationParameter* representation) + { + E_TransferSyntax xfer; + if (!LookupDcmtkTransferSyntax(xfer, syntax)) + { + throw OrthancException(ErrorCode_InternalError); + } + else + { + return (dicom.getDataset()->chooseRepresentation(xfer, representation).good() && + dicom.getDataset()->canWriteXfer(xfer) && + SaveToMemoryBufferInternal(buffer, dicom, xfer)); } } @@ -2064,6 +2120,12 @@ DJEncoderRegistration::registerCodecs(); # endif #endif + + LOG(INFO) << "Registering RLE codecs in DCMTK"; + DcmRLEDecoderRegistration::registerCodecs(); +#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 + DcmRLEEncoderRegistration::registerCodecs(); +#endif } @@ -2084,6 +2146,11 @@ DJEncoderRegistration::cleanup(); # endif #endif + + DcmRLEDecoderRegistration::cleanup(); +#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 + DcmRLEEncoderRegistration::cleanup(); +#endif } diff -r 7b6058f8f7aa -r ca36e3f1112c Core/DicomParsing/FromDcmtkBridge.h --- a/Core/DicomParsing/FromDcmtkBridge.h Fri Mar 13 08:32:13 2020 +0100 +++ b/Core/DicomParsing/FromDcmtkBridge.h Fri Mar 13 16:50:13 2020 +0100 @@ -205,6 +205,14 @@ static bool SaveToMemoryBuffer(std::string& buffer, DcmDataset& dataSet); + static bool SaveToMemoryBuffer(std::string& buffer, + DcmFileFormat& dicom); + + static bool Transcode(std::string& buffer, + DcmFileFormat& dicom, + DicomTransferSyntax syntax, + const DcmRepresentationParameter* representation); + static ValueRepresentation Convert(DcmEVR vr); static ValueRepresentation LookupValueRepresentation(const DicomTag& tag); diff -r 7b6058f8f7aa -r ca36e3f1112c UnitTestsSources/FromDcmtkTests.cpp --- a/UnitTestsSources/FromDcmtkTests.cpp Fri Mar 13 08:32:13 2020 +0100 +++ b/UnitTestsSources/FromDcmtkTests.cpp Fri Mar 13 16:50:13 2020 +0100 @@ -1946,8 +1946,11 @@ virtual void GetCompressedFrame(std::string& target, unsigned int frame) = 0; - virtual IDicomTranscoder* Transcode(std::set syntaxes, - bool allowNewSopInstanceUid) = 0; + virtual bool Transcode(std::string& target, + std::set syntaxes, + bool allowNewSopInstanceUid) = 0; + + virtual void WriteToMemoryBuffer(std::string& target) = 0; }; @@ -2040,6 +2043,15 @@ return index_->GetFramesCount(); } + virtual void WriteToMemoryBuffer(std::string& target) ORTHANC_OVERRIDE + { + if (!FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_)) + { + throw OrthancException(ErrorCode_InternalError, + "Cannot write the DICOM instance to a memory buffer"); + } + } + virtual ImageAccessor* DecodeFrame(unsigned int frame) ORTHANC_OVERRIDE { assert(dicom_->getDataset() != NULL); @@ -2049,48 +2061,32 @@ virtual void GetCompressedFrame(std::string& target, unsigned int frame) ORTHANC_OVERRIDE { -#if 1 index_->GetRawFrame(target, frame); - printf("%d: %d\n", frame, target.size()); -#endif - -#if 1 - assert(dicom_->getDataset() != NULL); - DcmDataset& dataset = *dicom_->getDataset(); - - DcmPixelSequence* pixelSequence = FromDcmtkBridge::GetPixelSequence(dataset); - - if (pixelSequence != NULL && - frame == 0 && - pixelSequence->card() != GetFramesCount() + 1) - { - printf("COMPRESSED\n"); - - // Check out "djcodecd.cc" - - printf("%d fragments\n", pixelSequence->card()); - - // Skip the first fragment, that is the offset table - for (unsigned long i = 1; ;i++) - { - DcmPixelItem *fragment = NULL; - if (pixelSequence->getItem(fragment, i).good()) - { - printf("fragment %d %d\n", i, fragment->getLength()); - } - else - { - break; - } - } - } -#endif } - virtual IDicomTranscoder* Transcode(std::set syntaxes, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE + virtual bool Transcode(std::string& target, + std::set syntaxes, + bool allowNewSopInstanceUid) ORTHANC_OVERRIDE { - throw OrthancException(ErrorCode_NotImplemented); + if (syntaxes.find(DicomTransferSyntax_LittleEndianImplicit) != syntaxes.end() && + FromDcmtkBridge::Transcode(target, *dicom_, DicomTransferSyntax_LittleEndianImplicit, NULL)) + { + return true; + } + else if (syntaxes.find(DicomTransferSyntax_LittleEndianExplicit) != syntaxes.end() && + FromDcmtkBridge::Transcode(target, *dicom_, DicomTransferSyntax_LittleEndianExplicit, NULL)) + { + return true; + } + else if (syntaxes.find(DicomTransferSyntax_BigEndianExplicit) != syntaxes.end() && + FromDcmtkBridge::Transcode(target, *dicom_, DicomTransferSyntax_BigEndianExplicit, NULL)) + { + return true; + } + else + { + return false; + } } }; } @@ -2182,9 +2178,9 @@ Orthanc::DcmtkTranscoder transcoder(s.c_str(), s.size()); - printf("[%s] [%s] [%s] %d\n", GetTransferSyntaxUid(transcoder.GetTransferSyntax()), + printf("[%s] [%s] [%s] %d %d\n", GetTransferSyntaxUid(transcoder.GetTransferSyntax()), transcoder.GetSopClassUid().c_str(), transcoder.GetSopInstanceUid().c_str(), - transcoder.GetFramesCount()); + transcoder.GetFramesCount(), transcoder.GetTransferSyntax()); for (size_t i = 0; i < transcoder.GetFramesCount(); i++) { @@ -2201,6 +2197,29 @@ } } + { + std::string t; + transcoder.WriteToMemoryBuffer(t); + + Orthanc::DcmtkTranscoder transcoder2(t.c_str(), t.size()); + printf(">> %d %d ; %d bytes\n", transcoder.GetTransferSyntax(), transcoder2.GetTransferSyntax(), t.size()); + } + + { + std::set syntaxes; + syntaxes.insert(DicomTransferSyntax_LittleEndianExplicit); + + std::string t; + bool ok = transcoder.Transcode(t, syntaxes, false); + printf("Transcoding: %d\n", ok); + + if (ok) + { + Orthanc::DcmtkTranscoder transcoder2(t.c_str(), t.size()); + printf(" => transcoded transfer syntax %d ; %d bytes\n", transcoder2.GetTransferSyntax(), t.size()); + } + } + printf("\n"); }