Mercurial > hg > orthanc
comparison Core/DicomParsing/DicomModification.cpp @ 2382:7284093111b0
big reorganization to cleanly separate framework vs. server
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 29 Aug 2017 21:17:35 +0200 |
parents | OrthancServer/DicomModification.cpp@f5fc61337bdf |
children | 878b59270859 |
comparison
equal
deleted
inserted
replaced
2381:b8969010b534 | 2382:7284093111b0 |
---|---|
1 /** | |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017 Osimis, Belgium | |
6 * | |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU General Public License as | |
9 * published by the Free Software Foundation, either version 3 of the | |
10 * License, or (at your option) any later version. | |
11 * | |
12 * In addition, as a special exception, the copyright holders of this | |
13 * program give permission to link the code of its release with the | |
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it | |
15 * that use the same license as the "OpenSSL" library), and distribute | |
16 * the linked executables. You must obey the GNU General Public License | |
17 * in all respects for all of the code used other than "OpenSSL". If you | |
18 * modify file(s) with this exception, you may extend this exception to | |
19 * your version of the file(s), but you are not obligated to do so. If | |
20 * you do not wish to do so, delete this exception statement from your | |
21 * version. If you delete this exception statement from all source files | |
22 * in the program, then also delete it here. | |
23 * | |
24 * This program is distributed in the hope that it will be useful, but | |
25 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
27 * General Public License for more details. | |
28 * | |
29 * You should have received a copy of the GNU General Public License | |
30 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
31 **/ | |
32 | |
33 | |
34 #include "../PrecompiledHeaders.h" | |
35 #include "DicomModification.h" | |
36 | |
37 #include "../Logging.h" | |
38 #include "../OrthancException.h" | |
39 #include "FromDcmtkBridge.h" | |
40 | |
41 #include <memory> // For std::auto_ptr | |
42 | |
43 | |
44 static const std::string ORTHANC_DEIDENTIFICATION_METHOD_2008 = | |
45 "Orthanc " ORTHANC_VERSION " - PS 3.15-2008 Table E.1-1"; | |
46 | |
47 static const std::string ORTHANC_DEIDENTIFICATION_METHOD_2017c = | |
48 "Orthanc " ORTHANC_VERSION " - PS 3.15-2017c Table E.1-1 Basic Profile"; | |
49 | |
50 namespace Orthanc | |
51 { | |
52 bool DicomModification::CancelReplacement(const DicomTag& tag) | |
53 { | |
54 Replacements::iterator it = replacements_.find(tag); | |
55 | |
56 if (it != replacements_.end()) | |
57 { | |
58 delete it->second; | |
59 replacements_.erase(it); | |
60 return true; | |
61 } | |
62 else | |
63 { | |
64 return false; | |
65 } | |
66 } | |
67 | |
68 | |
69 void DicomModification::ReplaceInternal(const DicomTag& tag, | |
70 const Json::Value& value) | |
71 { | |
72 Replacements::iterator it = replacements_.find(tag); | |
73 | |
74 if (it != replacements_.end()) | |
75 { | |
76 delete it->second; | |
77 it->second = NULL; // In the case of an exception during the clone | |
78 it->second = new Json::Value(value); // Clone | |
79 } | |
80 else | |
81 { | |
82 replacements_[tag] = new Json::Value(value); // Clone | |
83 } | |
84 } | |
85 | |
86 | |
87 void DicomModification::ClearReplacements() | |
88 { | |
89 for (Replacements::iterator it = replacements_.begin(); | |
90 it != replacements_.end(); ++it) | |
91 { | |
92 delete it->second; | |
93 } | |
94 | |
95 replacements_.clear(); | |
96 } | |
97 | |
98 | |
99 void DicomModification::MarkNotOrthancAnonymization() | |
100 { | |
101 Replacements::iterator it = replacements_.find(DICOM_TAG_DEIDENTIFICATION_METHOD); | |
102 | |
103 if (it != replacements_.end() && | |
104 (it->second->asString() == ORTHANC_DEIDENTIFICATION_METHOD_2008 || | |
105 it->second->asString() == ORTHANC_DEIDENTIFICATION_METHOD_2017c)) | |
106 { | |
107 delete it->second; | |
108 replacements_.erase(it); | |
109 } | |
110 } | |
111 | |
112 | |
113 void DicomModification::MapDicomIdentifier(ParsedDicomFile& dicom, | |
114 ResourceType level) | |
115 { | |
116 std::auto_ptr<DicomTag> tag; | |
117 | |
118 switch (level) | |
119 { | |
120 case ResourceType_Study: | |
121 tag.reset(new DicomTag(DICOM_TAG_STUDY_INSTANCE_UID)); | |
122 break; | |
123 | |
124 case ResourceType_Series: | |
125 tag.reset(new DicomTag(DICOM_TAG_SERIES_INSTANCE_UID)); | |
126 break; | |
127 | |
128 case ResourceType_Instance: | |
129 tag.reset(new DicomTag(DICOM_TAG_SOP_INSTANCE_UID)); | |
130 break; | |
131 | |
132 default: | |
133 throw OrthancException(ErrorCode_InternalError); | |
134 } | |
135 | |
136 std::string original; | |
137 if (!dicom.GetTagValue(original, *tag)) | |
138 { | |
139 original = ""; | |
140 } | |
141 | |
142 std::string mapped; | |
143 | |
144 UidMap::const_iterator previous = uidMap_.find(std::make_pair(level, original)); | |
145 if (previous == uidMap_.end()) | |
146 { | |
147 mapped = FromDcmtkBridge::GenerateUniqueIdentifier(level); | |
148 uidMap_.insert(std::make_pair(std::make_pair(level, original), mapped)); | |
149 } | |
150 else | |
151 { | |
152 mapped = previous->second; | |
153 } | |
154 | |
155 dicom.Replace(*tag, mapped, false /* don't try and decode data URI scheme for UIDs */, DicomReplaceMode_InsertIfAbsent); | |
156 } | |
157 | |
158 DicomModification::DicomModification() : | |
159 removePrivateTags_(false), | |
160 level_(ResourceType_Instance), | |
161 allowManualIdentifiers_(true), | |
162 keepStudyInstanceUid_(false), | |
163 keepSeriesInstanceUid_(false) | |
164 { | |
165 } | |
166 | |
167 DicomModification::~DicomModification() | |
168 { | |
169 ClearReplacements(); | |
170 } | |
171 | |
172 void DicomModification::Keep(const DicomTag& tag) | |
173 { | |
174 bool wasRemoved = IsRemoved(tag); | |
175 bool wasCleared = IsCleared(tag); | |
176 | |
177 removals_.erase(tag); | |
178 clearings_.erase(tag); | |
179 | |
180 bool wasReplaced = CancelReplacement(tag); | |
181 | |
182 if (tag == DICOM_TAG_STUDY_INSTANCE_UID) | |
183 { | |
184 keepStudyInstanceUid_ = true; | |
185 } | |
186 else if (tag == DICOM_TAG_SERIES_INSTANCE_UID) | |
187 { | |
188 keepSeriesInstanceUid_ = true; | |
189 } | |
190 else if (tag.IsPrivate()) | |
191 { | |
192 privateTagsToKeep_.insert(tag); | |
193 } | |
194 else if (!wasRemoved && | |
195 !wasReplaced && | |
196 !wasCleared) | |
197 { | |
198 LOG(WARNING) << "Marking this tag as to be kept has no effect: " << tag.Format(); | |
199 } | |
200 | |
201 MarkNotOrthancAnonymization(); | |
202 } | |
203 | |
204 void DicomModification::Remove(const DicomTag& tag) | |
205 { | |
206 removals_.insert(tag); | |
207 clearings_.erase(tag); | |
208 CancelReplacement(tag); | |
209 privateTagsToKeep_.erase(tag); | |
210 | |
211 MarkNotOrthancAnonymization(); | |
212 } | |
213 | |
214 void DicomModification::Clear(const DicomTag& tag) | |
215 { | |
216 removals_.erase(tag); | |
217 clearings_.insert(tag); | |
218 CancelReplacement(tag); | |
219 privateTagsToKeep_.erase(tag); | |
220 | |
221 MarkNotOrthancAnonymization(); | |
222 } | |
223 | |
224 bool DicomModification::IsRemoved(const DicomTag& tag) const | |
225 { | |
226 return removals_.find(tag) != removals_.end(); | |
227 } | |
228 | |
229 bool DicomModification::IsCleared(const DicomTag& tag) const | |
230 { | |
231 return clearings_.find(tag) != clearings_.end(); | |
232 } | |
233 | |
234 void DicomModification::Replace(const DicomTag& tag, | |
235 const Json::Value& value, | |
236 bool safeForAnonymization) | |
237 { | |
238 clearings_.erase(tag); | |
239 removals_.erase(tag); | |
240 privateTagsToKeep_.erase(tag); | |
241 ReplaceInternal(tag, value); | |
242 | |
243 if (!safeForAnonymization) | |
244 { | |
245 MarkNotOrthancAnonymization(); | |
246 } | |
247 } | |
248 | |
249 | |
250 bool DicomModification::IsReplaced(const DicomTag& tag) const | |
251 { | |
252 return replacements_.find(tag) != replacements_.end(); | |
253 } | |
254 | |
255 const Json::Value& DicomModification::GetReplacement(const DicomTag& tag) const | |
256 { | |
257 Replacements::const_iterator it = replacements_.find(tag); | |
258 | |
259 if (it == replacements_.end()) | |
260 { | |
261 throw OrthancException(ErrorCode_InexistentItem); | |
262 } | |
263 else | |
264 { | |
265 return *it->second; | |
266 } | |
267 } | |
268 | |
269 | |
270 std::string DicomModification::GetReplacementAsString(const DicomTag& tag) const | |
271 { | |
272 const Json::Value& json = GetReplacement(tag); | |
273 | |
274 if (json.type() != Json::stringValue) | |
275 { | |
276 throw OrthancException(ErrorCode_BadParameterType); | |
277 } | |
278 else | |
279 { | |
280 return json.asString(); | |
281 } | |
282 } | |
283 | |
284 | |
285 void DicomModification::SetRemovePrivateTags(bool removed) | |
286 { | |
287 removePrivateTags_ = removed; | |
288 | |
289 if (!removed) | |
290 { | |
291 MarkNotOrthancAnonymization(); | |
292 } | |
293 } | |
294 | |
295 void DicomModification::SetLevel(ResourceType level) | |
296 { | |
297 uidMap_.clear(); | |
298 level_ = level; | |
299 | |
300 if (level != ResourceType_Patient) | |
301 { | |
302 MarkNotOrthancAnonymization(); | |
303 } | |
304 } | |
305 | |
306 | |
307 void DicomModification::SetupAnonymization2008() | |
308 { | |
309 // This is Table E.1-1 from PS 3.15-2008 - DICOM Part 15: Security and System Management Profiles | |
310 // https://raw.githubusercontent.com/jodogne/dicom-specification/master/2008/08_15pu.pdf | |
311 | |
312 removals_.insert(DicomTag(0x0008, 0x0014)); // Instance Creator UID | |
313 //removals_.insert(DicomTag(0x0008, 0x0018)); // SOP Instance UID => set in Apply() | |
314 removals_.insert(DicomTag(0x0008, 0x0050)); // Accession Number | |
315 removals_.insert(DicomTag(0x0008, 0x0080)); // Institution Name | |
316 removals_.insert(DicomTag(0x0008, 0x0081)); // Institution Address | |
317 removals_.insert(DicomTag(0x0008, 0x0090)); // Referring Physician's Name | |
318 removals_.insert(DicomTag(0x0008, 0x0092)); // Referring Physician's Address | |
319 removals_.insert(DicomTag(0x0008, 0x0094)); // Referring Physician's Telephone Numbers | |
320 removals_.insert(DicomTag(0x0008, 0x1010)); // Station Name | |
321 removals_.insert(DicomTag(0x0008, 0x1030)); // Study Description | |
322 removals_.insert(DicomTag(0x0008, 0x103e)); // Series Description | |
323 removals_.insert(DicomTag(0x0008, 0x1040)); // Institutional Department Name | |
324 removals_.insert(DicomTag(0x0008, 0x1048)); // Physician(s) of Record | |
325 removals_.insert(DicomTag(0x0008, 0x1050)); // Performing Physicians' Name | |
326 removals_.insert(DicomTag(0x0008, 0x1060)); // Name of Physician(s) Reading Study | |
327 removals_.insert(DicomTag(0x0008, 0x1070)); // Operators' Name | |
328 removals_.insert(DicomTag(0x0008, 0x1080)); // Admitting Diagnoses Description | |
329 removals_.insert(DicomTag(0x0008, 0x1155)); // Referenced SOP Instance UID | |
330 removals_.insert(DicomTag(0x0008, 0x2111)); // Derivation Description | |
331 //removals_.insert(DicomTag(0x0010, 0x0010)); // Patient's Name => cf. below (*) | |
332 //removals_.insert(DicomTag(0x0010, 0x0020)); // Patient ID => cf. below (*) | |
333 removals_.insert(DicomTag(0x0010, 0x0030)); // Patient's Birth Date | |
334 removals_.insert(DicomTag(0x0010, 0x0032)); // Patient's Birth Time | |
335 removals_.insert(DicomTag(0x0010, 0x0040)); // Patient's Sex | |
336 removals_.insert(DicomTag(0x0010, 0x1000)); // Other Patient Ids | |
337 removals_.insert(DicomTag(0x0010, 0x1001)); // Other Patient Names | |
338 removals_.insert(DicomTag(0x0010, 0x1010)); // Patient's Age | |
339 removals_.insert(DicomTag(0x0010, 0x1020)); // Patient's Size | |
340 removals_.insert(DicomTag(0x0010, 0x1030)); // Patient's Weight | |
341 removals_.insert(DicomTag(0x0010, 0x1090)); // Medical Record Locator | |
342 removals_.insert(DicomTag(0x0010, 0x2160)); // Ethnic Group | |
343 removals_.insert(DicomTag(0x0010, 0x2180)); // Occupation | |
344 removals_.insert(DicomTag(0x0010, 0x21b0)); // Additional Patient's History | |
345 removals_.insert(DicomTag(0x0010, 0x4000)); // Patient Comments | |
346 removals_.insert(DicomTag(0x0018, 0x1000)); // Device Serial Number | |
347 removals_.insert(DicomTag(0x0018, 0x1030)); // Protocol Name | |
348 //removals_.insert(DicomTag(0x0020, 0x000d)); // Study Instance UID => set in Apply() | |
349 //removals_.insert(DicomTag(0x0020, 0x000e)); // Series Instance UID => set in Apply() | |
350 removals_.insert(DicomTag(0x0020, 0x0010)); // Study ID | |
351 removals_.insert(DicomTag(0x0020, 0x0052)); // Frame of Reference UID | |
352 removals_.insert(DicomTag(0x0020, 0x0200)); // Synchronization Frame of Reference UID | |
353 removals_.insert(DicomTag(0x0020, 0x4000)); // Image Comments | |
354 removals_.insert(DicomTag(0x0040, 0x0275)); // Request Attributes Sequence | |
355 removals_.insert(DicomTag(0x0040, 0xa124)); // UID | |
356 removals_.insert(DicomTag(0x0040, 0xa730)); // Content Sequence | |
357 removals_.insert(DicomTag(0x0088, 0x0140)); // Storage Media File-set UID | |
358 removals_.insert(DicomTag(0x3006, 0x0024)); // Referenced Frame of Reference UID | |
359 removals_.insert(DicomTag(0x3006, 0x00c2)); // Related Frame of Reference UID | |
360 | |
361 // Some more removals (from the experience of DICOM files at the CHU of Liege) | |
362 removals_.insert(DicomTag(0x0010, 0x1040)); // Patient's Address | |
363 removals_.insert(DicomTag(0x0032, 0x1032)); // Requesting Physician | |
364 removals_.insert(DicomTag(0x0010, 0x2154)); // PatientTelephoneNumbers | |
365 removals_.insert(DicomTag(0x0010, 0x2000)); // Medical Alerts | |
366 | |
367 // Set the DeidentificationMethod tag | |
368 ReplaceInternal(DICOM_TAG_DEIDENTIFICATION_METHOD, ORTHANC_DEIDENTIFICATION_METHOD_2008); | |
369 } | |
370 | |
371 | |
372 #if 0 | |
373 /** | |
374 * This is a manual implementation by Alain Mazy. Only kept for reference. | |
375 * https://bitbucket.org/sjodogne/orthanc/commits/c6defdc4c611fca2ab528ba2c6937a742e0329a8?at=issue-46-anonymization | |
376 **/ | |
377 | |
378 void DicomModification::SetupAnonymization2011() | |
379 { | |
380 // This is Table E.1-1 from PS 3.15-2011 - DICOM Part 15: Security and System Management Profiles | |
381 // https://raw.githubusercontent.com/jodogne/dicom-specification/master/2011/11_15pu.pdf | |
382 | |
383 removals_.insert(DicomTag(0x0000, 0x1000)); // Affected SOP Instance UID | |
384 removals_.insert(DicomTag(0x0000, 0x1001)); // Requested SOP Instance UID | |
385 removals_.insert(DicomTag(0x0002, 0x0003)); // Media Storage SOP Instance UID => TODO: replace with a non-zero length UID that is internally consistent within a set of Instances | |
386 removals_.insert(DicomTag(0x0004, 0x1511)); // Referenced SOP Instance UID in File | |
387 removals_.insert(DicomTag(0x0008, 0x0010)); // Irradiation Event UID | |
388 removals_.insert(DicomTag(0x0008, 0x0014)); // Instance Creator UID | |
389 //removals_.insert(DicomTag(0x0008, 0x0018)); // SOP Instance UID => set in Apply() | |
390 clearings_.insert(DicomTag(0x0008, 0x0020)); // Study Date | |
391 clearings_.insert(DicomTag(0x0008, 0x0021)); // Series Date | |
392 clearings_.insert(DicomTag(0x0008, 0x0030)); // Study Time | |
393 clearings_.insert(DicomTag(0x0008, 0x0031)); // Series Time | |
394 removals_.insert(DicomTag(0x0008, 0x0022)); // Acquisition Date | |
395 removals_.insert(DicomTag(0x0008, 0x0023)); // Content Date | |
396 removals_.insert(DicomTag(0x0008, 0x0024)); // Overlay Date | |
397 removals_.insert(DicomTag(0x0008, 0x0025)); // Curve Date | |
398 removals_.insert(DicomTag(0x0008, 0x002a)); // Acquisition DateTime | |
399 removals_.insert(DicomTag(0x0008, 0x0032)); // Acquisition Time | |
400 removals_.insert(DicomTag(0x0008, 0x0033)); // Content Time | |
401 removals_.insert(DicomTag(0x0008, 0x0034)); // Overlay Time | |
402 removals_.insert(DicomTag(0x0008, 0x0035)); // Curve Time | |
403 removals_.insert(DicomTag(0x0008, 0x0050)); // Accession Number | |
404 removals_.insert(DicomTag(0x0008, 0x0058)); // Failed SOP Instance UID List | |
405 removals_.insert(DicomTag(0x0008, 0x0080)); // Institution Name | |
406 removals_.insert(DicomTag(0x0008, 0x0081)); // Institution Address | |
407 removals_.insert(DicomTag(0x0008, 0x0082)); // Institution Code Sequence | |
408 removals_.insert(DicomTag(0x0008, 0x0090)); // Referring Physician's Name | |
409 removals_.insert(DicomTag(0x0008, 0x0092)); // Referring Physician's Address | |
410 removals_.insert(DicomTag(0x0008, 0x0094)); // Referring Physician's Telephone Numbers | |
411 removals_.insert(DicomTag(0x0008, 0x0096)); // Referring Physician's Identification Sequence | |
412 removals_.insert(DicomTag(0x0008, 0x010d)); // Context Group Extension Creator UID | |
413 removals_.insert(DicomTag(0x0008, 0x0201)); // Timezone Offset From UTC | |
414 removals_.insert(DicomTag(0x0008, 0x0300)); // Current Patient Location | |
415 removals_.insert(DicomTag(0x0008, 0x1010)); // Station Name | |
416 removals_.insert(DicomTag(0x0008, 0x1030)); // Study Description | |
417 removals_.insert(DicomTag(0x0008, 0x103e)); // Series Description | |
418 removals_.insert(DicomTag(0x0008, 0x1040)); // Institutional Department Name | |
419 removals_.insert(DicomTag(0x0008, 0x1048)); // Physician(s) of Record | |
420 removals_.insert(DicomTag(0x0008, 0x1049)); // Physician(s) of Record Identification Sequence | |
421 removals_.insert(DicomTag(0x0008, 0x1050)); // Performing Physicians' Name | |
422 removals_.insert(DicomTag(0x0008, 0x1052)); // Performing Physicians Identification Sequence | |
423 removals_.insert(DicomTag(0x0008, 0x1060)); // Name of Physician(s) Reading Study | |
424 removals_.insert(DicomTag(0x0008, 0x1062)); // Physician Reading Study Identification Sequence | |
425 removals_.insert(DicomTag(0x0008, 0x1070)); // Operators' Name | |
426 removals_.insert(DicomTag(0x0008, 0x1072)); // Operators' Identification Sequence | |
427 removals_.insert(DicomTag(0x0008, 0x1080)); // Admitting Diagnoses Description | |
428 removals_.insert(DicomTag(0x0008, 0x1084)); // Admitting Diagnoses Code Sequence | |
429 removals_.insert(DicomTag(0x0008, 0x1110)); // Referenced Study Sequence | |
430 removals_.insert(DicomTag(0x0008, 0x1111)); // Referenced Performed Procedure Step Sequence | |
431 removals_.insert(DicomTag(0x0008, 0x1120)); // Referenced Patient Sequence | |
432 removals_.insert(DicomTag(0x0008, 0x1140)); // Referenced Image Sequence | |
433 removals_.insert(DicomTag(0x0008, 0x1155)); // Referenced SOP Instance UID | |
434 removals_.insert(DicomTag(0x0008, 0x1195)); // Transaction UID | |
435 removals_.insert(DicomTag(0x0008, 0x2111)); // Derivation Description | |
436 removals_.insert(DicomTag(0x0008, 0x2112)); // Source Image Sequence | |
437 removals_.insert(DicomTag(0x0008, 0x4000)); // Identifying Comments | |
438 removals_.insert(DicomTag(0x0008, 0x9123)); // Creator Version UID | |
439 //removals_.insert(DicomTag(0x0010, 0x0010)); // Patient's Name => cf. below (*) | |
440 //removals_.insert(DicomTag(0x0010, 0x0020)); // Patient ID => cf. below (*) | |
441 removals_.insert(DicomTag(0x0010, 0x0030)); // Patient's Birth Date | |
442 removals_.insert(DicomTag(0x0010, 0x0032)); // Patient's Birth Time | |
443 clearings_.insert(DicomTag(0x0010, 0x0040)); // Patient's Sex | |
444 removals_.insert(DicomTag(0x0010, 0x0050)); // Patient's Insurance Plan Code Sequence | |
445 removals_.insert(DicomTag(0x0010, 0x0101)); // Patient's Primary Language Code Sequence | |
446 removals_.insert(DicomTag(0x0010, 0x0102)); // Patient's Primary Language Modifier Code Sequence | |
447 removals_.insert(DicomTag(0x0010, 0x1000)); // Other Patient Ids | |
448 removals_.insert(DicomTag(0x0010, 0x1001)); // Other Patient Names | |
449 removals_.insert(DicomTag(0x0010, 0x1002)); // Other Patient IDs Sequence | |
450 removals_.insert(DicomTag(0x0010, 0x1005)); // Patient's Birth Name | |
451 removals_.insert(DicomTag(0x0010, 0x1010)); // Patient's Age | |
452 removals_.insert(DicomTag(0x0010, 0x1020)); // Patient's Size | |
453 removals_.insert(DicomTag(0x0010, 0x1030)); // Patient's Weight | |
454 removals_.insert(DicomTag(0x0010, 0x1040)); // Patient's Address | |
455 removals_.insert(DicomTag(0x0010, 0x1050)); // Insurance Plan Identification | |
456 removals_.insert(DicomTag(0x0010, 0x1060)); // Patient's Mother's Birth Name | |
457 removals_.insert(DicomTag(0x0010, 0x1080)); // Military Rank | |
458 removals_.insert(DicomTag(0x0010, 0x1081)); // Branch of Service | |
459 removals_.insert(DicomTag(0x0010, 0x1090)); // Medical Record Locator | |
460 removals_.insert(DicomTag(0x0010, 0x2000)); // Medical Alerts | |
461 removals_.insert(DicomTag(0x0010, 0x2110)); // Allergies | |
462 removals_.insert(DicomTag(0x0010, 0x2150)); // Country of Residence | |
463 removals_.insert(DicomTag(0x0010, 0x2152)); // Region of Residence | |
464 removals_.insert(DicomTag(0x0010, 0x2154)); // PatientTelephoneNumbers | |
465 removals_.insert(DicomTag(0x0010, 0x2160)); // Ethnic Group | |
466 removals_.insert(DicomTag(0x0010, 0x2180)); // Occupation | |
467 removals_.insert(DicomTag(0x0010, 0x21a0)); // Smoking Status | |
468 removals_.insert(DicomTag(0x0010, 0x21b0)); // Additional Patient's History | |
469 removals_.insert(DicomTag(0x0010, 0x21c0)); // Pregnancy Status | |
470 removals_.insert(DicomTag(0x0010, 0x21d0)); // Last Menstrual Date | |
471 removals_.insert(DicomTag(0x0010, 0x21f0)); // Patient's Religious Preference | |
472 removals_.insert(DicomTag(0x0010, 0x2203)); // Patient's Sex Neutered | |
473 removals_.insert(DicomTag(0x0010, 0x2297)); // Responsible Person | |
474 removals_.insert(DicomTag(0x0010, 0x2299)); // Responsible Organization | |
475 removals_.insert(DicomTag(0x0010, 0x4000)); // Patient Comments | |
476 removals_.insert(DicomTag(0x0018, 0x0010)); // Contrast Bolus Agent | |
477 removals_.insert(DicomTag(0x0018, 0x1000)); // Device Serial Number | |
478 removals_.insert(DicomTag(0x0018, 0x1002)); // Device UID | |
479 removals_.insert(DicomTag(0x0018, 0x1004)); // Plate ID | |
480 removals_.insert(DicomTag(0x0018, 0x1005)); // Generator ID | |
481 removals_.insert(DicomTag(0x0018, 0x1007)); // Cassette ID | |
482 removals_.insert(DicomTag(0x0018, 0x1008)); // Gantry ID | |
483 removals_.insert(DicomTag(0x0018, 0x1030)); // Protocol Name | |
484 removals_.insert(DicomTag(0x0018, 0x1400)); // Acquisition Device Processing Description | |
485 removals_.insert(DicomTag(0x0018, 0x4000)); // Acquisition Comments | |
486 removals_.insert(DicomTag(0x0018, 0x700a)); // Detector ID | |
487 removals_.insert(DicomTag(0x0018, 0xa003)); // Contribution Description | |
488 removals_.insert(DicomTag(0x0018, 0x9424)); // Acquisition Protocol Description | |
489 //removals_.insert(DicomTag(0x0020, 0x000d)); // Study Instance UID => set in Apply() | |
490 //removals_.insert(DicomTag(0x0020, 0x000e)); // Series Instance UID => set in Apply() | |
491 removals_.insert(DicomTag(0x0020, 0x0010)); // Study ID | |
492 removals_.insert(DicomTag(0x0020, 0x0052)); // Frame of Reference UID | |
493 removals_.insert(DicomTag(0x0020, 0x0200)); // Synchronization Frame of Reference UID | |
494 removals_.insert(DicomTag(0x0020, 0x3401)); // Modifying Device ID | |
495 removals_.insert(DicomTag(0x0020, 0x3404)); // Modifying Device Manufacturer | |
496 removals_.insert(DicomTag(0x0020, 0x3406)); // Modified Image Description | |
497 removals_.insert(DicomTag(0x0020, 0x4000)); // Image Comments | |
498 removals_.insert(DicomTag(0x0020, 0x9158)); // Frame Comments | |
499 removals_.insert(DicomTag(0x0020, 0x9161)); // Concatenation UID | |
500 removals_.insert(DicomTag(0x0020, 0x9164)); // Dimension Organization UID | |
501 //removals_.insert(DicomTag(0x0028, 0x1199)); // Palette Color Lookup Table UID => TODO: replace with a non-zero length UID that is internally consistent within a set of Instances | |
502 //removals_.insert(DicomTag(0x0028, 0x1214)); // Large Palette Color Lookup Table UID => TODO: replace with a non-zero length UID that is internally consistent within a set of Instances | |
503 removals_.insert(DicomTag(0x0028, 0x4000)); // Image Presentation Comments | |
504 removals_.insert(DicomTag(0x0032, 0x0012)); // Study ID Issuer | |
505 removals_.insert(DicomTag(0x0032, 0x1020)); // Scheduled Study Location | |
506 removals_.insert(DicomTag(0x0032, 0x1021)); // Scheduled Study Location AE Title | |
507 removals_.insert(DicomTag(0x0032, 0x1030)); // Reason for Study | |
508 removals_.insert(DicomTag(0x0032, 0x1032)); // Requesting Physician | |
509 removals_.insert(DicomTag(0x0032, 0x1033)); // Requesting Service | |
510 removals_.insert(DicomTag(0x0032, 0x1060)); // Requesting Procedure Description | |
511 removals_.insert(DicomTag(0x0032, 0x1070)); // Requested Contrast Agent | |
512 removals_.insert(DicomTag(0x0032, 0x4000)); // Study Comments | |
513 removals_.insert(DicomTag(0x0038, 0x0010)); // Admission ID | |
514 removals_.insert(DicomTag(0x0038, 0x0011)); // Issuer of Admission ID | |
515 removals_.insert(DicomTag(0x0038, 0x001e)); // Scheduled Patient Institution Residence | |
516 removals_.insert(DicomTag(0x0038, 0x0020)); // Admitting Date | |
517 removals_.insert(DicomTag(0x0038, 0x0021)); // Admitting Time | |
518 removals_.insert(DicomTag(0x0038, 0x0040)); // Discharge Diagnosis Description | |
519 removals_.insert(DicomTag(0x0038, 0x0050)); // Special Needs | |
520 removals_.insert(DicomTag(0x0038, 0x0060)); // Service Episode ID | |
521 removals_.insert(DicomTag(0x0038, 0x0061)); // Issuer of Service Episode ID | |
522 removals_.insert(DicomTag(0x0038, 0x0062)); // Service Episode Description | |
523 removals_.insert(DicomTag(0x0038, 0x0400)); // Patient's Institution Residence | |
524 removals_.insert(DicomTag(0x0038, 0x0500)); // Patient State | |
525 removals_.insert(DicomTag(0x0038, 0x4000)); // Visit Comments | |
526 removals_.insert(DicomTag(0x0038, 0x1234)); // Referenced Patient Alias Sequence | |
527 removals_.insert(DicomTag(0x0040, 0x0001)); // Scheduled Station AE Title | |
528 removals_.insert(DicomTag(0x0040, 0x0002)); // Scheduled Procedure Step Start Date | |
529 removals_.insert(DicomTag(0x0040, 0x0003)); // Scheduled Procedure Step Start Time | |
530 removals_.insert(DicomTag(0x0040, 0x0004)); // Scheduled Procedure Step End Date | |
531 removals_.insert(DicomTag(0x0040, 0x0005)); // Scheduled Procedure Step End Time | |
532 removals_.insert(DicomTag(0x0040, 0x0006)); // Scheduled Performing Physician Name | |
533 removals_.insert(DicomTag(0x0040, 0x0007)); // Scheduled Procedure Step Description | |
534 removals_.insert(DicomTag(0x0040, 0x000b)); // Scheduled Performing Physician Identification Sequence | |
535 removals_.insert(DicomTag(0x0040, 0x0010)); // Scheduled Station Name | |
536 removals_.insert(DicomTag(0x0040, 0x0011)); // Scheduled Procedure Step Location | |
537 removals_.insert(DicomTag(0x0040, 0x0012)); // Pre-Medication | |
538 removals_.insert(DicomTag(0x0040, 0x0241)); // Performed Station AE Title | |
539 removals_.insert(DicomTag(0x0040, 0x0242)); // Performed Station Name | |
540 removals_.insert(DicomTag(0x0040, 0x0243)); // Performed Location | |
541 removals_.insert(DicomTag(0x0040, 0x0244)); // Performed Procedure Step Start Date | |
542 removals_.insert(DicomTag(0x0040, 0x0245)); // Performed Procedure Step Start Time | |
543 removals_.insert(DicomTag(0x0040, 0x0248)); // Performed Station Name Code Sequence | |
544 removals_.insert(DicomTag(0x0040, 0x0253)); // Performed Procedure Step ID | |
545 removals_.insert(DicomTag(0x0040, 0x0254)); // Performed Procedure Step Description | |
546 removals_.insert(DicomTag(0x0040, 0x0275)); // Request Attributes Sequence | |
547 removals_.insert(DicomTag(0x0040, 0x0280)); // Comments on Performed Procedure Step | |
548 removals_.insert(DicomTag(0x0040, 0x0555)); // Acquisition Context Sequence | |
549 removals_.insert(DicomTag(0x0040, 0x1001)); // Requested Procedure ID | |
550 removals_.insert(DicomTag(0x0040, 0x1010)); // Names of Intended Recipient of Results | |
551 removals_.insert(DicomTag(0x0040, 0x1011)); // Intended Recipient of Results Identification Sequence | |
552 removals_.insert(DicomTag(0x0040, 0x1004)); // Patient Transport Arrangements | |
553 removals_.insert(DicomTag(0x0040, 0x1005)); // Requested Procedure Location | |
554 removals_.insert(DicomTag(0x0040, 0x1101)); // Person Identification Code Sequence | |
555 removals_.insert(DicomTag(0x0040, 0x1102)); // Person Address | |
556 removals_.insert(DicomTag(0x0040, 0x1103)); // Person Telephone Numbers | |
557 removals_.insert(DicomTag(0x0040, 0x1400)); // Requested Procedure Comments | |
558 removals_.insert(DicomTag(0x0040, 0x2001)); // Reason for Imaging Service Request | |
559 removals_.insert(DicomTag(0x0040, 0x2008)); // Order Entered By | |
560 removals_.insert(DicomTag(0x0040, 0x2009)); // Order Enterer Location | |
561 removals_.insert(DicomTag(0x0040, 0x2010)); // Order Callback Phone Number | |
562 removals_.insert(DicomTag(0x0040, 0x2016)); // Placer Order Number of Imaging Service Request | |
563 removals_.insert(DicomTag(0x0040, 0x2017)); // Filler Order Number of Imaging Service Request | |
564 removals_.insert(DicomTag(0x0040, 0x2400)); // Imaging Service Request Comments | |
565 removals_.insert(DicomTag(0x0040, 0x4023)); // Referenced General Purpose Scheduled Procedure Step Transaction UID | |
566 removals_.insert(DicomTag(0x0040, 0x4025)); // Scheduled Station Name Code Sequence | |
567 removals_.insert(DicomTag(0x0040, 0x4027)); // Scheduled Station Geographic Location Code Sequence | |
568 removals_.insert(DicomTag(0x0040, 0x4030)); // Performed Station Geographic Location Code Sequence | |
569 removals_.insert(DicomTag(0x0040, 0x4034)); // Scheduled Human Performers Sequence | |
570 removals_.insert(DicomTag(0x0040, 0x4035)); // Actual Human Performers Sequence | |
571 removals_.insert(DicomTag(0x0040, 0x4036)); // Human Performers Organization | |
572 removals_.insert(DicomTag(0x0040, 0x4037)); // Human Performers Name | |
573 removals_.insert(DicomTag(0x0040, 0xa027)); // Verifying Organization | |
574 removals_.insert(DicomTag(0x0040, 0xa073)); // Verifying Observer Sequence | |
575 removals_.insert(DicomTag(0x0040, 0xa075)); // Verifying Observer Name | |
576 removals_.insert(DicomTag(0x0040, 0xa078)); // Author Observer Sequence | |
577 removals_.insert(DicomTag(0x0040, 0xa07a)); // Participant Sequence | |
578 removals_.insert(DicomTag(0x0040, 0xa07c)); // Custodial Organization Sequence | |
579 removals_.insert(DicomTag(0x0040, 0xa088)); // Verifying Observer Identification Code Sequence | |
580 removals_.insert(DicomTag(0x0040, 0xa123)); // Person Name | |
581 removals_.insert(DicomTag(0x0040, 0xa124)); // UID | |
582 removals_.insert(DicomTag(0x0040, 0xa730)); // Content Sequence | |
583 removals_.insert(DicomTag(0x0040, 0x3001)); // Confidentiality Constraint on Patient Data Description | |
584 removals_.insert(DicomTag(0x0040, 0xdb0c)); // Template Extension Organization UID | |
585 removals_.insert(DicomTag(0x0040, 0xdb0d)); // Template Extension Creator UID | |
586 removals_.insert(DicomTag(0x0070, 0x0001)); // Graphic Annotation Sequence | |
587 removals_.insert(DicomTag(0x0070, 0x0084)); // Content Creator's Name | |
588 removals_.insert(DicomTag(0x0070, 0x0086)); // Content Creator's Identification Code Sequence | |
589 removals_.insert(DicomTag(0x0070, 0x031a)); // Fiducial UID | |
590 removals_.insert(DicomTag(0x0088, 0x0140)); // Storage Media File-set UID | |
591 removals_.insert(DicomTag(0x0088, 0x0200)); // Icon Image Sequence | |
592 removals_.insert(DicomTag(0x0088, 0x0904)); // Topic Title | |
593 removals_.insert(DicomTag(0x0088, 0x0906)); // Topic Subject | |
594 removals_.insert(DicomTag(0x0088, 0x0910)); // Topic Author | |
595 removals_.insert(DicomTag(0x0088, 0x0912)); // Topic Key Words | |
596 removals_.insert(DicomTag(0x0400, 0x0100)); // Digital Signature UID | |
597 removals_.insert(DicomTag(0x0400, 0x0402)); // Referenced Digital Signature Sequence | |
598 removals_.insert(DicomTag(0x0400, 0x0403)); // Referenced SOP Instance MAC Sequence | |
599 removals_.insert(DicomTag(0x0400, 0x0404)); // MAC | |
600 removals_.insert(DicomTag(0x0400, 0x0550)); // Modified Attributes Sequence | |
601 removals_.insert(DicomTag(0x0400, 0x0561)); // Original Attributes Sequence | |
602 removals_.insert(DicomTag(0x2030, 0x0020)); // Text String | |
603 removals_.insert(DicomTag(0x3006, 0x0024)); // Referenced Frame of Reference UID | |
604 removals_.insert(DicomTag(0x3006, 0x00c2)); // Related Frame of Reference UID | |
605 removals_.insert(DicomTag(0x300a, 0x0013)); // Dose Reference UID | |
606 removals_.insert(DicomTag(0x300e, 0x0008)); // Reviewer Name | |
607 removals_.insert(DicomTag(0x4000, 0x0010)); // Arbitrary | |
608 removals_.insert(DicomTag(0x4000, 0x4000)); // Text Comments | |
609 removals_.insert(DicomTag(0x4008, 0x0042)); // Results ID Issuer | |
610 removals_.insert(DicomTag(0x4008, 0x0102)); // Interpretation Recorder | |
611 removals_.insert(DicomTag(0x4008, 0x010a)); // Interpretation Transcriber | |
612 removals_.insert(DicomTag(0x4008, 0x010b)); // Interpretation Text | |
613 removals_.insert(DicomTag(0x4008, 0x010c)); // Interpretation Author | |
614 removals_.insert(DicomTag(0x4008, 0x0111)); // Interpretation Approver Sequence | |
615 removals_.insert(DicomTag(0x4008, 0x0114)); // Physician Approving Interpretation | |
616 removals_.insert(DicomTag(0x4008, 0x0115)); // Interpretation Diagnosis Description | |
617 removals_.insert(DicomTag(0x4008, 0x0118)); // Results Distribution List Sequence | |
618 removals_.insert(DicomTag(0x4008, 0x0119)); // Distribution Name | |
619 removals_.insert(DicomTag(0x4008, 0x011a)); // Distribution Address | |
620 removals_.insert(DicomTag(0x4008, 0x0202)); // Interpretation ID Issuer | |
621 removals_.insert(DicomTag(0x4008, 0x0300)); // Impressions | |
622 removals_.insert(DicomTag(0x4008, 0x4000)); // Results Comments | |
623 removals_.insert(DicomTag(0xfffa, 0xfffa)); // Digital Signature Sequence | |
624 removals_.insert(DicomTag(0xfffc, 0xfffc)); // Data Set Trailing Padding | |
625 //removals_.insert(DicomTag(0x60xx, 0x4000)); // Overlay Comments => TODO | |
626 //removals_.insert(DicomTag(0x60xx, 0x3000)); // Overlay Data => TODO | |
627 | |
628 // Set the DeidentificationMethod tag | |
629 ReplaceInternal(DICOM_TAG_DEIDENTIFICATION_METHOD, ORTHANC_DEIDENTIFICATION_METHOD_2011); | |
630 } | |
631 #endif | |
632 | |
633 | |
634 | |
635 void DicomModification::SetupAnonymization2017c() | |
636 { | |
637 /** | |
638 * This is Table E.1-1 from PS 3.15-2017c (DICOM Part 15: Security | |
639 * and System Management Profiles), "basic profile" column. It was | |
640 * generated automatically with the | |
641 * "../Resources/GenerateAnonymizationProfile.py" script. | |
642 * https://raw.githubusercontent.com/jodogne/dicom-specification/master/2017c/part15.pdf | |
643 **/ | |
644 | |
645 // TODO: (50xx,xxxx) with rule X // Curve Data | |
646 // TODO: (60xx,3000) with rule X // Overlay Data | |
647 // TODO: (60xx,4000) with rule X // Overlay Comments | |
648 // Tag (0x0008, 0x0018) is set in Apply() // SOP Instance UID | |
649 // Tag (0x0010, 0x0010) is set below (*) // Patient's Name | |
650 // Tag (0x0010, 0x0020) is set below (*) // Patient ID | |
651 // Tag (0x0020, 0x000d) is set in Apply() // Study Instance UID | |
652 // Tag (0x0020, 0x000e) is set in Apply() // Series Instance UID | |
653 clearings_.insert(DicomTag(0x0008, 0x0020)); // Study Date | |
654 clearings_.insert(DicomTag(0x0008, 0x0023)); /* Z/D */ // Content Date | |
655 clearings_.insert(DicomTag(0x0008, 0x0030)); // Study Time | |
656 clearings_.insert(DicomTag(0x0008, 0x0033)); /* Z/D */ // Content Time | |
657 clearings_.insert(DicomTag(0x0008, 0x0050)); // Accession Number | |
658 clearings_.insert(DicomTag(0x0008, 0x0090)); // Referring Physician's Name | |
659 clearings_.insert(DicomTag(0x0008, 0x009c)); // Consulting Physician's Name | |
660 clearings_.insert(DicomTag(0x0010, 0x0030)); // Patient's Birth Date | |
661 clearings_.insert(DicomTag(0x0010, 0x0040)); // Patient's Sex | |
662 clearings_.insert(DicomTag(0x0018, 0x0010)); /* Z/D */ // Contrast Bolus Agent | |
663 clearings_.insert(DicomTag(0x0020, 0x0010)); // Study ID | |
664 clearings_.insert(DicomTag(0x0040, 0x1101)); /* D */ // Person Identification Code Sequence | |
665 clearings_.insert(DicomTag(0x0040, 0x2016)); // Placer Order Number / Imaging Service Request | |
666 clearings_.insert(DicomTag(0x0040, 0x2017)); // Filler Order Number / Imaging Service Request | |
667 clearings_.insert(DicomTag(0x0040, 0xa073)); /* D */ // Verifying Observer Sequence | |
668 clearings_.insert(DicomTag(0x0040, 0xa075)); /* D */ // Verifying Observer Name | |
669 clearings_.insert(DicomTag(0x0040, 0xa088)); // Verifying Observer Identification Code Sequence | |
670 clearings_.insert(DicomTag(0x0040, 0xa123)); /* D */ // Person Name | |
671 clearings_.insert(DicomTag(0x0070, 0x0001)); /* D */ // Graphic Annotation Sequence | |
672 clearings_.insert(DicomTag(0x0070, 0x0084)); // Content Creator's Name | |
673 removals_.insert(DicomTag(0x0000, 0x1000)); // Affected SOP Instance UID | |
674 removals_.insert(DicomTag(0x0000, 0x1001)); /* TODO UID */ // Requested SOP Instance UID | |
675 removals_.insert(DicomTag(0x0002, 0x0003)); /* TODO UID */ // Media Storage SOP Instance UID | |
676 removals_.insert(DicomTag(0x0004, 0x1511)); /* TODO UID */ // Referenced SOP Instance UID in File | |
677 removals_.insert(DicomTag(0x0008, 0x0014)); /* TODO UID */ // Instance Creator UID | |
678 removals_.insert(DicomTag(0x0008, 0x0015)); // Instance Coercion DateTime | |
679 removals_.insert(DicomTag(0x0008, 0x0021)); /* X/D */ // Series Date | |
680 removals_.insert(DicomTag(0x0008, 0x0022)); /* X/Z */ // Acquisition Date | |
681 removals_.insert(DicomTag(0x0008, 0x0024)); // Overlay Date | |
682 removals_.insert(DicomTag(0x0008, 0x0025)); // Curve Date | |
683 removals_.insert(DicomTag(0x0008, 0x002a)); /* X/D */ // Acquisition DateTime | |
684 removals_.insert(DicomTag(0x0008, 0x0031)); /* X/D */ // Series Time | |
685 removals_.insert(DicomTag(0x0008, 0x0032)); /* X/Z */ // Acquisition Time | |
686 removals_.insert(DicomTag(0x0008, 0x0034)); // Overlay Time | |
687 removals_.insert(DicomTag(0x0008, 0x0035)); // Curve Time | |
688 removals_.insert(DicomTag(0x0008, 0x0058)); /* TODO UID */ // Failed SOP Instance UID List | |
689 removals_.insert(DicomTag(0x0008, 0x0080)); /* X/Z/D */ // Institution Name | |
690 removals_.insert(DicomTag(0x0008, 0x0081)); // Institution Address | |
691 removals_.insert(DicomTag(0x0008, 0x0082)); /* X/Z/D */ // Institution Code Sequence | |
692 removals_.insert(DicomTag(0x0008, 0x0092)); // Referring Physician's Address | |
693 removals_.insert(DicomTag(0x0008, 0x0094)); // Referring Physician's Telephone Numbers | |
694 removals_.insert(DicomTag(0x0008, 0x0096)); // Referring Physician Identification Sequence | |
695 removals_.insert(DicomTag(0x0008, 0x009d)); // Consulting Physician Identification Sequence | |
696 removals_.insert(DicomTag(0x0008, 0x0201)); // Timezone Offset From UTC | |
697 removals_.insert(DicomTag(0x0008, 0x1010)); /* X/Z/D */ // Station Name | |
698 removals_.insert(DicomTag(0x0008, 0x1030)); // Study Description | |
699 removals_.insert(DicomTag(0x0008, 0x103e)); // Series Description | |
700 removals_.insert(DicomTag(0x0008, 0x1040)); // Institutional Department Name | |
701 removals_.insert(DicomTag(0x0008, 0x1048)); // Physician(s) of Record | |
702 removals_.insert(DicomTag(0x0008, 0x1049)); // Physician(s) of Record Identification Sequence | |
703 removals_.insert(DicomTag(0x0008, 0x1050)); // Performing Physicians' Name | |
704 removals_.insert(DicomTag(0x0008, 0x1052)); // Performing Physician Identification Sequence | |
705 removals_.insert(DicomTag(0x0008, 0x1060)); // Name of Physician(s) Reading Study | |
706 removals_.insert(DicomTag(0x0008, 0x1062)); // Physician(s) Reading Study Identification Sequence | |
707 removals_.insert(DicomTag(0x0008, 0x1070)); /* X/Z/D */ // Operators' Name | |
708 removals_.insert(DicomTag(0x0008, 0x1072)); /* X/D */ // Operators' Identification Sequence | |
709 removals_.insert(DicomTag(0x0008, 0x1080)); // Admitting Diagnoses Description | |
710 removals_.insert(DicomTag(0x0008, 0x1084)); // Admitting Diagnoses Code Sequence | |
711 removals_.insert(DicomTag(0x0008, 0x1110)); /* X/Z */ // Referenced Study Sequence | |
712 removals_.insert(DicomTag(0x0008, 0x1111)); /* X/Z/D */ // Referenced Performed Procedure Step Sequence | |
713 removals_.insert(DicomTag(0x0008, 0x1120)); // Referenced Patient Sequence | |
714 removals_.insert(DicomTag(0x0008, 0x1140)); /* X/Z/U* */ // Referenced Image Sequence | |
715 removals_.insert(DicomTag(0x0008, 0x1155)); /* TODO UID */ // Referenced SOP Instance UID | |
716 removals_.insert(DicomTag(0x0008, 0x1195)); /* TODO UID */ // Transaction UID | |
717 removals_.insert(DicomTag(0x0008, 0x2111)); // Derivation Description | |
718 removals_.insert(DicomTag(0x0008, 0x2112)); /* X/Z/U* */ // Source Image Sequence | |
719 removals_.insert(DicomTag(0x0008, 0x3010)); /* TODO UID */ // Irradiation Event UID | |
720 removals_.insert(DicomTag(0x0008, 0x4000)); // Identifying Comments | |
721 removals_.insert(DicomTag(0x0010, 0x0021)); // Issuer of Patient ID | |
722 removals_.insert(DicomTag(0x0010, 0x0032)); // Patient's Birth Time | |
723 removals_.insert(DicomTag(0x0010, 0x0050)); // Patient's Insurance Plan Code Sequence | |
724 removals_.insert(DicomTag(0x0010, 0x0101)); // Patient's Primary Language Code Sequence | |
725 removals_.insert(DicomTag(0x0010, 0x0102)); // Patient's Primary Language Modifier Code Sequence | |
726 removals_.insert(DicomTag(0x0010, 0x1000)); // Other Patient IDs | |
727 removals_.insert(DicomTag(0x0010, 0x1001)); // Other Patient Names | |
728 removals_.insert(DicomTag(0x0010, 0x1002)); // Other Patient IDs Sequence | |
729 removals_.insert(DicomTag(0x0010, 0x1005)); // Patient's Birth Name | |
730 removals_.insert(DicomTag(0x0010, 0x1010)); // Patient's Age | |
731 removals_.insert(DicomTag(0x0010, 0x1020)); // Patient's Size | |
732 removals_.insert(DicomTag(0x0010, 0x1030)); // Patient's Weight | |
733 removals_.insert(DicomTag(0x0010, 0x1040)); // Patient Address | |
734 removals_.insert(DicomTag(0x0010, 0x1050)); // Insurance Plan Identification | |
735 removals_.insert(DicomTag(0x0010, 0x1060)); // Patient's Mother's Birth Name | |
736 removals_.insert(DicomTag(0x0010, 0x1080)); // Military Rank | |
737 removals_.insert(DicomTag(0x0010, 0x1081)); // Branch of Service | |
738 removals_.insert(DicomTag(0x0010, 0x1090)); // Medical Record Locator | |
739 removals_.insert(DicomTag(0x0010, 0x1100)); // Referenced Patient Photo Sequence | |
740 removals_.insert(DicomTag(0x0010, 0x2000)); // Medical Alerts | |
741 removals_.insert(DicomTag(0x0010, 0x2110)); // Allergies | |
742 removals_.insert(DicomTag(0x0010, 0x2150)); // Country of Residence | |
743 removals_.insert(DicomTag(0x0010, 0x2152)); // Region of Residence | |
744 removals_.insert(DicomTag(0x0010, 0x2154)); // Patient's Telephone Numbers | |
745 removals_.insert(DicomTag(0x0010, 0x2155)); // Patient's Telecom Information | |
746 removals_.insert(DicomTag(0x0010, 0x2160)); // Ethnic Group | |
747 removals_.insert(DicomTag(0x0010, 0x2180)); // Occupation | |
748 removals_.insert(DicomTag(0x0010, 0x21a0)); // Smoking Status | |
749 removals_.insert(DicomTag(0x0010, 0x21b0)); // Additional Patient's History | |
750 removals_.insert(DicomTag(0x0010, 0x21c0)); // Pregnancy Status | |
751 removals_.insert(DicomTag(0x0010, 0x21d0)); // Last Menstrual Date | |
752 removals_.insert(DicomTag(0x0010, 0x21f0)); // Patient's Religious Preference | |
753 removals_.insert(DicomTag(0x0010, 0x2203)); /* X/Z */ // Patient Sex Neutered | |
754 removals_.insert(DicomTag(0x0010, 0x2297)); // Responsible Person | |
755 removals_.insert(DicomTag(0x0010, 0x2299)); // Responsible Organization | |
756 removals_.insert(DicomTag(0x0010, 0x4000)); // Patient Comments | |
757 removals_.insert(DicomTag(0x0018, 0x1000)); /* X/Z/D */ // Device Serial Number | |
758 removals_.insert(DicomTag(0x0018, 0x1002)); /* TODO UID */ // Device UID | |
759 removals_.insert(DicomTag(0x0018, 0x1004)); // Plate ID | |
760 removals_.insert(DicomTag(0x0018, 0x1005)); // Generator ID | |
761 removals_.insert(DicomTag(0x0018, 0x1007)); // Cassette ID | |
762 removals_.insert(DicomTag(0x0018, 0x1008)); // Gantry ID | |
763 removals_.insert(DicomTag(0x0018, 0x1030)); /* X/D */ // Protocol Name | |
764 removals_.insert(DicomTag(0x0018, 0x1400)); /* X/D */ // Acquisition Device Processing Description | |
765 removals_.insert(DicomTag(0x0018, 0x2042)); /* TODO UID */ // Target UID | |
766 removals_.insert(DicomTag(0x0018, 0x4000)); // Acquisition Comments | |
767 removals_.insert(DicomTag(0x0018, 0x700a)); /* X/D */ // Detector ID | |
768 removals_.insert(DicomTag(0x0018, 0x9424)); // Acquisition Protocol Description | |
769 removals_.insert(DicomTag(0x0018, 0x9516)); /* X/D */ // Start Acquisition DateTime | |
770 removals_.insert(DicomTag(0x0018, 0x9517)); /* X/D */ // End Acquisition DateTime | |
771 removals_.insert(DicomTag(0x0018, 0xa003)); // Contribution Description | |
772 removals_.insert(DicomTag(0x0020, 0x0052)); /* TODO UID */ // Frame of Reference UID | |
773 removals_.insert(DicomTag(0x0020, 0x0200)); /* TODO UID */ // Synchronization Frame of Reference UID | |
774 removals_.insert(DicomTag(0x0020, 0x3401)); // Modifying Device ID | |
775 removals_.insert(DicomTag(0x0020, 0x3404)); // Modifying Device Manufacturer | |
776 removals_.insert(DicomTag(0x0020, 0x3406)); // Modified Image Description | |
777 removals_.insert(DicomTag(0x0020, 0x4000)); // Image Comments | |
778 removals_.insert(DicomTag(0x0020, 0x9158)); // Frame Comments | |
779 removals_.insert(DicomTag(0x0020, 0x9161)); /* TODO UID */ // Concatenation UID | |
780 removals_.insert(DicomTag(0x0020, 0x9164)); /* TODO UID */ // Dimension Organization UID | |
781 removals_.insert(DicomTag(0x0028, 0x1199)); /* TODO UID */ // Palette Color Lookup Table UID | |
782 removals_.insert(DicomTag(0x0028, 0x1214)); /* TODO UID */ // Large Palette Color Lookup Table UID | |
783 removals_.insert(DicomTag(0x0028, 0x4000)); // Image Presentation Comments | |
784 removals_.insert(DicomTag(0x0032, 0x0012)); // Study ID Issuer | |
785 removals_.insert(DicomTag(0x0032, 0x1020)); // Scheduled Study Location | |
786 removals_.insert(DicomTag(0x0032, 0x1021)); // Scheduled Study Location AE Title | |
787 removals_.insert(DicomTag(0x0032, 0x1030)); // Reason for Study | |
788 removals_.insert(DicomTag(0x0032, 0x1032)); // Requesting Physician | |
789 removals_.insert(DicomTag(0x0032, 0x1033)); // Requesting Service | |
790 removals_.insert(DicomTag(0x0032, 0x1060)); /* X/Z */ // Requested Procedure Description | |
791 removals_.insert(DicomTag(0x0032, 0x1070)); // Requested Contrast Agent | |
792 removals_.insert(DicomTag(0x0032, 0x4000)); // Study Comments | |
793 removals_.insert(DicomTag(0x0038, 0x0004)); // Referenced Patient Alias Sequence | |
794 removals_.insert(DicomTag(0x0038, 0x0010)); // Admission ID | |
795 removals_.insert(DicomTag(0x0038, 0x0011)); // Issuer of Admission ID | |
796 removals_.insert(DicomTag(0x0038, 0x001e)); // Scheduled Patient Institution Residence | |
797 removals_.insert(DicomTag(0x0038, 0x0020)); // Admitting Date | |
798 removals_.insert(DicomTag(0x0038, 0x0021)); // Admitting Time | |
799 removals_.insert(DicomTag(0x0038, 0x0040)); // Discharge Diagnosis Description | |
800 removals_.insert(DicomTag(0x0038, 0x0050)); // Special Needs | |
801 removals_.insert(DicomTag(0x0038, 0x0060)); // Service Episode ID | |
802 removals_.insert(DicomTag(0x0038, 0x0061)); // Issuer of Service Episode ID | |
803 removals_.insert(DicomTag(0x0038, 0x0062)); // Service Episode Description | |
804 removals_.insert(DicomTag(0x0038, 0x0300)); // Current Patient Location | |
805 removals_.insert(DicomTag(0x0038, 0x0400)); // Patient's Institution Residence | |
806 removals_.insert(DicomTag(0x0038, 0x0500)); // Patient State | |
807 removals_.insert(DicomTag(0x0038, 0x4000)); // Visit Comments | |
808 removals_.insert(DicomTag(0x0040, 0x0001)); // Scheduled Station AE Title | |
809 removals_.insert(DicomTag(0x0040, 0x0002)); // Scheduled Procedure Step Start Date | |
810 removals_.insert(DicomTag(0x0040, 0x0003)); // Scheduled Procedure Step Start Time | |
811 removals_.insert(DicomTag(0x0040, 0x0004)); // Scheduled Procedure Step End Date | |
812 removals_.insert(DicomTag(0x0040, 0x0005)); // Scheduled Procedure Step End Time | |
813 removals_.insert(DicomTag(0x0040, 0x0006)); // Scheduled Performing Physician Name | |
814 removals_.insert(DicomTag(0x0040, 0x0007)); // Scheduled Procedure Step Description | |
815 removals_.insert(DicomTag(0x0040, 0x000b)); // Scheduled Performing Physician Identification Sequence | |
816 removals_.insert(DicomTag(0x0040, 0x0010)); // Scheduled Station Name | |
817 removals_.insert(DicomTag(0x0040, 0x0011)); // Scheduled Procedure Step Location | |
818 removals_.insert(DicomTag(0x0040, 0x0012)); // Pre-Medication | |
819 removals_.insert(DicomTag(0x0040, 0x0241)); // Performed Station AE Title | |
820 removals_.insert(DicomTag(0x0040, 0x0242)); // Performed Station Name | |
821 removals_.insert(DicomTag(0x0040, 0x0243)); // Performed Location | |
822 removals_.insert(DicomTag(0x0040, 0x0244)); // Performed Procedure Step Start Date | |
823 removals_.insert(DicomTag(0x0040, 0x0245)); // Performed Procedure Step Start Time | |
824 removals_.insert(DicomTag(0x0040, 0x0250)); // Performed Procedure Step End Date | |
825 removals_.insert(DicomTag(0x0040, 0x0251)); // Performed Procedure Step End Time | |
826 removals_.insert(DicomTag(0x0040, 0x0253)); // Performed Procedure Step ID | |
827 removals_.insert(DicomTag(0x0040, 0x0254)); // Performed Procedure Step Description | |
828 removals_.insert(DicomTag(0x0040, 0x0275)); // Request Attributes Sequence | |
829 removals_.insert(DicomTag(0x0040, 0x0280)); // Comments on the Performed Procedure Step | |
830 removals_.insert(DicomTag(0x0040, 0x0555)); // Acquisition Context Sequence | |
831 removals_.insert(DicomTag(0x0040, 0x1001)); // Requested Procedure ID | |
832 removals_.insert(DicomTag(0x0040, 0x1004)); // Patient Transport Arrangements | |
833 removals_.insert(DicomTag(0x0040, 0x1005)); // Requested Procedure Location | |
834 removals_.insert(DicomTag(0x0040, 0x1010)); // Names of Intended Recipient of Results | |
835 removals_.insert(DicomTag(0x0040, 0x1011)); // Intended Recipients of Results Identification Sequence | |
836 removals_.insert(DicomTag(0x0040, 0x1102)); // Person Address | |
837 removals_.insert(DicomTag(0x0040, 0x1103)); // Person's Telephone Numbers | |
838 removals_.insert(DicomTag(0x0040, 0x1104)); // Person's Telecom Information | |
839 removals_.insert(DicomTag(0x0040, 0x1400)); // Requested Procedure Comments | |
840 removals_.insert(DicomTag(0x0040, 0x2001)); // Reason for the Imaging Service Request | |
841 removals_.insert(DicomTag(0x0040, 0x2008)); // Order Entered By | |
842 removals_.insert(DicomTag(0x0040, 0x2009)); // Order Enterer Location | |
843 removals_.insert(DicomTag(0x0040, 0x2010)); // Order Callback Phone Number | |
844 removals_.insert(DicomTag(0x0040, 0x2011)); // Order Callback Telecom Information | |
845 removals_.insert(DicomTag(0x0040, 0x2400)); // Imaging Service Request Comments | |
846 removals_.insert(DicomTag(0x0040, 0x3001)); // Confidentiality Constraint on Patient Data Description | |
847 removals_.insert(DicomTag(0x0040, 0x4005)); // Scheduled Procedure Step Start DateTime | |
848 removals_.insert(DicomTag(0x0040, 0x4010)); // Scheduled Procedure Step Modification DateTime | |
849 removals_.insert(DicomTag(0x0040, 0x4011)); // Expected Completion DateTime | |
850 removals_.insert(DicomTag(0x0040, 0x4023)); /* TODO UID */ // Referenced General Purpose Scheduled Procedure Step Transaction UID | |
851 removals_.insert(DicomTag(0x0040, 0x4025)); // Scheduled Station Name Code Sequence | |
852 removals_.insert(DicomTag(0x0040, 0x4027)); // Scheduled Station Geographic Location Code Sequence | |
853 removals_.insert(DicomTag(0x0040, 0x4028)); // Performed Station Name Code Sequence | |
854 removals_.insert(DicomTag(0x0040, 0x4030)); // Performed Station Geographic Location Code Sequence | |
855 removals_.insert(DicomTag(0x0040, 0x4034)); // Scheduled Human Performers Sequence | |
856 removals_.insert(DicomTag(0x0040, 0x4035)); // Actual Human Performers Sequence | |
857 removals_.insert(DicomTag(0x0040, 0x4036)); // Human Performers Organization | |
858 removals_.insert(DicomTag(0x0040, 0x4037)); // Human Performers Name | |
859 removals_.insert(DicomTag(0x0040, 0x4050)); // Performed Procedure Step Start DateTime | |
860 removals_.insert(DicomTag(0x0040, 0x4051)); // Performed Procedure Step End DateTime | |
861 removals_.insert(DicomTag(0x0040, 0x4052)); // Procedure Step Cancellation DateTime | |
862 removals_.insert(DicomTag(0x0040, 0xa027)); // Verifying Organization | |
863 removals_.insert(DicomTag(0x0040, 0xa078)); // Author Observer Sequence | |
864 removals_.insert(DicomTag(0x0040, 0xa07a)); // Participant Sequence | |
865 removals_.insert(DicomTag(0x0040, 0xa07c)); // Custodial Organization Sequence | |
866 removals_.insert(DicomTag(0x0040, 0xa124)); /* TODO UID */ // UID | |
867 removals_.insert(DicomTag(0x0040, 0xa171)); /* TODO UID */ // Observation UID | |
868 removals_.insert(DicomTag(0x0040, 0xa172)); /* TODO UID */ // Referenced Observation UID (Trial) | |
869 removals_.insert(DicomTag(0x0040, 0xa192)); // Observation Date (Trial) | |
870 removals_.insert(DicomTag(0x0040, 0xa193)); // Observation Time (Trial) | |
871 removals_.insert(DicomTag(0x0040, 0xa307)); // Current Observer (Trial) | |
872 removals_.insert(DicomTag(0x0040, 0xa352)); // Verbal Source (Trial) | |
873 removals_.insert(DicomTag(0x0040, 0xa353)); // Address (Trial) | |
874 removals_.insert(DicomTag(0x0040, 0xa354)); // Telephone Number (Trial) | |
875 removals_.insert(DicomTag(0x0040, 0xa358)); // Verbal Source Identifier Code Sequence (Trial) | |
876 removals_.insert(DicomTag(0x0040, 0xa402)); /* TODO UID */ // Observation Subject UID (Trial) | |
877 removals_.insert(DicomTag(0x0040, 0xa730)); // Content Sequence | |
878 removals_.insert(DicomTag(0x0040, 0xdb0c)); /* TODO UID */ // Template Extension Organization UID | |
879 removals_.insert(DicomTag(0x0040, 0xdb0d)); /* TODO UID */ // Template Extension Creator UID | |
880 removals_.insert(DicomTag(0x0062, 0x0021)); /* TODO UID */ // Tracking UID | |
881 removals_.insert(DicomTag(0x0070, 0x0086)); // Content Creator's Identification Code Sequence | |
882 removals_.insert(DicomTag(0x0070, 0x031a)); /* TODO UID */ // Fiducial UID | |
883 removals_.insert(DicomTag(0x0070, 0x1101)); /* TODO UID */ // Presentation Display Collection UID | |
884 removals_.insert(DicomTag(0x0070, 0x1102)); /* TODO UID */ // Presentation Sequence Collection UID | |
885 removals_.insert(DicomTag(0x0088, 0x0140)); /* TODO UID */ // Storage Media File-set UID | |
886 removals_.insert(DicomTag(0x0088, 0x0200)); // Icon Image Sequence(see Note 12) | |
887 removals_.insert(DicomTag(0x0088, 0x0904)); // Topic Title | |
888 removals_.insert(DicomTag(0x0088, 0x0906)); // Topic Subject | |
889 removals_.insert(DicomTag(0x0088, 0x0910)); // Topic Author | |
890 removals_.insert(DicomTag(0x0088, 0x0912)); // Topic Keywords | |
891 removals_.insert(DicomTag(0x0400, 0x0100)); // Digital Signature UID | |
892 removals_.insert(DicomTag(0x0400, 0x0402)); // Referenced Digital Signature Sequence | |
893 removals_.insert(DicomTag(0x0400, 0x0403)); // Referenced SOP Instance MAC Sequence | |
894 removals_.insert(DicomTag(0x0400, 0x0404)); // MAC | |
895 removals_.insert(DicomTag(0x0400, 0x0550)); // Modified Attributes Sequence | |
896 removals_.insert(DicomTag(0x0400, 0x0561)); // Original Attributes Sequence | |
897 removals_.insert(DicomTag(0x2030, 0x0020)); // Text String | |
898 removals_.insert(DicomTag(0x3006, 0x0024)); /* TODO UID */ // Referenced Frame of Reference UID | |
899 removals_.insert(DicomTag(0x3006, 0x00c2)); /* TODO UID */ // Related Frame of Reference UID | |
900 removals_.insert(DicomTag(0x3008, 0x0105)); // Source Serial Number | |
901 removals_.insert(DicomTag(0x300a, 0x0013)); /* TODO UID */ // Dose Reference UID | |
902 removals_.insert(DicomTag(0x300c, 0x0113)); // Reason for Omission Description | |
903 removals_.insert(DicomTag(0x300e, 0x0008)); /* X/Z */ // Reviewer Name | |
904 removals_.insert(DicomTag(0x4000, 0x0010)); // Arbitrary | |
905 removals_.insert(DicomTag(0x4000, 0x4000)); // Text Comments | |
906 removals_.insert(DicomTag(0x4008, 0x0042)); // Results ID Issuer | |
907 removals_.insert(DicomTag(0x4008, 0x0102)); // Interpretation Recorder | |
908 removals_.insert(DicomTag(0x4008, 0x010a)); // Interpretation Transcriber | |
909 removals_.insert(DicomTag(0x4008, 0x010b)); // Interpretation Text | |
910 removals_.insert(DicomTag(0x4008, 0x010c)); // Interpretation Author | |
911 removals_.insert(DicomTag(0x4008, 0x0111)); // Interpretation Approver Sequence | |
912 removals_.insert(DicomTag(0x4008, 0x0114)); // Physician Approving Interpretation | |
913 removals_.insert(DicomTag(0x4008, 0x0115)); // Interpretation Diagnosis Description | |
914 removals_.insert(DicomTag(0x4008, 0x0118)); // Results Distribution List Sequence | |
915 removals_.insert(DicomTag(0x4008, 0x0119)); // Distribution Name | |
916 removals_.insert(DicomTag(0x4008, 0x011a)); // Distribution Address | |
917 removals_.insert(DicomTag(0x4008, 0x0202)); // Interpretation ID Issuer | |
918 removals_.insert(DicomTag(0x4008, 0x0300)); // Impressions | |
919 removals_.insert(DicomTag(0x4008, 0x4000)); // Results Comments | |
920 removals_.insert(DicomTag(0xfffa, 0xfffa)); // Digital Signatures Sequence | |
921 removals_.insert(DicomTag(0xfffc, 0xfffc)); // Data Set Trailing Padding | |
922 | |
923 // Set the DeidentificationMethod tag | |
924 ReplaceInternal(DICOM_TAG_DEIDENTIFICATION_METHOD, ORTHANC_DEIDENTIFICATION_METHOD_2017c); | |
925 } | |
926 | |
927 | |
928 void DicomModification::SetupAnonymization(DicomVersion version) | |
929 { | |
930 removals_.clear(); | |
931 clearings_.clear(); | |
932 ClearReplacements(); | |
933 removePrivateTags_ = true; | |
934 level_ = ResourceType_Patient; | |
935 uidMap_.clear(); | |
936 privateTagsToKeep_.clear(); | |
937 | |
938 switch (version) | |
939 { | |
940 case DicomVersion_2008: | |
941 SetupAnonymization2008(); | |
942 break; | |
943 | |
944 case DicomVersion_2017c: | |
945 SetupAnonymization2017c(); | |
946 break; | |
947 | |
948 default: | |
949 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
950 } | |
951 | |
952 // Set the PatientIdentityRemoved tag | |
953 ReplaceInternal(DicomTag(0x0012, 0x0062), "YES"); | |
954 | |
955 // (*) Choose a random patient name and ID | |
956 std::string patientId = FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Patient); | |
957 ReplaceInternal(DICOM_TAG_PATIENT_ID, patientId); | |
958 ReplaceInternal(DICOM_TAG_PATIENT_NAME, patientId); | |
959 } | |
960 | |
961 void DicomModification::Apply(ParsedDicomFile& toModify) | |
962 { | |
963 // Check the request | |
964 assert(ResourceType_Patient + 1 == ResourceType_Study && | |
965 ResourceType_Study + 1 == ResourceType_Series && | |
966 ResourceType_Series + 1 == ResourceType_Instance); | |
967 | |
968 if (IsRemoved(DICOM_TAG_PATIENT_ID) || | |
969 IsRemoved(DICOM_TAG_STUDY_INSTANCE_UID) || | |
970 IsRemoved(DICOM_TAG_SERIES_INSTANCE_UID) || | |
971 IsRemoved(DICOM_TAG_SOP_INSTANCE_UID)) | |
972 { | |
973 throw OrthancException(ErrorCode_BadRequest); | |
974 } | |
975 | |
976 | |
977 // Sanity checks at the patient level | |
978 if (level_ == ResourceType_Patient && !IsReplaced(DICOM_TAG_PATIENT_ID)) | |
979 { | |
980 LOG(ERROR) << "When modifying a patient, her PatientID is required to be modified"; | |
981 throw OrthancException(ErrorCode_BadRequest); | |
982 } | |
983 | |
984 if (!allowManualIdentifiers_) | |
985 { | |
986 if (level_ == ResourceType_Patient && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) | |
987 { | |
988 LOG(ERROR) << "When modifying a patient, the StudyInstanceUID cannot be manually modified"; | |
989 throw OrthancException(ErrorCode_BadRequest); | |
990 } | |
991 | |
992 if (level_ == ResourceType_Patient && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) | |
993 { | |
994 LOG(ERROR) << "When modifying a patient, the SeriesInstanceUID cannot be manually modified"; | |
995 throw OrthancException(ErrorCode_BadRequest); | |
996 } | |
997 | |
998 if (level_ == ResourceType_Patient && IsReplaced(DICOM_TAG_SOP_INSTANCE_UID)) | |
999 { | |
1000 LOG(ERROR) << "When modifying a patient, the SopInstanceUID cannot be manually modified"; | |
1001 throw OrthancException(ErrorCode_BadRequest); | |
1002 } | |
1003 } | |
1004 | |
1005 | |
1006 // Sanity checks at the study level | |
1007 if (level_ == ResourceType_Study && IsReplaced(DICOM_TAG_PATIENT_ID)) | |
1008 { | |
1009 LOG(ERROR) << "When modifying a study, the parent PatientID cannot be manually modified"; | |
1010 throw OrthancException(ErrorCode_BadRequest); | |
1011 } | |
1012 | |
1013 if (!allowManualIdentifiers_) | |
1014 { | |
1015 if (level_ == ResourceType_Study && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) | |
1016 { | |
1017 LOG(ERROR) << "When modifying a study, the SeriesInstanceUID cannot be manually modified"; | |
1018 throw OrthancException(ErrorCode_BadRequest); | |
1019 } | |
1020 | |
1021 if (level_ == ResourceType_Study && IsReplaced(DICOM_TAG_SOP_INSTANCE_UID)) | |
1022 { | |
1023 LOG(ERROR) << "When modifying a study, the SopInstanceUID cannot be manually modified"; | |
1024 throw OrthancException(ErrorCode_BadRequest); | |
1025 } | |
1026 } | |
1027 | |
1028 | |
1029 // Sanity checks at the series level | |
1030 if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_PATIENT_ID)) | |
1031 { | |
1032 LOG(ERROR) << "When modifying a series, the parent PatientID cannot be manually modified"; | |
1033 throw OrthancException(ErrorCode_BadRequest); | |
1034 } | |
1035 | |
1036 if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) | |
1037 { | |
1038 LOG(ERROR) << "When modifying a series, the parent StudyInstanceUID cannot be manually modified"; | |
1039 throw OrthancException(ErrorCode_BadRequest); | |
1040 } | |
1041 | |
1042 if (!allowManualIdentifiers_) | |
1043 { | |
1044 if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_SOP_INSTANCE_UID)) | |
1045 { | |
1046 LOG(ERROR) << "When modifying a series, the SopInstanceUID cannot be manually modified"; | |
1047 throw OrthancException(ErrorCode_BadRequest); | |
1048 } | |
1049 } | |
1050 | |
1051 | |
1052 // Sanity checks at the instance level | |
1053 if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_PATIENT_ID)) | |
1054 { | |
1055 LOG(ERROR) << "When modifying an instance, the parent PatientID cannot be manually modified"; | |
1056 throw OrthancException(ErrorCode_BadRequest); | |
1057 } | |
1058 | |
1059 if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) | |
1060 { | |
1061 LOG(ERROR) << "When modifying an instance, the parent StudyInstanceUID cannot be manually modified"; | |
1062 throw OrthancException(ErrorCode_BadRequest); | |
1063 } | |
1064 | |
1065 if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) | |
1066 { | |
1067 LOG(ERROR) << "When modifying an instance, the parent SeriesInstanceUID cannot be manually modified"; | |
1068 throw OrthancException(ErrorCode_BadRequest); | |
1069 } | |
1070 | |
1071 | |
1072 // (1) Remove the private tags, if need be | |
1073 if (removePrivateTags_) | |
1074 { | |
1075 toModify.RemovePrivateTags(privateTagsToKeep_); | |
1076 } | |
1077 | |
1078 // (2) Clear the tags specified by the user | |
1079 for (SetOfTags::const_iterator it = clearings_.begin(); | |
1080 it != clearings_.end(); ++it) | |
1081 { | |
1082 toModify.Clear(*it, true /* only clear if the tag exists in the original file */); | |
1083 } | |
1084 | |
1085 // (3) Remove the tags specified by the user | |
1086 for (SetOfTags::const_iterator it = removals_.begin(); | |
1087 it != removals_.end(); ++it) | |
1088 { | |
1089 toModify.Remove(*it); | |
1090 } | |
1091 | |
1092 // (4) Replace the tags | |
1093 for (Replacements::const_iterator it = replacements_.begin(); | |
1094 it != replacements_.end(); ++it) | |
1095 { | |
1096 toModify.Replace(it->first, *it->second, true /* decode data URI scheme */, DicomReplaceMode_InsertIfAbsent); | |
1097 } | |
1098 | |
1099 // (5) Update the DICOM identifiers | |
1100 if (level_ <= ResourceType_Study && | |
1101 !IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) | |
1102 { | |
1103 if (keepStudyInstanceUid_) | |
1104 { | |
1105 LOG(WARNING) << "Modifying a study while keeping its original StudyInstanceUID: This should be avoided!"; | |
1106 } | |
1107 else | |
1108 { | |
1109 MapDicomIdentifier(toModify, ResourceType_Study); | |
1110 } | |
1111 } | |
1112 | |
1113 if (level_ <= ResourceType_Series && | |
1114 !IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) | |
1115 { | |
1116 if (keepSeriesInstanceUid_) | |
1117 { | |
1118 LOG(WARNING) << "Modifying a series while keeping its original SeriesInstanceUID: This should be avoided!"; | |
1119 } | |
1120 else | |
1121 { | |
1122 MapDicomIdentifier(toModify, ResourceType_Series); | |
1123 } | |
1124 } | |
1125 | |
1126 if (level_ <= ResourceType_Instance && // Always true | |
1127 !IsReplaced(DICOM_TAG_SOP_INSTANCE_UID)) | |
1128 { | |
1129 MapDicomIdentifier(toModify, ResourceType_Instance); | |
1130 } | |
1131 } | |
1132 } |