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