Mercurial > hg > orthanc
comparison Core/DicomFormat/DicomMap.cpp @ 3652:335611d2b6cd storage-commitment
integration mainline->storage-commitment
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 05 Feb 2020 13:24:48 +0100 |
parents | 05df4860aea6 46cb00e4adbb |
children | cccd97333e3d |
comparison
equal
deleted
inserted
replaced
3649:05df4860aea6 | 3652:335611d2b6cd |
---|---|
53 const DicomTag tag_; | 53 const DicomTag tag_; |
54 const char* name_; | 54 const char* name_; |
55 }; | 55 }; |
56 } | 56 } |
57 | 57 |
58 static const MainDicomTag PATIENT_MAIN_DICOM_TAGS_2[] = | 58 static const MainDicomTag PATIENT_MAIN_DICOM_TAGS[] = |
59 { | 59 { |
60 // { DicomTag(0x0010, 0x1010), "PatientAge" }, | 60 // { DicomTag(0x0010, 0x1010), "PatientAge" }, |
61 // { DicomTag(0x0010, 0x1040), "PatientAddress" }, | 61 // { DicomTag(0x0010, 0x1040), "PatientAddress" }, |
62 { DicomTag(0x0010, 0x0010), "PatientName" }, | 62 { DicomTag(0x0010, 0x0010), "PatientName" }, |
63 { DicomTag(0x0010, 0x0030), "PatientBirthDate" }, | 63 { DicomTag(0x0010, 0x0030), "PatientBirthDate" }, |
64 { DicomTag(0x0010, 0x0040), "PatientSex" }, | 64 { DicomTag(0x0010, 0x0040), "PatientSex" }, |
65 { DicomTag(0x0010, 0x1000), "OtherPatientIDs" }, | 65 { DicomTag(0x0010, 0x1000), "OtherPatientIDs" }, |
66 { DICOM_TAG_PATIENT_ID, "PatientID" } | 66 { DICOM_TAG_PATIENT_ID, "PatientID" } |
67 }; | 67 }; |
68 | 68 |
69 static const MainDicomTag STUDY_MAIN_DICOM_TAGS_2[] = | 69 static const MainDicomTag STUDY_MAIN_DICOM_TAGS[] = |
70 { | 70 { |
71 // { DicomTag(0x0010, 0x1020), "PatientSize" }, | 71 // { DicomTag(0x0010, 0x1020), "PatientSize" }, |
72 // { DicomTag(0x0010, 0x1030), "PatientWeight" }, | 72 // { DicomTag(0x0010, 0x1030), "PatientWeight" }, |
73 { DICOM_TAG_STUDY_DATE, "StudyDate" }, | 73 { DICOM_TAG_STUDY_DATE, "StudyDate" }, |
74 { DicomTag(0x0008, 0x0030), "StudyTime" }, | 74 { DicomTag(0x0008, 0x0030), "StudyTime" }, |
82 { DICOM_TAG_INSTITUTION_NAME, "InstitutionName" }, | 82 { DICOM_TAG_INSTITUTION_NAME, "InstitutionName" }, |
83 { DICOM_TAG_REQUESTING_PHYSICIAN, "RequestingPhysician" }, | 83 { DICOM_TAG_REQUESTING_PHYSICIAN, "RequestingPhysician" }, |
84 { DICOM_TAG_REFERRING_PHYSICIAN_NAME, "ReferringPhysicianName" } | 84 { DICOM_TAG_REFERRING_PHYSICIAN_NAME, "ReferringPhysicianName" } |
85 }; | 85 }; |
86 | 86 |
87 static const MainDicomTag SERIES_MAIN_DICOM_TAGS_2[] = | 87 static const MainDicomTag SERIES_MAIN_DICOM_TAGS[] = |
88 { | 88 { |
89 // { DicomTag(0x0010, 0x1080), "MilitaryRank" }, | 89 // { DicomTag(0x0010, 0x1080), "MilitaryRank" }, |
90 { DicomTag(0x0008, 0x0021), "SeriesDate" }, | 90 { DicomTag(0x0008, 0x0021), "SeriesDate" }, |
91 { DicomTag(0x0008, 0x0031), "SeriesTime" }, | 91 { DicomTag(0x0008, 0x0031), "SeriesTime" }, |
92 { DICOM_TAG_MODALITY, "Modality" }, | 92 { DICOM_TAG_MODALITY, "Modality" }, |
95 { DICOM_TAG_SERIES_DESCRIPTION, "SeriesDescription" }, | 95 { DICOM_TAG_SERIES_DESCRIPTION, "SeriesDescription" }, |
96 { DicomTag(0x0018, 0x0015), "BodyPartExamined" }, | 96 { DicomTag(0x0018, 0x0015), "BodyPartExamined" }, |
97 { DicomTag(0x0018, 0x0024), "SequenceName" }, | 97 { DicomTag(0x0018, 0x0024), "SequenceName" }, |
98 { DicomTag(0x0018, 0x1030), "ProtocolName" }, | 98 { DicomTag(0x0018, 0x1030), "ProtocolName" }, |
99 { DicomTag(0x0020, 0x0011), "SeriesNumber" }, | 99 { DicomTag(0x0020, 0x0011), "SeriesNumber" }, |
100 { DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES, "CardiacNumberOfImage" }, | 100 { DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES, "CardiacNumberOfImages" }, |
101 { DICOM_TAG_IMAGES_IN_ACQUISITION, "ImagesInAcquisition" }, | 101 { DICOM_TAG_IMAGES_IN_ACQUISITION, "ImagesInAcquisition" }, |
102 { DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS, "NumberOfTemporalPositions" }, | 102 { DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS, "NumberOfTemporalPositions" }, |
103 { DICOM_TAG_NUMBER_OF_SLICES, "NumberOfSlices" }, | 103 { DICOM_TAG_NUMBER_OF_SLICES, "NumberOfSlices" }, |
104 { DICOM_TAG_NUMBER_OF_TIME_SLICES, "NumberOfTimeSlices" }, | 104 { DICOM_TAG_NUMBER_OF_TIME_SLICES, "NumberOfTimeSlices" }, |
105 { DICOM_TAG_SERIES_INSTANCE_UID, "SeriesInstanceUID" }, | 105 { DICOM_TAG_SERIES_INSTANCE_UID, "SeriesInstanceUID" }, |
106 | 106 |
107 // New in db v6 | 107 // New in db v6 |
108 { DICOM_TAG_IMAGE_ORIENTATION_PATIENT, "ImageOrientationPatientt" }, // TODO - Should have an unit test that fails | 108 { DICOM_TAG_IMAGE_ORIENTATION_PATIENT, "ImageOrientationPatient" }, |
109 { DICOM_TAG_SERIES_TYPE, "SeriesType" }, | 109 { DICOM_TAG_SERIES_TYPE, "SeriesType" }, |
110 { DICOM_TAG_OPERATOR_NAME, "OperatorName" }, | 110 { DICOM_TAG_OPERATOR_NAME, "OperatorsName" }, |
111 { DICOM_TAG_PERFORMED_PROCEDURE_STEP_DESCRIPTION, "PerformedProcedureStepDescription" }, | 111 { DICOM_TAG_PERFORMED_PROCEDURE_STEP_DESCRIPTION, "PerformedProcedureStepDescription" }, |
112 { DICOM_TAG_ACQUISITION_DEVICE_PROCESSING_DESCRIPTION, "AcquisitionDeviceProcessingDescription" }, | 112 { DICOM_TAG_ACQUISITION_DEVICE_PROCESSING_DESCRIPTION, "AcquisitionDeviceProcessingDescription" }, |
113 { DICOM_TAG_CONTRAST_BOLUS_AGENT, "ContrastBolusAgen" } | 113 { DICOM_TAG_CONTRAST_BOLUS_AGENT, "ContrastBolusAgent" } |
114 }; | 114 }; |
115 | 115 |
116 static const MainDicomTag INSTANCE_MAIN_DICOM_TAGS_2[] = | 116 static const MainDicomTag INSTANCE_MAIN_DICOM_TAGS[] = |
117 { | 117 { |
118 { DicomTag(0x0008, 0x0012), "InstanceCreationDate" }, | 118 { DicomTag(0x0008, 0x0012), "InstanceCreationDate" }, |
119 { DicomTag(0x0008, 0x0013), "InstanceCreationTime" }, | 119 { DicomTag(0x0008, 0x0013), "InstanceCreationTime" }, |
120 { DicomTag(0x0020, 0x0012), "AcquisitionNumber" }, | 120 { DicomTag(0x0020, 0x0012), "AcquisitionNumber" }, |
121 { DICOM_TAG_IMAGE_INDEX, "ImageIndex" }, | 121 { DICOM_TAG_IMAGE_INDEX, "ImageIndex" }, |
135 * access these tags if the corresponding DICOM files where | 135 * access these tags if the corresponding DICOM files where |
136 * indexed in the database by an older version of Orthanc. | 136 * indexed in the database by an older version of Orthanc. |
137 **/ | 137 **/ |
138 { DICOM_TAG_IMAGE_ORIENTATION_PATIENT, "ImageOrientationPatient" } // New in Orthanc 1.4.2 | 138 { DICOM_TAG_IMAGE_ORIENTATION_PATIENT, "ImageOrientationPatient" } // New in Orthanc 1.4.2 |
139 }; | 139 }; |
140 | 140 |
141 | 141 |
142 | 142 static void LoadMainDicomTags(const MainDicomTag*& tags, |
143 static const DicomTag PATIENT_MAIN_DICOM_TAGS[] = | 143 size_t& size, |
144 { | 144 ResourceType level) |
145 //DicomTag(0x0010, 0x1010), // PatientAge | |
146 //DicomTag(0x0010, 0x1040) // PatientAddress | |
147 DicomTag(0x0010, 0x0010), // PatientName | |
148 DicomTag(0x0010, 0x0030), // PatientBirthDate | |
149 DicomTag(0x0010, 0x0040), // PatientSex | |
150 DicomTag(0x0010, 0x1000), // OtherPatientIDs | |
151 DICOM_TAG_PATIENT_ID | |
152 }; | |
153 | |
154 static const DicomTag STUDY_MAIN_DICOM_TAGS[] = | |
155 { | |
156 //DicomTag(0x0010, 0x1020), // PatientSize | |
157 //DicomTag(0x0010, 0x1030) // PatientWeight | |
158 DICOM_TAG_STUDY_DATE, | |
159 DicomTag(0x0008, 0x0030), // StudyTime | |
160 DicomTag(0x0020, 0x0010), // StudyID | |
161 DICOM_TAG_STUDY_DESCRIPTION, | |
162 DICOM_TAG_ACCESSION_NUMBER, | |
163 DICOM_TAG_STUDY_INSTANCE_UID, | |
164 DICOM_TAG_REQUESTED_PROCEDURE_DESCRIPTION, // New in db v6 | |
165 DICOM_TAG_INSTITUTION_NAME, // New in db v6 | |
166 DICOM_TAG_REQUESTING_PHYSICIAN, // New in db v6 | |
167 DICOM_TAG_REFERRING_PHYSICIAN_NAME // New in db v6 | |
168 }; | |
169 | |
170 static const DicomTag SERIES_MAIN_DICOM_TAGS[] = | |
171 { | |
172 //DicomTag(0x0010, 0x1080), // MilitaryRank | |
173 DicomTag(0x0008, 0x0021), // SeriesDate | |
174 DicomTag(0x0008, 0x0031), // SeriesTime | |
175 DICOM_TAG_MODALITY, | |
176 DicomTag(0x0008, 0x0070), // Manufacturer | |
177 DicomTag(0x0008, 0x1010), // StationName | |
178 DICOM_TAG_SERIES_DESCRIPTION, | |
179 DicomTag(0x0018, 0x0015), // BodyPartExamined | |
180 DicomTag(0x0018, 0x0024), // SequenceName | |
181 DicomTag(0x0018, 0x1030), // ProtocolName | |
182 DicomTag(0x0020, 0x0011), // SeriesNumber | |
183 DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES, | |
184 DICOM_TAG_IMAGES_IN_ACQUISITION, | |
185 DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS, | |
186 DICOM_TAG_NUMBER_OF_SLICES, | |
187 DICOM_TAG_NUMBER_OF_TIME_SLICES, | |
188 DICOM_TAG_SERIES_INSTANCE_UID, | |
189 DICOM_TAG_IMAGE_ORIENTATION_PATIENT, // New in db v6 | |
190 DICOM_TAG_SERIES_TYPE, // New in db v6 | |
191 DICOM_TAG_OPERATOR_NAME, // New in db v6 | |
192 DICOM_TAG_PERFORMED_PROCEDURE_STEP_DESCRIPTION, // New in db v6 | |
193 DICOM_TAG_ACQUISITION_DEVICE_PROCESSING_DESCRIPTION, // New in db v6 | |
194 DICOM_TAG_CONTRAST_BOLUS_AGENT // New in db v6 | |
195 }; | |
196 | |
197 static const DicomTag INSTANCE_MAIN_DICOM_TAGS[] = | |
198 { | |
199 DicomTag(0x0008, 0x0012), // InstanceCreationDate | |
200 DicomTag(0x0008, 0x0013), // InstanceCreationTime | |
201 DicomTag(0x0020, 0x0012), // AcquisitionNumber | |
202 DICOM_TAG_IMAGE_INDEX, | |
203 DICOM_TAG_INSTANCE_NUMBER, | |
204 DICOM_TAG_NUMBER_OF_FRAMES, | |
205 DICOM_TAG_TEMPORAL_POSITION_IDENTIFIER, | |
206 DICOM_TAG_SOP_INSTANCE_UID, | |
207 DICOM_TAG_IMAGE_POSITION_PATIENT, // New in db v6 | |
208 DICOM_TAG_IMAGE_COMMENTS, // New in db v6 | |
209 | |
210 /** | |
211 * Main DICOM tags that are not part of any release of the | |
212 * database schema yet, and that will be part of future db v7. In | |
213 * the meantime, the user must call "/tools/reconstruct" once to | |
214 * access these tags if the corresponding DICOM files where | |
215 * indexed in the database by an older version of Orthanc. | |
216 **/ | |
217 DICOM_TAG_IMAGE_ORIENTATION_PATIENT // New in Orthanc 1.4.2 | |
218 }; | |
219 | |
220 | |
221 void DicomMap::LoadMainDicomTags(const DicomTag*& tags, | |
222 size_t& size, | |
223 ResourceType level) | |
224 { | 145 { |
225 switch (level) | 146 switch (level) |
226 { | 147 { |
227 case ResourceType_Patient: | 148 case ResourceType_Patient: |
228 tags = PATIENT_MAIN_DICOM_TAGS; | 149 tags = PATIENT_MAIN_DICOM_TAGS; |
229 size = sizeof(PATIENT_MAIN_DICOM_TAGS) / sizeof(DicomTag); | 150 size = sizeof(PATIENT_MAIN_DICOM_TAGS) / sizeof(MainDicomTag); |
230 break; | 151 break; |
231 | 152 |
232 case ResourceType_Study: | 153 case ResourceType_Study: |
233 tags = STUDY_MAIN_DICOM_TAGS; | 154 tags = STUDY_MAIN_DICOM_TAGS; |
234 size = sizeof(STUDY_MAIN_DICOM_TAGS) / sizeof(DicomTag); | 155 size = sizeof(STUDY_MAIN_DICOM_TAGS) / sizeof(MainDicomTag); |
235 break; | 156 break; |
236 | 157 |
237 case ResourceType_Series: | 158 case ResourceType_Series: |
238 tags = SERIES_MAIN_DICOM_TAGS; | 159 tags = SERIES_MAIN_DICOM_TAGS; |
239 size = sizeof(SERIES_MAIN_DICOM_TAGS) / sizeof(DicomTag); | 160 size = sizeof(SERIES_MAIN_DICOM_TAGS) / sizeof(MainDicomTag); |
240 break; | 161 break; |
241 | 162 |
242 case ResourceType_Instance: | 163 case ResourceType_Instance: |
243 tags = INSTANCE_MAIN_DICOM_TAGS; | 164 tags = INSTANCE_MAIN_DICOM_TAGS; |
244 size = sizeof(INSTANCE_MAIN_DICOM_TAGS) / sizeof(DicomTag); | 165 size = sizeof(INSTANCE_MAIN_DICOM_TAGS) / sizeof(MainDicomTag); |
245 break; | 166 break; |
246 | 167 |
247 default: | 168 default: |
248 throw OrthancException(ErrorCode_ParameterOutOfRange); | 169 throw OrthancException(ErrorCode_ParameterOutOfRange); |
249 } | 170 } |
250 } | 171 } |
251 | 172 |
252 | 173 |
253 void DicomMap::SetValue(uint16_t group, | 174 static void LoadMainDicomTags(std::map<DicomTag, std::string>& target, |
254 uint16_t element, | 175 ResourceType level) |
255 DicomValue* value) | 176 { |
177 const MainDicomTag* tags = NULL; | |
178 size_t size; | |
179 LoadMainDicomTags(tags, size, level); | |
180 | |
181 assert(tags != NULL && | |
182 size != 0); | |
183 | |
184 for (size_t i = 0; i < size; i++) | |
185 { | |
186 assert(target.find(tags[i].tag_) == target.end()); | |
187 | |
188 target[tags[i].tag_] = tags[i].name_; | |
189 } | |
190 } | |
191 | |
192 | |
193 namespace | |
194 { | |
195 class DicomTag2 : public DicomTag | |
196 { | |
197 public: | |
198 DicomTag2() : | |
199 DicomTag(0, 0) // To make std::map<> happy | |
200 { | |
201 } | |
202 | |
203 DicomTag2(const DicomTag& tag) : | |
204 DicomTag(tag) | |
205 { | |
206 } | |
207 }; | |
208 } | |
209 | |
210 | |
211 static void LoadMainDicomTags(std::map<std::string, DicomTag2>& target, | |
212 ResourceType level) | |
213 { | |
214 const MainDicomTag* tags = NULL; | |
215 size_t size; | |
216 LoadMainDicomTags(tags, size, level); | |
217 | |
218 assert(tags != NULL && | |
219 size != 0); | |
220 | |
221 for (size_t i = 0; i < size; i++) | |
222 { | |
223 assert(target.find(tags[i].name_) == target.end()); | |
224 | |
225 target[tags[i].name_] = tags[i].tag_; | |
226 } | |
227 } | |
228 | |
229 | |
230 void DicomMap::SetValueInternal(uint16_t group, | |
231 uint16_t element, | |
232 DicomValue* value) | |
256 { | 233 { |
257 DicomTag tag(group, element); | 234 DicomTag tag(group, element); |
258 Map::iterator it = map_.find(tag); | 235 Content::iterator it = content_.find(tag); |
259 | 236 |
260 if (it != map_.end()) | 237 if (it != content_.end()) |
261 { | 238 { |
262 delete it->second; | 239 delete it->second; |
263 it->second = value; | 240 it->second = value; |
264 } | 241 } |
265 else | 242 else |
266 { | 243 { |
267 map_.insert(std::make_pair(tag, value)); | 244 content_.insert(std::make_pair(tag, value)); |
268 } | 245 } |
269 } | |
270 | |
271 void DicomMap::SetValue(DicomTag tag, | |
272 DicomValue* value) | |
273 { | |
274 SetValue(tag.GetGroup(), tag.GetElement(), value); | |
275 } | 246 } |
276 | 247 |
277 | 248 |
278 void DicomMap::Clear() | 249 void DicomMap::Clear() |
279 { | 250 { |
280 for (Map::iterator it = map_.begin(); it != map_.end(); ++it) | 251 for (Content::iterator it = content_.begin(); it != content_.end(); ++it) |
281 { | 252 { |
282 assert(it->second != NULL); | 253 assert(it->second != NULL); |
283 delete it->second; | 254 delete it->second; |
284 } | 255 } |
285 | 256 |
286 map_.clear(); | 257 content_.clear(); |
287 } | 258 } |
288 | 259 |
289 | 260 |
290 void DicomMap::ExtractTags(DicomMap& result, | 261 static void ExtractTags(DicomMap& result, |
291 const DicomTag* tags, | 262 const DicomMap::Content& source, |
292 size_t count) const | 263 const MainDicomTag* tags, |
264 size_t count) | |
293 { | 265 { |
294 result.Clear(); | 266 result.Clear(); |
295 | 267 |
296 for (unsigned int i = 0; i < count; i++) | 268 for (unsigned int i = 0; i < count; i++) |
297 { | 269 { |
298 Map::const_iterator it = map_.find(tags[i]); | 270 DicomMap::Content::const_iterator it = source.find(tags[i].tag_); |
299 if (it != map_.end()) | 271 if (it != source.end()) |
300 { | 272 { |
301 result.SetValue(it->first, it->second->Clone()); | 273 result.SetValue(it->first, *it->second /* value will be cloned */); |
302 } | 274 } |
303 } | 275 } |
304 } | 276 } |
305 | 277 |
306 | 278 |
307 void DicomMap::ExtractPatientInformation(DicomMap& result) const | 279 void DicomMap::ExtractPatientInformation(DicomMap& result) const |
308 { | 280 { |
309 ExtractTags(result, PATIENT_MAIN_DICOM_TAGS, sizeof(PATIENT_MAIN_DICOM_TAGS) / sizeof(DicomTag)); | 281 ExtractTags(result, content_, PATIENT_MAIN_DICOM_TAGS, sizeof(PATIENT_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); |
310 } | 282 } |
311 | 283 |
312 void DicomMap::ExtractStudyInformation(DicomMap& result) const | 284 void DicomMap::ExtractStudyInformation(DicomMap& result) const |
313 { | 285 { |
314 ExtractTags(result, STUDY_MAIN_DICOM_TAGS, sizeof(STUDY_MAIN_DICOM_TAGS) / sizeof(DicomTag)); | 286 ExtractTags(result, content_, STUDY_MAIN_DICOM_TAGS, sizeof(STUDY_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); |
315 } | 287 } |
316 | 288 |
317 void DicomMap::ExtractSeriesInformation(DicomMap& result) const | 289 void DicomMap::ExtractSeriesInformation(DicomMap& result) const |
318 { | 290 { |
319 ExtractTags(result, SERIES_MAIN_DICOM_TAGS, sizeof(SERIES_MAIN_DICOM_TAGS) / sizeof(DicomTag)); | 291 ExtractTags(result, content_, SERIES_MAIN_DICOM_TAGS, sizeof(SERIES_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); |
320 } | 292 } |
321 | 293 |
322 void DicomMap::ExtractInstanceInformation(DicomMap& result) const | 294 void DicomMap::ExtractInstanceInformation(DicomMap& result) const |
323 { | 295 { |
324 ExtractTags(result, INSTANCE_MAIN_DICOM_TAGS, sizeof(INSTANCE_MAIN_DICOM_TAGS) / sizeof(DicomTag)); | 296 ExtractTags(result, content_, INSTANCE_MAIN_DICOM_TAGS, sizeof(INSTANCE_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); |
325 } | 297 } |
326 | 298 |
327 | 299 |
328 | 300 |
329 DicomMap* DicomMap::Clone() const | 301 DicomMap* DicomMap::Clone() const |
330 { | 302 { |
331 std::auto_ptr<DicomMap> result(new DicomMap); | 303 std::auto_ptr<DicomMap> result(new DicomMap); |
332 | 304 |
333 for (Map::const_iterator it = map_.begin(); it != map_.end(); ++it) | 305 for (Content::const_iterator it = content_.begin(); it != content_.end(); ++it) |
334 { | 306 { |
335 result->map_.insert(std::make_pair(it->first, it->second->Clone())); | 307 result->content_.insert(std::make_pair(it->first, it->second->Clone())); |
336 } | 308 } |
337 | 309 |
338 return result.release(); | 310 return result.release(); |
339 } | 311 } |
340 | 312 |
341 | 313 |
342 void DicomMap::Assign(const DicomMap& other) | 314 void DicomMap::Assign(const DicomMap& other) |
343 { | 315 { |
344 Clear(); | 316 Clear(); |
345 | 317 |
346 for (Map::const_iterator it = other.map_.begin(); it != other.map_.end(); ++it) | 318 for (Content::const_iterator it = other.content_.begin(); it != other.content_.end(); ++it) |
347 { | 319 { |
348 map_.insert(std::make_pair(it->first, it->second->Clone())); | 320 content_.insert(std::make_pair(it->first, it->second->Clone())); |
349 } | 321 } |
350 } | 322 } |
351 | 323 |
352 | 324 |
353 const DicomValue& DicomMap::GetValue(const DicomTag& tag) const | 325 const DicomValue& DicomMap::GetValue(const DicomTag& tag) const |
365 } | 337 } |
366 | 338 |
367 | 339 |
368 const DicomValue* DicomMap::TestAndGetValue(const DicomTag& tag) const | 340 const DicomValue* DicomMap::TestAndGetValue(const DicomTag& tag) const |
369 { | 341 { |
370 Map::const_iterator it = map_.find(tag); | 342 Content::const_iterator it = content_.find(tag); |
371 | 343 |
372 if (it == map_.end()) | 344 if (it == content_.end()) |
373 { | 345 { |
374 return NULL; | 346 return NULL; |
375 } | 347 } |
376 else | 348 else |
377 { | 349 { |
380 } | 352 } |
381 | 353 |
382 | 354 |
383 void DicomMap::Remove(const DicomTag& tag) | 355 void DicomMap::Remove(const DicomTag& tag) |
384 { | 356 { |
385 Map::iterator it = map_.find(tag); | 357 Content::iterator it = content_.find(tag); |
386 if (it != map_.end()) | 358 if (it != content_.end()) |
387 { | 359 { |
388 delete it->second; | 360 delete it->second; |
389 map_.erase(it); | 361 content_.erase(it); |
390 } | 362 } |
391 } | 363 } |
392 | 364 |
393 | 365 |
394 static void SetupFindTemplate(DicomMap& result, | 366 static void SetupFindTemplate(DicomMap& result, |
395 const DicomTag* tags, | 367 const MainDicomTag* tags, |
396 size_t count) | 368 size_t count) |
397 { | 369 { |
398 result.Clear(); | 370 result.Clear(); |
399 | 371 |
400 for (size_t i = 0; i < count; i++) | 372 for (size_t i = 0; i < count; i++) |
401 { | 373 { |
402 result.SetValue(tags[i], "", false); | 374 result.SetValue(tags[i].tag_, "", false); |
403 } | 375 } |
404 } | 376 } |
405 | 377 |
406 void DicomMap::SetupFindPatientTemplate(DicomMap& result) | 378 void DicomMap::SetupFindPatientTemplate(DicomMap& result) |
407 { | 379 { |
408 SetupFindTemplate(result, PATIENT_MAIN_DICOM_TAGS, sizeof(PATIENT_MAIN_DICOM_TAGS) / sizeof(DicomTag)); | 380 SetupFindTemplate(result, PATIENT_MAIN_DICOM_TAGS, sizeof(PATIENT_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); |
409 } | 381 } |
410 | 382 |
411 void DicomMap::SetupFindStudyTemplate(DicomMap& result) | 383 void DicomMap::SetupFindStudyTemplate(DicomMap& result) |
412 { | 384 { |
413 SetupFindTemplate(result, STUDY_MAIN_DICOM_TAGS, sizeof(STUDY_MAIN_DICOM_TAGS) / sizeof(DicomTag)); | 385 SetupFindTemplate(result, STUDY_MAIN_DICOM_TAGS, sizeof(STUDY_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); |
414 result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false); | 386 result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false); |
415 result.SetValue(DICOM_TAG_PATIENT_ID, "", false); | 387 result.SetValue(DICOM_TAG_PATIENT_ID, "", false); |
416 | 388 |
417 // These main DICOM tags are only indirectly related to the | 389 // These main DICOM tags are only indirectly related to the |
418 // General Study Module, remove them | 390 // General Study Module, remove them |
421 result.Remove(DICOM_TAG_REQUESTED_PROCEDURE_DESCRIPTION); | 393 result.Remove(DICOM_TAG_REQUESTED_PROCEDURE_DESCRIPTION); |
422 } | 394 } |
423 | 395 |
424 void DicomMap::SetupFindSeriesTemplate(DicomMap& result) | 396 void DicomMap::SetupFindSeriesTemplate(DicomMap& result) |
425 { | 397 { |
426 SetupFindTemplate(result, SERIES_MAIN_DICOM_TAGS, sizeof(SERIES_MAIN_DICOM_TAGS) / sizeof(DicomTag)); | 398 SetupFindTemplate(result, SERIES_MAIN_DICOM_TAGS, sizeof(SERIES_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); |
427 result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false); | 399 result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false); |
428 result.SetValue(DICOM_TAG_PATIENT_ID, "", false); | 400 result.SetValue(DICOM_TAG_PATIENT_ID, "", false); |
429 result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "", false); | 401 result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "", false); |
430 | 402 |
431 // These tags are considered as "main" by Orthanc, but are not in the Series module | 403 // These tags are considered as "main" by Orthanc, but are not in the Series module |
443 result.Remove(DICOM_TAG_CONTRAST_BOLUS_AGENT); | 415 result.Remove(DICOM_TAG_CONTRAST_BOLUS_AGENT); |
444 } | 416 } |
445 | 417 |
446 void DicomMap::SetupFindInstanceTemplate(DicomMap& result) | 418 void DicomMap::SetupFindInstanceTemplate(DicomMap& result) |
447 { | 419 { |
448 SetupFindTemplate(result, INSTANCE_MAIN_DICOM_TAGS, sizeof(INSTANCE_MAIN_DICOM_TAGS) / sizeof(DicomTag)); | 420 SetupFindTemplate(result, INSTANCE_MAIN_DICOM_TAGS, sizeof(INSTANCE_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); |
449 result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false); | 421 result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false); |
450 result.SetValue(DICOM_TAG_PATIENT_ID, "", false); | 422 result.SetValue(DICOM_TAG_PATIENT_ID, "", false); |
451 result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "", false); | 423 result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "", false); |
452 result.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, "", false); | 424 result.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, "", false); |
453 } | 425 } |
463 } | 435 } |
464 | 436 |
465 | 437 |
466 bool DicomMap::IsMainDicomTag(const DicomTag& tag, ResourceType level) | 438 bool DicomMap::IsMainDicomTag(const DicomTag& tag, ResourceType level) |
467 { | 439 { |
468 const DicomTag *tags = NULL; | 440 const MainDicomTag *tags = NULL; |
469 size_t size; | 441 size_t size; |
470 | 442 LoadMainDicomTags(tags, size, level); |
471 switch (level) | |
472 { | |
473 case ResourceType_Patient: | |
474 tags = PATIENT_MAIN_DICOM_TAGS; | |
475 size = sizeof(PATIENT_MAIN_DICOM_TAGS) / sizeof(DicomTag); | |
476 break; | |
477 | |
478 case ResourceType_Study: | |
479 tags = STUDY_MAIN_DICOM_TAGS; | |
480 size = sizeof(STUDY_MAIN_DICOM_TAGS) / sizeof(DicomTag); | |
481 break; | |
482 | |
483 case ResourceType_Series: | |
484 tags = SERIES_MAIN_DICOM_TAGS; | |
485 size = sizeof(SERIES_MAIN_DICOM_TAGS) / sizeof(DicomTag); | |
486 break; | |
487 | |
488 case ResourceType_Instance: | |
489 tags = INSTANCE_MAIN_DICOM_TAGS; | |
490 size = sizeof(INSTANCE_MAIN_DICOM_TAGS) / sizeof(DicomTag); | |
491 break; | |
492 | |
493 default: | |
494 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
495 } | |
496 | 443 |
497 for (size_t i = 0; i < size; i++) | 444 for (size_t i = 0; i < size; i++) |
498 { | 445 { |
499 if (tags[i] == tag) | 446 if (tags[i].tag_ == tag) |
500 { | 447 { |
501 return true; | 448 return true; |
502 } | 449 } |
503 } | 450 } |
504 | 451 |
514 } | 461 } |
515 | 462 |
516 | 463 |
517 void DicomMap::GetMainDicomTagsInternal(std::set<DicomTag>& result, ResourceType level) | 464 void DicomMap::GetMainDicomTagsInternal(std::set<DicomTag>& result, ResourceType level) |
518 { | 465 { |
519 const DicomTag *tags = NULL; | 466 const MainDicomTag *tags = NULL; |
520 size_t size; | 467 size_t size; |
521 | 468 LoadMainDicomTags(tags, size, level); |
522 switch (level) | |
523 { | |
524 case ResourceType_Patient: | |
525 tags = PATIENT_MAIN_DICOM_TAGS; | |
526 size = sizeof(PATIENT_MAIN_DICOM_TAGS) / sizeof(DicomTag); | |
527 break; | |
528 | |
529 case ResourceType_Study: | |
530 tags = STUDY_MAIN_DICOM_TAGS; | |
531 size = sizeof(STUDY_MAIN_DICOM_TAGS) / sizeof(DicomTag); | |
532 break; | |
533 | |
534 case ResourceType_Series: | |
535 tags = SERIES_MAIN_DICOM_TAGS; | |
536 size = sizeof(SERIES_MAIN_DICOM_TAGS) / sizeof(DicomTag); | |
537 break; | |
538 | |
539 case ResourceType_Instance: | |
540 tags = INSTANCE_MAIN_DICOM_TAGS; | |
541 size = sizeof(INSTANCE_MAIN_DICOM_TAGS) / sizeof(DicomTag); | |
542 break; | |
543 | |
544 default: | |
545 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
546 } | |
547 | 469 |
548 for (size_t i = 0; i < size; i++) | 470 for (size_t i = 0; i < size; i++) |
549 { | 471 { |
550 result.insert(tags[i]); | 472 result.insert(tags[i].tag_); |
551 } | 473 } |
552 } | 474 } |
553 | 475 |
554 | 476 |
555 void DicomMap::GetMainDicomTags(std::set<DicomTag>& result, ResourceType level) | 477 void DicomMap::GetMainDicomTags(std::set<DicomTag>& result, ResourceType level) |
571 | 493 |
572 void DicomMap::GetTags(std::set<DicomTag>& tags) const | 494 void DicomMap::GetTags(std::set<DicomTag>& tags) const |
573 { | 495 { |
574 tags.clear(); | 496 tags.clear(); |
575 | 497 |
576 for (Map::const_iterator it = map_.begin(); | 498 for (Content::const_iterator it = content_.begin(); |
577 it != map_.end(); ++it) | 499 it != content_.end(); ++it) |
578 { | 500 { |
579 tags.insert(it->first); | 501 tags.insert(it->first); |
580 } | 502 } |
581 } | 503 } |
582 | 504 |
1122 } | 1044 } |
1123 | 1045 |
1124 | 1046 |
1125 void DicomMap::Merge(const DicomMap& other) | 1047 void DicomMap::Merge(const DicomMap& other) |
1126 { | 1048 { |
1127 for (Map::const_iterator it = other.map_.begin(); | 1049 for (Content::const_iterator it = other.content_.begin(); |
1128 it != other.map_.end(); ++it) | 1050 it != other.content_.end(); ++it) |
1129 { | 1051 { |
1130 assert(it->second != NULL); | 1052 assert(it->second != NULL); |
1131 | 1053 |
1132 if (map_.find(it->first) == map_.end()) | 1054 if (content_.find(it->first) == content_.end()) |
1133 { | 1055 { |
1134 map_[it->first] = it->second->Clone(); | 1056 content_[it->first] = it->second->Clone(); |
1135 } | 1057 } |
1136 } | 1058 } |
1137 } | 1059 } |
1138 | 1060 |
1139 | 1061 |
1140 void DicomMap::ExtractMainDicomTagsInternal(const DicomMap& other, | 1062 void DicomMap::ExtractMainDicomTagsInternal(const DicomMap& other, |
1141 ResourceType level) | 1063 ResourceType level) |
1142 { | 1064 { |
1143 const DicomTag* tags = NULL; | 1065 const MainDicomTag* tags = NULL; |
1144 size_t size = 0; | 1066 size_t size = 0; |
1145 | 1067 |
1146 LoadMainDicomTags(tags, size, level); | 1068 LoadMainDicomTags(tags, size, level); |
1147 assert(tags != NULL && size > 0); | 1069 assert(tags != NULL && size > 0); |
1148 | 1070 |
1149 for (size_t i = 0; i < size; i++) | 1071 for (size_t i = 0; i < size; i++) |
1150 { | 1072 { |
1151 Map::const_iterator found = other.map_.find(tags[i]); | 1073 Content::const_iterator found = other.content_.find(tags[i].tag_); |
1152 | 1074 |
1153 if (found != other.map_.end() && | 1075 if (found != other.content_.end() && |
1154 map_.find(tags[i]) == map_.end()) | 1076 content_.find(tags[i].tag_) == content_.end()) |
1155 { | 1077 { |
1156 assert(found->second != NULL); | 1078 assert(found->second != NULL); |
1157 map_[tags[i]] = found->second->Clone(); | 1079 content_[tags[i].tag_] = found->second->Clone(); |
1158 } | 1080 } |
1159 } | 1081 } |
1160 } | 1082 } |
1161 | 1083 |
1162 | 1084 |
1175 // TODO - Speed up possible by making this std::set a global variable | 1097 // TODO - Speed up possible by making this std::set a global variable |
1176 | 1098 |
1177 std::set<DicomTag> mainDicomTags; | 1099 std::set<DicomTag> mainDicomTags; |
1178 GetMainDicomTags(mainDicomTags); | 1100 GetMainDicomTags(mainDicomTags); |
1179 | 1101 |
1180 for (Map::const_iterator it = map_.begin(); it != map_.end(); ++it) | 1102 for (Content::const_iterator it = content_.begin(); it != content_.end(); ++it) |
1181 { | 1103 { |
1182 if (mainDicomTags.find(it->first) == mainDicomTags.end()) | 1104 if (mainDicomTags.find(it->first) == mainDicomTags.end()) |
1183 { | 1105 { |
1184 return false; | 1106 return false; |
1185 } | 1107 } |
1191 | 1113 |
1192 void DicomMap::Serialize(Json::Value& target) const | 1114 void DicomMap::Serialize(Json::Value& target) const |
1193 { | 1115 { |
1194 target = Json::objectValue; | 1116 target = Json::objectValue; |
1195 | 1117 |
1196 for (Map::const_iterator it = map_.begin(); it != map_.end(); ++it) | 1118 for (Content::const_iterator it = content_.begin(); it != content_.end(); ++it) |
1197 { | 1119 { |
1198 assert(it->second != NULL); | 1120 assert(it->second != NULL); |
1199 | 1121 |
1200 std::string tag = it->first.Format(); | 1122 std::string tag = it->first.Format(); |
1201 | 1123 |
1221 for (size_t i = 0; i < tags.size(); i++) | 1143 for (size_t i = 0; i < tags.size(); i++) |
1222 { | 1144 { |
1223 DicomTag tag(0, 0); | 1145 DicomTag tag(0, 0); |
1224 | 1146 |
1225 if (!DicomTag::ParseHexadecimal(tag, tags[i].c_str()) || | 1147 if (!DicomTag::ParseHexadecimal(tag, tags[i].c_str()) || |
1226 map_.find(tag) != map_.end()) | 1148 content_.find(tag) != content_.end()) |
1227 { | 1149 { |
1228 throw OrthancException(ErrorCode_BadFileFormat); | 1150 throw OrthancException(ErrorCode_BadFileFormat); |
1229 } | 1151 } |
1230 | 1152 |
1231 std::auto_ptr<DicomValue> value(new DicomValue); | 1153 std::auto_ptr<DicomValue> value(new DicomValue); |
1232 value->Unserialize(source[tags[i]]); | 1154 value->Unserialize(source[tags[i]]); |
1233 | 1155 |
1234 map_[tag] = value.release(); | 1156 content_[tag] = value.release(); |
1235 } | 1157 } |
1236 } | 1158 } |
1237 | 1159 |
1238 | 1160 |
1239 void DicomMap::FromDicomWeb(const Json::Value& source) | 1161 void DicomMap::FromDicomWeb(const Json::Value& source) |
1388 } | 1310 } |
1389 | 1311 |
1390 | 1312 |
1391 void DicomMap::RemoveBinaryTags() | 1313 void DicomMap::RemoveBinaryTags() |
1392 { | 1314 { |
1393 Map kept; | 1315 Content kept; |
1394 | 1316 |
1395 for (Map::iterator it = map_.begin(); it != map_.end(); ++it) | 1317 for (Content::iterator it = content_.begin(); it != content_.end(); ++it) |
1396 { | 1318 { |
1397 assert(it->second != NULL); | 1319 assert(it->second != NULL); |
1398 | 1320 |
1399 if (!it->second->IsBinary() && | 1321 if (!it->second->IsBinary() && |
1400 !it->second->IsNull()) | 1322 !it->second->IsNull()) |
1405 { | 1327 { |
1406 delete it->second; | 1328 delete it->second; |
1407 } | 1329 } |
1408 } | 1330 } |
1409 | 1331 |
1410 map_ = kept; | 1332 content_ = kept; |
1333 } | |
1334 | |
1335 | |
1336 void DicomMap::DumpMainDicomTags(Json::Value& target, | |
1337 ResourceType level) const | |
1338 { | |
1339 std::map<DicomTag, std::string> mainTags; // TODO - Create a singleton to hold this map | |
1340 LoadMainDicomTags(mainTags, level); | |
1341 | |
1342 target = Json::objectValue; | |
1343 | |
1344 for (Content::const_iterator it = content_.begin(); it != content_.end(); ++it) | |
1345 { | |
1346 assert(it->second != NULL); | |
1347 | |
1348 if (!it->second->IsBinary() && | |
1349 !it->second->IsNull()) | |
1350 { | |
1351 std::map<DicomTag, std::string>::const_iterator found = mainTags.find(it->first); | |
1352 | |
1353 if (found != mainTags.end()) | |
1354 { | |
1355 target[found->second] = it->second->GetContent(); | |
1356 } | |
1357 } | |
1358 } | |
1359 } | |
1360 | |
1361 | |
1362 void DicomMap::ParseMainDicomTags(const Json::Value& source, | |
1363 ResourceType level) | |
1364 { | |
1365 if (source.type() != Json::objectValue) | |
1366 { | |
1367 throw OrthancException(ErrorCode_BadFileFormat); | |
1368 } | |
1369 | |
1370 Clear(); | |
1371 | |
1372 std::map<std::string, DicomTag2> mainTags; // TODO - Create a singleton to hold this map | |
1373 LoadMainDicomTags(mainTags, level); | |
1374 | |
1375 Json::Value::Members members = source.getMemberNames(); | |
1376 for (size_t i = 0; i < members.size(); i++) | |
1377 { | |
1378 std::map<std::string, DicomTag2>::const_iterator found = mainTags.find(members[i]); | |
1379 | |
1380 if (found != mainTags.end()) | |
1381 { | |
1382 const Json::Value& value = source[members[i]]; | |
1383 if (value.type() != Json::stringValue) | |
1384 { | |
1385 throw OrthancException(ErrorCode_BadFileFormat); | |
1386 } | |
1387 else | |
1388 { | |
1389 SetValue(found->second, value.asString(), false); | |
1390 } | |
1391 } | |
1392 } | |
1411 } | 1393 } |
1412 | 1394 |
1413 | 1395 |
1414 void DicomMap::Print(FILE* fp) const | 1396 void DicomMap::Print(FILE* fp) const |
1415 { | 1397 { |