Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/NIfTI.jl
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ Read a NIfTI file to a NIVolume. Set `mmap=true` to memory map the volume.
function niread(file::AbstractString; mmap::Bool=false, mode::AbstractString="r")
io = niopen(file, mode)
hdr, swapped = read_header(io)
ex = read_extensions(io, hdr.vox_offset - 352)
ex = read_extensions(io, hdr.vox_offset - 352, swapbyte=swapped)

if hdr.magic === NP1_MAGIC
vol = read_volume(io, to_eltype(hdr.datatype), to_dimensions(hdr.dim), mmap)
Expand Down
57 changes: 37 additions & 20 deletions src/extensions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -141,42 +141,59 @@ function esize(ex::NIfTIExtension)
return ret
end

function read_extensions(io, n)
function read_extensions(io, n; swapbyte::Bool=false, skip_extension_flag::Bool=false)
ret = NIfTIExtension[]
if eof(io)
return ret
else
end

if !skip_extension_flag
b1 = read(io, UInt8)
# GZIP doesn't skip so we read and throw away
read(io, UInt8)
read(io, UInt8)
read(io, UInt8)
if b1 === zero(UInt8)
return ret
else
counter = 0
while counter < (n - 1)
esize = read(io, Int32)
ec = read(io, Int32)
push!(ret, NIfTIExtension(ec, read!(io, Array{UInt8}(undef, esize - 8))))
counter += esize
end
return ret
end
end

swap_int32 = swapbyte ? bswap : x -> x
counter = skip_extension_flag ? 0 : 4
while counter < (n - 1)
esize = swap_int32(read(io, Int32))
ec = swap_int32(read(io, Int32))
push!(ret, NIfTIExtension(ec, read!(io, Array{UInt8}(undef, esize - 8))))
counter += esize
end
return ret

end

write(path::AbstractString, x::Vector{NIfTIExtension}; swapbyte::Bool=false, skip_extension_flag::Bool=false) =
open(path, "w") do io
write(io, x, swapbyte=swapbyte, skip_extension_flag=skip_extension_flag)
end

function write(io::IO, x::Vector{NIfTIExtension})
function write(io::IO, x::Vector{NIfTIExtension}; swapbyte::Bool=false, skip_extension_flag::Bool=false)
if isempty(x)
write(io, fill(UInt8(0), 4))
else
write(io, UInt8[1, 0, 0, 0])
for ex in x
write(io, Int32(esize(ex)))
write(io, ex.ecode)
write(io, ex.edata)
# write(io, zeros(UInt8, esize(ex) - length(ex.edata)))
if !skip_extension_flag
write(io, fill(UInt8(0), 4))
end
return
end
if !skip_extension_flag
write(io, UInt8[1, 0, 0, 0])
end

swap_int32 = swapbyte ? bswap : x -> x

for ex in x
write(io, swap_int32(Int32(esize(ex))))
write(io, swap_int32(ex.ecode))
write(io, ex.edata)
# write(io, zeros(UInt8, esize(ex) - length(ex.edata)))
end

end

71 changes: 50 additions & 21 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,17 @@ function image_tests(fname, mmap)
@assert maximum(img) == maximum(img.raw)

@test getaffine(img) ≈ [
-2.0 6.714715653593746e-19 9.081024511081715e-18 117.8551025390625
6.714715653593746e-19 1.9737114906311035 -0.35552823543548584 -35.72294235229492
8.25548088896093e-18 0.3232076168060303 2.171081781387329 -7.248798370361328
0.0 0.0 0.0 1.0
-2.0 6.714715653593746e-19 9.081024511081715e-18 117.8551025390625
6.714715653593746e-19 1.9737114906311035 -0.35552823543548584 -35.72294235229492
8.25548088896093e-18 0.3232076168060303 2.171081781387329 -7.248798370361328
0.0 0.0 0.0 1.0
]

