Mercurial > hg > orthanc
comparison OrthancServer/ServerToolbox.cpp @ 1668:de1413733c97 db-changes
reconstructing main dicom tags
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 30 Sep 2015 17:18:39 +0200 |
parents | f967bdf8534e |
children | a412ad57f0f9 |
comparison
equal
deleted
inserted
replaced
1667:9e875db36aef | 1668:de1413733c97 |
---|---|
33 #include "PrecompiledHeadersServer.h" | 33 #include "PrecompiledHeadersServer.h" |
34 #include "ServerToolbox.h" | 34 #include "ServerToolbox.h" |
35 | 35 |
36 #include "../Core/Logging.h" | 36 #include "../Core/Logging.h" |
37 #include "../Core/OrthancException.h" | 37 #include "../Core/OrthancException.h" |
38 #include "../Core/DicomFormat/DicomArray.h" | |
39 #include "ParsedDicomFile.h" | |
38 | 40 |
39 #include <cassert> | 41 #include <cassert> |
40 | 42 |
41 namespace Orthanc | 43 namespace Orthanc |
42 { | 44 { |
43 void SimplifyTags(Json::Value& target, | 45 namespace Toolbox |
44 const Json::Value& source) | |
45 { | 46 { |
46 assert(source.isObject()); | 47 void SimplifyTags(Json::Value& target, |
47 | 48 const Json::Value& source) |
48 target = Json::objectValue; | 49 { |
49 Json::Value::Members members = source.getMemberNames(); | 50 assert(source.isObject()); |
50 | 51 |
51 for (size_t i = 0; i < members.size(); i++) | 52 target = Json::objectValue; |
52 { | 53 Json::Value::Members members = source.getMemberNames(); |
53 const Json::Value& v = source[members[i]]; | 54 |
54 const std::string& name = v["Name"].asString(); | 55 for (size_t i = 0; i < members.size(); i++) |
55 const std::string& type = v["Type"].asString(); | 56 { |
56 | 57 const Json::Value& v = source[members[i]]; |
57 if (type == "String") | 58 const std::string& name = v["Name"].asString(); |
58 { | 59 const std::string& type = v["Type"].asString(); |
59 target[name] = v["Value"].asString(); | 60 |
60 } | 61 if (type == "String") |
61 else if (type == "TooLong" || | 62 { |
62 type == "Null") | 63 target[name] = v["Value"].asString(); |
63 { | 64 } |
64 target[name] = Json::nullValue; | 65 else if (type == "TooLong" || |
65 } | 66 type == "Null") |
66 else if (type == "Sequence") | 67 { |
67 { | 68 target[name] = Json::nullValue; |
68 const Json::Value& array = v["Value"]; | 69 } |
69 assert(array.isArray()); | 70 else if (type == "Sequence") |
70 | 71 { |
71 Json::Value children = Json::arrayValue; | 72 const Json::Value& array = v["Value"]; |
72 for (Json::Value::ArrayIndex i = 0; i < array.size(); i++) | 73 assert(array.isArray()); |
73 { | 74 |
74 Json::Value c; | 75 Json::Value children = Json::arrayValue; |
75 SimplifyTags(c, array[i]); | 76 for (Json::Value::ArrayIndex i = 0; i < array.size(); i++) |
76 children.append(c); | 77 { |
77 } | 78 Json::Value c; |
78 | 79 SimplifyTags(c, array[i]); |
79 target[name] = children; | 80 children.append(c); |
80 } | 81 } |
81 else | 82 |
82 { | 83 target[name] = children; |
83 assert(0); | 84 } |
84 } | 85 else |
85 } | 86 { |
86 } | 87 assert(0); |
87 | 88 } |
88 | 89 } |
89 void LogMissingRequiredTag(const DicomMap& summary) | 90 } |
90 { | 91 |
91 std::string s, t; | 92 |
92 | 93 void LogMissingRequiredTag(const DicomMap& summary) |
93 if (summary.HasTag(DICOM_TAG_PATIENT_ID)) | 94 { |
94 { | 95 std::string s, t; |
95 if (t.size() > 0) | 96 |
96 t += ", "; | 97 if (summary.HasTag(DICOM_TAG_PATIENT_ID)) |
97 t += "PatientID=" + summary.GetValue(DICOM_TAG_PATIENT_ID).AsString(); | 98 { |
98 } | 99 if (t.size() > 0) |
99 else | 100 t += ", "; |
100 { | 101 t += "PatientID=" + summary.GetValue(DICOM_TAG_PATIENT_ID).AsString(); |
101 if (s.size() > 0) | 102 } |
102 s += ", "; | 103 else |
103 s += "PatientID"; | 104 { |
104 } | 105 if (s.size() > 0) |
105 | 106 s += ", "; |
106 if (summary.HasTag(DICOM_TAG_STUDY_INSTANCE_UID)) | 107 s += "PatientID"; |
107 { | 108 } |
108 if (t.size() > 0) | 109 |
109 t += ", "; | 110 if (summary.HasTag(DICOM_TAG_STUDY_INSTANCE_UID)) |
110 t += "StudyInstanceUID=" + summary.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).AsString(); | 111 { |
111 } | 112 if (t.size() > 0) |
112 else | 113 t += ", "; |
113 { | 114 t += "StudyInstanceUID=" + summary.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).AsString(); |
114 if (s.size() > 0) | 115 } |
115 s += ", "; | 116 else |
116 s += "StudyInstanceUID"; | 117 { |
117 } | 118 if (s.size() > 0) |
118 | 119 s += ", "; |
119 if (summary.HasTag(DICOM_TAG_SERIES_INSTANCE_UID)) | 120 s += "StudyInstanceUID"; |
120 { | 121 } |
121 if (t.size() > 0) | 122 |
122 t += ", "; | 123 if (summary.HasTag(DICOM_TAG_SERIES_INSTANCE_UID)) |
123 t += "SeriesInstanceUID=" + summary.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).AsString(); | 124 { |
124 } | 125 if (t.size() > 0) |
125 else | 126 t += ", "; |
126 { | 127 t += "SeriesInstanceUID=" + summary.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).AsString(); |
127 if (s.size() > 0) | 128 } |
128 s += ", "; | 129 else |
129 s += "SeriesInstanceUID"; | 130 { |
130 } | 131 if (s.size() > 0) |
131 | 132 s += ", "; |
132 if (summary.HasTag(DICOM_TAG_SOP_INSTANCE_UID)) | 133 s += "SeriesInstanceUID"; |
133 { | 134 } |
134 if (t.size() > 0) | 135 |
135 t += ", "; | 136 if (summary.HasTag(DICOM_TAG_SOP_INSTANCE_UID)) |
136 t += "SOPInstanceUID=" + summary.GetValue(DICOM_TAG_SOP_INSTANCE_UID).AsString(); | 137 { |
137 } | 138 if (t.size() > 0) |
138 else | 139 t += ", "; |
139 { | 140 t += "SOPInstanceUID=" + summary.GetValue(DICOM_TAG_SOP_INSTANCE_UID).AsString(); |
140 if (s.size() > 0) | 141 } |
141 s += ", "; | 142 else |
142 s += "SOPInstanceUID"; | 143 { |
143 } | 144 if (s.size() > 0) |
144 | 145 s += ", "; |
145 if (t.size() == 0) | 146 s += "SOPInstanceUID"; |
146 { | 147 } |
147 LOG(ERROR) << "Store has failed because all the required tags (" << s << ") are missing (is it a DICOMDIR file?)"; | 148 |
148 } | 149 if (t.size() == 0) |
149 else | 150 { |
150 { | 151 LOG(ERROR) << "Store has failed because all the required tags (" << s << ") are missing (is it a DICOMDIR file?)"; |
151 LOG(ERROR) << "Store has failed because required tags (" << s << ") are missing for the following instance: " << t; | 152 } |
153 else | |
154 { | |
155 LOG(ERROR) << "Store has failed because required tags (" << s << ") are missing for the following instance: " << t; | |
156 } | |
157 } | |
158 | |
159 | |
160 void SetMainDicomTags(IDatabaseWrapper& database, | |
161 int64_t resource, | |
162 ResourceType level, | |
163 const DicomMap& dicomSummary, | |
164 bool includeIdentifiers) | |
165 { | |
166 // WARNING: The database should be locked with a transaction! | |
167 | |
168 DicomMap tags; | |
169 | |
170 switch (level) | |
171 { | |
172 case ResourceType_Patient: | |
173 dicomSummary.ExtractPatientInformation(tags); | |
174 break; | |
175 | |
176 case ResourceType_Study: | |
177 dicomSummary.ExtractStudyInformation(tags); | |
178 break; | |
179 | |
180 case ResourceType_Series: | |
181 dicomSummary.ExtractSeriesInformation(tags); | |
182 break; | |
183 | |
184 case ResourceType_Instance: | |
185 dicomSummary.ExtractInstanceInformation(tags); | |
186 break; | |
187 | |
188 default: | |
189 throw OrthancException(ErrorCode_InternalError); | |
190 } | |
191 | |
192 DicomArray flattened(tags); | |
193 for (size_t i = 0; i < flattened.GetSize(); i++) | |
194 { | |
195 const DicomElement& element = flattened.GetElement(i); | |
196 | |
197 if (includeIdentifiers || | |
198 !element.GetTag().IsIdentifier()) | |
199 { | |
200 database.SetMainDicomTag(resource, element.GetTag(), element.GetValue().AsString()); | |
201 } | |
202 } | |
203 } | |
204 | |
205 | |
206 bool FindOneChildInstance(int64_t& result, | |
207 IDatabaseWrapper& database, | |
208 int64_t resource, | |
209 ResourceType type) | |
210 { | |
211 for (;;) | |
212 { | |
213 if (type == ResourceType_Instance) | |
214 { | |
215 result = resource; | |
216 return true; | |
217 } | |
218 | |
219 std::list<int64_t> children; | |
220 database.GetChildrenInternalId(children, resource); | |
221 if (children.empty()) | |
222 { | |
223 return false; | |
224 } | |
225 | |
226 resource = children.front(); | |
227 type = GetChildResourceType(type); | |
228 } | |
229 } | |
230 | |
231 | |
232 void ReconstructMainDicomTags(IDatabaseWrapper& database, | |
233 IStorageArea& storageArea, | |
234 ResourceType level) | |
235 { | |
236 // WARNING: The database should be locked with a transaction! | |
237 | |
238 std::list<std::string> resources; | |
239 database.GetAllPublicIds(resources, level); | |
240 | |
241 for (std::list<std::string>::const_iterator | |
242 it = resources.begin(); it != resources.end(); it++) | |
243 { | |
244 // Locate the resource and one of its child instances | |
245 int64_t resource, instance; | |
246 ResourceType tmp; | |
247 | |
248 if (!database.LookupResource(resource, tmp, *it) || | |
249 tmp != level || | |
250 !FindOneChildInstance(instance, database, resource, level)) | |
251 { | |
252 throw OrthancException(ErrorCode_InternalError); | |
253 } | |
254 | |
255 // Get the DICOM file attached to some instances in the resource | |
256 FileInfo attachment; | |
257 if (!database.LookupAttachment(attachment, instance, FileContentType_Dicom)) | |
258 { | |
259 throw OrthancException(ErrorCode_InternalError); | |
260 } | |
261 | |
262 // Read and parse the content of the DICOM file | |
263 std::string content; | |
264 storageArea.Read(content, attachment.GetUuid(), FileContentType_Dicom); | |
265 | |
266 ParsedDicomFile dicom(content); | |
267 | |
268 // Update the tags of this resource | |
269 DicomMap dicomSummary; | |
270 dicom.Convert(dicomSummary); | |
271 | |
272 database.ClearMainDicomTags(resource); | |
273 | |
274 switch (level) | |
275 { | |
276 case ResourceType_Patient: | |
277 Toolbox::SetMainDicomTags(database, resource, ResourceType_Patient, dicomSummary, true); | |
278 break; | |
279 | |
280 case ResourceType_Study: | |
281 Toolbox::SetMainDicomTags(database, resource, ResourceType_Study, dicomSummary, true); | |
282 | |
283 // Duplicate the patient tags at the study level | |
284 Toolbox::SetMainDicomTags(database, resource, ResourceType_Patient, dicomSummary, false); | |
285 break; | |
286 | |
287 case ResourceType_Series: | |
288 Toolbox::SetMainDicomTags(database, resource, ResourceType_Series, dicomSummary, true); | |
289 break; | |
290 | |
291 case ResourceType_Instance: | |
292 Toolbox::SetMainDicomTags(database, resource, ResourceType_Instance, dicomSummary, true); | |
293 break; | |
294 | |
295 default: | |
296 throw OrthancException(ErrorCode_InternalError); | |
297 } | |
298 } | |
152 } | 299 } |
153 } | 300 } |
154 } | 301 } |