From 9eb530acf941fba53d166658dbd41ff424ef7827 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 31 May 2023 08:33:57 -0700 Subject: [PATCH 01/25] I have no idea what I'm doing, but I'm adding the generation of extensions and extensionsequences --- Cargo.toml | 4 ++++ src/extension.rs | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 1754a6d..45c388a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,10 @@ tempfile = "3.1" name = "niftidump" path = "examples/niftidump/main.rs" +[[example]] +name = "gen_nifti" +path = "examples/gen_nifti/main.rs" + [features] default = ["ndarray_volumes"] nalgebra_affine = ["nalgebra", "simba"] diff --git a/src/extension.rs b/src/extension.rs index 20e39bc..8c2c8ec 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -130,6 +130,14 @@ impl<'a> IntoIterator for &'a ExtensionSequence { } impl ExtensionSequence { + /// Provide a public constructor + pub fn new(extender: Extender, extensions: Vec) -> Self { + ExtensionSequence { + extender, + extensions, + } + } + /// Read a sequence of extensions from a source, up until `len` bytes. pub fn from_reader( extender: Extender, From e68df755bca24c3402d8f5bb3b1b482273a5f62e Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 31 May 2023 08:34:36 -0700 Subject: [PATCH 02/25] add an example that generates NIFTs --- examples/gen_nifti/main.rs | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 examples/gen_nifti/main.rs diff --git a/examples/gen_nifti/main.rs b/examples/gen_nifti/main.rs new file mode 100644 index 0000000..0464ba4 --- /dev/null +++ b/examples/gen_nifti/main.rs @@ -0,0 +1,40 @@ +//! An application for writing a NIFTI file from scratch + +extern crate nifti; + +use std::env; + +use crate::nifti::{ + header::{MAGIC_CODE_NI1, MAGIC_CODE_NIP1}, + volume::shape::Dim, + DataElement, NiftiHeader, NiftiType, Result, Extension, ExtensionSequence, Extender +}; + +fn main() { + let mut args = env::args().skip(1); + let filename = args.next().expect("Path to NIFTI file is required"); + + // generate some test data 256x256 float32 + let data = ndarray::Array3::::zeros((256, 256, 1)); + let datatype = NiftiType::Float32; + + let extension1 = Extension::new(8 + 4, 0, vec![0, 0, 0, 0]); + + let extension2 = Extension::new(8 + 4, 0, vec![0, 0, 0, 0]); + + let extension_sequence = ExtensionSequence::new(Extender::from([0u8; 4]), vec![extension1, extension2]); + + let header = NiftiHeader{ + dim: *Dim::from_slice(data.shape()).expect("Don't know why this wouldn't work").raw(), + sizeof_hdr: 348, + datatype: datatype as i16, + bitpix: (datatype.size_of() * 8) as i16, + vox_offset: 352.0, + scl_inter: 0.0, + scl_slope: 1.0, + magic: *MAGIC_CODE_NIP1, + ..Default::default() + }; + + println!("{:#?}", &header); +} From 4f104eb453cc6fa3cda9aed258bac5e30a933698 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 31 May 2023 11:38:53 -0700 Subject: [PATCH 03/25] added some writing functions for the extensions --- examples/gen_nifti/main.rs | 2 +- src/extension.rs | 7 +++++ src/writer.rs | 59 ++++++++++++++++++++++++++++++++++---- 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/examples/gen_nifti/main.rs b/examples/gen_nifti/main.rs index 0464ba4..c863c3d 100644 --- a/examples/gen_nifti/main.rs +++ b/examples/gen_nifti/main.rs @@ -29,7 +29,7 @@ fn main() { sizeof_hdr: 348, datatype: datatype as i16, bitpix: (datatype.size_of() * 8) as i16, - vox_offset: 352.0, + vox_offset: 352.0 + extension_sequence.bytes_on_disk() as f32, scl_inter: 0.0, scl_slope: 1.0, magic: *MAGIC_CODE_NIP1, diff --git a/src/extension.rs b/src/extension.rs index 8c2c8ec..6efa716 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -194,6 +194,13 @@ impl ExtensionSequence { self.extensions.len() } + /// return the number of bytes the extensions take on disk + pub fn bytes_on_disk(&self) -> usize { + self.extensions + .iter() + .map(|e| e.size() as usize) + .sum::() + } /// Get the extender code from this extension sequence. pub fn extender(&self) -> Extender { self.extender diff --git a/src/writer.rs b/src/writer.rs index d7a12ba..ae66849 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -14,7 +14,7 @@ use crate::{ header::{MAGIC_CODE_NI1, MAGIC_CODE_NIP1}, util::{adapt_bytes, is_gz_file, is_hdr_file}, volume::shape::Dim, - DataElement, NiftiHeader, NiftiType, Result, + DataElement, NiftiHeader, NiftiType, Result, ExtensionSequence }; #[derive(Debug, Clone, PartialEq)] @@ -57,6 +57,9 @@ pub struct WriterOptions<'a> { /// The header file will only be compressed if the caller specifically asked for a path ending /// with "hdr.gz". Otherwise, only the volume will be compressed (if requested). force_header_compression: bool, + + /// optional ExtensionSequence + extension_sequence: Option } impl<'a> WriterOptions<'a> { @@ -81,6 +84,7 @@ impl<'a> WriterOptions<'a> { write_header_file, compression, force_header_compression: write_header_file && compression.is_some(), + extension_sequence: None, } } @@ -127,6 +131,11 @@ impl<'a> WriterOptions<'a> { self } + pub fn extension_sequence(mut self, extension_sequence: ExtensionSequence) -> Self { + self.extension_sequence = Some(extension_sequence); + self + } + /// Write a nifti file (.nii or .nii.gz). pub fn write_nifti(&self, data: &ArrayBase) -> Result<()> where @@ -149,12 +158,22 @@ impl<'a> WriterOptions<'a> { header.endianness, ); write_header(writer.as_mut(), &header)?; + if let Some(extension_sequence) = self.extension_sequence.as_ref() { + write_extensions(writer.as_mut(), extension_sequence)?; + } else { + write_zero_extender(writer.as_mut())?; + } write_data::<_, A, _, _, _, _>(writer.as_mut(), data)?; let _ = writer.into_inner().finish()?; } else { let mut writer = ByteOrdered::runtime(BufWriter::new(header_file), header.endianness); write_header(writer.as_mut(), &header)?; + if let Some(extension_sequence) = self.extension_sequence.as_ref() { + write_extensions(writer.as_mut(), extension_sequence)?; + } else { + write_zero_extender(writer.as_mut())?; + } write_data::<_, A, _, _, _, _>(writer, data)?; } } else { @@ -206,12 +225,22 @@ impl<'a> WriterOptions<'a> { header.endianness, ); write_header(writer.as_mut(), &header)?; + if let Some(extension_sequence) = self.extension_sequence.as_ref() { + write_extensions(writer.as_mut(), extension_sequence)?; + } else { + write_zero_extender(writer.as_mut())?; + } write_data::<_, u8, _, _, _, _>(writer.as_mut(), data)?; let _ = writer.into_inner().finish()?; } else { let mut writer = ByteOrdered::runtime(BufWriter::new(header_file), header.endianness); write_header(writer.as_mut(), &header)?; + if let Some(extension_sequence) = self.extension_sequence.as_ref() { + write_extensions(writer.as_mut(), extension_sequence)?; + } else { + write_zero_extender(writer.as_mut())?; + } write_data::<_, u8, _, _, _, _>(writer, data)?; } } else { @@ -297,6 +326,30 @@ impl<'a> WriterOptions<'a> { } } +fn write_extensions(mut writer: ByteOrdered, extensions: &ExtensionSequence) -> Result<()> +where + W: Write, + E: Endian, +{ + let mut extender = extensions.extender(); + writer.write_all(extender.as_bytes())?; + for extension in extensions.iter() { + writer.write_i32(extension.size())?; + writer.write_i32(extension.code())?; + writer.write_all(extension.data())?; + } + Ok(()) +} + +fn write_zero_extender(mut writer: ByteOrdered) -> Result<()> +where + W: Write, + E: Endian, +{ + writer.write_u32(0)?; + Ok(()) +} + fn write_header(mut writer: ByteOrdered, header: &NiftiHeader) -> Result<()> where W: Write, @@ -360,10 +413,6 @@ where writer.write_all(&header.intent_name)?; writer.write_all(&header.magic)?; - // Empty 4 bytes after the header - // TODO(#19) Support writing extension data. - writer.write_u32(0)?; - Ok(()) } From c450dd7c5533c335f60a7f4686d50419b7f37fba Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 31 May 2023 12:12:00 -0700 Subject: [PATCH 04/25] fix the header vox_offset calculation internally --- src/writer.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/writer.rs b/src/writer.rs index ae66849..f1355af 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -282,12 +282,19 @@ impl<'a> WriterOptions<'a> { T: Data, D: Dimension, { + let mut vox_offset:f32 = 352.0; + + if let Some(extension_sequence) = self.extension_sequence.as_ref() { + if extension_sequence.bytes_on_disk() > 0 { + vox_offset += extension_sequence.bytes_on_disk() as f32; + } + } let mut header = NiftiHeader { dim: *Dim::from_slice(data.shape())?.raw(), sizeof_hdr: 348, datatype: datatype as i16, bitpix: (datatype.size_of() * 8) as i16, - vox_offset: 352.0, + vox_offset: vox_offset, scl_inter: 0.0, scl_slope: 1.0, magic: *MAGIC_CODE_NIP1, From 6e9deaf8e167e66102ac07ea570834768988e36c Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 31 May 2023 13:28:40 -0700 Subject: [PATCH 05/25] minor cleanup --- examples/gen_nifti/main.rs | 25 ++++++++----------------- src/writer.rs | 21 ++++++++++++++------- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/examples/gen_nifti/main.rs b/examples/gen_nifti/main.rs index c863c3d..6eca23e 100644 --- a/examples/gen_nifti/main.rs +++ b/examples/gen_nifti/main.rs @@ -7,7 +7,7 @@ use std::env; use crate::nifti::{ header::{MAGIC_CODE_NI1, MAGIC_CODE_NIP1}, volume::shape::Dim, - DataElement, NiftiHeader, NiftiType, Result, Extension, ExtensionSequence, Extender + DataElement, NiftiHeader, NiftiType, Result, Extension, ExtensionSequence, Extender, writer::WriterOptions }; fn main() { @@ -18,23 +18,14 @@ fn main() { let data = ndarray::Array3::::zeros((256, 256, 1)); let datatype = NiftiType::Float32; - let extension1 = Extension::new(8 + 4, 0, vec![0, 0, 0, 0]); + let extension1 = Extension::new(8 + 4, 3, vec![0, 0, 0, 0]); - let extension2 = Extension::new(8 + 4, 0, vec![0, 0, 0, 0]); + let extension2 = Extension::new(8 + 4, 6, vec![0, 0, 0, 0]); - let extension_sequence = ExtensionSequence::new(Extender::from([0u8; 4]), vec![extension1, extension2]); + let extension_sequence = ExtensionSequence::new(Extender::from([1u8; 4]), vec![extension1, extension2]); - let header = NiftiHeader{ - dim: *Dim::from_slice(data.shape()).expect("Don't know why this wouldn't work").raw(), - sizeof_hdr: 348, - datatype: datatype as i16, - bitpix: (datatype.size_of() * 8) as i16, - vox_offset: 352.0 + extension_sequence.bytes_on_disk() as f32, - scl_inter: 0.0, - scl_slope: 1.0, - magic: *MAGIC_CODE_NIP1, - ..Default::default() - }; - - println!("{:#?}", &header); + WriterOptions::new(&filename) + .extension_sequence(extension_sequence) + .write_nifti(&data) + .unwrap(); } diff --git a/src/writer.rs b/src/writer.rs index f1355af..47320c4 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -161,7 +161,7 @@ impl<'a> WriterOptions<'a> { if let Some(extension_sequence) = self.extension_sequence.as_ref() { write_extensions(writer.as_mut(), extension_sequence)?; } else { - write_zero_extender(writer.as_mut())?; + write_header_terminator(writer.as_mut())?; } write_data::<_, A, _, _, _, _>(writer.as_mut(), data)?; let _ = writer.into_inner().finish()?; @@ -172,7 +172,7 @@ impl<'a> WriterOptions<'a> { if let Some(extension_sequence) = self.extension_sequence.as_ref() { write_extensions(writer.as_mut(), extension_sequence)?; } else { - write_zero_extender(writer.as_mut())?; + write_header_terminator(writer.as_mut())?; } write_data::<_, A, _, _, _, _>(writer, data)?; } @@ -228,7 +228,7 @@ impl<'a> WriterOptions<'a> { if let Some(extension_sequence) = self.extension_sequence.as_ref() { write_extensions(writer.as_mut(), extension_sequence)?; } else { - write_zero_extender(writer.as_mut())?; + write_header_terminator(writer.as_mut())?; } write_data::<_, u8, _, _, _, _>(writer.as_mut(), data)?; let _ = writer.into_inner().finish()?; @@ -239,7 +239,7 @@ impl<'a> WriterOptions<'a> { if let Some(extension_sequence) = self.extension_sequence.as_ref() { write_extensions(writer.as_mut(), extension_sequence)?; } else { - write_zero_extender(writer.as_mut())?; + write_header_terminator(writer.as_mut())?; } write_data::<_, u8, _, _, _, _>(writer, data)?; } @@ -338,8 +338,13 @@ where W: Write, E: Endian, { - let mut extender = extensions.extender(); - writer.write_all(extender.as_bytes())?; + if extensions.is_empty() { + // write an extender code of 4 zeros, which for NIFTI means that there are no extensions + writer.write_u32(0)?; + return Ok(()); + } + + writer.write_all(extensions.extender().as_bytes())?; for extension in extensions.iter() { writer.write_i32(extension.size())?; writer.write_i32(extension.code())?; @@ -348,12 +353,14 @@ where Ok(()) } -fn write_zero_extender(mut writer: ByteOrdered) -> Result<()> +fn write_header_terminator(mut writer: ByteOrdered) -> Result<()> where W: Write, E: Endian, { + // write an extender code of 4 zeros, which for NIFTI means that there are no extensions writer.write_u32(0)?; + Ok(()) } From ff340ec5776db6e46e15ab10cc42f99971923113 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 31 May 2023 15:14:47 -0700 Subject: [PATCH 06/25] added a from_str and added a Hello World example --- examples/gen_nifti/main.rs | 3 +-- src/extension.rs | 7 +++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/gen_nifti/main.rs b/examples/gen_nifti/main.rs index 6eca23e..88cad4b 100644 --- a/examples/gen_nifti/main.rs +++ b/examples/gen_nifti/main.rs @@ -16,11 +16,10 @@ fn main() { // generate some test data 256x256 float32 let data = ndarray::Array3::::zeros((256, 256, 1)); - let datatype = NiftiType::Float32; let extension1 = Extension::new(8 + 4, 3, vec![0, 0, 0, 0]); - let extension2 = Extension::new(8 + 4, 6, vec![0, 0, 0, 0]); + let extension2 = Extension::from_str(6, "Hello World!"); let extension_sequence = ExtensionSequence::new(Extender::from([1u8; 4]), vec![extension1, extension2]); diff --git a/src/extension.rs b/src/extension.rs index 6efa716..26e9a7a 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -82,6 +82,13 @@ impl Extension { } } + /// Create a new extension out of a &str + pub fn from_str(ecode: i32, edata: &str) -> Self + { + let esize = 8 + edata.len() as i32; + Extension::new(esize, ecode, edata.as_bytes().to_vec()) + } + /// Obtain the claimed extension raw size (`esize` field). pub fn size(&self) -> i32 { self.esize From 50ce3975ec229eb007b47b17eecc3bb2ab2579fe Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 31 May 2023 15:30:39 -0700 Subject: [PATCH 07/25] added a missing comment --- examples/gen_nifti/main.rs | 4 +--- src/writer.rs | 5 +++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/gen_nifti/main.rs b/examples/gen_nifti/main.rs index 88cad4b..c3ab274 100644 --- a/examples/gen_nifti/main.rs +++ b/examples/gen_nifti/main.rs @@ -5,9 +5,7 @@ extern crate nifti; use std::env; use crate::nifti::{ - header::{MAGIC_CODE_NI1, MAGIC_CODE_NIP1}, - volume::shape::Dim, - DataElement, NiftiHeader, NiftiType, Result, Extension, ExtensionSequence, Extender, writer::WriterOptions + Extension, ExtensionSequence, Extender, writer::WriterOptions }; fn main() { diff --git a/src/writer.rs b/src/writer.rs index 47320c4..bf7e39e 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -131,8 +131,9 @@ impl<'a> WriterOptions<'a> { self } - pub fn extension_sequence(mut self, extension_sequence: ExtensionSequence) -> Self { - self.extension_sequence = Some(extension_sequence); + /// Sets an extension sequence for the writer + pub fn extension_sequence(mut self, extension_sequence: Option) -> Self { + self.extension_sequence = extension_sequence; self } From ab1c6f24794abcf7256c1943195574d75a6b9fae Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 31 May 2023 15:31:40 -0700 Subject: [PATCH 08/25] fixed setting the extension sequence --- examples/gen_nifti/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gen_nifti/main.rs b/examples/gen_nifti/main.rs index c3ab274..113cadb 100644 --- a/examples/gen_nifti/main.rs +++ b/examples/gen_nifti/main.rs @@ -22,7 +22,7 @@ fn main() { let extension_sequence = ExtensionSequence::new(Extender::from([1u8; 4]), vec![extension1, extension2]); WriterOptions::new(&filename) - .extension_sequence(extension_sequence) + .extension_sequence(Some(extension_sequence)) .write_nifti(&data) .unwrap(); } From 6f11508134f899c3ebad8e12fcaa9bb3869bc47f Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 31 May 2023 15:54:05 -0700 Subject: [PATCH 09/25] make only byte[0] of the extender non-zero --- examples/gen_nifti/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gen_nifti/main.rs b/examples/gen_nifti/main.rs index 113cadb..b01059d 100644 --- a/examples/gen_nifti/main.rs +++ b/examples/gen_nifti/main.rs @@ -19,7 +19,7 @@ fn main() { let extension2 = Extension::from_str(6, "Hello World!"); - let extension_sequence = ExtensionSequence::new(Extender::from([1u8; 4]), vec![extension1, extension2]); + let extension_sequence = ExtensionSequence::new(Extender::from([1u8,0u8,0u8,0u8]), vec![extension1, extension2]); WriterOptions::new(&filename) .extension_sequence(Some(extension_sequence)) From 23669681cc6aae4c9d597d121a34bdfb0b1249f2 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Thu, 1 Jun 2023 09:37:15 -0700 Subject: [PATCH 10/25] rustfmt the branch removed unnecessary if statement --- examples/gen_nifti/main.rs | 15 ++++++++------- src/extension.rs | 3 +-- src/writer.rs | 20 +++++++++++--------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/examples/gen_nifti/main.rs b/examples/gen_nifti/main.rs index b01059d..603ce7d 100644 --- a/examples/gen_nifti/main.rs +++ b/examples/gen_nifti/main.rs @@ -4,9 +4,7 @@ extern crate nifti; use std::env; -use crate::nifti::{ - Extension, ExtensionSequence, Extender, writer::WriterOptions -}; +use crate::nifti::{writer::WriterOptions, Extender, Extension, ExtensionSequence}; fn main() { let mut args = env::args().skip(1); @@ -19,10 +17,13 @@ fn main() { let extension2 = Extension::from_str(6, "Hello World!"); - let extension_sequence = ExtensionSequence::new(Extender::from([1u8,0u8,0u8,0u8]), vec![extension1, extension2]); + let extension_sequence = ExtensionSequence::new( + Extender::from([1u8, 0u8, 0u8, 0u8]), + vec![extension1, extension2], + ); WriterOptions::new(&filename) - .extension_sequence(Some(extension_sequence)) - .write_nifti(&data) - .unwrap(); + .extension_sequence(Some(extension_sequence)) + .write_nifti(&data) + .unwrap(); } diff --git a/src/extension.rs b/src/extension.rs index 26e9a7a..8198bff 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -83,8 +83,7 @@ impl Extension { } /// Create a new extension out of a &str - pub fn from_str(ecode: i32, edata: &str) -> Self - { + pub fn from_str(ecode: i32, edata: &str) -> Self { let esize = 8 + edata.len() as i32; Extension::new(esize, ecode, edata.as_bytes().to_vec()) } diff --git a/src/writer.rs b/src/writer.rs index bf7e39e..2cfb92f 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -14,7 +14,7 @@ use crate::{ header::{MAGIC_CODE_NI1, MAGIC_CODE_NIP1}, util::{adapt_bytes, is_gz_file, is_hdr_file}, volume::shape::Dim, - DataElement, NiftiHeader, NiftiType, Result, ExtensionSequence + DataElement, ExtensionSequence, NiftiHeader, NiftiType, Result, }; #[derive(Debug, Clone, PartialEq)] @@ -59,7 +59,7 @@ pub struct WriterOptions<'a> { force_header_compression: bool, /// optional ExtensionSequence - extension_sequence: Option + extension_sequence: Option, } impl<'a> WriterOptions<'a> { @@ -283,13 +283,12 @@ impl<'a> WriterOptions<'a> { T: Data, D: Dimension, { - let mut vox_offset:f32 = 352.0; - + let mut vox_offset: f32 = 352.0; + if let Some(extension_sequence) = self.extension_sequence.as_ref() { - if extension_sequence.bytes_on_disk() > 0 { - vox_offset += extension_sequence.bytes_on_disk() as f32; - } - } + vox_offset += extension_sequence.bytes_on_disk() as f32; + } + let mut header = NiftiHeader { dim: *Dim::from_slice(data.shape())?.raw(), sizeof_hdr: 348, @@ -334,7 +333,10 @@ impl<'a> WriterOptions<'a> { } } -fn write_extensions(mut writer: ByteOrdered, extensions: &ExtensionSequence) -> Result<()> +fn write_extensions( + mut writer: ByteOrdered, + extensions: &ExtensionSequence, +) -> Result<()> where W: Write, E: Endian, From 0de4635595943a1d7001991ac8225cb17cf8dccf Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Thu, 1 Jun 2023 10:07:10 -0700 Subject: [PATCH 11/25] fixed missing terminator writes --- src/writer.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/writer.rs b/src/writer.rs index 2cfb92f..20a87fd 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -185,6 +185,7 @@ impl<'a> WriterOptions<'a> { header.endianness, ); write_header(writer.as_mut(), &header)?; + write_header_terminator(writer.as_mut())?; let _ = writer.into_inner().finish()?; let mut writer = ByteOrdered::runtime( @@ -197,6 +198,7 @@ impl<'a> WriterOptions<'a> { let header_writer = ByteOrdered::runtime(BufWriter::new(header_file), header.endianness); write_header(header_writer, &header)?; + write_header_terminator(writer.as_mut())?; let data_writer = ByteOrdered::runtime(BufWriter::new(data_file), header.endianness); write_data::<_, A, _, _, _, _>(data_writer, data)?; @@ -252,6 +254,7 @@ impl<'a> WriterOptions<'a> { header.endianness, ); write_header(writer.as_mut(), &header)?; + write_header_terminator(writer.as_mut())?; let _ = writer.into_inner().finish()?; let mut writer = ByteOrdered::runtime( @@ -264,7 +267,7 @@ impl<'a> WriterOptions<'a> { let header_writer = ByteOrdered::runtime(BufWriter::new(header_file), header.endianness); write_header(header_writer, &header)?; - + write_header_terminator(writer.as_mut())?; let data_writer = ByteOrdered::runtime(BufWriter::new(data_file), header.endianness); write_data::<_, u8, _, _, _, _>(data_writer, data)?; From 974fd05b16f2059d3f1a56cac804f2bc5d49bc77 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Thu, 1 Jun 2023 10:13:06 -0700 Subject: [PATCH 12/25] fix some header writing spelling, make tests pass --- src/writer.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/writer.rs b/src/writer.rs index 20a87fd..67bdd62 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -195,10 +195,10 @@ impl<'a> WriterOptions<'a> { write_data::<_, A, _, _, _, _>(writer.as_mut(), data)?; let _ = writer.into_inner().finish()?; } else { - let header_writer = + let mut header_writer = ByteOrdered::runtime(BufWriter::new(header_file), header.endianness); - write_header(header_writer, &header)?; - write_header_terminator(writer.as_mut())?; + write_header(header_writer.as_mut(), &header)?; + write_header_terminator(header_writer.as_mut())?; let data_writer = ByteOrdered::runtime(BufWriter::new(data_file), header.endianness); write_data::<_, A, _, _, _, _>(data_writer, data)?; @@ -264,10 +264,10 @@ impl<'a> WriterOptions<'a> { write_data::<_, u8, _, _, _, _>(writer.as_mut(), data)?; let _ = writer.into_inner().finish()?; } else { - let header_writer = + let mut header_writer = ByteOrdered::runtime(BufWriter::new(header_file), header.endianness); - write_header(header_writer, &header)?; - write_header_terminator(writer.as_mut())?; + write_header(header_writer.as_mut(), &header)?; + write_header_terminator(header_writer.as_mut())?; let data_writer = ByteOrdered::runtime(BufWriter::new(data_file), header.endianness); write_data::<_, u8, _, _, _, _>(data_writer, data)?; From cd8fa6e4812311824f7c7ecf66c8959552bce7ea Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Thu, 1 Jun 2023 11:28:55 -0700 Subject: [PATCH 13/25] hide my example behind a feature, so that the cargo test pipeline doesn't choke on it --- examples/gen_nifti/main.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/gen_nifti/main.rs b/examples/gen_nifti/main.rs index 603ce7d..e838230 100644 --- a/examples/gen_nifti/main.rs +++ b/examples/gen_nifti/main.rs @@ -4,8 +4,10 @@ extern crate nifti; use std::env; +#[cfg(feature = "ndarray_volumes")] use crate::nifti::{writer::WriterOptions, Extender, Extension, ExtensionSequence}; +#[cfg(feature = "ndarray_volumes")] fn main() { let mut args = env::args().skip(1); let filename = args.next().expect("Path to NIFTI file is required"); @@ -27,3 +29,8 @@ fn main() { .write_nifti(&data) .unwrap(); } + +#[cfg(not(feature = "ndarray_volumes"))] +fn main() { + println!("This example requires the ndarray_volumes feature to be enabled"); +} \ No newline at end of file From 24e83eb986b5b5dd04c05d5d8dd8e8d56c40081f Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Thu, 1 Jun 2023 11:34:31 -0700 Subject: [PATCH 14/25] one clippy nit less --- src/writer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/writer.rs b/src/writer.rs index 67bdd62..e35a496 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -297,7 +297,7 @@ impl<'a> WriterOptions<'a> { sizeof_hdr: 348, datatype: datatype as i16, bitpix: (datatype.size_of() * 8) as i16, - vox_offset: vox_offset, + vox_offset, scl_inter: 0.0, scl_slope: 1.0, magic: *MAGIC_CODE_NIP1, From 066ad92e44600d851eeb6fc782b0ca119855d737 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Thu, 1 Jun 2023 18:26:43 -0700 Subject: [PATCH 15/25] test almost works, but the qform code doesn't match --- resources/minimal_extended_hdr.nii | Bin 0 -> 896 bytes src/extension.rs | 6 +++++- tests/writer.rs | 21 +++++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 resources/minimal_extended_hdr.nii diff --git a/resources/minimal_extended_hdr.nii b/resources/minimal_extended_hdr.nii new file mode 100644 index 0000000000000000000000000000000000000000..64bce689dd6e081a4b7d7d77518b939527af4902 GIT binary patch literal 896 zcma!HWFQJKF>nAOBOIb?a$s-(3pCg>FyO-noFVe4x(ANOgvV--KhOcOVhjv<+J?Ze gVqj1JVm2W5NX^N~R|wB9%1KcKa!0{v2!KNX09a8F8~^|S literal 0 HcmV?d00001 diff --git a/src/extension.rs b/src/extension.rs index 8198bff..3d7dc22 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -85,7 +85,11 @@ impl Extension { /// Create a new extension out of a &str pub fn from_str(ecode: i32, edata: &str) -> Self { let esize = 8 + edata.len() as i32; - Extension::new(esize, ecode, edata.as_bytes().to_vec()) + // pad the esize to a multiple of 16 + let padded_esize = (esize + 15) & !15; + let mut edata = edata.as_bytes().to_vec(); + edata.resize(padded_esize as usize - 8, 0); + Extension::new(padded_esize, ecode, edata) } /// Obtain the claimed extension raw size (`esize` field). diff --git a/tests/writer.rs b/tests/writer.rs index 81252d5..328c259 100644 --- a/tests/writer.rs +++ b/tests/writer.rs @@ -407,4 +407,25 @@ mod tests { fs::read("resources/rgb/4D.nii").unwrap() ); } + + #[test] + fn write_extended_header() { + let data: ndarray::ArrayBase, ndarray::Dim<[usize; 2]>> = Array2::zeros((8, 8)); + + let path = get_temporary_path("2d_extended_header.nii"); + let extension = nifti::Extension::from_str(6, "Hello World!"); + + let extension_sequence = nifti::ExtensionSequence::new(nifti::Extender::from([1u8, 0u8, 0u8, 0u8]), vec![extension]); + + WriterOptions::new(&path) + .extension_sequence(Some(extension_sequence)) + .write_nifti(&data) + .unwrap(); + fs::copy(&path, "/tmp/test.nii").unwrap(); + assert_eq!( + fs::read(&path).unwrap(), + fs::read("resources/minimal_extended_hdr.nii").unwrap() + ); + + } } From 7d97c8828498dd4f3350903ca75bd67a89c9d656 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Thu, 1 Jun 2023 19:11:18 -0700 Subject: [PATCH 16/25] changed the nibabel write to set the qform_code to 1 to match the default of this crate --- resources/minimal_extended_hdr.nii | Bin 896 -> 896 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/resources/minimal_extended_hdr.nii b/resources/minimal_extended_hdr.nii index 64bce689dd6e081a4b7d7d77518b939527af4902..d2ae6e9e45611a94cf2aaca8872f88fc1e987502 100644 GIT binary patch delta 26 gcmZo*Z(yJBhnbOqX=0=FWIaX=AQssi#;C;v0A+**!~g&Q delta 26 gcmZo*Z(yJBhnazaX=0=FWIaX=AQssi#;C;v0A+Co!vFvP From 61b96651e6c0dbca75e7b57e28f0ff94768b2003 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Thu, 1 Jun 2023 19:15:49 -0700 Subject: [PATCH 17/25] improved comment, removed the copy of the binary file --- tests/writer.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/writer.rs b/tests/writer.rs index 328c259..d7c2a7d 100644 --- a/tests/writer.rs +++ b/tests/writer.rs @@ -421,7 +421,8 @@ mod tests { .extension_sequence(Some(extension_sequence)) .write_nifti(&data) .unwrap(); - fs::copy(&path, "/tmp/test.nii").unwrap(); + + // verify the binary identity to the nibabel generated file assert_eq!( fs::read(&path).unwrap(), fs::read("resources/minimal_extended_hdr.nii").unwrap() From 42f65afa5f6b5b32de15b65df08af83f726e78ba Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Thu, 1 Jun 2023 23:05:39 -0700 Subject: [PATCH 18/25] added some knownn ecodes --- src/extension.rs | 14 ++++++++++++++ tests/writer.rs | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/extension.rs b/src/extension.rs index 3d7dc22..50f6de2 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -7,6 +7,20 @@ use crate::error::{NiftiError, Result}; use byteordered::{ByteOrdered, Endian}; use std::io::{ErrorKind as IoErrorKind, Read}; +use num_derive::FromPrimitive; + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, FromPrimitive)] +#[repr(u32)] +pub enum NiftiEcode { + NiftEcodeIgnore = 0, + NiftiEcodeDicom = 2, + NiftiEcodeAFNI = 4, + NiftiEcodeComment = 6, + NiftiEcodeXCEDE = 8, + NiftiEcodeJimDimInfo = 10, + NiftiEcodeWorkflowFWDS = 12, + NiftiEcodeFreesurfer = 14, +} /// Data type for the extender code. #[derive(Debug, Default, PartialEq, Clone, Copy)] diff --git a/tests/writer.rs b/tests/writer.rs index d7c2a7d..8509f80 100644 --- a/tests/writer.rs +++ b/tests/writer.rs @@ -421,7 +421,7 @@ mod tests { .extension_sequence(Some(extension_sequence)) .write_nifti(&data) .unwrap(); - + // verify the binary identity to the nibabel generated file assert_eq!( fs::read(&path).unwrap(), From 6aa45de5adae5df9fe27ef620861ade83330f574 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Thu, 1 Jun 2023 23:10:06 -0700 Subject: [PATCH 19/25] updated documentation --- src/extension.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/extension.rs b/src/extension.rs index 50f6de2..fd7cfee 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -9,16 +9,25 @@ use byteordered::{ByteOrdered, Endian}; use std::io::{ErrorKind as IoErrorKind, Read}; use num_derive::FromPrimitive; +/// Data type for representing a NIFTI ecodes #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, FromPrimitive)] #[repr(u32)] pub enum NiftiEcode { + /// Ignore the extension NiftEcodeIgnore = 0, + /// DICOM NiftiEcodeDicom = 2, + /// AFNI extension in XML format NiftiEcodeAFNI = 4, + /// String Comment NiftiEcodeComment = 6, + /// XCEDE extension in XML format NiftiEcodeXCEDE = 8, + /// JimDimInfo NiftiEcodeJimDimInfo = 10, + /// WorkflowFWDS NiftiEcodeWorkflowFWDS = 12, + /// Freesurfer NiftiEcodeFreesurfer = 14, } From 8f90a66de0e883d81199fff53a3c4f973fc96746 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 2 Jun 2023 09:11:03 -0700 Subject: [PATCH 20/25] some cleanup to make a bit more rusty --- examples/gen_nifti/main.rs | 2 +- src/writer.rs | 52 +++++++++++--------------------------- tests/writer.rs | 2 +- 3 files changed, 17 insertions(+), 39 deletions(-) diff --git a/examples/gen_nifti/main.rs b/examples/gen_nifti/main.rs index e838230..8f94978 100644 --- a/examples/gen_nifti/main.rs +++ b/examples/gen_nifti/main.rs @@ -25,7 +25,7 @@ fn main() { ); WriterOptions::new(&filename) - .extension_sequence(Some(extension_sequence)) + .with_extensions(Some(extension_sequence)) .write_nifti(&data) .unwrap(); } diff --git a/src/writer.rs b/src/writer.rs index e35a496..154946c 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -132,7 +132,7 @@ impl<'a> WriterOptions<'a> { } /// Sets an extension sequence for the writer - pub fn extension_sequence(mut self, extension_sequence: Option) -> Self { + pub fn with_extensions(mut self, extension_sequence: Option) -> Self { self.extension_sequence = extension_sequence; self } @@ -159,22 +159,14 @@ impl<'a> WriterOptions<'a> { header.endianness, ); write_header(writer.as_mut(), &header)?; - if let Some(extension_sequence) = self.extension_sequence.as_ref() { - write_extensions(writer.as_mut(), extension_sequence)?; - } else { - write_header_terminator(writer.as_mut())?; - } + write_extensions(writer.as_mut(), self.extension_sequence.as_ref())?; write_data::<_, A, _, _, _, _>(writer.as_mut(), data)?; let _ = writer.into_inner().finish()?; } else { let mut writer = ByteOrdered::runtime(BufWriter::new(header_file), header.endianness); write_header(writer.as_mut(), &header)?; - if let Some(extension_sequence) = self.extension_sequence.as_ref() { - write_extensions(writer.as_mut(), extension_sequence)?; - } else { - write_header_terminator(writer.as_mut())?; - } + write_extensions(writer.as_mut(), self.extension_sequence.as_ref())?; write_data::<_, A, _, _, _, _>(writer, data)?; } } else { @@ -185,7 +177,7 @@ impl<'a> WriterOptions<'a> { header.endianness, ); write_header(writer.as_mut(), &header)?; - write_header_terminator(writer.as_mut())?; + write_extensions(writer.as_mut(), self.extension_sequence.as_ref())?; let _ = writer.into_inner().finish()?; let mut writer = ByteOrdered::runtime( @@ -198,7 +190,7 @@ impl<'a> WriterOptions<'a> { let mut header_writer = ByteOrdered::runtime(BufWriter::new(header_file), header.endianness); write_header(header_writer.as_mut(), &header)?; - write_header_terminator(header_writer.as_mut())?; + write_extensions(header_writer.as_mut(), self.extension_sequence.as_ref())?; let data_writer = ByteOrdered::runtime(BufWriter::new(data_file), header.endianness); write_data::<_, A, _, _, _, _>(data_writer, data)?; @@ -228,22 +220,14 @@ impl<'a> WriterOptions<'a> { header.endianness, ); write_header(writer.as_mut(), &header)?; - if let Some(extension_sequence) = self.extension_sequence.as_ref() { - write_extensions(writer.as_mut(), extension_sequence)?; - } else { - write_header_terminator(writer.as_mut())?; - } + write_extensions(writer.as_mut(), self.extension_sequence.as_ref())?; write_data::<_, u8, _, _, _, _>(writer.as_mut(), data)?; let _ = writer.into_inner().finish()?; } else { let mut writer = ByteOrdered::runtime(BufWriter::new(header_file), header.endianness); write_header(writer.as_mut(), &header)?; - if let Some(extension_sequence) = self.extension_sequence.as_ref() { - write_extensions(writer.as_mut(), extension_sequence)?; - } else { - write_header_terminator(writer.as_mut())?; - } + write_extensions(writer.as_mut(), self.extension_sequence.as_ref())?; write_data::<_, u8, _, _, _, _>(writer, data)?; } } else { @@ -254,7 +238,7 @@ impl<'a> WriterOptions<'a> { header.endianness, ); write_header(writer.as_mut(), &header)?; - write_header_terminator(writer.as_mut())?; + write_extensions(writer.as_mut(), self.extension_sequence.as_ref())?; let _ = writer.into_inner().finish()?; let mut writer = ByteOrdered::runtime( @@ -267,7 +251,7 @@ impl<'a> WriterOptions<'a> { let mut header_writer = ByteOrdered::runtime(BufWriter::new(header_file), header.endianness); write_header(header_writer.as_mut(), &header)?; - write_header_terminator(header_writer.as_mut())?; + write_extensions(header_writer.as_mut(), self.extension_sequence.as_ref())?; let data_writer = ByteOrdered::runtime(BufWriter::new(data_file), header.endianness); write_data::<_, u8, _, _, _, _>(data_writer, data)?; @@ -338,12 +322,17 @@ impl<'a> WriterOptions<'a> { fn write_extensions( mut writer: ByteOrdered, - extensions: &ExtensionSequence, + extensions: Option<&ExtensionSequence>, ) -> Result<()> where W: Write, E: Endian, { + let extensions = match extensions { + Some(extensions) => extensions, + None => { writer.write_u32(0)?; return Ok(())}, + }; + if extensions.is_empty() { // write an extender code of 4 zeros, which for NIFTI means that there are no extensions writer.write_u32(0)?; @@ -359,17 +348,6 @@ where Ok(()) } -fn write_header_terminator(mut writer: ByteOrdered) -> Result<()> -where - W: Write, - E: Endian, -{ - // write an extender code of 4 zeros, which for NIFTI means that there are no extensions - writer.write_u32(0)?; - - Ok(()) -} - fn write_header(mut writer: ByteOrdered, header: &NiftiHeader) -> Result<()> where W: Write, diff --git a/tests/writer.rs b/tests/writer.rs index 8509f80..2eff634 100644 --- a/tests/writer.rs +++ b/tests/writer.rs @@ -418,7 +418,7 @@ mod tests { let extension_sequence = nifti::ExtensionSequence::new(nifti::Extender::from([1u8, 0u8, 0u8, 0u8]), vec![extension]); WriterOptions::new(&path) - .extension_sequence(Some(extension_sequence)) + .with_extensions(Some(extension_sequence)) .write_nifti(&data) .unwrap(); From ece944bf30cfd79e8fc1cbbbb394ab007d985f5b Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 2 Jun 2023 09:14:34 -0700 Subject: [PATCH 21/25] annotated the f32 type in the NIFTI header --- src/header.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/header.rs b/src/header.rs index f20ed45..bc7cb8d 100644 --- a/src/header.rs +++ b/src/header.rs @@ -91,6 +91,7 @@ pub struct NiftiHeader { /// Grid spacings pub pixdim: [f32; 8], /// Offset into .nii file to reach the volume + /// Note: the highly unusual choice of f32 is intentional and due to trying to achieve header backwards compatibility to ANALYZE 7.5 pub vox_offset: f32, /// Data scaling: slope pub scl_slope: f32, From 605f0bb0c7e81ec68261eceb172bb2cc9b5337f9 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 2 Jun 2023 09:58:14 -0700 Subject: [PATCH 22/25] more improvements based on review feedback --- examples/gen_nifti/main.rs | 2 +- src/extension.rs | 6 +++--- src/writer.rs | 9 ++++++--- tests/writer.rs | 10 ++++++---- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/examples/gen_nifti/main.rs b/examples/gen_nifti/main.rs index 8f94978..7110911 100644 --- a/examples/gen_nifti/main.rs +++ b/examples/gen_nifti/main.rs @@ -33,4 +33,4 @@ fn main() { #[cfg(not(feature = "ndarray_volumes"))] fn main() { println!("This example requires the ndarray_volumes feature to be enabled"); -} \ No newline at end of file +} diff --git a/src/extension.rs b/src/extension.rs index fd7cfee..d2c8844 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -6,8 +6,8 @@ use crate::error::{NiftiError, Result}; use byteordered::{ByteOrdered, Endian}; -use std::io::{ErrorKind as IoErrorKind, Read}; use num_derive::FromPrimitive; +use std::io::{ErrorKind as IoErrorKind, Read}; /// Data type for representing a NIFTI ecodes #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, FromPrimitive)] @@ -15,7 +15,7 @@ use num_derive::FromPrimitive; pub enum NiftiEcode { /// Ignore the extension NiftEcodeIgnore = 0, - /// DICOM + /// DICOM NiftiEcodeDicom = 2, /// AFNI extension in XML format NiftiEcodeAFNI = 4, @@ -227,7 +227,7 @@ impl ExtensionSequence { self.extensions.len() } - /// return the number of bytes the extensions take on disk + /// Return the number of bytes the extensions take on disk pub fn bytes_on_disk(&self) -> usize { self.extensions .iter() diff --git a/src/writer.rs b/src/writer.rs index 154946c..a880467 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -58,7 +58,7 @@ pub struct WriterOptions<'a> { /// with "hdr.gz". Otherwise, only the volume will be compressed (if requested). force_header_compression: bool, - /// optional ExtensionSequence + /// Optional ExtensionSequence extension_sequence: Option, } @@ -330,11 +330,14 @@ where { let extensions = match extensions { Some(extensions) => extensions, - None => { writer.write_u32(0)?; return Ok(())}, + None => { + writer.write_u32(0)?; + return Ok(()); + } }; if extensions.is_empty() { - // write an extender code of 4 zeros, which for NIFTI means that there are no extensions + // Write an extender code of 4 zeros, which for NIFTI means that there are no extensions writer.write_u32(0)?; return Ok(()); } diff --git a/tests/writer.rs b/tests/writer.rs index 2eff634..e147ad8 100644 --- a/tests/writer.rs +++ b/tests/writer.rs @@ -410,23 +410,25 @@ mod tests { #[test] fn write_extended_header() { - let data: ndarray::ArrayBase, ndarray::Dim<[usize; 2]>> = Array2::zeros((8, 8)); + let data: Array2 = Array2::zeros((8, 8)); let path = get_temporary_path("2d_extended_header.nii"); let extension = nifti::Extension::from_str(6, "Hello World!"); - let extension_sequence = nifti::ExtensionSequence::new(nifti::Extender::from([1u8, 0u8, 0u8, 0u8]), vec![extension]); + let extension_sequence = nifti::ExtensionSequence::new( + nifti::Extender::from([1u8, 0u8, 0u8, 0u8]), + vec![extension], + ); WriterOptions::new(&path) .with_extensions(Some(extension_sequence)) .write_nifti(&data) .unwrap(); - // verify the binary identity to the nibabel generated file + // Verify the binary identity to the nibabel generated file assert_eq!( fs::read(&path).unwrap(), fs::read("resources/minimal_extended_hdr.nii").unwrap() ); - } } From 72ccc53f5086d564b7b44469459f3d47efca4dde Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 2 Jun 2023 10:47:41 -0700 Subject: [PATCH 23/25] fixed idiotic interface --- examples/gen_nifti/main.rs | 2 +- src/writer.rs | 4 ++-- tests/writer.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/gen_nifti/main.rs b/examples/gen_nifti/main.rs index 7110911..310d36a 100644 --- a/examples/gen_nifti/main.rs +++ b/examples/gen_nifti/main.rs @@ -25,7 +25,7 @@ fn main() { ); WriterOptions::new(&filename) - .with_extensions(Some(extension_sequence)) + .with_extensions(extension_sequence) .write_nifti(&data) .unwrap(); } diff --git a/src/writer.rs b/src/writer.rs index a880467..d44e63b 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -132,8 +132,8 @@ impl<'a> WriterOptions<'a> { } /// Sets an extension sequence for the writer - pub fn with_extensions(mut self, extension_sequence: Option) -> Self { - self.extension_sequence = extension_sequence; + pub fn with_extensions(mut self, extension_sequence: ExtensionSequence) -> Self { + self.extension_sequence = Some(extension_sequence); self } diff --git a/tests/writer.rs b/tests/writer.rs index e147ad8..b0769c2 100644 --- a/tests/writer.rs +++ b/tests/writer.rs @@ -421,7 +421,7 @@ mod tests { ); WriterOptions::new(&path) - .with_extensions(Some(extension_sequence)) + .with_extensions(extension_sequence) .write_nifti(&data) .unwrap(); From 926e4d1d61ab733e55e3dedfe8ee044094486e7c Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sat, 3 Jun 2023 19:48:01 -0700 Subject: [PATCH 24/25] Update src/extension.rs Co-authored-by: Eduardo Pinho --- src/extension.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extension.rs b/src/extension.rs index d2c8844..250e4bc 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -9,7 +9,7 @@ use byteordered::{ByteOrdered, Endian}; use num_derive::FromPrimitive; use std::io::{ErrorKind as IoErrorKind, Read}; -/// Data type for representing a NIFTI ecodes +/// Data type for representing a NIfTI-1.1 extension code #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, FromPrimitive)] #[repr(u32)] pub enum NiftiEcode { From eb227f9ebdc5c301fb2056b30619c8175ccfda92 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sat, 3 Jun 2023 19:48:21 -0700 Subject: [PATCH 25/25] Update src/header.rs Co-authored-by: Eduardo Pinho --- src/header.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/header.rs b/src/header.rs index bc7cb8d..54d6e76 100644 --- a/src/header.rs +++ b/src/header.rs @@ -90,8 +90,10 @@ pub struct NiftiHeader { pub slice_start: i16, /// Grid spacings pub pixdim: [f32; 8], - /// Offset into .nii file to reach the volume - /// Note: the highly unusual choice of f32 is intentional and due to trying to achieve header backwards compatibility to ANALYZE 7.5 + /// Offset into .nii file to reach the volume. + /// + /// Note: the highly unusual choice of f32 is intentional + /// and due to trying to achieve header backwards compatibility to ANALYZE 7.5 pub vox_offset: f32, /// Data scaling: slope pub scl_slope: f32,