-
Notifications
You must be signed in to change notification settings - Fork 6
/
nifti.ts
60 lines (58 loc) · 2.08 KB
/
nifti.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import { isCompressed, readHeader } from '@mango/nifti'
import type { BIDSFile } from '../types/filetree.ts'
import { logger } from '../utils/logger.ts'
import type { NiftiHeader } from '@bids/schema/context'
async function extract(buffer: Uint8Array, nbytes: number): Promise<Uint8Array> {
// The fflate decompression that is used in nifti-reader does not like
// truncated data, so pretend that we have a stream and stop reading
// when we have enough bytes.
const result = new Uint8Array(nbytes)
const stream = new ReadableStream({
start(controller) {
controller.enqueue(buffer)
},
})
const reader = stream.pipeThrough(new DecompressionStream('gzip')).getReader()
let offset = 0
while (offset < nbytes) {
const { value, done } = await reader.read()
if (done) {
break
}
result.set(value.subarray(0, Math.min(value.length, nbytes - offset)), offset)
offset += value.length
}
await reader.cancel()
return result
}
export async function loadHeader(file: BIDSFile): Promise<NiftiHeader> {
try {
const buf = await file.readBytes(1024)
const data = isCompressed(buf.buffer) ? await extract(buf, 540) : buf
const header = readHeader(data.buffer)
if (!header) {
throw { key: 'NIFTI_HEADER_UNREADABLE' }
}
const ndim = header.dims[0]
return {
dim: header.dims,
// Hack: round pixdim to 3 decimal places; schema should add rounding function
pixdim: header.pixDims.map((pixdim) => Math.round(pixdim * 1000) / 1000),
shape: header.dims.slice(1, ndim + 1),
voxel_sizes: header.pixDims.slice(1, ndim + 1),
dim_info: {
freq: header.dim_info & 0x03,
phase: (header.dim_info >> 2) & 0x03,
slice: (header.dim_info >> 4) & 0x03,
},
xyzt_units: {
xyz: ['unknown', 'meter', 'mm', 'um'][header.xyzt_units & 0x03],
t: ['unknown', 'sec', 'msec', 'usec'][(header.xyzt_units >> 3) & 0x03],
},
qform_code: header.qform_code,
sform_code: header.sform_code,
} as NiftiHeader
} catch (err) {
throw { key: 'NIFTI_HEADER_UNREADABLE' }
}
}