Mercurial > hg > orthanc
changeset 5665:d8c86698110c find-refactoring
implemented computed tag: Instance Availability
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 04 Jul 2024 14:36:24 +0200 |
parents | 301212a3fa08 |
children | aa231c18b9d2 |
files | OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp OrthancServer/Sources/ResourceFinder.cpp OrthancServer/Sources/ResourceFinder.h |
diffstat | 4 files changed, 155 insertions(+), 78 deletions(-) [+] |
line wrap: on
line diff
--- a/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h Thu Jul 04 11:59:50 2024 +0200 +++ b/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h Thu Jul 04 14:36:24 2024 +0200 @@ -745,7 +745,7 @@ } OrthancPluginResourceType; - + /** * The supported types of changes that can be signaled to the change callback. * @ingroup Callbacks
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp Thu Jul 04 11:59:50 2024 +0200 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp Thu Jul 04 14:36:24 2024 +0200 @@ -3481,7 +3481,7 @@ std::set<DicomTag> requestedTags; OrthancRestApi::GetRequestedTags(requestedTags, call); - if (false) + if (true) { /** * EXPERIMENTAL VERSION
--- a/OrthancServer/Sources/ResourceFinder.cpp Thu Jul 04 11:59:50 2024 +0200 +++ b/OrthancServer/Sources/ResourceFinder.cpp Thu Jul 04 14:36:24 2024 +0200 @@ -421,6 +421,8 @@ request_.GetParentRetrieveSpecification(ResourceType_Study).SetRetrieveMetadata(true); requestedStudyTags_.insert(tag); } + + hasRequestedTags_ = true; } else if (DicomMap::IsMainDicomTag(tag, ResourceType_Study)) { @@ -437,6 +439,8 @@ request_.GetParentRetrieveSpecification(ResourceType_Study).SetRetrieveMetadata(true); requestedStudyTags_.insert(tag); } + + hasRequestedTags_ = true; } else if (DicomMap::IsMainDicomTag(tag, ResourceType_Series)) { @@ -454,6 +458,8 @@ request_.GetParentRetrieveSpecification(ResourceType_Series).SetRetrieveMetadata(true); requestedSeriesTags_.insert(tag); } + + hasRequestedTags_ = true; } else if (DicomMap::IsMainDicomTag(tag, ResourceType_Instance)) { @@ -473,19 +479,36 @@ assert(request_.IsRetrieveMetadata()); requestedInstanceTags_.insert(tag); } + + hasRequestedTags_ = true; + } + else if (tag == DICOM_TAG_INSTANCE_AVAILABILITY) + { + requestedComputedTags_.insert(tag); + hasRequestedTags_ = true; + } + else if (tag == DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES) + { + if (request_.GetLevel() == ResourceType_Series) + { + requestedComputedTags_.insert(tag); + hasRequestedTags_ = true; + request_.GetChildrenRetrieveSpecification(ResourceType_Instance).SetRetrieveCount(true); + } } else { - // This is not a main DICOM tag: We will be forced to access the DICOM file anyway + // This is neither a main DICOM tag, nor a computed DICOM tag: + // We will be forced to access the DICOM file anyway requestedTagsFromFileStorage_.insert(tag); if (request_.GetLevel() != ResourceType_Instance) { request_.SetRetrieveOneInstanceIdentifier(true); } + + hasRequestedTags_ = true; } - - hasRequestedTags_ = true; } @@ -498,6 +521,111 @@ } + void ResourceFinder::InjectComputedTags(DicomMap& requestedTags, + const FindResponse::Resource& resource) const + { + switch (resource.GetLevel()) + { + case ResourceType_Patient: + break; + + case ResourceType_Study: + break; + + case ResourceType_Series: + if (IsRequestedComputedTag(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES)) + { + requestedTags.SetValue(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES, + boost::lexical_cast<std::string>(resource.GetChildrenIdentifiers().size()), false); + } + break; + + case ResourceType_Instance: + if (IsRequestedComputedTag(DICOM_TAG_INSTANCE_AVAILABILITY)) + { + requestedTags.SetValue(DICOM_TAG_INSTANCE_AVAILABILITY, "ONLINE", false); + } + break; + + default: + throw OrthancException(ErrorCode_InternalError); + } + } + + + static void ReadMissingTagsFromStorageArea(DicomMap& requestedTags, + ServerContext& context, + const FindRequest& request, + const FindResponse::Resource& resource, + const std::set<DicomTag>& missingTags) + { + OrthancConfiguration::ReaderLock lock; + if (lock.GetConfiguration().IsWarningEnabled(Warnings_001_TagsBeingReadFromStorage)) + { + std::string missings; + FromDcmtkBridge::FormatListOfTags(missings, missingTags); + + LOG(WARNING) << "W001: Accessing Dicom tags from storage when accessing " + << Orthanc::GetResourceTypeText(resource.GetLevel(), false, false) + << ": " << missings; + } + + std::string instancePublicId; + + if (request.IsRetrieveOneInstanceIdentifier()) + { + instancePublicId = resource.GetOneInstanceIdentifier(); + } + else if (request.GetLevel() == ResourceType_Instance) + { + instancePublicId = resource.GetIdentifier(); + } + else + { + FindRequest requestDicomAttachment(request.GetLevel()); + requestDicomAttachment.SetOrthancId(request.GetLevel(), resource.GetIdentifier()); + requestDicomAttachment.SetRetrieveOneInstanceIdentifier(true); + + FindResponse responseDicomAttachment; + context.GetIndex().ExecuteFind(responseDicomAttachment, requestDicomAttachment); + + if (responseDicomAttachment.GetSize() != 1 || + !responseDicomAttachment.GetResourceByIndex(0).HasOneInstanceIdentifier()) + { + throw OrthancException(ErrorCode_InexistentFile); + } + else + { + instancePublicId = responseDicomAttachment.GetResourceByIndex(0).GetOneInstanceIdentifier(); + } + } + + LOG(INFO) << "Will retrieve missing DICOM tags from instance: " << instancePublicId; + + // TODO-FIND: What do we do if the DICOM has been removed since the request? + // Do we fail, or do we skip the resource? + + Json::Value tmpDicomAsJson; + context.ReadDicomAsJson(tmpDicomAsJson, instancePublicId, missingTags /* ignoreTagLength */); + + DicomMap tmpDicomMap; + tmpDicomMap.FromDicomAsJson(tmpDicomAsJson, false /* append */, true /* parseSequences*/); + + for (std::set<DicomTag>::const_iterator it = missingTags.begin(); it != missingTags.end(); ++it) + { + assert(!requestedTags.HasTag(*it)); + if (tmpDicomMap.HasTag(*it)) + { + requestedTags.SetValue(*it, tmpDicomMap.GetValue(*it)); + } + else + { + requestedTags.SetNullValue(*it); // TODO-FIND: Is this compatible with Orthanc <= 1.12.3? + } + } + } + + void ResourceFinder::Execute(Json::Value& target, ServerContext& context) const { @@ -521,90 +649,30 @@ Json::Value item; Expand(item, resource, context.GetIndex()); - std::set<DicomTag> missingTags = requestedTagsFromFileStorage_; - - DicomMap requestedTags; - InjectRequestedTags(requestedTags, missingTags, resource, ResourceType_Patient, requestedPatientTags_); - InjectRequestedTags(requestedTags, missingTags, resource, ResourceType_Study, requestedStudyTags_); - InjectRequestedTags(requestedTags, missingTags, resource, ResourceType_Series, requestedSeriesTags_); - InjectRequestedTags(requestedTags, missingTags, resource, ResourceType_Instance, requestedInstanceTags_); - - if (!missingTags.empty()) + if (hasRequestedTags_) { - if (!allowStorageAccess_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "Cannot add missing requested tags, as access to file storage is disallowed"); - } - - OrthancConfiguration::ReaderLock lock; - if (lock.GetConfiguration().IsWarningEnabled(Warnings_001_TagsBeingReadFromStorage)) - { - std::string missings; - FromDcmtkBridge::FormatListOfTags(missings, missingTags); + DicomMap requestedTags; + InjectComputedTags(requestedTags, resource); - LOG(WARNING) << "W001: Accessing Dicom tags from storage when accessing " - << Orthanc::GetResourceTypeText(resource.GetLevel(), false, false) - << ": " << missings; - } + std::set<DicomTag> missingTags = requestedTagsFromFileStorage_; + InjectRequestedTags(requestedTags, missingTags, resource, ResourceType_Patient, requestedPatientTags_); + InjectRequestedTags(requestedTags, missingTags, resource, ResourceType_Study, requestedStudyTags_); + InjectRequestedTags(requestedTags, missingTags, resource, ResourceType_Series, requestedSeriesTags_); + InjectRequestedTags(requestedTags, missingTags, resource, ResourceType_Instance, requestedInstanceTags_); - std::string instancePublicId; - - if (request_.IsRetrieveOneInstanceIdentifier()) - { - instancePublicId = resource.GetOneInstanceIdentifier(); - } - else if (request_.GetLevel() == ResourceType_Instance) + if (!missingTags.empty()) { - instancePublicId = resource.GetIdentifier(); - } - else - { - FindRequest requestDicomAttachment(request_.GetLevel()); - requestDicomAttachment.SetOrthancId(request_.GetLevel(), resource.GetIdentifier()); - requestDicomAttachment.SetRetrieveOneInstanceIdentifier(true); - - FindResponse responseDicomAttachment; - context.GetIndex().ExecuteFind(responseDicomAttachment, requestDicomAttachment); - - if (responseDicomAttachment.GetSize() != 1 || - !responseDicomAttachment.GetResourceByIndex(0).HasOneInstanceIdentifier()) + if (!allowStorageAccess_) { - throw OrthancException(ErrorCode_InexistentFile); + throw OrthancException(ErrorCode_BadSequenceOfCalls, + "Cannot add missing requested tags, as access to file storage is disallowed"); } else { - instancePublicId = responseDicomAttachment.GetResourceByIndex(0).GetOneInstanceIdentifier(); + ReadMissingTagsFromStorageArea(requestedTags, context, request_, resource, missingTags); } } - LOG(INFO) << "Will retrieve missing DICOM tags from instance: " << instancePublicId; - - // TODO-FIND: What do we do if the DICOM has been removed since the request? - // Do we fail, or do we skip the resource? - - Json::Value tmpDicomAsJson; - context.ReadDicomAsJson(tmpDicomAsJson, instancePublicId, missingTags /* ignoreTagLength */); - - DicomMap tmpDicomMap; - tmpDicomMap.FromDicomAsJson(tmpDicomAsJson, false /* append */, true /* parseSequences*/); - - for (std::set<DicomTag>::const_iterator it = missingTags.begin(); it != missingTags.end(); ++it) - { - assert(!requestedTags.HasTag(*it)); - if (tmpDicomMap.HasTag(*it)) - { - requestedTags.SetValue(*it, tmpDicomMap.GetValue(*it)); - } - else - { - requestedTags.SetNullValue(*it); // TODO-FIND: Is this compatible with Orthanc <= 1.12.3? - } - } - } - - if (hasRequestedTags_) - { static const char* const REQUESTED_TAGS = "RequestedTags"; item[REQUESTED_TAGS] = Json::objectValue; FromDcmtkBridge::ToJson(item[REQUESTED_TAGS], requestedTags, format_);
--- a/OrthancServer/Sources/ResourceFinder.h Thu Jul 04 11:59:50 2024 +0200 +++ b/OrthancServer/Sources/ResourceFinder.h Thu Jul 04 14:36:24 2024 +0200 @@ -44,11 +44,20 @@ std::set<DicomTag> requestedSeriesTags_; std::set<DicomTag> requestedInstanceTags_; std::set<DicomTag> requestedTagsFromFileStorage_; + std::set<DicomTag> requestedComputedTags_; bool includeAllMetadata_; // Same as: ExpandResourceFlags_IncludeAllMetadata + bool IsRequestedComputedTag(const DicomTag& tag) const + { + return requestedComputedTags_.find(tag) != requestedComputedTags_.end(); + } + SeriesStatus GetSeriesStatus(uint32_t& expectedNumberOfInstances, const FindResponse::Resource& resource) const; + void InjectComputedTags(DicomMap& requestedTags, + const FindResponse::Resource& resource) const; + void Expand(Json::Value& target, const FindResponse::Resource& resource, ServerIndex& index) const;