]> Creatis software - clitk.git/blob - common/clitkGateAsciiImageIO.cxx
744f413f55e7dcc800e3b7a6676b97ef3da9026c
[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 <regex.h>
21 #include <cstdio>
22 #include <sstream>
23 #include <iostream>
24 using std::cout;
25 using std::endl;
26
27 // clitk include
28 #include "clitkGateAsciiImageIO.h"
29 #include "clitkCommon.h"
30
31 // itk include
32 #include <itkMetaDataObject.h>
33
34 std::ostream& operator<<(std::ostream& os, const clitk::GateAsciiImageIO::GateAsciiHeader& header)
35 {
36     os << "matrix_size=[" << header.matrix_size[0] << "," << header.matrix_size[1] << "," << header.matrix_size[2] << "]" << endl;
37     os << "resolution=[" << header.resolution[0] << "," << header.resolution[1] << "," << header.resolution[2] << "]" << endl;
38     os << "voxel_size=[" << header.voxel_size[0] << "," << header.voxel_size[1] << "," << header.voxel_size[2] << "]" << endl;
39     os << "nb_value=" << header.nb_value << endl;
40     return os;
41 }
42
43 //--------------------------------------------------------------------
44 // Read Image Information
45 void clitk::GateAsciiImageIO::ReadImageInformation()
46 {
47     FILE* handle = fopen(m_FileName.c_str(),"r");
48     if (!handle) {
49         itkGenericExceptionMacro(<< "Could not open file (for reading): " << m_FileName);
50         return;
51     }
52
53     GateAsciiHeader header;
54     if (!ReadHeader(handle,header)) {
55         itkGenericExceptionMacro(<< "Could not read header: " << m_FileName);
56         fclose(handle);
57         return;
58     }
59     fclose(handle);
60
61     int real_length = -1;
62     double real_spacing = 0;
63     for (int kk=0; kk<3; kk++) {
64         if (header.resolution[kk]>1) {
65             if (real_length>0) {
66                 itkGenericExceptionMacro(<< "Could not image dimension: " << m_FileName);
67                 return;
68             }
69             real_length = header.resolution[kk];
70             real_spacing = header.voxel_size[kk];
71         }
72     }
73     assert(real_length == header.nb_value);
74
75     // Set image information
76     SetNumberOfDimensions(2);
77     SetDimensions(0, real_length);
78     SetDimensions(1, 1);
79     SetSpacing(0, real_spacing);
80     SetSpacing(1, 1);
81     SetOrigin(0, 0);
82     SetOrigin(1, 0);
83     SetComponentType(itk::ImageIOBase::DOUBLE);
84 }
85
86 //--------------------------------------------------------------------
87 bool clitk::GateAsciiImageIO::CanReadFile(const char* FileNameToRead)
88 {
89     std::string filename(FileNameToRead);
90
91     { // check extension
92         std::string filenameext = GetExtension(filename);
93         if (filenameext != "txt") return false;
94     }
95
96     { // check header
97         FILE* handle = fopen(filename.c_str(),"r");
98         if (!handle) return false;
99
100         GateAsciiHeader header;
101         if (!ReadHeader(handle,header)) { fclose(handle); return false; }
102         fclose(handle);
103     }
104
105     return true;
106 }
107
108 //--------------------------------------------------------------------
109 // Read Line in file
110 bool clitk::GateAsciiImageIO::ReadLine(FILE* handle, std::string& line)
111 {
112     std::stringstream stream;
113     while (true)
114     {
115         char item;
116         if (ferror(handle)) return false;
117         if (fread(&item,1,1,handle) != 1) return false;
118
119         if (item=='\n' or feof(handle)) {
120             line = stream.str();
121             return true;
122         }
123
124         stream << item;
125     }
126 }
127
128 std::string ExtractMatch(const std::string& base, const regmatch_t& match) 
129 {
130     return base.substr(match.rm_so,match.rm_eo-match.rm_so);
131 }
132
133 template <typename T>
134 T ConvertFromString(const std::string& value)
135 {
136     std::stringstream stream;
137     stream << value;
138     T converted;
139     stream >> converted;
140     return converted;
141 }
142
143 //--------------------------------------------------------------------
144 // Read Image Header
145 bool clitk::GateAsciiImageIO::ReadHeader(FILE* handle, GateAsciiHeader& header)
146 {
147     assert(handle);
148     std::string line;
149
150     regex_t re_comment;
151     regex_t re_matrix_size;
152     regex_t re_resol;
153     regex_t re_voxel_size;
154     regex_t re_nb_value;
155     regmatch_t matches[4];
156
157     { // build regex
158         assert(regcomp(&re_comment,"^#.+$",REG_EXTENDED|REG_NEWLINE) == 0);
159         assert(regcomp(&re_matrix_size,"^# +Matrix *Size *= +\\(([0-9]+\\.?[0-9]*),([0-9]+\\.?[0-9]*),([0-9]+\\.?[0-9]*)\\)$",REG_EXTENDED|REG_NEWLINE) == 0);
160         assert(regcomp(&re_resol,"^# +Resol *= +\\(([0-9]+),([0-9]+),([0-9]+)\\)$",REG_EXTENDED|REG_NEWLINE) == 0);
161         assert(regcomp(&re_voxel_size,"^# +Voxel *Size *= +\\(([0-9]+\\.?[0-9]*),([0-9]+\\.?[0-9]*),([0-9]+\\.?[0-9]*)\\)$",REG_EXTENDED|REG_NEWLINE) == 0);
162         assert(regcomp(&re_nb_value,"^# +nbVal *= +([0-9]+)$",REG_EXTENDED|REG_NEWLINE) == 0);
163     }
164
165     if (!ReadLine(handle,line)) return false;
166     if (regexec(&re_comment,line.c_str(),1,matches,0) == REG_NOMATCH) return false;
167
168     if (!ReadLine(handle,line)) return false;
169     if (regexec(&re_matrix_size,line.c_str(),4,matches,0) == REG_NOMATCH) return false;
170     header.matrix_size[0] = ConvertFromString<double>(ExtractMatch(line,matches[1]));
171     header.matrix_size[1] = ConvertFromString<double>(ExtractMatch(line,matches[2]));
172     header.matrix_size[2] = ConvertFromString<double>(ExtractMatch(line,matches[3]));
173
174     if (!ReadLine(handle,line)) return false;
175     if (regexec(&re_resol,line.c_str(),4,matches,0) == REG_NOMATCH) return false;
176     header.resolution[0] = ConvertFromString<int>(ExtractMatch(line,matches[1]));
177     header.resolution[1] = ConvertFromString<int>(ExtractMatch(line,matches[2]));
178     header.resolution[2] = ConvertFromString<int>(ExtractMatch(line,matches[3]));
179
180     if (!ReadLine(handle,line)) return false;
181     if (regexec(&re_voxel_size,line.c_str(),4,matches,0) == REG_NOMATCH) return false;
182     header.voxel_size[0] = ConvertFromString<double>(ExtractMatch(line,matches[1]));
183     header.voxel_size[1] = ConvertFromString<double>(ExtractMatch(line,matches[2]));
184     header.voxel_size[2] = ConvertFromString<double>(ExtractMatch(line,matches[3]));
185
186     if (!ReadLine(handle,line)) return false;
187     if (regexec(&re_nb_value,line.c_str(),2,matches,0) == REG_NOMATCH) return false;
188     header.nb_value = ConvertFromString<int>(ExtractMatch(line,matches[1]));
189
190     if (!ReadLine(handle,line)) return false;
191     if (regexec(&re_comment,line.c_str(),1,matches,0) == REG_NOMATCH) return false;
192
193     return true;
194 }
195
196 //--------------------------------------------------------------------
197 // Read Image Content
198 void clitk::GateAsciiImageIO::Read(void* abstract_buffer)
199 {
200     FILE* handle = fopen(m_FileName.c_str(),"r");
201     if (!handle) {
202         itkGenericExceptionMacro(<< "Could not open file (for reading): " << m_FileName);
203         return;
204     }
205
206     GateAsciiHeader header;
207     if (!ReadHeader(handle,header)) {
208         itkGenericExceptionMacro(<< "Could not read header: " << m_FileName);
209         fclose(handle);
210         return;
211     }
212
213     {
214         double* buffer = static_cast<double*>(abstract_buffer);
215         int read_count = 0;
216         while (true) { 
217             std::string line;
218             if (!ReadLine(handle,line)) break;
219             *buffer = ConvertFromString<double>(line);
220             read_count++;
221             buffer++;
222         }
223         assert(read_count == header.nb_value);
224     }
225
226     fclose(handle);
227 }
228
229 //--------------------------------------------------------------------
230 bool clitk::GateAsciiImageIO::CanWriteFile(const char* FileNameToWrite)
231 {
232     if (GetExtension(std::string(FileNameToWrite)) != "txt") return false;
233     return true;
234 }
235
236 void clitk::GateAsciiImageIO::WriteImageInformation()
237 {
238     cout << GetNumberOfDimensions() << endl;
239 }
240
241 bool clitk::GateAsciiImageIO::SupportsDimension(unsigned long dim)
242 {
243     if (dim==2) return true;
244     return false;
245 }
246
247 //--------------------------------------------------------------------
248 // Write Image
249 void clitk::GateAsciiImageIO::Write(const void* abstract_buffer)
250 {
251     const unsigned long nb_value = GetDimensions(0)*GetDimensions(1);
252     std::stringstream stream;
253     stream << "######################" << endl;
254     stream << "# Matrix Size= (" << GetSpacing(0)*GetDimensions(0) << "," << GetSpacing(1)*GetDimensions(1) << ",1)" << endl;
255     stream << "# Resol      = (" << GetDimensions(0) << "," << GetDimensions(1) << ",1)" << endl;
256     stream << "# VoxelSize  = (" << GetSpacing(0) << "," << GetSpacing(1) << ",1)" << endl;
257     stream << "# nbVal      = " << nb_value << endl;
258     stream << "######################" << endl;
259
260     const double* buffer = static_cast<const double*>(abstract_buffer);
261     for (unsigned long kk=0; kk<nb_value; kk++) { stream << buffer[kk] << endl; }
262
263     FILE* handle = fopen(m_FileName.c_str(),"w");
264     if (!handle) {
265         itkGenericExceptionMacro(<< "Could not open file (for writing): " << m_FileName);
266         return;
267     }
268
269     fwrite(stream.str().c_str(),1,stream.str().size(),handle);
270
271     fclose(handle);
272 }