Mercurial > hg > orthanc
changeset 5899:f622e5964cfa get-scu
Get-SCU: proposed TS + Get-SCP: accept more transcoding
line wrap: on
line diff
--- a/NEWS Mon Dec 02 15:49:03 2024 +0100 +++ b/NEWS Tue Dec 03 15:19:55 2024 +0100 @@ -33,6 +33,8 @@ - When opening a DICOM SCU connection, Orthanc now only proposes the contexts that it is going to use in the connection and not all contexts as in previous versions. E.g, when performing a C-ECHO, Orthanc will not propose C-MOVE or C-FIND. +* DICOM Get-SCP: Orthanc won't refuse anymore to send e.g. a LittleEndianExplicit file when + the accepted transfer syntax is a compressed one. * Introduced a new thread to update the statistics at regular interval for the DB plugins that are implementing the UpdateAndGetStatistics function (currently only PostgreSQL). This avoids very long update times in case you don't call /statistics
--- a/OrthancFramework/Sources/DicomNetworking/DicomAssociation.cpp Mon Dec 02 15:49:03 2024 +0100 +++ b/OrthancFramework/Sources/DicomNetworking/DicomAssociation.cpp Tue Dec 03 15:19:55 2024 +0100 @@ -346,12 +346,12 @@ assert(presentationContextId <= 255); const char* abstractSyntax = proposed_[i].abstractSyntax_.c_str(); - const std::set<DicomTransferSyntax>& source = proposed_[i].transferSyntaxes_; + const std::list<DicomTransferSyntax>& source = proposed_[i].transferSyntaxes_; std::vector<const char*> transferSyntaxes; transferSyntaxes.reserve(source.size()); - for (std::set<DicomTransferSyntax>::const_iterator + for (std::list<DicomTransferSyntax>::const_iterator it = source.begin(); it != source.end(); ++it) { transferSyntaxes.push_back(GetTransferSyntaxUid(*it)); @@ -454,10 +454,10 @@ void DicomAssociation::ProposeGenericPresentationContext(const std::string& abstractSyntax, DicomAssociationRole role) { - std::set<DicomTransferSyntax> ts; - ts.insert(DicomTransferSyntax_LittleEndianImplicit); - ts.insert(DicomTransferSyntax_LittleEndianExplicit); - ts.insert(DicomTransferSyntax_BigEndianExplicit); // Retired + std::list<DicomTransferSyntax> ts; + ts.push_back(DicomTransferSyntax_LittleEndianExplicit); // the most standard one first ! + ts.push_back(DicomTransferSyntax_LittleEndianImplicit); + ts.push_back(DicomTransferSyntax_BigEndianExplicit); // Retired but was historicaly proposed by Orthanc ProposePresentationContext(abstractSyntax, ts, role); } @@ -478,8 +478,8 @@ DicomTransferSyntax transferSyntax, DicomAssociationRole role) { - std::set<DicomTransferSyntax> ts; - ts.insert(transferSyntax); + std::list<DicomTransferSyntax> ts; + ts.push_back(transferSyntax); ProposePresentationContext(abstractSyntax, ts, role); } @@ -491,7 +491,7 @@ void DicomAssociation::ProposePresentationContext( const std::string& abstractSyntax, - const std::set<DicomTransferSyntax>& transferSyntaxes) + const std::list<DicomTransferSyntax>& transferSyntaxes) { ProposePresentationContext(abstractSyntax, transferSyntaxes, DicomAssociationRole_Default); } @@ -499,7 +499,7 @@ void DicomAssociation::ProposePresentationContext( const std::string& abstractSyntax, - const std::set<DicomTransferSyntax>& transferSyntaxes, + const std::list<DicomTransferSyntax>& transferSyntaxes, DicomAssociationRole role) { if (transferSyntaxes.empty()) @@ -694,9 +694,9 @@ DicomAssociation association; { - std::set<DicomTransferSyntax> transferSyntaxes; - transferSyntaxes.insert(DicomTransferSyntax_LittleEndianExplicit); - transferSyntaxes.insert(DicomTransferSyntax_LittleEndianImplicit); + std::list<DicomTransferSyntax> transferSyntaxes; + transferSyntaxes.push_back(DicomTransferSyntax_LittleEndianExplicit); + transferSyntaxes.push_back(DicomTransferSyntax_LittleEndianImplicit); association.ProposePresentationContext(UID_StorageCommitmentPushModelSOPClass, transferSyntaxes, DicomAssociationRole_Scp); @@ -872,9 +872,9 @@ DicomAssociation association; { - std::set<DicomTransferSyntax> transferSyntaxes; - transferSyntaxes.insert(DicomTransferSyntax_LittleEndianExplicit); - transferSyntaxes.insert(DicomTransferSyntax_LittleEndianImplicit); + std::list<DicomTransferSyntax> transferSyntaxes; + transferSyntaxes.push_back(DicomTransferSyntax_LittleEndianExplicit); + transferSyntaxes.push_back(DicomTransferSyntax_LittleEndianImplicit); // association.SetRole(DicomAssociationRole_Default); association.ProposePresentationContext(UID_StorageCommitmentPushModelSOPClass,
--- a/OrthancFramework/Sources/DicomNetworking/DicomAssociation.h Mon Dec 02 15:49:03 2024 +0100 +++ b/OrthancFramework/Sources/DicomNetworking/DicomAssociation.h Tue Dec 03 15:19:55 2024 +0100 @@ -44,6 +44,7 @@ #include <stdint.h> // For uint8_t #include <boost/noncopyable.hpp> #include <set> +#include <list> namespace Orthanc { @@ -58,7 +59,7 @@ struct ProposedPresentationContext { std::string abstractSyntax_; - std::set<DicomTransferSyntax> transferSyntaxes_; + std::list<DicomTransferSyntax> transferSyntaxes_; DicomAssociationRole role_; }; @@ -121,11 +122,11 @@ void ProposePresentationContext( const std::string& abstractSyntax, - const std::set<DicomTransferSyntax>& transferSyntaxes); + const std::list<DicomTransferSyntax>& transferSyntaxes); void ProposePresentationContext( const std::string& abstractSyntax, - const std::set<DicomTransferSyntax>& transferSyntaxes, + const std::list<DicomTransferSyntax>& transferSyntaxes, DicomAssociationRole role); T_ASC_Association& GetDcmtkAssociation() const;
--- a/OrthancFramework/Sources/DicomNetworking/DicomControlUserConnection.cpp Mon Dec 02 15:49:03 2024 +0100 +++ b/OrthancFramework/Sources/DicomNetworking/DicomControlUserConnection.cpp Tue Dec 03 15:19:55 2024 +0100 @@ -237,7 +237,7 @@ void DicomControlUserConnection::SetupPresentationContexts( ScuOperationFlags scuOperation, const std::set<std::string>& acceptedStorageSopClasses, - const std::set<DicomTransferSyntax>& acceptedTransferSyntaxes) + const std::list<DicomTransferSyntax>& proposedStorageTransferSyntaxes) { assert(association_.get() != NULL); @@ -283,7 +283,7 @@ for (std::set<std::string>::const_iterator it = acceptedStorageSopClasses.begin(); it != acceptedStorageSopClasses.end(); ++it) { - association_->ProposePresentationContext(*it, acceptedTransferSyntaxes, DicomAssociationRole_Scp); + association_->ProposePresentationContext(*it, proposedStorageTransferSyntaxes, DicomAssociationRole_Scp); } } } @@ -708,7 +708,7 @@ { assert((scuOperation & ScuOperationFlags_Get) == 0); // you must provide acceptedStorageSopClassUids for Get SCU std::set<std::string> emptyStorageSopClasses; - std::set<DicomTransferSyntax> emptyStorageTransferSyntaxes; + std::list<DicomTransferSyntax> emptyStorageTransferSyntaxes; SetupPresentationContexts(scuOperation, emptyStorageSopClasses, emptyStorageTransferSyntaxes); } @@ -716,11 +716,11 @@ DicomControlUserConnection::DicomControlUserConnection(const DicomAssociationParameters& params, ScuOperationFlags scuOperation, const std::set<std::string>& acceptedStorageSopClasses, - const std::set<DicomTransferSyntax>& acceptedTransferSyntaxes) : + const std::list<DicomTransferSyntax>& proposedStorageTransferSyntaxes) : parameters_(params), association_(new DicomAssociation) { - SetupPresentationContexts(scuOperation, acceptedStorageSopClasses, acceptedTransferSyntaxes); + SetupPresentationContexts(scuOperation, acceptedStorageSopClasses, proposedStorageTransferSyntaxes); }
--- a/OrthancFramework/Sources/DicomNetworking/DicomControlUserConnection.h Mon Dec 02 15:49:03 2024 +0100 +++ b/OrthancFramework/Sources/DicomNetworking/DicomControlUserConnection.h Tue Dec 03 15:19:55 2024 +0100 @@ -69,7 +69,7 @@ void SetupPresentationContexts(ScuOperationFlags scuOperation, const std::set<std::string>& acceptedStorageSopClasses, - const std::set<DicomTransferSyntax>& acceptedTransferSyntaxes); // TODO-GET: in order of preference ? + const std::list<DicomTransferSyntax>& proposedStorageTransferSyntaxes); void FindInternal(DicomFindAnswers& answers, DcmDataset* dataset, @@ -88,7 +88,7 @@ explicit DicomControlUserConnection(const DicomAssociationParameters& params, ScuOperationFlags scuOperation, const std::set<std::string>& acceptedStorageSopClasses, - const std::set<DicomTransferSyntax>& acceptedTransferSyntaxes); // TODO-GET: in order of preference ? + const std::list<DicomTransferSyntax>& proposedStorageTransferSyntaxes); const DicomAssociationParameters& GetParameters() const {
--- a/OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.cpp Mon Dec 02 15:49:03 2024 +0100 +++ b/OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.cpp Tue Dec 03 15:19:55 2024 +0100 @@ -57,7 +57,7 @@ bool hasPreferred, DicomTransferSyntax preferred) { - typedef std::list< std::set<DicomTransferSyntax> > GroupsOfSyntaxes; + typedef std::list< std::list<DicomTransferSyntax> > GroupsOfSyntaxes; GroupsOfSyntaxes groups; @@ -65,8 +65,8 @@ for (std::set<DicomTransferSyntax>::const_iterator it = sourceSyntaxes.begin(); it != sourceSyntaxes.end(); ++it) { - std::set<DicomTransferSyntax> group; - group.insert(*it); + std::list<DicomTransferSyntax> group; + group.push_back(*it); groups.push_back(group); } @@ -74,8 +74,8 @@ if (hasPreferred && sourceSyntaxes.find(preferred) == sourceSyntaxes.end()) { - std::set<DicomTransferSyntax> group; - group.insert(preferred); + std::list<DicomTransferSyntax> group; + group.push_back(preferred); groups.push_back(group); } @@ -89,7 +89,7 @@ DicomTransferSyntax_BigEndianExplicit }; - std::set<DicomTransferSyntax> group; + std::list<DicomTransferSyntax> group; for (size_t i = 0; i < N; i++) { @@ -97,7 +97,7 @@ if (sourceSyntaxes.find(syntax) == sourceSyntaxes.end() && (!hasPreferred || preferred != syntax)) { - group.insert(syntax); + group.push_back(syntax); } }
--- a/OrthancFramework/Sources/DicomNetworking/IApplicationEntityFilter.h Mon Dec 02 15:49:03 2024 +0100 +++ b/OrthancFramework/Sources/DicomNetworking/IApplicationEntityFilter.h Tue Dec 03 15:19:55 2024 +0100 @@ -28,6 +28,7 @@ #include <boost/noncopyable.hpp> #include <string> +#include <list> namespace Orthanc { @@ -47,11 +48,18 @@ const std::string& calledAet, DicomRequestType type) = 0; + // Get the set of TransferSyntaxes that are accepted when negotiation a C-Store association, acting as SCP when it has been initiated by the C-Store SCU. virtual void GetAcceptedTransferSyntaxes(std::set<DicomTransferSyntax>& target, const std::string& remoteIp, const std::string& remoteAet, const std::string& calledAet) = 0; - + + // Get the list of TransferSyntaxes that are proposed when initiating a C-Store SCP which actually only happens in a C-Get SCU + virtual void GetProposedStorageTransferSyntaxes(std::list<DicomTransferSyntax>& target, + const std::string& remoteIp, + const std::string& remoteAet, + const std::string& calledAet) = 0; + virtual bool IsUnknownSopClassAccepted(const std::string& remoteIp, const std::string& remoteAet, const std::string& calledAet) = 0;
--- a/OrthancServer/Plugins/Samples/MultitenantDicom/DicomFilter.cpp Mon Dec 02 15:49:03 2024 +0100 +++ b/OrthancServer/Plugins/Samples/MultitenantDicom/DicomFilter.cpp Tue Dec 03 15:19:55 2024 +0100 @@ -201,6 +201,18 @@ } +void DicomFilter::GetProposedStorageTransferSyntaxes(std::list<Orthanc::DicomTransferSyntax>& target, + const std::string& remoteIp, + const std::string& remoteAet, + const std::string& calledAet) +{ + // default TS + target.push_back(Orthanc::DicomTransferSyntax_LittleEndianExplicit); + target.push_back(Orthanc::DicomTransferSyntax_LittleEndianImplicit); + target.push_back(Orthanc::DicomTransferSyntax_BigEndianExplicit); +} + + bool DicomFilter::IsUnknownSopClassAccepted(const std::string& remoteIp, const std::string& remoteAet, const std::string& calledAet)
--- a/OrthancServer/Plugins/Samples/MultitenantDicom/DicomFilter.h Mon Dec 02 15:49:03 2024 +0100 +++ b/OrthancServer/Plugins/Samples/MultitenantDicom/DicomFilter.h Tue Dec 03 15:19:55 2024 +0100 @@ -64,6 +64,12 @@ const std::string& remoteAet, const std::string& calledAet) ORTHANC_OVERRIDE; + virtual void GetProposedStorageTransferSyntaxes(std::list<Orthanc::DicomTransferSyntax>& target, + const std::string& remoteIp, + const std::string& remoteAet, + const std::string& calledAet) ORTHANC_OVERRIDE; + + virtual bool IsUnknownSopClassAccepted(const std::string& remoteIp, const std::string& remoteAet, const std::string& calledAet) ORTHANC_OVERRIDE;
--- a/OrthancServer/Sources/QueryRetrieveHandler.cpp Mon Dec 02 15:49:03 2024 +0100 +++ b/OrthancServer/Sources/QueryRetrieveHandler.cpp Tue Dec 03 15:19:55 2024 +0100 @@ -79,13 +79,7 @@ params.SetTimeout(timeout_); } - std::set<std::string> acceptedStorageClasses; - std::set<DicomTransferSyntax> acceptedTransferSyntaxes; - - context_.GetAcceptedSopClasses(acceptedStorageClasses, 120); // limit to 120 SOP Classes since there are 128 presentation contexts available. - context_.GetAcceptedTransferSyntaxes(acceptedTransferSyntaxes); - - DicomControlUserConnection connection(params, static_cast<ScuOperationFlags>(ScuOperationFlags_Find | ScuOperationFlags_Move | ScuOperationFlags_Get), acceptedStorageClasses, acceptedTransferSyntaxes); + DicomControlUserConnection connection(params, static_cast<ScuOperationFlags>(ScuOperationFlags_Find)); connection.Find(answers_, level_, fixed, findNormalized_); }
--- a/OrthancServer/Sources/ServerContext.cpp Mon Dec 02 15:49:03 2024 +0100 +++ b/OrthancServer/Sources/ServerContext.cpp Tue Dec 03 15:19:55 2024 +0100 @@ -2241,6 +2241,24 @@ } + void ServerContext::GetProposedStorageTransferSyntaxes(std::list<DicomTransferSyntax>& syntaxes) const + { + boost::mutex::scoped_lock lock(dynamicOptionsMutex_); + + // // TODO: investigate: actually, neither Orthanc 1.12.4 nor DCM4CHEE will accept to send a LittleEndianExplicit file + // // while e.g., Jpeg-LS has been presented (and accepted) as the preferred TS for the C-Store SCP. + // // if we have defined IngestTranscoding, let's propose this TS first to avoid any unnecessary transcoding + // if (isIngestTranscoding_) + // { + // syntaxes.push_back(ingestTransferSyntax_); + // } + + // then, propose the default ones + syntaxes.push_back(DicomTransferSyntax_LittleEndianExplicit); + syntaxes.push_back(DicomTransferSyntax_LittleEndianImplicit); + } + + bool ServerContext::IsUnknownSopClassAccepted() const { boost::mutex::scoped_lock lock(dynamicOptionsMutex_);
--- a/OrthancServer/Sources/ServerContext.h Mon Dec 02 15:49:03 2024 +0100 +++ b/OrthancServer/Sources/ServerContext.h Tue Dec 03 15:19:55 2024 +0100 @@ -597,6 +597,8 @@ void SetAcceptedTransferSyntaxes(const std::set<DicomTransferSyntax>& syntaxes); + void GetProposedStorageTransferSyntaxes(std::list<DicomTransferSyntax>& syntaxes) const; + void SetAcceptedSopClasses(const std::list<std::string>& acceptedSopClasses, const std::set<std::string>& rejectedSopClasses);
--- a/OrthancServer/Sources/ServerJobs/DicomGetScuJob.cpp Mon Dec 02 15:49:03 2024 +0100 +++ b/OrthancServer/Sources/ServerJobs/DicomGetScuJob.cpp Tue Dec 03 15:19:55 2024 +0100 @@ -116,7 +116,7 @@ std::set<std::string> sopClassesToPropose; std::set<std::string> sopClassesInStudy; std::set<std::string> acceptedSopClasses; - std::set<DicomTransferSyntax> storageAcceptedTransferSyntaxes; + std::list<DicomTransferSyntax> proposedTransferSyntaxes; if (findAnswer.HasTag(DICOM_TAG_SOP_CLASSES_IN_STUDY) && findAnswer.LookupStringValues(sopClassesInStudy, DICOM_TAG_SOP_CLASSES_IN_STUDY, false)) @@ -138,12 +138,12 @@ throw OrthancException(ErrorCode_NoPresentationContext, "Cannot perform C-Get, no SOPClassUID have been accepted by Orthanc."); } - context_.GetAcceptedTransferSyntaxes(storageAcceptedTransferSyntaxes); + context_.GetProposedStorageTransferSyntaxes(proposedTransferSyntaxes); connection_.reset(new DicomControlUserConnection(parameters_, ScuOperationFlags_Get, sopClassesToPropose, - storageAcceptedTransferSyntaxes)); + proposedTransferSyntaxes)); } connection_->Get(findAnswer, InstanceReceivedHandler, &context_);
--- a/OrthancServer/Sources/main.cpp Mon Dec 02 15:49:03 2024 +0100 +++ b/OrthancServer/Sources/main.cpp Tue Dec 03 15:19:55 2024 +0100 @@ -494,6 +494,13 @@ context_.GetAcceptedTransferSyntaxes(target); } + virtual void GetProposedStorageTransferSyntaxes(std::list<DicomTransferSyntax>& target, + const std::string& remoteIp, + const std::string& remoteAet, + const std::string& calledAet) ORTHANC_OVERRIDE + { + context_.GetProposedStorageTransferSyntaxes(target); + } virtual bool IsUnknownSopClassAccepted(const std::string& remoteIp, const std::string& remoteAet,