1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef _itkGDCMSeriesFileNames_h
19 #define _itkGDCMSeriesFileNames_h
20 
21 #include "itkGDCMSeriesFileNames.h"
22 #include "itksys/SystemTools.hxx"
23 #include "itkProgressReporter.h"
24 
25 namespace itk
26 {
GDCMSeriesFileNames()27 GDCMSeriesFileNames::GDCMSeriesFileNames()
28 {
29   m_SerieHelper = new gdcm::SerieHelper();
30   m_InputDirectory = "";
31   m_OutputDirectory = "";
32   m_UseSeriesDetails = true;
33   m_Recursive = false;
34   m_LoadSequences = false;
35   m_LoadPrivateTags = false;
36 }
37 
~GDCMSeriesFileNames()38 GDCMSeriesFileNames::~GDCMSeriesFileNames()
39 {
40   delete m_SerieHelper;
41 }
42 
SetInputDirectory(const char * name)43 void GDCMSeriesFileNames::SetInputDirectory(const char *name)
44 {
45   if ( !name )
46     {
47     itkExceptionMacro(<< "SetInputDirectory() received a nullptr string");
48     }
49   std::string fname = name;
50   this->SetInputDirectory(fname);
51 }
52 
SetInputDirectory(std::string const & name)53 void GDCMSeriesFileNames::SetInputDirectory(std::string const & name)
54 {
55   if ( name.empty() )
56     {
57     itkWarningMacro(<< "You need to specify a directory where "
58                        "the DICOM files are located");
59     return;
60     }
61   if ( m_InputDirectory == name )
62     {
63     return;
64     }
65   if ( !itksys::SystemTools::FileIsDirectory( name.c_str() ) )
66     {
67     itkWarningMacro(<< name << " is not a directory");
68     return;
69     }
70   m_InputDirectory = name;
71   m_SerieHelper->Clear();
72   m_SerieHelper->SetUseSeriesDetails(m_UseSeriesDetails);
73   m_SerieHelper->SetLoadMode( ( m_LoadSequences ? 0 : gdcm::LD_NOSEQ )
74                               | ( m_LoadPrivateTags ? 0 : gdcm::LD_NOSHADOW ) );
75   m_SerieHelper->SetDirectory(name, m_Recursive);
76   //as a side effect it also execute
77   this->Modified();
78 }
79 
GetSeriesUIDs()80 const GDCMSeriesFileNames::SeriesUIDContainerType & GDCMSeriesFileNames::GetSeriesUIDs()
81 {
82   m_SeriesUIDs.clear();
83   // Accessing the first serie found (assume there is at least one)
84   gdcm::FileList *flist = m_SerieHelper->GetFirstSingleSerieUIDFileSet();
85   while ( flist )
86     {
87     if ( !flist->empty() ) //make sure we have at leat one serie
88       {
89       gdcm::File *file = ( *flist )[0]; //for example take the first one
90 
91       // Create its unique series ID
92       std::string id = m_SerieHelper->
93                        CreateUniqueSeriesIdentifier(file).c_str();
94 
95       m_SeriesUIDs.push_back( id.c_str() );
96       }
97     flist = m_SerieHelper->GetNextSingleSerieUIDFileSet();
98     }
99   if ( m_SeriesUIDs.empty() )
100     {
101     itkWarningMacro(<< "No Series were found");
102     }
103   return m_SeriesUIDs;
104 }
105 
GetFileNames(const std::string serie)106 const GDCMSeriesFileNames::FileNamesContainerType & GDCMSeriesFileNames::GetFileNames(const std::string serie)
107 {
108   m_InputFileNames.clear();
109   // Accessing the first serie found (assume there is at least one)
110   gdcm::FileList *flist = m_SerieHelper->GetFirstSingleSerieUIDFileSet();
111   if ( !flist )
112     {
113     itkWarningMacro(
114       << "No Series can be found, make sure your restrictions are not too strong");
115     return m_InputFileNames;
116     }
117   if ( !serie.empty() ) // user did not specify any sub selection based on UID
118     {
119     bool found = false;
120     while ( flist && !found )
121       {
122       if ( !flist->empty() ) //make sure we have at leat one serie
123         {
124         gdcm::File *file = ( *flist )[0]; //for example take the first one
125         std::string id = m_SerieHelper->
126                          CreateUniqueSeriesIdentifier(file).c_str();
127 
128         if ( id == serie )
129           {
130           found = true; // we found a match
131           break;
132           }
133         }
134       flist = m_SerieHelper->GetNextSingleSerieUIDFileSet();
135       }
136     if ( !found )
137       {
138       itkWarningMacro(<< "No Series were found");
139       return m_InputFileNames;
140       }
141     }
142   m_SerieHelper->OrderFileList(flist);
143 
144   gdcm::FileList::iterator it;
145   if ( !flist->empty() )
146     {
147     ProgressReporter progress(this, 0,
148       static_cast<itk::SizeValueType>(flist->size()), 10);
149     for ( it = flist->begin();
150           it != flist->end(); ++it )
151       {
152 #if GDCM_MAJOR_VERSION < 2
153       gdcm::File *header = *it;
154       if ( !header )
155         {
156         itkWarningMacro(<< "GDCMSeriesFileNames got nullptr header, "
157                            "this is a serious bug");
158         continue;
159         }
160       if ( !header->IsReadable() )
161         {
162         itkWarningMacro( << "GDCMSeriesFileNames got a non DICOM file:"
163                          << header->GetFileName() );
164         continue;
165         }
166       m_InputFileNames.push_back( header->GetFileName() );
167       progress.CompletedPixel();
168 #else
169       gdcm::FileWithName *header = *it;
170       m_InputFileNames.push_back(header->filename);
171       progress.CompletedPixel();
172 #endif
173       }
174     }
175   else
176     {
177     itkDebugMacro(<< "No files were found");
178     }
179 
180   return m_InputFileNames;
181 }
182 
GetInputFileNames()183 const GDCMSeriesFileNames::FileNamesContainerType & GDCMSeriesFileNames::GetInputFileNames()
184 {
185   // Do not specify any UID
186   return this->GetFileNames("");
187 }
188 
GetOutputFileNames()189 const GDCMSeriesFileNames::FileNamesContainerType & GDCMSeriesFileNames::GetOutputFileNames()
190 {
191   // We are trying to extract the original filename and compose it with a path:
192 
193   //There are two different approaches if directory does not exist:
194   // 1. Exit
195   // 2. Mkdir
196   //bool SystemTools::FileExists(const char* filename)
197   //bool SystemTools::FileIsDirectory(const char* name)
198   m_OutputFileNames.clear();
199 
200   if ( m_OutputDirectory.empty() )
201     {
202     itkDebugMacro(<< "No output directory was specified");
203     return m_OutputFileNames;
204     }
205 
206   itksys::SystemTools::ConvertToUnixSlashes(m_OutputDirectory);
207   if ( m_OutputDirectory[m_OutputDirectory.size() - 1] != '/' )
208     {
209     m_OutputDirectory += '/';
210     }
211 
212   if ( !m_InputFileNames.empty() )
213     {
214     bool hasExtension = false;
215     for ( std::vector< std::string >::const_iterator it = m_InputFileNames.begin();
216           it != m_InputFileNames.end(); ++it )
217       {
218       // look for extension ".dcm" and ".DCM"
219       std::string::size_type dcmPos = ( *it ).rfind(".dcm");
220       if ( ( dcmPos != std::string::npos )
221            && ( dcmPos == ( *it ).length() - 4 ) )
222         {
223         hasExtension = true;
224         }
225       else
226         {
227         dcmPos = ( *it ).rfind(".DCM");
228         if ( ( dcmPos != std::string::npos )
229              && ( dcmPos == ( *it ).length() - 4 ) )
230           {
231           hasExtension = true;
232           }
233         }
234 
235       // look for extension ".dicom" and ".DICOM"
236       std::string::size_type dicomPos = ( *it ).rfind(".dicom");
237       if ( ( dicomPos != std::string::npos )
238            && ( dicomPos == ( *it ).length() - 6 ) )
239         {
240         hasExtension = true;
241         }
242       else
243         {
244         dicomPos = ( *it ).rfind(".DICOM");
245         if ( ( dicomPos != std::string::npos )
246              && ( dicomPos == ( *it ).length() - 6 ) )
247           {
248           hasExtension = true;
249           }
250         }
251 
252       // construct a filename, adding an extension if necessary
253       std::string filename =
254         m_OutputDirectory + itksys::SystemTools::GetFilenameName(*it);
255       if ( !hasExtension )
256         {
257         // input filename has no extension, add a ".dcm"
258         filename += ".dcm";
259         }
260 
261       // Add the file name to the output list
262       m_OutputFileNames.push_back(filename);
263       }
264     }
265   else
266     {
267     itkDebugMacro(<< "No files were found.");
268     }
269 
270   return m_OutputFileNames;
271 }
272 
PrintSelf(std::ostream & os,Indent indent) const273 void GDCMSeriesFileNames::PrintSelf(std::ostream & os, Indent indent) const
274 {
275   Superclass::PrintSelf(os, indent);
276 
277   unsigned int i;
278   os << indent << "InputDirectory: " << m_InputDirectory << std::endl;
279   os << indent << "LoadSequences:" << m_LoadSequences << std::endl;
280   os << indent << "LoadPrivateTags:" << m_LoadPrivateTags << std::endl;
281   if ( m_Recursive )
282     {
283     os << indent << "Recursive: True" << std::endl;
284     }
285   else
286     {
287     os << indent << "Recursive: False" << std::endl;
288     }
289 
290   for ( i = 0; i < m_InputFileNames.size(); i++ )
291     {
292     os << indent << "InputFileNames[" << i << "]: " << m_InputFileNames[i] << std::endl;
293     }
294 
295   os << indent << "OutputDirectory: " << m_OutputDirectory << std::endl;
296   for ( i = 0; i < m_OutputFileNames.size(); i++ )
297     {
298     os << indent << "OutputFileNames[" << i << "]: " << m_OutputFileNames[i] << std::endl;
299     }
300 }
301 
SetUseSeriesDetails(bool useSeriesDetails)302 void GDCMSeriesFileNames::SetUseSeriesDetails(bool useSeriesDetails)
303 {
304   m_UseSeriesDetails = useSeriesDetails;
305   m_SerieHelper->SetUseSeriesDetails(m_UseSeriesDetails);
306   m_SerieHelper->CreateDefaultUniqueSeriesIdentifier();
307 }
308 } //namespace ITK
309 
310 #endif
311