Mercurial > hg > orthanc
changeset 6478:b168eb544b0c pixel-anon
added enum TranscodingSopInstanceUidMode
line wrap: on
line diff
--- a/OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake Sat Nov 22 12:29:36 2025 +0100 +++ b/OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake Tue Nov 25 08:08:08 2025 +0100 @@ -558,6 +558,7 @@ ${CMAKE_CURRENT_LIST_DIR}/../../Sources/DicomParsing/Internals/DicomFrameIndex.cpp ${CMAKE_CURRENT_LIST_DIR}/../../Sources/DicomParsing/Internals/DicomImageDecoder.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../Sources/DicomParsing/Internals/SopInstanceUidFixer.cpp ) if (NOT ORTHANC_SANDBOXED)
--- a/OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.cpp Sat Nov 22 12:29:36 2025 +0100 +++ b/OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.cpp Tue Nov 25 08:08:08 2025 +0100 @@ -581,7 +581,7 @@ targetSyntaxes.insert(preferredTransferSyntax); attemptedSyntaxes.insert(preferredTransferSyntax); - success = transcoder.Transcode(transcoded, source, targetSyntaxes, true); + success = transcoder.Transcode(transcoded, source, targetSyntaxes, TranscodingSopInstanceUidMode_AllowNew); isDestructiveCompressionAllowed = true; } @@ -612,7 +612,7 @@ if (!targetSyntaxes.empty()) { - success = transcoder.Transcode(transcoded, source, targetSyntaxes, false); + success = transcoder.Transcode(transcoded, source, targetSyntaxes, TranscodingSopInstanceUidMode_NoChange); isDestructiveCompressionAllowed = false; } }
--- a/OrthancFramework/Sources/DicomParsing/DcmtkTranscoder.cpp Sat Nov 22 12:29:36 2025 +0100 +++ b/OrthancFramework/Sources/DicomParsing/DcmtkTranscoder.cpp Tue Nov 25 08:08:08 2025 +0100 @@ -36,6 +36,7 @@ #include "FromDcmtkBridge.h" +#include "Internals/SopInstanceUidFixer.h" #include "../Logging.h" #include "../OrthancException.h" #include "../Toolbox.h" @@ -105,11 +106,12 @@ return false; } + bool DcmtkTranscoder::InplaceTranscode(DicomTransferSyntax& selectedSyntax /* out */, std::string& failureReason /* out */, DcmFileFormat& dicom, /* in/out */ const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid, + TranscodingSopInstanceUidMode mode, unsigned int lossyQuality) { std::vector<std::string> failureReasons; @@ -155,6 +157,12 @@ return true; } + // The SOP Instance UID fixer has only an effect if "mode" is TranscodingSopInstanceUidMode_Preserve + // and if transcoding to a lossy transfer syntax + const Internals::SopInstanceUidFixer fixer(mode, dicom); + + const bool allowNewSopInstanceUid = (mode == TranscodingSopInstanceUidMode_AllowNew || + mode == TranscodingSopInstanceUidMode_Preserve); #if ORTHANC_ENABLE_DCMTK_JPEG == 1 if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess1) != allowedSyntaxes.end()) @@ -174,6 +182,7 @@ if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess1, ¶meters)) { + fixer.Apply(dicom); selectedSyntax = DicomTransferSyntax_JPEGProcess1; return true; } @@ -199,6 +208,7 @@ DJ_RPLossy parameters(lossyQuality); if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess2_4, ¶meters)) { + fixer.Apply(dicom); selectedSyntax = DicomTransferSyntax_JPEGProcess2_4; return true; } @@ -215,6 +225,7 @@ 0 /* opt_point_transform */); if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess14, ¶meters)) { + fixer.Apply(dicom); selectedSyntax = DicomTransferSyntax_JPEGProcess14; return true; } @@ -271,6 +282,7 @@ **/ if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGLSLossy, ¶meters)) { + fixer.Apply(dicom); selectedSyntax = DicomTransferSyntax_JPEGLSLossy; return true; } @@ -316,16 +328,16 @@ bool DcmtkTranscoder::Transcode(DicomImage& target, DicomImage& source /* in, "GetParsed()" possibly modified */, const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid) + TranscodingSopInstanceUidMode mode) { - return Transcode(target, source, allowedSyntaxes, allowNewSopInstanceUid, defaultLossyQuality_); + return Transcode(target, source, allowedSyntaxes, mode, defaultLossyQuality_); } bool DcmtkTranscoder::Transcode(DicomImage& target, DicomImage& source /* in, "GetParsed()" possibly modified */, const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid, + TranscodingSopInstanceUidMode mode, unsigned int lossyQuality) { Semaphore::Locker lock(maxConcurrentExecutionsSemaphore_); // limit the number of concurrent executions @@ -373,7 +385,7 @@ return true; } else if (InplaceTranscode(targetSyntax, failureReason, source.GetParsed(), - allowedSyntaxes, allowNewSopInstanceUid, lossyQuality)) + allowedSyntaxes, mode, lossyQuality)) { // Sanity check DicomTransferSyntax targetSyntax2; @@ -385,9 +397,13 @@ source.Clear(); #if !defined(NDEBUG) - // Only run the sanity check in debug mode - CheckTranscoding(target, sourceSyntax, sourceSopInstanceUid, - allowedSyntaxes, allowNewSopInstanceUid); + { + // Only run the sanity check in debug mode + const bool allowNewSopInstanceUid = (mode == TranscodingSopInstanceUidMode_AllowNew || + mode == TranscodingSopInstanceUidMode_Preserve); + CheckTranscoding(target, sourceSyntax, sourceSopInstanceUid, + allowedSyntaxes, allowNewSopInstanceUid); + } #endif return true;
--- a/OrthancFramework/Sources/DicomParsing/DcmtkTranscoder.h Sat Nov 22 12:29:36 2025 +0100 +++ b/OrthancFramework/Sources/DicomParsing/DcmtkTranscoder.h Tue Nov 25 08:08:08 2025 +0100 @@ -48,7 +48,7 @@ std::string& failureReason /* out */, DcmFileFormat& dicom, const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid, + TranscodingSopInstanceUidMode mode, unsigned int lossyQuality); public: @@ -63,12 +63,12 @@ virtual bool Transcode(DicomImage& target, DicomImage& source /* in, "GetParsed()" possibly modified */, const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE; + TranscodingSopInstanceUidMode mode) ORTHANC_OVERRIDE; virtual bool Transcode(DicomImage& target, DicomImage& source /* in, "GetParsed()" possibly modified */, const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid, + TranscodingSopInstanceUidMode mode, unsigned int lossyQuality) ORTHANC_OVERRIDE; }; }
--- a/OrthancFramework/Sources/DicomParsing/IDicomTranscoder.h Sat Nov 22 12:29:36 2025 +0100 +++ b/OrthancFramework/Sources/DicomParsing/IDicomTranscoder.h Tue Nov 25 08:08:08 2025 +0100 @@ -56,8 +56,6 @@ void Serialize(); - DcmFileFormat* ReleaseParsed(); - public: DicomImage(); @@ -81,6 +79,8 @@ DcmFileFormat& GetParsed(); + DcmFileFormat* ReleaseParsed(); + ParsedDicomFile* ReleaseAsParsedDicomFile(); const void* GetBufferData(); @@ -114,12 +114,12 @@ virtual bool Transcode(DicomImage& target, DicomImage& source /* in, "GetParsed()" possibly modified */, const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid) = 0; + TranscodingSopInstanceUidMode mode) = 0; virtual bool Transcode(DicomImage& target, DicomImage& source /* in, "GetParsed()" possibly modified */, const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid, + TranscodingSopInstanceUidMode mode, unsigned int lossyQuality) = 0; static std::string GetSopInstanceUid(DcmFileFormat& dicom);
--- a/OrthancFramework/Sources/DicomParsing/MemoryBufferTranscoder.cpp Sat Nov 22 12:29:36 2025 +0100 +++ b/OrthancFramework/Sources/DicomParsing/MemoryBufferTranscoder.cpp Tue Nov 25 08:08:08 2025 +0100 @@ -28,6 +28,7 @@ #include "../Logging.h" #include "../OrthancException.h" #include "FromDcmtkBridge.h" +#include "Internals/SopInstanceUidFixer.h" #if !defined(NDEBUG) // For debugging # include "ParsedDicomFile.h" @@ -59,16 +60,16 @@ bool MemoryBufferTranscoder::Transcode(DicomImage& target, DicomImage& source, const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid, + TranscodingSopInstanceUidMode mode, unsigned int lossyQualityNotUsed) { - return Transcode(target, source, allowedSyntaxes, allowNewSopInstanceUid); + return Transcode(target, source, allowedSyntaxes, mode); } bool MemoryBufferTranscoder::Transcode(DicomImage& target, DicomImage& source, const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid) + TranscodingSopInstanceUidMode mode) { target.Clear(); @@ -84,6 +85,10 @@ const std::string sourceSopInstanceUid = GetSopInstanceUid(source.GetParsed()); #endif + Internals::SopInstanceUidFixer fixer(mode, source); + const bool allowNewSopInstanceUid = (mode == TranscodingSopInstanceUidMode_AllowNew || + mode == TranscodingSopInstanceUidMode_Preserve); + std::string buffer; if (TranscodeBuffer(buffer, source.GetBufferData(), source.GetBufferSize(), allowedSyntaxes, allowNewSopInstanceUid)) @@ -98,6 +103,7 @@ allowedSyntaxes, allowNewSopInstanceUid); #endif + fixer.Apply(target); return true; } else
--- a/OrthancFramework/Sources/DicomParsing/MemoryBufferTranscoder.h Sat Nov 22 12:29:36 2025 +0100 +++ b/OrthancFramework/Sources/DicomParsing/MemoryBufferTranscoder.h Tue Nov 25 08:08:08 2025 +0100 @@ -42,12 +42,12 @@ virtual bool Transcode(DicomImage& target /* out */, DicomImage& source, const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE; + TranscodingSopInstanceUidMode mode) ORTHANC_OVERRIDE; virtual bool Transcode(DicomImage& target /* out */, DicomImage& source, const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid, + TranscodingSopInstanceUidMode mode, unsigned int lossyQualityNotUsed) ORTHANC_OVERRIDE; }; }
--- a/OrthancFramework/Sources/Enumerations.h Sat Nov 22 12:29:36 2025 +0100 +++ b/OrthancFramework/Sources/Enumerations.h Tue Nov 25 08:08:08 2025 +0100 @@ -809,6 +809,13 @@ ErrorPayloadType_RetrieveJob = 3, }; + enum TranscodingSopInstanceUidMode + { + TranscodingSopInstanceUidMode_NoChange, // Never change the SOP Instance UID (only allows transcoding to lossless) + TranscodingSopInstanceUidMode_AllowNew, // Allow transcoding to lossless and lossy (if lossy, a new SOP Instance UID is generated) + TranscodingSopInstanceUidMode_Preserve // Allow transcoding to lossless and lossy (if lossy, preserve the original SOP Instance UID) + }; + ORTHANC_PUBLIC const char* EnumerationToString(ErrorCode code);
--- a/OrthancFramework/UnitTestsSources/FromDcmtkTests.cpp Sat Nov 22 12:29:36 2025 +0100 +++ b/OrthancFramework/UnitTestsSources/FromDcmtkTests.cpp Tue Nov 25 08:08:08 2025 +0100 @@ -3681,7 +3681,7 @@ IDicomTranscoder::DicomImage source, target; source.AcquireParsed(dynamic_cast<DcmFileFormat*>(toto->clone())); - if (!transcoder.Transcode(target, source, s, true)) + if (!transcoder.Transcode(target, source, s, TranscodingSopInstanceUidMode_AllowNew)) { printf("**************** CANNOT: [%s] => [%s]\n", GetTransferSyntaxUid(sourceSyntax), GetTransferSyntaxUid(a));
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Sat Nov 22 12:29:36 2025 +0100 +++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Tue Nov 25 08:08:08 2025 +0100 @@ -5792,11 +5792,10 @@ IDicomTranscoder::DicomImage transcoded; bool success; - + { PImpl::ServerContextReference lock(*pimpl_); - success = lock.GetContext().Transcode( - transcoded, source, syntaxes, true /* allow new sop */); + success = lock.GetContext().Transcode(transcoded, source, syntaxes, TranscodingSopInstanceUidMode_AllowNew); } if (success)
--- a/OrthancServer/Sources/OrthancGetRequestHandler.cpp Sat Nov 22 12:29:36 2025 +0100 +++ b/OrthancServer/Sources/OrthancGetRequestHandler.cpp Tue Nov 25 08:08:08 2025 +0100 @@ -325,7 +325,7 @@ std::set<DicomTransferSyntax> ts; ts.insert(selectedSyntax); - if (context_.Transcode(transcoded, source, ts, true)) + if (context_.Transcode(transcoded, source, ts, TranscodingSopInstanceUidMode_AllowNew)) { // Transcoding has succeeded DcmDataset *stDetailTmp = NULL;
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp Sat Nov 22 12:29:36 2025 +0100 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp Tue Nov 25 08:08:08 2025 +0100 @@ -432,7 +432,7 @@ std::set<DicomTransferSyntax> allowedSyntaxes; allowedSyntaxes.insert(GetTransferSyntax(call.GetArgument(GET_TRANSCODE, ""))); - if (context.Transcode(targetImage, sourceImage, allowedSyntaxes, true, lossyQuality)) + if (context.Transcode(targetImage, sourceImage, allowedSyntaxes, TranscodingSopInstanceUidMode_AllowNew, lossyQuality)) { call.GetOutput().SetContentFilename(filename.c_str()); call.GetOutput().AnswerBuffer(targetImage.GetBufferData(), targetImage.GetBufferSize(), MimeType_Dicom);
--- a/OrthancServer/Sources/ServerContext.cpp Sat Nov 22 12:29:36 2025 +0100 +++ b/OrthancServer/Sources/ServerContext.cpp Tue Nov 25 08:08:08 2025 +0100 @@ -1018,7 +1018,7 @@ IDicomTranscoder::DicomImage transcoded; - if (Transcode(transcoded, source, syntaxes, true /* allow new SOP instance UID */)) + if (Transcode(transcoded, source, syntaxes, TranscodingSopInstanceUidMode_AllowNew /* allow new SOP instance UID */)) { std::unique_ptr<ParsedDicomFile> tmp(transcoded.ReleaseAsParsedDicomFile()); @@ -1943,7 +1943,7 @@ source.SetExternalBuffer(buffer, size); allowedSyntaxes.insert(DicomTransferSyntax_LittleEndianExplicit); - if (Transcode(explicitTemporaryImage, source, allowedSyntaxes, true)) + if (Transcode(explicitTemporaryImage, source, allowedSyntaxes, TranscodingSopInstanceUidMode_AllowNew)) { std::unique_ptr<ParsedDicomFile> file(explicitTemporaryImage.ReleaseAsParsedDicomFile()); return file->DecodeFrame(frameIndex); @@ -2017,7 +2017,7 @@ std::set<DicomTransferSyntax> syntaxes; syntaxes.insert(targetSyntax); - if (Transcode(targetDicom, sourceDicom, syntaxes, true)) + if (Transcode(targetDicom, sourceDicom, syntaxes, TranscodingSopInstanceUidMode_AllowNew)) { cacheAccessor.AddTranscodedInstance(attachmentId, targetSyntax, reinterpret_cast<const char*>(targetDicom.GetBufferData()), targetDicom.GetBufferSize()); target = std::string(reinterpret_cast<const char*>(targetDicom.GetBufferData()), targetDicom.GetBufferSize()); @@ -2033,7 +2033,7 @@ bool ServerContext::Transcode(DicomImage& target, DicomImage& source /* in, "GetParsed()" possibly modified */, const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid) + TranscodingSopInstanceUidMode mode) { unsigned int lossyQuality; @@ -2042,19 +2042,19 @@ lossyQuality = lock.GetConfiguration().GetDicomLossyTranscodingQuality(); } - return Transcode(target, source, allowedSyntaxes, allowNewSopInstanceUid, lossyQuality); + return Transcode(target, source, allowedSyntaxes, mode, lossyQuality); } bool ServerContext::Transcode(DicomImage& target, DicomImage& source /* in, "GetParsed()" possibly modified */, const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid, + TranscodingSopInstanceUidMode mode, unsigned int lossyQuality) { if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_Before) { - if (dcmtkTranscoder_->Transcode(target, source, allowedSyntaxes, allowNewSopInstanceUid, lossyQuality)) + if (dcmtkTranscoder_->Transcode(target, source, allowedSyntaxes, mode, lossyQuality)) { return true; } @@ -2064,7 +2064,7 @@ if (HasPlugins() && GetPlugins().HasCustomTranscoder()) { - if (GetPlugins().Transcode(target, source, allowedSyntaxes, allowNewSopInstanceUid)) // TODO: pass lossyQuality to plugins -> needs a new plugin interface + if (GetPlugins().Transcode(target, source, allowedSyntaxes, mode)) // TODO: pass lossyQuality to plugins -> needs a new plugin interface { return true; } @@ -2078,7 +2078,7 @@ if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_After) { - return dcmtkTranscoder_->Transcode(target, source, allowedSyntaxes, allowNewSopInstanceUid, lossyQuality); + return dcmtkTranscoder_->Transcode(target, source, allowedSyntaxes, mode, lossyQuality); } else { @@ -2109,7 +2109,7 @@ std::set<DicomTransferSyntax> uncompressedTransferSyntax; uncompressedTransferSyntax.insert(DicomTransferSyntax_LittleEndianExplicit); - Transcode(transcoded, source, uncompressedTransferSyntax, true); + Transcode(transcoded, source, uncompressedTransferSyntax, TranscodingSopInstanceUidMode_AllowNew); dicomFile.reset(transcoded.ReleaseAsParsedDicomFile()); @@ -2154,24 +2154,19 @@ std::set<DicomTransferSyntax> s; s.insert(targetSyntax); - if (Transcode(transcoded, source, s, true, lossyQuality)) - { - dicomFile.reset(transcoded.ReleaseAsParsedDicomFile()); + TranscodingSopInstanceUidMode mode; + if (keepSOPInstanceUidDuringLossyTranscoding) + { + mode = TranscodingSopInstanceUidMode_Preserve; + } + else + { + mode = TranscodingSopInstanceUidMode_AllowNew; + } - if (keepSOPInstanceUidDuringLossyTranscoding) - { - // Fix the SOP instance UID in order the preserve the - // references between instance UIDs in the DICOM hierarchy - // (the UID might have changed during this last transcoding step in the case of lossy transcoding) - if (dicomFile.get() == NULL || - dicomFile->GetDcmtkObject().getDataset() == NULL || - !dicomFile->GetDcmtkObject().getDataset()->putAndInsertString( - DCM_SOPInstanceUID, modifiedUid.c_str(), OFTrue /* replace */).good()) - { - throw OrthancException(ErrorCode_InternalError); - } - } - return; + if (Transcode(transcoded, source, s, mode, lossyQuality)) + { + dicomFile.reset(transcoded.ReleaseAsParsedDicomFile()); } else {
--- a/OrthancServer/Sources/ServerContext.h Sat Nov 22 12:29:36 2025 +0100 +++ b/OrthancServer/Sources/ServerContext.h Tue Nov 25 08:08:08 2025 +0100 @@ -590,12 +590,12 @@ virtual bool Transcode(DicomImage& target, DicomImage& source /* in, "GetParsed()" possibly modified */, const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE; - + TranscodingSopInstanceUidMode mode) ORTHANC_OVERRIDE; + virtual bool Transcode(DicomImage& target, DicomImage& source /* in, "GetParsed()" possibly modified */, const std::set<DicomTransferSyntax>& allowedSyntaxes, - bool allowNewSopInstanceUid, + TranscodingSopInstanceUidMode mode, unsigned int lossyQuality) ORTHANC_OVERRIDE; virtual bool TranscodeWithCache(std::string& target,
--- a/OrthancServer/Sources/ServerJobs/ArchiveJob.cpp Sat Nov 22 12:29:36 2025 +0100 +++ b/OrthancServer/Sources/ServerJobs/ArchiveJob.cpp Tue Nov 25 08:08:08 2025 +0100 @@ -116,7 +116,7 @@ IDicomTranscoder::DicomImage source, transcoded; source.SetExternalBuffer(sourceBuffer); - if (context_.Transcode(transcoded, source, syntaxes, true /* allow new SOP instance UID */, lossyQuality_)) + if (context_.Transcode(transcoded, source, syntaxes, TranscodingSopInstanceUidMode_AllowNew, lossyQuality_)) { transcodedBuffer.assign(reinterpret_cast<const char*>(transcoded.GetBufferData()), transcoded.GetBufferSize()); return true;
--- a/OrthancServer/Sources/ServerJobs/OrthancPeerStoreJob.cpp Sat Nov 22 12:29:36 2025 +0100 +++ b/OrthancServer/Sources/ServerJobs/OrthancPeerStoreJob.cpp Tue Nov 25 08:08:08 2025 +0100 @@ -69,7 +69,7 @@ IDicomTranscoder::DicomImage source, transcoded; source.SetExternalBuffer(dicom); - if (context_.Transcode(transcoded, source, syntaxes, true)) + if (context_.Transcode(transcoded, source, syntaxes, TranscodingSopInstanceUidMode_AllowNew)) { body.assign(reinterpret_cast<const char*>(transcoded.GetBufferData()), transcoded.GetBufferSize());
