Mercurial > hg > orthanc
comparison 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 |
comparison
equal
deleted
inserted
replaced
5035:67d98fccc850 | 5036:877bc3b96476 |
---|---|
43 #include <stack> | 43 #include <stack> |
44 | 44 |
45 | 45 |
46 namespace Orthanc | 46 namespace Orthanc |
47 { | 47 { |
48 // copy all tags from Json | |
49 void DicomSequencesMap::FromJson(const Json::Value& value) | |
50 { | |
51 Json::Value::Members members = value.getMemberNames(); | |
52 for (size_t i = 0; i < members.size(); i++) | |
53 { | |
54 DicomTag tag = FromDcmtkBridge::ParseTag(members[i].c_str()); | |
55 sequences_[tag] = value[members[i]]; | |
56 } | |
57 } | |
58 | |
59 // copy a subset of tags from Json | |
60 void DicomSequencesMap::FromDicomAsJson(const Json::Value& dicomAsJson, const std::set<DicomTag>& tags) | |
61 { | |
62 for (std::set<DicomTag>::const_iterator it = tags.begin(); | |
63 it != tags.end(); ++it) | |
64 { | |
65 std::string tag = it->Format(); | |
66 if (dicomAsJson.isMember(tag)) | |
67 { | |
68 sequences_[*it] = dicomAsJson[tag]; | |
69 } | |
70 } | |
71 } | |
72 | |
73 void DicomSequencesMap::ToJson(Json::Value& target, DicomToJsonFormat format) const | |
74 { | |
75 // add the sequences to "target" | |
76 for (std::map<DicomTag, Json::Value>::const_iterator it = sequences_.begin(); | |
77 it != sequences_.end(); ++it) | |
78 { | |
79 Json::Value sequenceForConversion = Json::objectValue; | |
80 sequenceForConversion[it->first.Format()] = it->second; | |
81 | |
82 Json::Value requestedFormatJson; | |
83 Toolbox::SimplifyDicomAsJson(requestedFormatJson, sequenceForConversion, format); | |
84 | |
85 Json::Value::Members keys = requestedFormatJson.getMemberNames(); | |
86 for (size_t i = 0; i < keys.size(); i++) // there should always be only one member in this JSON | |
87 { | |
88 target[keys[i]] = requestedFormatJson[keys[i]]; | |
89 } | |
90 } | |
91 } | |
92 | |
48 namespace | 93 namespace |
49 { | 94 { |
50 /** | 95 /** |
51 * Some handy templates to reduce the verbosity in the definitions | 96 * Some handy templates to reduce the verbosity in the definitions |
52 * of the internal classes. | 97 * of the internal classes. |
871 if (expandFlags & ExpandResourceDbFlags_IncludeMainDicomTags) | 916 if (expandFlags & ExpandResourceDbFlags_IncludeMainDicomTags) |
872 { | 917 { |
873 // read all tags from DB | 918 // read all tags from DB |
874 transaction.GetMainDicomTags(target.tags_, internalId); | 919 transaction.GetMainDicomTags(target.tags_, internalId); |
875 | 920 |
921 // read all main sequences from DB | |
922 std::string serializedSequences; | |
923 if (LookupStringMetadata(serializedSequences, target.metadata_, MetadataType_MainDicomSequences)) | |
924 { | |
925 Json::Value jsonMetadata; | |
926 Toolbox::ReadJson(jsonMetadata, serializedSequences); | |
927 | |
928 assert(jsonMetadata["Version"].asInt() == 1); | |
929 target.sequences_.FromJson(jsonMetadata["Sequences"]); | |
930 } | |
931 | |
876 // check if we have access to all requestedTags or if we must get tags from parents | 932 // check if we have access to all requestedTags or if we must get tags from parents |
877 const std::set<DicomTag>& requestedTags = tuple.get<4>(); | 933 const std::set<DicomTag>& requestedTags = tuple.get<4>(); |
878 | 934 |
879 if (requestedTags.size() > 0) | 935 if (requestedTags.size() > 0) |
880 { | 936 { |
881 std::set<DicomTag> savedMainDicomTags; | 937 std::set<DicomTag> savedMainDicomTags; |
882 | 938 |
883 FromDcmtkBridge::ParseListOfTags(savedMainDicomTags, target.mainDicomTagsSignature_); | 939 FromDcmtkBridge::ParseListOfTags(savedMainDicomTags, target.mainDicomTagsSignature_); |
884 | 940 |
885 // read parent main dicom tags as long as we don't have gathered all requested tags | 941 // read parent main dicom tags as long as we have not gathered all requested tags |
886 ResourceType currentLevel = target.type_; | 942 ResourceType currentLevel = target.type_; |
887 int64_t currentInternalId = internalId; | 943 int64_t currentInternalId = internalId; |
888 Toolbox::GetMissingsFromSet(target.missingRequestedTags_, requestedTags, savedMainDicomTags); | 944 Toolbox::GetMissingsFromSet(target.missingRequestedTags_, requestedTags, savedMainDicomTags); |
889 | 945 |
890 while ((target.missingRequestedTags_.size() > 0) | 946 while ((target.missingRequestedTags_.size() > 0) |
2839 } | 2895 } |
2840 | 2896 |
2841 | 2897 |
2842 StoreStatus StatelessDatabaseOperations::Store(std::map<MetadataType, std::string>& instanceMetadata, | 2898 StoreStatus StatelessDatabaseOperations::Store(std::map<MetadataType, std::string>& instanceMetadata, |
2843 const DicomMap& dicomSummary, | 2899 const DicomMap& dicomSummary, |
2900 const std::map<DicomTag, Json::Value>& sequencesToStore, | |
2844 const Attachments& attachments, | 2901 const Attachments& attachments, |
2845 const MetadataMap& metadata, | 2902 const MetadataMap& metadata, |
2846 const DicomInstanceOrigin& origin, | 2903 const DicomInstanceOrigin& origin, |
2847 bool overwrite, | 2904 bool overwrite, |
2848 bool hasTransferSyntax, | 2905 bool hasTransferSyntax, |
2857 { | 2914 { |
2858 private: | 2915 private: |
2859 StoreStatus storeStatus_; | 2916 StoreStatus storeStatus_; |
2860 std::map<MetadataType, std::string>& instanceMetadata_; | 2917 std::map<MetadataType, std::string>& instanceMetadata_; |
2861 const DicomMap& dicomSummary_; | 2918 const DicomMap& dicomSummary_; |
2919 const std::map<DicomTag, Json::Value>& sequencesToStore_; | |
2862 const Attachments& attachments_; | 2920 const Attachments& attachments_; |
2863 const MetadataMap& metadata_; | 2921 const MetadataMap& metadata_; |
2864 const DicomInstanceOrigin& origin_; | 2922 const DicomInstanceOrigin& origin_; |
2865 bool overwrite_; | 2923 bool overwrite_; |
2866 bool hasTransferSyntax_; | 2924 bool hasTransferSyntax_; |
2888 { | 2946 { |
2889 content.AddMetadata(instance, metadata, value); | 2947 content.AddMetadata(instance, metadata, value); |
2890 instanceMetadata[metadata] = value; | 2948 instanceMetadata[metadata] = value; |
2891 } | 2949 } |
2892 | 2950 |
2951 static void SetMainDicomSequenceMetadata(ResourcesContent& content, | |
2952 int64_t resource, | |
2953 const std::map<DicomTag, Json::Value>& sequencesToStore, // all sequences for all levels ! | |
2954 ResourceType level) | |
2955 { | |
2956 if (sequencesToStore.size() > 0) | |
2957 { | |
2958 const std::set<DicomTag>& levelTags = DicomMap::GetMainDicomTags(level); | |
2959 std::set<DicomTag> levelSequences; | |
2960 DicomMap::ExtractSequences(levelSequences, levelTags); | |
2961 | |
2962 if (levelSequences.size() == 0) | |
2963 { | |
2964 return; | |
2965 } | |
2966 | |
2967 Json::Value jsonMetadata; | |
2968 jsonMetadata["Version"] = 1; | |
2969 Json::Value jsonSequences = Json::objectValue; | |
2970 | |
2971 for (std::set<DicomTag>::const_iterator it = levelSequences.begin(); | |
2972 it != levelSequences.end(); ++it) | |
2973 { | |
2974 std::map<DicomTag, Json::Value>::const_iterator foundSeq = sequencesToStore.find(*it); | |
2975 if (foundSeq != sequencesToStore.end()) | |
2976 { | |
2977 jsonSequences[it->Format()] = foundSeq->second; | |
2978 } | |
2979 } | |
2980 jsonMetadata["Sequences"] = jsonSequences; | |
2981 | |
2982 std::string serialized; | |
2983 Toolbox::WriteFastJson(serialized, jsonMetadata); | |
2984 | |
2985 content.AddMetadata(resource, MetadataType_MainDicomSequences, serialized); | |
2986 } | |
2987 | |
2988 } | |
2893 | 2989 |
2894 static bool ComputeExpectedNumberOfInstances(int64_t& target, | 2990 static bool ComputeExpectedNumberOfInstances(int64_t& target, |
2895 const DicomMap& dicomSummary) | 2991 const DicomMap& dicomSummary) |
2896 { | 2992 { |
2897 try | 2993 try |
2946 } | 3042 } |
2947 | 3043 |
2948 public: | 3044 public: |
2949 Operations(std::map<MetadataType, std::string>& instanceMetadata, | 3045 Operations(std::map<MetadataType, std::string>& instanceMetadata, |
2950 const DicomMap& dicomSummary, | 3046 const DicomMap& dicomSummary, |
3047 const std::map<DicomTag, Json::Value>& sequencesToStore, | |
2951 const Attachments& attachments, | 3048 const Attachments& attachments, |
2952 const MetadataMap& metadata, | 3049 const MetadataMap& metadata, |
2953 const DicomInstanceOrigin& origin, | 3050 const DicomInstanceOrigin& origin, |
2954 bool overwrite, | 3051 bool overwrite, |
2955 bool hasTransferSyntax, | 3052 bool hasTransferSyntax, |
2960 unsigned int maximumPatientCount, | 3057 unsigned int maximumPatientCount, |
2961 bool isReconstruct) : | 3058 bool isReconstruct) : |
2962 storeStatus_(StoreStatus_Failure), | 3059 storeStatus_(StoreStatus_Failure), |
2963 instanceMetadata_(instanceMetadata), | 3060 instanceMetadata_(instanceMetadata), |
2964 dicomSummary_(dicomSummary), | 3061 dicomSummary_(dicomSummary), |
3062 sequencesToStore_(sequencesToStore), | |
2965 attachments_(attachments), | 3063 attachments_(attachments), |
2966 metadata_(metadata), | 3064 metadata_(metadata), |
2967 origin_(origin), | 3065 origin_(origin), |
2968 overwrite_(overwrite), | 3066 overwrite_(overwrite), |
2969 hasTransferSyntax_(hasTransferSyntax), | 3067 hasTransferSyntax_(hasTransferSyntax), |
3110 | 3208 |
3111 // Populate the tags of the newly-created resources | 3209 // Populate the tags of the newly-created resources |
3112 | 3210 |
3113 content.AddResource(instanceId, ResourceType_Instance, dicomSummary_); | 3211 content.AddResource(instanceId, ResourceType_Instance, dicomSummary_); |
3114 SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Instance)); // New in Orthanc 1.11.0 | 3212 SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Instance)); // New in Orthanc 1.11.0 |
3213 SetMainDicomSequenceMetadata(content, instanceId, sequencesToStore_, ResourceType_Instance); // new in Orthanc 1.11.1 | |
3115 | 3214 |
3116 if (status.isNewSeries_) | 3215 if (status.isNewSeries_) |
3117 { | 3216 { |
3118 content.AddResource(status.seriesId_, ResourceType_Series, dicomSummary_); | 3217 content.AddResource(status.seriesId_, ResourceType_Series, dicomSummary_); |
3119 content.AddMetadata(status.seriesId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Series)); // New in Orthanc 1.11.0 | 3218 content.AddMetadata(status.seriesId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Series)); // New in Orthanc 1.11.0 |
3219 SetMainDicomSequenceMetadata(content, status.seriesId_, sequencesToStore_, ResourceType_Series); // new in Orthanc 1.11.1 | |
3120 } | 3220 } |
3121 | 3221 |
3122 if (status.isNewStudy_) | 3222 if (status.isNewStudy_) |
3123 { | 3223 { |
3124 content.AddResource(status.studyId_, ResourceType_Study, dicomSummary_); | 3224 content.AddResource(status.studyId_, ResourceType_Study, dicomSummary_); |
3125 content.AddMetadata(status.studyId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Study)); // New in Orthanc 1.11.0 | 3225 content.AddMetadata(status.studyId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Study)); // New in Orthanc 1.11.0 |
3226 SetMainDicomSequenceMetadata(content, status.studyId_, sequencesToStore_, ResourceType_Study); // new in Orthanc 1.11.1 | |
3126 } | 3227 } |
3127 | 3228 |
3128 if (status.isNewPatient_) | 3229 if (status.isNewPatient_) |
3129 { | 3230 { |
3130 content.AddResource(status.patientId_, ResourceType_Patient, dicomSummary_); | 3231 content.AddResource(status.patientId_, ResourceType_Patient, dicomSummary_); |
3131 content.AddMetadata(status.patientId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Patient)); // New in Orthanc 1.11.0 | 3232 content.AddMetadata(status.patientId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Patient)); // New in Orthanc 1.11.0 |
3233 SetMainDicomSequenceMetadata(content, status.patientId_, sequencesToStore_, ResourceType_Patient); // new in Orthanc 1.11.1 | |
3132 } | 3234 } |
3133 | 3235 |
3134 // Attach the auto-computed metadata for the patient/study/series levels | 3236 // Attach the auto-computed metadata for the patient/study/series levels |
3135 std::string now = SystemToolbox::GetNowIsoString(true /* use UTC time (not local time) */); | 3237 std::string now = SystemToolbox::GetNowIsoString(true /* use UTC time (not local time) */); |
3136 content.AddMetadata(status.seriesId_, MetadataType_LastUpdate, now); | 3238 content.AddMetadata(status.seriesId_, MetadataType_LastUpdate, now); |
3271 } | 3373 } |
3272 } | 3374 } |
3273 }; | 3375 }; |
3274 | 3376 |
3275 | 3377 |
3276 Operations operations(instanceMetadata, dicomSummary, attachments, metadata, origin, | 3378 Operations operations(instanceMetadata, dicomSummary, sequencesToStore, attachments, metadata, origin, |
3277 overwrite, hasTransferSyntax, transferSyntax, hasPixelDataOffset, | 3379 overwrite, hasTransferSyntax, transferSyntax, hasPixelDataOffset, |
3278 pixelDataOffset, maximumStorageSize, maximumPatients, isReconstruct); | 3380 pixelDataOffset, maximumStorageSize, maximumPatients, isReconstruct); |
3279 Apply(operations); | 3381 Apply(operations); |
3280 return operations.GetStoreStatus(); | 3382 return operations.GetStoreStatus(); |
3281 } | 3383 } |