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 }