fw4spl
DicomAnonymizer.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2018.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #include "fwGdcmIO/helper/DicomAnonymizer.hpp"
8 
9 #include "fwGdcmIO/exception/InvalidTag.hpp"
10 #include "fwGdcmIO/helper/CsvIO.hpp"
11 #include "fwGdcmIO/helper/DicomSearch.hpp"
12 #include "fwGdcmIO/helper/tags.hpp"
13 
14 #include <fwCore/base.hpp>
15 
16 #include <fwJobs/IJob.hpp>
17 #include <fwJobs/Observer.hpp>
18 
19 #include <fwRuntime/operations.hpp>
20 
21 #include <fwTools/System.hpp>
22 
23 #include <boost/algorithm/string/join.hpp>
24 #include <boost/assign/list_of.hpp>
25 #include <boost/date_time/gregorian/gregorian.hpp>
26 #include <boost/exception/all.hpp>
27 #include <boost/filesystem/fstream.hpp>
28 #include <boost/filesystem/operations.hpp>
29 #include <boost/range/algorithm/for_each.hpp>
30 
31 #include <gdcmGlobal.h>
32 #include <gdcmReader.h>
33 #include <gdcmUIDGenerator.h>
34 #include <gdcmWriter.h>
35 #include <time.h>
36 
37 #include <cstdint>
38 #include <iomanip>
39 
40 namespace fwGdcmIO
41 {
42 namespace helper
43 {
44 
45 const std::string c_MIN_DATE_STRING = "19000101";
46 
47 ::gdcm::UIDGenerator GENERATOR;
48 
50  m_publicDictionary(::gdcm::Global::GetInstance().GetDicts().GetPublicDict()),
51  m_observer(::fwJobs::Observer::New("Anonymization process")),
52  m_archiving(false),
53  m_fileIndex(0),
54  m_referenceDate(::boost::gregorian::from_undelimited_string(c_MIN_DATE_STRING))
55 {
56  const ::boost::filesystem::path tagsPathStr = ::fwRuntime::getLibraryResourceFilePath(
57  "fwGdcmIO-" FWGDCMIO_VER "/tags.csv");
58  ::boost::filesystem::path tagsPath = tagsPathStr;
59  SLM_ASSERT("File '" + tagsPath.string() + "' must exists",
60  ::boost::filesystem::is_regular_file(tagsPath));
61 
62  auto csvStream = std::ifstream(tagsPath.string());
63  ::fwGdcmIO::helper::CsvIO csvReader(csvStream);
64  ::fwGdcmIO::helper::CsvIO::TokenContainerType tagVec = csvReader.getLine();
65 
66  while(!tagVec.empty())
67  {
68  if(tagVec.size() < 3)
69  {
70  const std::string errorMessage = "Error when loading tag '" + ::boost::algorithm::join(tagVec, ", ") + "'";
71  OSLM_WARN_IF(errorMessage, tagVec.size() != 4);
72  FW_RAISE_EXCEPTION(::fwGdcmIO::exception::InvalidTag(errorMessage));
73  }
74 
75  const std::string& actionCode = tagVec[0];
76  ::gdcm::Tag tag = ::fwGdcmIO::helper::getGdcmTag(tagVec[1], tagVec[2]);
77 
78  if(actionCode == "D")
79  {
80  m_actionCodeDTags.insert(tag);
81  }
82  else if(actionCode == "Z" || actionCode == "Z/D")
83  {
84  m_actionCodeZTags.insert(tag);
85  }
86  else if(actionCode == "X"
87  || actionCode == "X/Z"
88  || actionCode == "X/D"
89  || actionCode == "X/Z/D"
90  || actionCode == "X/Z/U*")
91  {
92  m_actionCodeXTags.insert(tag);
93  }
94  else if(actionCode == "K")
95  {
96  m_actionCodeKTags.insert(tag);
97  }
98  else if(actionCode == "C")
99  {
100  m_actionCodeCTags.insert(tag);
101  }
102  else if(actionCode == "U")
103  {
104  m_actionCodeUTags.insert(tag);
105  }
106  else
107  {
108  OSLM_ERROR("Action code '" + actionCode + "' is not managed.");
109  }
110 
111  tagVec = csvReader.getLine();
112  }
113 }
114 
115 //------------------------------------------------------------------------------
116 
118 {
119 }
120 
121 //------------------------------------------------------------------------------
122 
123 void DicomAnonymizer::setReferenceDate(const ::boost::gregorian::date& referenceDate)
124 {
125  m_referenceDate = referenceDate;
126 }
127 
128 //------------------------------------------------------------------------------
129 
130 void DicomAnonymizer::anonymize(const ::boost::filesystem::path& dirPath)
131 {
132  m_archiving = false;
133  m_observer->setTotalWorkUnits(100);
134  this->anonymizationProcess(dirPath);
135  m_observer->finish();
136 }
137 
138 //------------------------------------------------------------------------------
139 
140 void moveDirectory(const ::boost::filesystem::path& input,
141  const ::boost::filesystem::path& output)
142 {
143  ::boost::system::error_code ec;
144  ::boost::filesystem::copy_directory(input, output, ec);
145  FW_RAISE_IF("copy_directory " << input.string() << " " << output.string()
146  << " error : " << ec.message(), ec.value());
147 
148  ::boost::filesystem::directory_iterator it(input);
149  ::boost::filesystem::directory_iterator end;
150  ::boost::filesystem::permissions(output, ::boost::filesystem::owner_all, ec);
151  OSLM_ERROR_IF("set " << output.string() << " permission error : " << ec.message(), ec.value());
152 
153  for(; it != end; ++it)
154  {
155  ::boost::filesystem::path dest = output / it->path().filename();
156  if(::boost::filesystem::is_directory(*it))
157  {
158  moveDirectory(*it, dest);
159  }
160  else
161  {
162  ::boost::filesystem::rename(*it, dest, ec);
163  FW_RAISE_IF("rename " << it->path().string() << " " << dest.string()
164  << " error : " << ec.message(), ec.value());
165  }
166 
167  ::boost::filesystem::permissions(dest, ::boost::filesystem::owner_all, ec);
168  OSLM_ERROR_IF("set " << dest.string() << " permission error : " << ec.message(), ec.value());
169  }
170 }
171 
172 //------------------------------------------------------------------------------
173 
174 void DicomAnonymizer::removeAnonymizeTag(const ::gdcm::Tag& tag)
175 {
176  m_actionCodeDTags.erase(tag);
177  m_actionCodeZTags.erase(tag);
178  m_actionCodeXTags.erase(tag);
179  m_actionCodeKTags.erase(tag);
180  m_actionCodeCTags.erase(tag);
181  m_actionCodeUTags.erase(tag);
182 }
183 
184 //------------------------------------------------------------------------------
185 
186 const DicomAnonymizer::TagContainerType& DicomAnonymizer::getActionCodeDTags()
187 {
188  return m_actionCodeDTags;
189 }
190 
191 //------------------------------------------------------------------------------
192 
193 const DicomAnonymizer::TagContainerType& DicomAnonymizer::getActionCodeZTags()
194 {
195  return m_actionCodeZTags;
196 }
197 
198 //------------------------------------------------------------------------------
199 
200 const DicomAnonymizer::TagContainerType& DicomAnonymizer::getActionCodeXTags()
201 {
202  return m_actionCodeXTags;
203 }
204 
205 //------------------------------------------------------------------------------
206 
207 const DicomAnonymizer::TagContainerType& DicomAnonymizer::getActionCodeKTags()
208 {
209  return m_actionCodeKTags;
210 }
211 
212 //------------------------------------------------------------------------------
213 
214 const DicomAnonymizer::TagContainerType& DicomAnonymizer::getActionCodeCTags()
215 {
216  return m_actionCodeCTags;
217 }
218 
219 //------------------------------------------------------------------------------
220 
221 const DicomAnonymizer::TagContainerType& DicomAnonymizer::getActionCodeUTags()
222 {
223  return m_actionCodeUTags;
224 }
225 
226 //------------------------------------------------------------------------------
227 
228 void DicomAnonymizer::anonymizationProcess(const ::boost::filesystem::path& dirPath)
229 {
230  // Create temporary directory
231  ::boost::filesystem::path tmpPath = ::fwTools::System::getTemporaryFolder("DicomAnonymizer");
232  tmpPath /= "tmp";
233 
234  // Doesn't use ::boost::filesystem::rename because of potential issues when moving folders across volumes
235  moveDirectory(dirPath, tmpPath);
236 
237  ::boost::system::error_code ec;
238 
239  ::boost::filesystem::directory_iterator it(dirPath);
240  ::boost::filesystem::directory_iterator end;
241 
242  for(; it != end; ++it)
243  {
244  if(::boost::filesystem::is_directory(*it))
245  {
246  ::boost::filesystem::remove_all((*it), ec);
247  FW_RAISE_IF("remove_all " + dirPath.string() + " error : " + ec.message(), ec.value());
248  }
249  }
250 
251  std::vector< ::boost::filesystem::path > dicomFiles;
252  ::fwGdcmIO::helper::DicomSearch::searchRecursively(tmpPath, dicomFiles, false);
253 
254  unsigned int fileIndex = 0;
255  for(const auto file : dicomFiles)
256  {
257  if(m_observer->cancelRequested())
258  {
259  break;
260  }
261 
262  ::boost::filesystem::ifstream inStream(file, std::ios::binary);
263 
264  std::stringstream ss;
265  ss << std::setfill('0') << std::setw(7) << fileIndex++;
266 
267  ::boost::filesystem::ofstream outStream(dirPath / ss.str(), std::ios::binary | std::ios::trunc);
268 
269  this->anonymize(inStream, outStream);
270 
271  std::uint64_t progress = static_cast<std::uint64_t>(
272  ((m_archiving) ? 50 : 100) * static_cast<float>(fileIndex) / static_cast<float>(dicomFiles.size()));
273  m_observer->doneWork(progress);
274  }
275 
276 }
277 
278 //------------------------------------------------------------------------------
279 
281 {
282  m_fileIndex = 0;
283 }
284 
285 //------------------------------------------------------------------------------
286 
288 {
289  return m_fileIndex++;
290 }
291 
292 //------------------------------------------------------------------------------
293 
294 void DicomAnonymizer::anonymize(std::istream& inputStream, std::ostream& outputStream)
295 {
296  // File Reader
297  ::gdcm::Reader reader;
298  reader.SetStream(inputStream);
299  FW_RAISE_IF("Unable to anonymize (file read failed)", !reader.Read());
300 
301  // String filter
302  m_stringFilter.SetFile(reader.GetFile());
303 
304  // Objects used to scan groups of elements
305  ::gdcm::Tag tag;
306  ::gdcm::DataElement dataElement;
307  const ::gdcm::File& datasetFile = reader.GetFile();
308  ::gdcm::DataSet dataset = datasetFile.GetDataSet();
309 
310  std::vector< ::gdcm::DataElement > preservedTags;
311  for(const ::gdcm::Tag& t : m_privateTags)
312  {
313  if(dataset.FindDataElement(t))
314  {
315  preservedTags.push_back(dataset.GetDataElement(t));
316  }
317  }
318 
319  m_anonymizer.SetFile( datasetFile );
320 
321  m_anonymizer.RemoveGroupLength();
322  m_anonymizer.RemoveRetired();
323 
324  for(ExceptionTagMapType::value_type exception : m_exceptionTagMap)
325  {
326  m_anonymizer.Replace(exception.first, exception.second.c_str());
327  }
328 
329  // Shift dates
330  for(const auto& dateTag : m_actionShiftDateTags)
331  {
332  this->applyActionShiftDate(dateTag);
333  }
334 
335  for(const auto& tag : m_actionCodeDTags)
336  {
337  this->applyActionCodeD(tag);
338  }
339  for(const auto& tag : m_actionCodeZTags)
340  {
341  this->applyActionCodeZ(tag);
342  }
343  for(const auto& tag : m_actionCodeXTags)
344  {
345  this->applyActionCodeX(tag);
346  }
347  for(const auto& tag : m_actionCodeKTags)
348  {
349  this->applyActionCodeK(tag);
350  }
351  for(const auto& tag : m_actionCodeCTags)
352  {
353  this->applyActionCodeC(tag);
354  }
355  for(const auto& tag : m_actionCodeUTags)
356  {
357  this->applyActionCodeU(tag);
358  }
359 
360  auto applyActionCodeXWithException = [this](const ::gdcm::Tag& tag)
361  {
362  if(m_exceptionTagMap.find(tag) == m_exceptionTagMap.end())
363  {
364  this->applyActionCodeX(tag);
365  }
366  };
367 
368  const auto dataElementSet = dataset.GetDES();
369 
370  // Curve Data (0x50xx,0xxxxx)
371  auto element = dataElementSet.lower_bound(::gdcm::Tag(0x5000, 0x0));
372  auto end = dataElementSet.upper_bound(::gdcm::Tag(0x50ff, 0xffff));
373  for(; element != end; ++element)
374  {
375  tag = element->GetTag();
376  applyActionCodeXWithException(tag);
377  }
378 
379  // Overlay Data (0x60xx,0x3000) && Overlay Comments (0x60xx,0x4000)
380  element = dataElementSet.lower_bound(::gdcm::Tag(0x6000, 0x3000));
381  end = dataElementSet.upper_bound(::gdcm::Tag(0x60ff, 0x4000));
382  for(; element != end; ++element)
383  {
384  tag = element->GetTag();
385  if(tag.GetElement() == 0x3000 || tag.GetElement() == 0x4000)
386  {
387  applyActionCodeXWithException(tag);
388  }
389  }
390 
391  m_anonymizer.RemovePrivateTags(); // Private attributes (X)
392 
393  for(const ::gdcm::DataElement& de : preservedTags)
394  {
395  dataset.Insert(de);
396  }
397 
398  // Write file
399  ::gdcm::Writer writer;
400  writer.SetStream(outputStream);
401  writer.SetFile(datasetFile);
402 
403  FW_RAISE_IF("Unable to anonymize (file write failed)", !writer.Write());
404 }
405 
406 //------------------------------------------------------------------------------
407 
408 void DicomAnonymizer::addExceptionTag(uint16_t group, uint16_t element, const std::string& value)
409 {
410  ::gdcm::Tag tag(group, element);
411 
412  m_exceptionTagMap[tag] = value;
413 
414  m_actionCodeDTags.erase(tag);
415  m_actionCodeZTags.erase(tag);
416  m_actionCodeXTags.erase(tag);
417  m_actionCodeKTags.erase(tag);
418  m_actionCodeCTags.erase(tag);
419  m_actionCodeUTags.erase(tag);
420 }
421 
422 //------------------------------------------------------------------------------
423 
424 void DicomAnonymizer::preservePrivateTag(const ::gdcm::Tag& tag)
425 {
426  const bool found = std::find(m_privateTags.begin(), m_privateTags.end(), tag) != m_privateTags.end();
427  OSLM_WARN_IF("Private tag " << tag.GetGroup() << ", " << tag.GetElement() << " has already been added", !found);
428 
429  if(!found)
430  {
431  m_privateTags.push_back(tag);
432  }
433 }
434 
435 //------------------------------------------------------------------------------
436 
437 void DicomAnonymizer::applyActionCodeD(const ::gdcm::Tag& tag)
438 {
439  // Sequence of Items
440  if(m_publicDictionary.GetDictEntry(tag).GetVR() == ::gdcm::VR::SQ)
441  {
442  m_anonymizer.Empty(tag);
443  }
444  else
445  {
446  this->generateDummyValue(tag);
447  }
448 }
449 
450 //------------------------------------------------------------------------------
451 
452 void DicomAnonymizer::applyActionCodeZ(const ::gdcm::Tag& tag)
453 {
454  this->applyActionCodeD(tag);
455 }
456 
457 //------------------------------------------------------------------------------
458 
459 void DicomAnonymizer::applyActionCodeX(const ::gdcm::Tag& tag)
460 {
461  m_anonymizer.Remove(tag);
462 }
463 
464 //------------------------------------------------------------------------------
465 
466 void DicomAnonymizer::applyActionCodeK(const ::gdcm::Tag& tag)
467 {
468  // Sequence of Items
469  if(m_publicDictionary.GetDictEntry(tag).GetVR() == ::gdcm::VR::SQ)
470  {
471  m_anonymizer.Empty(tag);
472  }
473 }
474 
475 //------------------------------------------------------------------------------
476 
477 void DicomAnonymizer::applyActionCodeC(const ::gdcm::Tag& tag)
478 {
479  SLM_FATAL("Basic profile \"C\" is not supported yet: "
480  "Only basic profile is supported by the current implementation.");
481 }
482 
483 //------------------------------------------------------------------------------
484 
485 void DicomAnonymizer::applyActionCodeU(const ::gdcm::Tag& tag)
486 {
487  const std::string oldUID = m_stringFilter.ToString(tag);
488  if(!oldUID.empty())
489  {
490  auto it = m_uidMap.find(oldUID);
491  std::string uid;
492 
493  if(it == m_uidMap.end())
494  {
495  uid = GENERATOR.Generate();
496  m_uidMap.insert(std::pair<std::string, std::string>(oldUID, uid));
497  }
498  else
499  {
500  uid = it->second;
501  }
502 
503  m_anonymizer.Replace(tag, uid.c_str());
504  }
505 }
506 
507 //------------------------------------------------------------------------------
508 
509 void DicomAnonymizer::addShiftDateTag(const ::gdcm::Tag& tag)
510 {
511  m_actionCodeDTags.erase(tag);
512  m_actionCodeZTags.erase(tag);
513  m_actionCodeXTags.erase(tag);
514  m_actionCodeKTags.erase(tag);
515  m_actionCodeCTags.erase(tag);
516  m_actionCodeUTags.erase(tag);
517 
518  m_actionShiftDateTags.insert(tag);
519 }
520 
521 //------------------------------------------------------------------------------
522 
523 void DicomAnonymizer::applyActionShiftDate(const ::gdcm::Tag& tag)
524 {
525  const std::string oldDate = m_stringFilter.ToString(tag);
526  const ::boost::gregorian::date date = ::boost::gregorian::from_undelimited_string(oldDate);
527 
528  const auto shift = date - m_referenceDate;
529 
530  //Minimum date
531  const ::boost::gregorian::date min_date = ::boost::gregorian::from_undelimited_string(c_MIN_DATE_STRING);
532 
533  const auto shiftedDate = min_date + shift;
534 
535  m_anonymizer.Replace(tag, ::boost::gregorian::to_iso_string(shiftedDate).c_str());
536 }
537 
538 //------------------------------------------------------------------------------
539 
540 void DicomAnonymizer::generateDummyValue(const ::gdcm::Tag& tag)
541 {
542 
543  switch (m_publicDictionary.GetDictEntry(tag).GetVR())
544  {
545  case ::gdcm::VR::AE:
546  {
547  m_anonymizer.Replace(tag, "ANONYMIZED");
548  break;
549  }
550  case ::gdcm::VR::AS:
551  {
552  m_anonymizer.Replace(tag, "000Y");
553  break;
554  }
555  case ::gdcm::VR::AT:
556  {
557  m_anonymizer.Replace(tag, "00H,00H,00H,00H");
558  break;
559  }
560  case ::gdcm::VR::CS:
561  {
562  // Patient's sex
563  if(tag == ::gdcm::Tag(0x0010, 0x0040))
564  {
565  m_anonymizer.Replace(tag, "O");
566  }
567  else
568  {
569  m_anonymizer.Replace(tag, "ANONYMIZED");
570  }
571  break;
572  }
573  case ::gdcm::VR::DA:
574  {
575  m_anonymizer.Replace(tag, c_MIN_DATE_STRING.c_str());
576  break;
577  }
578  case ::gdcm::VR::DS:
579  {
580  m_anonymizer.Replace(tag, "0");
581  break;
582  }
583  case ::gdcm::VR::DT:
584  {
585  m_anonymizer.Replace(tag, std::string(c_MIN_DATE_STRING + "000000.000000").c_str());
586  break;
587  }
588  case ::gdcm::VR::FD:
589  {
590  m_anonymizer.Replace(tag, "0");
591  break;
592  }
593  case ::gdcm::VR::FL:
594  {
595  m_anonymizer.Replace(tag, "0");
596  break;
597  }
598  case ::gdcm::VR::IS:
599  {
600  m_anonymizer.Replace(tag, "0");
601  break;
602  }
603  case ::gdcm::VR::LO:
604  {
605  m_anonymizer.Replace(tag, "ANONYMIZED");
606  break;
607  }
608  case ::gdcm::VR::LT:
609  {
610  m_anonymizer.Replace(tag, "ANONYMIZED");
611  break;
612  }
613  case ::gdcm::VR::OB:
614  {
615  m_anonymizer.Replace(tag, "00H00H");
616  break;
617  }
618  case ::gdcm::VR::OF:
619  {
620  m_anonymizer.Replace(tag, "0");
621  break;
622  }
623  case ::gdcm::VR::OW:
624  {
625  m_anonymizer.Replace(tag, "0");
626  break;
627  }
628  case ::gdcm::VR::PN:
629  {
630  m_anonymizer.Replace(tag, "ANONYMIZED^ANONYMIZED");
631  break;
632  }
633  case ::gdcm::VR::SH:
634  {
635  m_anonymizer.Replace(tag, "ANONYMIZED");
636  break;
637  }
638  case ::gdcm::VR::SL:
639  {
640  m_anonymizer.Replace(tag, "0");
641  break;
642  }
643  case ::gdcm::VR::SQ:
644  {
645  m_anonymizer.Empty(tag);
646  break;
647  }
648  case ::gdcm::VR::SS:
649  {
650  m_anonymizer.Replace(tag, "0");
651  break;
652  }
653  case ::gdcm::VR::ST:
654  {
655  m_anonymizer.Replace(tag, "ANONYMIZED");
656  break;
657  }
658  case ::gdcm::VR::TM:
659  {
660  m_anonymizer.Replace(tag, "000000.000000");
661  break;
662  }
663  case ::gdcm::VR::UI:
664  {
665  m_anonymizer.Replace(tag, "ANONYMIZED");
666  break;
667  }
668  case ::gdcm::VR::UL:
669  {
670  m_anonymizer.Replace(tag, "0");
671  break;
672  }
673  case ::gdcm::VR::UN:
674  {
675  m_anonymizer.Replace(tag, "ANONYMIZED");
676  break;
677  }
678  case ::gdcm::VR::US:
679  {
680  m_anonymizer.Replace(tag, "0");
681  break;
682  }
683  case ::gdcm::VR::UT:
684  {
685  m_anonymizer.Replace(tag, "ANONYMIZED");
686  break;
687  }
688  default:
689  {
690  OSLM_ERROR(tag<<" is not supported. Emptied value. ");
691  m_anonymizer.Empty(tag);
692  break;
693  }
694  }
695 }
696 
697 //------------------------------------------------------------------------------
698 
699 void DicomAnonymizer::copyDirectory(const ::boost::filesystem::path& input,
700  const ::boost::filesystem::path& output)
701 {
702  ::boost::system::error_code ec;
703  ::boost::filesystem::copy_directory(input, output, ec);
704  FW_RAISE_IF("copy_directory " << input.string() << " " << output.string()
705  << " error : " << ec.message(), ec.value());
706 
707  ::boost::filesystem::directory_iterator it(input);
708  ::boost::filesystem::directory_iterator end;
709 
710  ec.clear();
711  ::boost::filesystem::permissions(output, ::boost::filesystem::owner_all, ec);
712  SLM_ERROR_IF("set " + output.string() + " permission error : " + ec.message(), ec.value());
713 
714  for(; it != end; ++it)
715  {
716  ::boost::filesystem::path dest = output / it->path().filename();
717  if(::boost::filesystem::is_directory(*it))
718  {
720  }
721  else
722  {
723  // Use stream instead of boost::copy_file (Unix c++11 issue)
724  ::boost::filesystem::ifstream inStream(it->path(), std::ios::binary);
725  FW_RAISE_IF("Unable to read file :" << it->path().string(), !inStream.good());
726  ::boost::filesystem::ofstream outStream(dest, std::ios::binary);
727  FW_RAISE_IF("Unable to write file :" << dest.string(), !outStream.good());
728 
729  outStream << inStream.rdbuf();
730 
731  inStream.close();
732  outStream.close();
733  }
734 
735  ec.clear();
736  ::boost::filesystem::permissions(dest, ::boost::filesystem::owner_all, ec);
737  SLM_ERROR_IF("set " + dest.string() + " permission error : " + ec.message(), ec.value());
738  }
739 }
740 
741 //------------------------------------------------------------------------------
742 
744 {
745  return m_observer;
746 }
747 //------------------------------------------------------------------------------
748 
749 } // namespace helper
750 } // namespace fwGdcmIO
FWGDCMIO_API void setReferenceDate(const ::boost::gregorian::date &referenceDate)
Set Reference date for shifting.
FWGDCMIO_API void addShiftDateTag(const ::gdcm::Tag &tag)
Add a date tag that must be shifted. The shift is made according to the interval between the date and...
#define SPTR(_cls_)
virtual FWGDCMIO_API ~DicomAnonymizer()
Destructor.
This class is an interface for class managing job.
Definition: IJob.hpp:28
FWGDCMIO_API void addExceptionTag(uint16_t group, uint16_t element, const std::string &value="")
Add an exceptional value for a tag.
FWGDCMIO_API DicomAnonymizer()
Constructor.
The namespace fwGdcmIO contains reader, writer and helper for dicom data.
FWGDCMIO_API void preservePrivateTag(const ::gdcm::Tag &tag)
Tells the anonymizer to do not anonymize the given private tag.
FWGDCMIO_API void resetIndex()
Reset file index to 0.
InvalidTag exception.
Definition: InvalidTag.hpp:22
#define SLM_FATAL(message)
Definition: spyLog.hpp:283
#define OSLM_ERROR(message)
Definition: spyLog.hpp:274
This class contains helpers to anonymize dicom files on filesystem. Anonymization is performed accord...
#define SLM_ERROR_IF(message, cond)
Definition: spyLog.hpp:276
static FWGDCMIO_API void searchRecursively(const ::boost::filesystem::path &dirPath, std::vector< ::boost::filesystem::path > &dicomFiles, bool checkIsDicom, const std::shared_ptr< ::fwJobs::Observer > &fileLookupObserver=nullptr)
Search Dicom files recursively by excluding files with known extensions.
#define SLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:308
std::vector< std::string > TokenContainerType
Containers to store parsed tokens.
Definition: CsvIO.hpp:42
static FWGDCMIO_API void copyDirectory(const ::boost::filesystem::path &input, const ::boost::filesystem::path &output)
Copy a directory recursively.
static FWTOOLS_APIconst::boost::filesystem::path getTemporaryFolder(const std::string &subFolderPrefix="") noexcept
Returns a unique per-process temporary folder. The top level temporary folder will be automatically d...
Definition: System.cpp:148
FWGDCMIO_API std::shared_ptr< ::fwJobs::IJob > getJob() const
Get job observer.
FWGDCMIO_API void removeAnonymizeTag(const ::gdcm::Tag &tag)
The removed tag will not be process by anonymization tag.
Read CSV file and returns parsed tokens. The input file is supposed to use comma separator, but another separator can be used when reading file.
Definition: CsvIO.hpp:26
#define OSLM_WARN_IF(message, cond)
Definition: spyLog.hpp:267
This namespace fwJobs provides jobs management.
#define OSLM_ERROR_IF(message, cond)
Definition: spyLog.hpp:278
FWGDCMIO_API void anonymize(const ::boost::filesystem::path &dirPath)
Anonymize a folder containing Dicom files.
FWGDCMIO_API unsigned int getNextIndex()
Return next file index.