@test NIfTI.get_qform(img) ≈ [
-2.0 7.75482f-26 -6.93824f-27 117.855
7.75482f-26 1.97371 -0.355528 -35.7229
6.30749f-27 0.323208 2.17108 -7.2488
0.0 0.0 0.0 1.0
-2.0 7.75482f-26 -6.93824f-27 117.855
7.75482f-26 1.97371 -0.355528 -35.7229
6.30749f-27 0.323208 2.17108 -7.2488
0.0 0.0 0.0 1.0
]
@test NIfTI.orientation(img) == (:right, :posterior, :inferior)
end
Expand Down Expand Up @@ -118,30 +118,59 @@ const WRITE = joinpath(TEMP_DIR_NAME, "$(tempname()).nii")
const VERIFY_WRITE = joinpath(TEMP_DIR_NAME, "$(tempname()).nii")
cp(NII, WRITE)
img = niread(WRITE; mmap=true, mode="r+")
img.raw[1,1,1,1] = 5
img.raw[:,2,1,1] = ones(size(img)[1])
img.raw[1, 1, 1, 1] = 5
img.raw[:, 2, 1, 1] = ones(size(img)[1])
cp(WRITE, VERIFY_WRITE)
@test niread(VERIFY_WRITE)[1,1,1,1] == 5
@test niread(VERIFY_WRITE)[:,2,1,1] == ones(size(img)[1])
@test niread(VERIFY_WRITE)[1, 1, 1, 1] == 5
@test niread(VERIFY_WRITE)[:, 2, 1, 1] == ones(size(img)[1])
# Site is currently down TODO: reintroduce this test when site is up
# Big endian
# const BE = "$(tempname()).nii"
# download("https://nifti.nimh.nih.gov/nifti-1/data/avg152T1_LR_nifti.nii.gz", BE)
img = niread(joinpath(dirname(@__FILE__), "data/avg152T1_LR_nifti.nii.gz"))
@test size(img) == (91,109,91)
@test size(img) == (91, 109, 91)

GC.gc() # closes mmapped files

@test NIfTI._dir2ori(-1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0) == (:right, :posterior, :inferior)
0.0, 1.0, 0.0,
0.0, 0.0, 1.0) == (:right, :posterior, :inferior)

@test NIfTI._dir2ori(1.0, 0.0, 0.0,
0.0, -1.0, 0.0,
0.0, 0.0, 1.0) == (:left, :anterior, :inferior)
@test NIfTI._dir2ori(1.0, 0.0, 0.0,
0.0, -1.0, 0.0,
0.0, 0.0, 1.0) == (:left, :anterior, :inferior)


@test NIfTI._dir2ori(1.0, 0.0, 0.0,
0.0, -1.0, 0.0,
0.0, 0.0, -1.0) == (:left, :anterior, :superior)
@test NIfTI._dir2ori(1.0, 0.0, 0.0,
0.0, -1.0, 0.0,
0.0, 0.0, -1.0) == (:left, :anterior, :superior)


@testset "Extension Read Write" begin
img = niread(GZIPPED_NII)
temp_bin = "$(tempname()).bin"
NIfTI.write(temp_bin, img.extensions)
extensions = NIfTI.read_extensions(open(temp_bin), 68)
fd = open(temp_bin, "r")
chunk = read(fd, Int32)
sys_order_size = read(fd, Int32)
sys_order_ecode = read(fd, Int32)
close(fd)
@test (chunk == 1 || chunk == bswap(Int32(1)))
@test sys_order_size == 32
@test extensions[1].ecode == sys_order_ecode

NIfTI.write(temp_bin, img.extensions, swapbyte=true, skip_extension_flag=true)

fd = open(temp_bin, "r")
reverse_order_size = read(fd, Int32)
reverse_order_ecode = read(fd, Int32)
close(fd)
extensions = NIfTI.read_extensions(open(temp_bin), 64, swapbyte=true, skip_extension_flag=true)
@test extensions[1].ecode == sys_order_ecode

@test reverse_order_size == bswap(Int32(sys_order_size))
@test reverse_order_ecode == bswap(Int32(sys_order_ecode))
end


Loading