Mercurial > hg > orthanc
diff OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp @ 5036:877bc3b96476
Handle Dicom sequences in ExtraMainDicomTags and save them in the 'MainDicomSequences' metadata
author | Alain Mazy <am@osimis.io> |
---|---|
date | Fri, 24 Jun 2022 15:47:10 +0200 |
parents | 8fba26292a9f |
children | 28db9663fc2d |
line wrap: on
line diff
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Wed Jun 22 15:37:08 2022 +0200 +++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Fri Jun 24 15:47:10 2022 +0200 @@ -45,6 +45,51 @@ namespace Orthanc { + // copy all tags from Json + void DicomSequencesMap::FromJson(const Json::Value& value) + { + Json::Value::Members members = value.getMemberNames(); + for (size_t i = 0; i < members.size(); i++) + { + DicomTag tag = FromDcmtkBridge::ParseTag(members[i].c_str()); + sequences_[tag] = value[members[i]]; + } + } + + // copy a subset of tags from Json + void DicomSequencesMap::FromDicomAsJson(const Json::Value& dicomAsJson, const std::set<DicomTag>& tags) + { + for (std::set<DicomTag>::const_iterator it = tags.begin(); + it != tags.end(); ++it) + { + std::string tag = it->Format(); + if (dicomAsJson.isMember(tag)) + { + sequences_[*it] = dicomAsJson[tag]; + } + } + } + + void DicomSequencesMap::ToJson(Json::Value& target, DicomToJsonFormat format) const + { + // add the sequences to "target" + for (std::map<DicomTag, Json::Value>::const_iterator it = sequences_.begin(); + it != sequences_.end(); ++it) + { + Json::Value sequenceForConversion = Json::objectValue; + sequenceForConversion[it->first.Format()] = it->second; + + Json::Value requestedFormatJson; + Toolbox::SimplifyDicomAsJson(requestedFormatJson, sequenceForConversion, format); + + Json::Value::Members keys = requestedFormatJson.getMemberNames(); + for (size_t i = 0; i < keys.size(); i++) // there should always be only one member in this JSON + { + target[keys[i]] = requestedFormatJson[keys[i]]; + } + } + } + namespace { /** @@ -873,6 +918,17 @@ // read all tags from DB transaction.GetMainDicomTags(target.tags_, internalId); + // read all main sequences from DB + std::string serializedSequences; + if (LookupStringMetadata(serializedSequences, target.metadata_, MetadataType_MainDicomSequences)) + { + Json::Value jsonMetadata; + Toolbox::ReadJson(jsonMetadata, serializedSequences); + + assert(jsonMetadata["Version"].asInt() == 1); + target.sequences_.FromJson(jsonMetadata["Sequences"]); + } + // check if we have access to all requestedTags or if we must get tags from parents const std::set<DicomTag>& requestedTags = tuple.get<4>(); @@ -882,7 +938,7 @@ FromDcmtkBridge::ParseListOfTags(savedMainDicomTags, target.mainDicomTagsSignature_); - // read parent main dicom tags as long as we don't have gathered all requested tags + // read parent main dicom tags as long as we have not gathered all requested tags ResourceType currentLevel = target.type_; int64_t currentInternalId = internalId; Toolbox::GetMissingsFromSet(target.missingRequestedTags_, requestedTags, savedMainDicomTags); @@ -2841,6 +2897,7 @@ StoreStatus StatelessDatabaseOperations::Store(std::map<MetadataType, std::string>& instanceMetadata, const DicomMap& dicomSummary, + const std::map<DicomTag, Json::Value>& sequencesToStore, const Attachments& attachments, const MetadataMap& metadata, const DicomInstanceOrigin& origin, @@ -2859,6 +2916,7 @@ StoreStatus storeStatus_; std::map<MetadataType, std::string>& instanceMetadata_; const DicomMap& dicomSummary_; + const std::map<DicomTag, Json::Value>& sequencesToStore_; const Attachments& attachments_; const MetadataMap& metadata_; const DicomInstanceOrigin& origin_; @@ -2890,6 +2948,44 @@ instanceMetadata[metadata] = value; } + static void SetMainDicomSequenceMetadata(ResourcesContent& content, + int64_t resource, + const std::map<DicomTag, Json::Value>& sequencesToStore, // all sequences for all levels ! + ResourceType level) + { + if (sequencesToStore.size() > 0) + { + const std::set<DicomTag>& levelTags = DicomMap::GetMainDicomTags(level); + std::set<DicomTag> levelSequences; + DicomMap::ExtractSequences(levelSequences, levelTags); + + if (levelSequences.size() == 0) + { + return; + } + + Json::Value jsonMetadata; + jsonMetadata["Version"] = 1; + Json::Value jsonSequences = Json::objectValue; + + for (std::set<DicomTag>::const_iterator it = levelSequences.begin(); + it != levelSequences.end(); ++it) + { + std::map<DicomTag, Json::Value>::const_iterator foundSeq = sequencesToStore.find(*it); + if (foundSeq != sequencesToStore.end()) + { + jsonSequences[it->Format()] = foundSeq->second; + } + } + jsonMetadata["Sequences"] = jsonSequences; + + std::string serialized; + Toolbox::WriteFastJson(serialized, jsonMetadata); + + content.AddMetadata(resource, MetadataType_MainDicomSequences, serialized); + } + + } static bool ComputeExpectedNumberOfInstances(int64_t& target, const DicomMap& dicomSummary) @@ -2948,6 +3044,7 @@ public: Operations(std::map<MetadataType, std::string>& instanceMetadata, const DicomMap& dicomSummary, + const std::map<DicomTag, Json::Value>& sequencesToStore, const Attachments& attachments, const MetadataMap& metadata, const DicomInstanceOrigin& origin, @@ -2962,6 +3059,7 @@ storeStatus_(StoreStatus_Failure), instanceMetadata_(instanceMetadata), dicomSummary_(dicomSummary), + sequencesToStore_(sequencesToStore), attachments_(attachments), metadata_(metadata), origin_(origin), @@ -3112,23 +3210,27 @@ content.AddResource(instanceId, ResourceType_Instance, dicomSummary_); SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Instance)); // New in Orthanc 1.11.0 + SetMainDicomSequenceMetadata(content, instanceId, sequencesToStore_, ResourceType_Instance); // new in Orthanc 1.11.1 if (status.isNewSeries_) { content.AddResource(status.seriesId_, ResourceType_Series, dicomSummary_); content.AddMetadata(status.seriesId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Series)); // New in Orthanc 1.11.0 + SetMainDicomSequenceMetadata(content, status.seriesId_, sequencesToStore_, ResourceType_Series); // new in Orthanc 1.11.1 } if (status.isNewStudy_) { content.AddResource(status.studyId_, ResourceType_Study, dicomSummary_); content.AddMetadata(status.studyId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Study)); // New in Orthanc 1.11.0 + SetMainDicomSequenceMetadata(content, status.studyId_, sequencesToStore_, ResourceType_Study); // new in Orthanc 1.11.1 } if (status.isNewPatient_) { content.AddResource(status.patientId_, ResourceType_Patient, dicomSummary_); content.AddMetadata(status.patientId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Patient)); // New in Orthanc 1.11.0 + SetMainDicomSequenceMetadata(content, status.patientId_, sequencesToStore_, ResourceType_Patient); // new in Orthanc 1.11.1 } // Attach the auto-computed metadata for the patient/study/series levels @@ -3273,7 +3375,7 @@ }; - Operations operations(instanceMetadata, dicomSummary, attachments, metadata, origin, + Operations operations(instanceMetadata, dicomSummary, sequencesToStore, attachments, metadata, origin, overwrite, hasTransferSyntax, transferSyntax, hasPixelDataOffset, pixelDataOffset, maximumStorageSize, maximumPatients, isReconstruct); Apply(operations);