1use std::{
2 fmt,
3 fs::File,
4 io::{BufReader, BufWriter, Error, ErrorKind, Read, Result, Seek, SeekFrom},
5 str::from_utf8,
6};
7
8use byteorder::{BigEndian, ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt};
9use nalgebra::Vector4;
10
11#[cfg(feature = "nifti_images")]
12use crate::Affine;
13use crate::{
14 orientation::{
15 affine_to_axcodes, axcodes_to_orientations, inverse_orientations_affine,
16 orientations_transform,
17 },
18 Affine4, TrkEndianness,
19};
20
21pub enum Endianness {
22 Little,
23 Big,
24}
25
26impl fmt::Display for Endianness {
27 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
28 match *self {
29 Endianness::Little => write!(f, "< (Little)"),
30 Endianness::Big => write!(f, "> (Big)"),
31 }
32 }
33}
34
35#[derive(Clone)]
37#[repr(C)]
38pub struct CHeader {
39 pub id_string: [u8; 6],
40 pub dim: [i16; 3],
41 pub voxel_size: [f32; 3],
42 pub origin: [f32; 3],
43 pub n_scalars: i16,
44 pub scalar_name: [u8; 200], pub n_properties: i16,
46 pub property_name: [u8; 200], pub vox_to_ras: [f32; 16], pub reserved: [u8; 444],
49 pub voxel_order: [u8; 4],
50 pub pad2: [u8; 4],
51 pub image_orientation_patient: [f32; 6],
52 pub pad1: [u8; 2],
53 pub invert_x: u8,
54 pub invert_y: u8,
55 pub invert_z: u8,
56 pub swap_x: u8,
57 pub swap_y: u8,
58 pub swap_z: u8,
59 pub n_count: i32,
60 pub version: i32,
61 pub hdr_size: i32,
62}
63
64pub const HEADER_SIZE: usize = std::mem::size_of::<CHeader>();
65
66impl CHeader {
67 #[cfg(feature = "nifti_images")]
68 pub fn from_nifti(
69 dim: [u16; 8],
70 pixdim: [f32; 8],
71 srow_x: [f32; 4],
72 srow_y: [f32; 4],
73 srow_z: [f32; 4],
74 ) -> CHeader {
75 #[rustfmt::skip]
76 let affine = Affine::new(
77 srow_x[0], srow_x[1], srow_x[2],
78 srow_y[0], srow_y[1], srow_y[2],
79 srow_z[0], srow_z[1], srow_z[2],
80 );
81 #[rustfmt::skip]
82 let vox_to_ras = [
83 srow_x[0], srow_x[1], srow_x[2], srow_x[3],
84 srow_y[0], srow_y[1], srow_y[2], srow_y[3],
85 srow_z[0], srow_z[1], srow_z[2], srow_z[3],
86 0.0, 0.0, 0.0, 1.0,
87 ];
88 let vo = affine_to_axcodes(&affine).into_bytes();
89 CHeader {
90 dim: [dim[1] as i16, dim[2] as i16, dim[3] as i16],
91 voxel_size: [pixdim[1], pixdim[2], pixdim[3]],
92 vox_to_ras,
93 voxel_order: [vo[0], vo[1], vo[2], 0u8],
94 ..CHeader::default()
95 }
96 }
97
98 pub fn seek_n_count_field(f: &mut BufWriter<File>) -> Result<()> {
99 let n_count_offset = (HEADER_SIZE - 12) as u64;
100 f.seek(SeekFrom::Start(n_count_offset))?;
101 Ok(())
102 }
103
104 pub fn clear_scalars(&mut self) {
105 self.n_scalars = 0;
106 for b in self.scalar_name.iter_mut() {
107 *b = 0;
108 }
109 }
110
111 pub fn add_scalar(&mut self, name: &str) -> Result<()> {
112 if self.n_scalars > 10 {
113 Err(Error::new(ErrorKind::InvalidInput, "Trk header is already full of scalars (10)"))
114 } else if name.len() > 20 {
115 Err(Error::new(ErrorKind::InvalidInput, "New scalar name must be <= 20 characters."))
116 } else if !name.is_ascii() {
117 Err(Error::new(ErrorKind::InvalidInput, "New scalar name must be pure ascii."))
118 } else {
119 let pos = 20 * self.n_scalars as usize;
120 self.scalar_name[pos..pos + name.len()].clone_from_slice(name.as_bytes());
121 self.n_scalars += 1;
122 return Ok(());
123 }
124 }
125
126 pub fn get_scalars_name(&self) -> Vec<String> {
127 read_names(&self.scalar_name, self.n_scalars as usize)
128 }
129
130 pub fn clear_properties(&mut self) {
131 self.n_properties = 0;
132 for b in self.property_name.iter_mut() {
133 *b = 0;
134 }
135 }
136
137 pub fn add_property(&mut self, name: &str) -> Result<()> {
138 if self.n_properties > 10 {
139 Err(Error::new(
140 ErrorKind::InvalidInput,
141 "Trk header is already full of properties (10)",
142 ))
143 } else if name.len() > 20 {
144 Err(Error::new(ErrorKind::InvalidInput, "New property name must be <= 20 characters."))
145 } else if !name.is_ascii() {
146 Err(Error::new(ErrorKind::InvalidInput, "New property name must be pure ascii."))
147 } else {
148 let pos = 20 * self.n_properties as usize;
149 self.property_name[pos..pos + name.len()].clone_from_slice(name.as_bytes());
150 self.n_properties += 1;
151 return Ok(());
152 }
153 }
154
155 pub fn get_properties_name(&self) -> Vec<String> {
156 read_names(&self.property_name, self.n_properties as usize)
157 }
158
159 pub fn get_affine_to_rasmm(&self) -> Affine4 {
167 let mut affine = Affine4::identity();
168
169 let scale = Affine4::from_diagonal(&Vector4::new(
170 1.0 / self.voxel_size[0],
171 1.0 / self.voxel_size[1],
172 1.0 / self.voxel_size[2],
173 1.0,
174 ));
175 affine = scale * affine;
176
177 #[rustfmt::skip]
178 let offset = Affine4::new(
179 1.0, 0.0, 0.0, -0.5,
180 0.0, 1.0, 0.0, -0.5,
181 0.0, 0.0, 1.0, -0.5,
182 0.0, 0.0, 0.0, 1.0,
183 );
184 affine = offset * affine;
185
186 let voxel_to_rasmm = Affine4::from_iterator(self.vox_to_ras.iter().cloned()).transpose();
187
188 let header_ornt = axcodes_to_orientations(from_utf8(&self.voxel_order).unwrap());
189 let affine_order = affine_to_axcodes(&voxel_to_rasmm.fixed_view::<3, 3>(0, 0).into_owned());
190 let affine_ornt = axcodes_to_orientations(&affine_order);
191 let orientations = orientations_transform(&header_ornt, &affine_ornt);
192 let inv = inverse_orientations_affine(&orientations, self.dim);
193 affine = inv * affine;
194
195 voxel_to_rasmm * affine
196 }
197
198 pub fn read(reader: &mut BufReader<File>) -> Result<(CHeader, Endianness)> {
199 reader.seek(SeekFrom::Start(0))?;
200 let endianness = test_endianness(reader)?;
201 let header = match endianness {
202 Endianness::Little => CHeader::read_::<LittleEndian>(reader)?,
203 Endianness::Big => CHeader::read_::<BigEndian>(reader)?,
204 };
205 Ok((header, endianness))
206 }
207
208 fn read_<E: ByteOrder>(reader: &mut BufReader<File>) -> Result<CHeader> {
209 let mut header = CHeader::default();
210
211 reader.read_exact(&mut header.id_string)?;
213 if &header.id_string != b"TRACK\0" {
214 return Err(Error::new(
215 ErrorKind::InvalidData,
216 "Not a TrackVis file (wrong file signature)",
217 ));
218 }
219
220 for i in &mut header.dim {
221 *i = reader.read_i16::<E>()?;
222 }
223 for f in &mut header.voxel_size {
224 *f = reader.read_f32::<E>()?;
225 }
226 for f in &mut header.origin {
227 *f = reader.read_f32::<E>()?;
228 }
229 header.n_scalars = reader.read_i16::<E>()?;
230 reader.read_exact(&mut header.scalar_name)?;
231 header.n_properties = reader.read_i16::<E>()?;
232 reader.read_exact(&mut header.property_name)?;
233 for f in &mut header.vox_to_ras {
234 *f = reader.read_f32::<E>()?;
235 }
236 reader.read_exact(&mut header.reserved)?;
237 reader.read_exact(&mut header.voxel_order)?;
238 reader.read_exact(&mut header.pad2)?;
239 for f in &mut header.image_orientation_patient {
240 *f = reader.read_f32::<E>()?;
241 }
242 reader.read_exact(&mut header.pad1)?;
243 header.invert_x = reader.read_u8()?;
244 header.invert_y = reader.read_u8()?;
245 header.invert_z = reader.read_u8()?;
246 header.swap_x = reader.read_u8()?;
247 header.swap_y = reader.read_u8()?;
248 header.swap_z = reader.read_u8()?;
249 header.n_count = reader.read_i32::<E>()?;
250 header.version = reader.read_i32::<E>()?;
251 header.hdr_size = reader.read_i32::<E>()?;
252
253 Ok(header)
254 }
255
256 pub fn write<W: WriteBytesExt>(&self, writer: &mut W) -> Result<()> {
257 writer.write(&self.id_string)?;
258 for i in &self.dim {
259 writer.write_i16::<TrkEndianness>(*i)?;
260 }
261 for f in &self.voxel_size {
262 writer.write_f32::<TrkEndianness>(*f)?;
263 }
264 for f in &self.origin {
265 writer.write_f32::<TrkEndianness>(*f)?;
266 }
267 writer.write_i16::<TrkEndianness>(self.n_scalars)?;
268 writer.write(&self.scalar_name)?;
269 writer.write_i16::<TrkEndianness>(self.n_properties)?;
270 writer.write(&self.property_name)?;
271 for f in &self.vox_to_ras {
272 writer.write_f32::<TrkEndianness>(*f)?;
273 }
274 writer.write(&self.reserved)?;
275 writer.write(&self.voxel_order)?;
276 writer.write(&self.pad2)?;
277 for f in &self.image_orientation_patient {
278 writer.write_f32::<TrkEndianness>(*f)?;
279 }
280 writer.write(&self.pad1)?;
281 writer.write_u8(self.invert_x)?;
282 writer.write_u8(self.invert_y)?;
283 writer.write_u8(self.invert_z)?;
284 writer.write_u8(self.swap_x)?;
285 writer.write_u8(self.swap_y)?;
286 writer.write_u8(self.swap_z)?;
287 writer.write_i32::<TrkEndianness>(self.n_count)?;
288 writer.write_i32::<TrkEndianness>(self.version)?;
289 writer.write_i32::<TrkEndianness>(self.hdr_size)?;
290
291 Ok(())
292 }
293}
294
295impl Default for CHeader {
296 fn default() -> CHeader {
297 CHeader {
298 id_string: *b"TRACK\0",
299 dim: [0, 0, 0],
300 voxel_size: [1.0, 1.0, 1.0],
301 origin: [0.0, 0.0, 0.0],
302 n_scalars: 0,
303 scalar_name: [0; 200],
304 n_properties: 0,
305 property_name: [0; 200],
306 vox_to_ras: [
307 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
308 ],
309 reserved: [0; 444],
310 voxel_order: [82, 65, 83, 0],
311 pad2: [0; 4],
312 image_orientation_patient: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
313 pad1: [0; 2],
314 invert_x: 0,
315 invert_y: 0,
316 invert_z: 0,
317 swap_x: 0,
318 swap_y: 0,
319 swap_z: 0,
320 n_count: 0,
321 version: 2,
322 hdr_size: HEADER_SIZE as i32,
323 }
324 }
325}
326
327fn test_endianness(reader: &mut BufReader<File>) -> Result<Endianness> {
335 let version_offset = (HEADER_SIZE - 8) as u64;
336 reader.seek(SeekFrom::Start(version_offset))?;
337 let version = reader.read_i32::<LittleEndian>()?;
338 let endianness = if version <= 255 { Endianness::Little } else { Endianness::Big };
339 reader.seek(SeekFrom::Start(0))?;
340
341 Ok(endianness)
342}
343
344fn read_names(names_bytes: &[u8], nb: usize) -> Vec<String> {
349 let mut at = 0;
350 let mut names = vec![String::from(""); nb];
351 for names_byte in names_bytes.chunks(20) {
352 if names_byte[0] == 0u8 {
353 break;
354 }
355
356 let idx = names_byte.iter().position(|&e| e == 0u8).unwrap_or(20);
357 let name = from_utf8(&names_byte[..idx]).unwrap().to_string();
358 if idx < 19 && names_byte[idx + 1] != 0u8 {
359 let number = names_byte[idx + 1] - 48;
360 for _ in 0..number {
361 names[at] = name.clone();
362 at += 1;
363 }
364 } else {
365 names[at] = name;
366 at += 1;
367 }
368 }
369 names
370}
371
372#[cfg(test)]
373mod tests {
374 use super::*;
375
376 #[test]
377 fn test_scalars() {
378 let mut header = CHeader::default();
379 header.add_scalar("color_x").unwrap();
380 header.add_scalar("color_y").unwrap();
381
382 let mut gt = [0u8; 200];
383 gt[..7].clone_from_slice(b"color_x");
384 gt[20..27].clone_from_slice(b"color_y");
385 assert_eq!(&header.scalar_name[..], >[..]);
386 }
387
388 #[test]
389 fn test_read_empty_names() {
390 let scalars = read_names(&vec![0; 80], 3);
393 assert_eq!(scalars, vec![String::from(""), String::from(""), String::from("")]);
394 }
395
396 #[test]
397 fn test_header_size() {
398 assert_eq!(HEADER_SIZE, 1000);
399 }
400}