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 }