]> Creatis software - clitk.git/blob - common/clitkGateAsciiImageIO.cxx
GateAsciiImageIO is now cross-platform using itksys::RegularExpression
[clitk.git] / common / clitkGateAsciiImageIO.cxx
1 /*=========================================================================
2   Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
3
4   Authors belong to:
5   - University of LYON              http://www.universite-lyon.fr/
6   - Léon Bérard cancer center       http://www.centreleonberard.fr
7   - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
8
9   This software is distributed WITHOUT ANY WARRANTY; without even
10   the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11   PURPOSE.  See the copyright notices for more information.
12
13   It is distributed under dual licence
14
15   - BSD        See included LICENSE.txt file
16   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17 ===========================================================================**/
18
19 // std include
20 #include <cstdio>
21 #include <sstream>
22 #include <iostream>
23 using std::cout;
24 using std::endl;
25
26 // clitk include
27 #include "clitkGateAsciiImageIO.h"
28 #include "clitkCommon.h"
29
30 // itk include
31 #include <itkMetaDataObject.h>
32
33 std::ostream& operator<<(std::ostream& os, const clitk::GateAsciiImageIO::GateAsciiHeader& header)
34 {
35     os << "matrix_size=[" << header.matrix_size[0] << "," << header.matrix_size[1] << "," << header.matrix_size[2] << "]" << endl;
36     os << "resolution=[" << header.resolution[0] << "," << header.resolution[1] << "," << header.resolution[2] << "]" << endl;
37     os << "voxel_size=[" << header.voxel_size[0] << "," << header.voxel_size[1] << "," << header.voxel_size[2] << "]" << endl;
38     os << "nb_value=" << header.nb_value << endl;
39     return os;
40 }
41
42 //--------------------------------------------------------------------
43 // Read Image Information
44 void clitk::GateAsciiImageIO::ReadImageInformation()
45 {
46     FILE* handle = fopen(m_FileName.c_str(),"r");
47     if (!handle) {
48         itkGenericExceptionMacro(<< "Could not open file (for reading): " << m_FileName);
49         return;
50     }
51
52     GateAsciiHeader header;
53     if (!ReadHeader(handle,header)) {
54         itkGenericExceptionMacro(<< "Could not read header: " << m_FileName);
55         fclose(handle);
56         return;
57     }
58     fclose(handle);
59
60     int real_length = -1;
61     double real_spacing = 0;
62     for (int kk=0; kk<3; kk++) {
63         if (header.resolution[kk]>1) {
64             if (real_length>0) {
65                 itkGenericExceptionMacro(<< "Could not image dimension: " << m_FileName);
66                 return;
67             }
68             real_length = header.resolution[kk];
69             real_spacing = header.voxel_size[kk];
70         }
71     }
72     assert(real_length == header.nb_value);
73
74     // Set image information
75     SetNumberOfDimensions(2);
76     SetDimensions(0, real_length);
77     SetDimensions(1, 1);
78     SetSpacing(0, real_spacing);
79     SetSpacing(1, 1);
80     SetOrigin(0, 0);
81     SetOrigin(1, 0);
82     SetComponentType(itk::ImageIOBase::DOUBLE);
83 }
84
85 //--------------------------------------------------------------------
86 bool clitk::GateAsciiImageIO::CanReadFile(const char* FileNameToRead)
87 {
88     std::string filename(FileNameToRead);
89
90     { // check extension
91         std::string filenameext = GetExtension(filename);
92         if (filenameext != "txt") return false;
93     }
94
95     { // check header
96         FILE* handle = fopen(filename.c_str(),"r");
97         if (!handle) return false;
98
99         GateAsciiHeader header;
100         if (!ReadHeader(handle,header)) { fclose(handle); return false; }
101         fclose(handle);
102     }
103
104     return true;
105 }
106
107 //--------------------------------------------------------------------
108 // Read Line in file
109 bool clitk::GateAsciiImageIO::ReadLine(FILE* handle, std::string& line)
110 {
111     std::stringstream stream;
112     while (true)
113     {
114         char item;
115         if (ferror(handle)) return false;
116         if (fread(&item,1,1,handle) != 1) return false;
117
118         if (item=='\n' || feof(handle)) {
119             line = stream.str();
120             return true;
121         }
122
123         stream << item;
124     }
125 }
126
127 template <typename T>
128 T ConvertFromString(const std::string& value)
129 {
130     std::stringstream stream;
131     stream << value;
132     T converted;
133     stream >> converted;
134     return converted;
135 }
136
137 bool
138 clitk::GateAsciiImageIO::FindRegularExpressionNextLine(itksys::RegularExpression &reg, std::string &s, FILE* handle)
139 {
140   std::string line;
141   if(!ReadLine(handle,line))  return false;
142   if(!reg.compile(s.c_str())) return false;
143   return reg.find(line.c_str());
144 }
145
146 //--------------------------------------------------------------------
147 // Read Image Header
148 bool clitk::GateAsciiImageIO::ReadHeader(FILE* handle, GateAsciiHeader& header)
149 {
150     assert(handle);
151
152   std::string regexstr[6] =
153     {"^#.+$",
154      "^# +Matrix *Size *= +\\(([0-9]+\\.?[0-9]*),([0-9]+\\.?[0-9]*),([0-9]+\\.?[0-9]*)\\)$",
155      "^# +Resol *= +\\(([0-9]+),([0-9]+),([0-9]+)\\)$",
156      "^# +Voxel *Size *= +\\(([0-9]+\\.?[0-9]*),([0-9]+\\.?[0-9]*),([0-9]+\\.?[0-9]*)\\)$",
157      "^# +nbVal *= +([0-9]+)$"};
158
159   itksys::RegularExpression regex;
160
161   if(!FindRegularExpressionNextLine(regex, regexstr[0], handle)) return false;
162
163   if(!FindRegularExpressionNextLine(regex, regexstr[1], handle)) return false;
164   header.matrix_size[0] = ConvertFromString<double>(regex.match(1));
165   header.matrix_size[1] = ConvertFromString<double>(regex.match(2));
166   header.matrix_size[2] = ConvertFromString<double>(regex.match(3));
167
168   if(!FindRegularExpressionNextLine(regex, regexstr[2], handle)) return false;
169   header.resolution[0] = ConvertFromString<int>(regex.match(1));
170   header.resolution[1] = ConvertFromString<int>(regex.match(2));
171   header.resolution[2] = ConvertFromString<int>(regex.match(3));
172
173   if(!FindRegularExpressionNextLine(regex, regexstr[3], handle)) return false;
174   header.voxel_size[0] = ConvertFromString<double>(regex.match(1));
175   header.voxel_size[1] = ConvertFromString<double>(regex.match(2));
176   header.voxel_size[2] = ConvertFromString<double>(regex.match(3));
177
178   if(!FindRegularExpressionNextLine(regex, regexstr[4], handle)) return false;
179   header.nb_value = ConvertFromString<int>(regex.match(1));
180
181   if(!FindRegularExpressionNextLine(regex, regexstr[0], handle)) return false;
182
183   return true;
184 }
185
186 //--------------------------------------------------------------------
187 // Read Image Content
188 void clitk::GateAsciiImageIO::Read(void* abstract_buffer)
189 {
190     FILE* handle = fopen(m_FileName.c_str(),"r");
191     if (!handle) {
192         itkGenericExceptionMacro(<< "Could not open file (for reading): " << m_FileName);
193         return;
194     }
195
196     GateAsciiHeader header;
197     if (!ReadHeader(handle,header)) {
198         itkGenericExceptionMacro(<< "Could not read header: " << m_FileName);
199         fclose(handle);
200         return;
201     }
202
203     {
204         double* buffer = static_cast<double*>(abstract_buffer);
205         int read_count = 0;
206         while (true) { 
207             std::string line;
208             if (!ReadLine(handle,line)) break;
209             *buffer = ConvertFromString<double>(line);
210             read_count++;
211             buffer++;
212         }
213         assert(read_count == header.nb_value);
214     }
215
216     fclose(handle);
217 }
218
219 //--------------------------------------------------------------------
220 bool clitk::GateAsciiImageIO::CanWriteFile(const char* FileNameToWrite)
221 {
222     if (GetExtension(std::string(FileNameToWrite)) != "txt") return false;
223     return true;
224 }
225
226 void clitk::GateAsciiImageIO::WriteImageInformation()
227 {
228     cout << GetNumberOfDimensions() << endl;
229 }
230
231 bool clitk::GateAsciiImageIO::SupportsDimension(unsigned long dim)
232 {
233     if (dim==2) return true;
234     return false;
235 }
236
237 //--------------------------------------------------------------------
238 // Write Image
239 void clitk::GateAsciiImageIO::Write(const void* abstract_buffer)
240 {
241     const unsigned long nb_value = GetDimensions(0)*GetDimensions(1);
242     std::stringstream stream;
243     stream << "######################" << endl;
244     stream << "# Matrix Size= (" << GetSpacing(0)*GetDimensions(0) << "," << GetSpacing(1)*GetDimensions(1) << ",1)" << endl;
245     stream << "# Resol      = (" << GetDimensions(0) << "," << GetDimensions(1) << ",1)" << endl;
246     stream << "# VoxelSize  = (" << GetSpacing(0) << "," << GetSpacing(1) << ",1)" << endl;
247     stream << "# nbVal      = " << nb_value << endl;
248     stream << "######################" << endl;
249
250     const double* buffer = static_cast<const double*>(abstract_buffer);
251     for (unsigned long kk=0; kk<nb_value; kk++) { stream << buffer[kk] << endl; }
252
253     FILE* handle = fopen(m_FileName.c_str(),"w");
254     if (!handle) {
255         itkGenericExceptionMacro(<< "Could not open file (for writing): " << m_FileName);
256         return;
257     }
258
259     fwrite(stream.str().c_str(),1,stream.str().size(),handle);
260
261     fclose(handle);
262 }