diff --git a/mri.js b/mri.js index 4ff835c..0480730 100644 --- a/mri.js +++ b/mri.js @@ -1,3 +1,4 @@ +/* globals Struct, pako */ 'use strict'; function MRI() { @@ -36,105 +37,105 @@ function MRI() { init: function init() { var pr = new Promise(function(resolve, reject) { me.loadScript(me.struct_url, function() {return window.Struct != undefined;}) - .then(function() {return me.loadScript(me.pako_url, function() {return window.pako != undefined;});}) + .then(function() {return me.loadScript(me.pako_url, function() {return window.pako != undefined;});}) /* var pr = me.loadScript('https://cdn.rawgit.com/r03ert0/mrijs/v0.0.2/mri.js',function(){return window.MRI!=undefined}); */ - .then(function() { - if (!me.NiiHdrLE) { - me.NiiHdrLE = Struct() - .word32Sle('sizeof_hdr') // Size of the header. Must be 348 (bytes) - .chars('data_type', 10) // Not used; compatibility with analyze. - .chars('db_name', 18) // Not used; compatibility with analyze. - .word32Sle('extents') // Not used; compatibility with analyze. - .word16Sle('session_error') // Not used; compatibility with analyze. - .word8('regular') // Not used; compatibility with analyze. - .word8('dim_info') // Encoding directions (phase, frequency, slice). - .array('dim', 8, 'word16Sle') // Data array dimensions. - .floatle('intent_p1') // 1st intent parameter. - .floatle('intent_p2') // 2nd intent parameter. - .floatle('intent_p3') // 3rd intent parameter. - .word16Sle('intent_code') // nifti intent. - .word16Sle('datatype') // Data type. - .word16Sle('bitpix') // Number of bits per voxel. - .word16Sle('slice_start') // First slice index. - .array('pixdim', 8, 'floatle') // Grid spacings (unit per dimension). - .floatle('vox_offset') // Offset into a .nii file. - .floatle('scl_slope') // Data scaling, slope. - .floatle('scl_inter') // Data scaling, offset. - .word16Sle('slice_end') // Last slice index. - .word8('slice_code') // Slice timing order. - .word8('xyzt_units') // Units of pixdim[1..4]. - .floatle('cal_max') // Maximum display intensity. - .floatle('cal_min') // Minimum display intensity. - .floatle('slice_duration') // Time for one slice. - .floatle('toffset') // Time axis shift. - .word32Sle('glmax') // Not used; compatibility with analyze. - .word32Sle('glmin') // Not used; compatibility with analyze. - .chars('descrip', 80) // Any text. - .chars('aux_file', 24) // Auxiliary filename. - .word16Sle('qform_code') // Use the quaternion fields. - .word16Sle('sform_code') // Use of the affine fields. - .floatle('quatern_b') // Quaternion b parameter. - .floatle('quatern_c') // Quaternion c parameter. - .floatle('quatern_d') // Quaternion d parameter. - .floatle('qoffset_x') // Quaternion x shift. - .floatle('qoffset_y') // Quaternion y shift. - .floatle('qoffset_z') // Quaternion z shift. - .array('srow_x', 4, 'floatle') // 1st row affine transform - .array('srow_y', 4, 'floatle') // 2nd row affine transform. - .array('srow_z', 4, 'floatle') // 3rd row affine transform. - .chars('intent_name', 16) // Name or meaning of the data. - .chars('magic', 4); // Magic string. - } - if (!me.NiiHdrBE) { - me.NiiHdrBE = Struct() - .word32Sbe('sizeof_hdr') // Size of the header. Must be 348 (bytes) - .chars('data_type', 10) // Not used; compatibility with analyze. - .chars('db_name', 18) // Not used; compatibility with analyze. - .word32Sbe('extents') // Not used; compatibility with analyze. - .word16Sbe('session_error') // Not used; compatibility with analyze. - .word8('regular') // Not used; compatibility with analyze. - .word8('dim_info') // Encoding directions (phase, frequency, slice). - .array('dim', 8, 'word16Sbe') // Data array dimensions. - .floatbe('intent_p1') // 1st intent parameter. - .floatbe('intent_p2') // 2nd intent parameter. - .floatbe('intent_p3') // 3rd intent parameter. - .word16Sbe('intent_code') // nifti intent. - .word16Sbe('datatype') // Data type. - .word16Sbe('bitpix') // Number of bits per voxel. - .word16Sbe('slice_start') // First slice index. - .array('pixdim', 8, 'floatbe') // Grid spacings (unit per dimension). - .floatbe('vox_offset') // Offset into a .nii file. - .floatbe('scl_slope') // Data scaling, slope. - .floatbe('scl_inter') // Data scaling, offset. - .word16Sbe('slice_end') // Last slice index. - .word8('slice_code') // Slice timing order. - .word8('xyzt_units') // Units of pixdim[1..4]. - .floatbe('cal_max') // Maximum display intensity. - .floatbe('cal_min') // Minimum display intensity. - .floatbe('slice_duration') // Time for one slice. - .floatbe('toffset') // Time axis shift. - .word32Sbe('glmax') // Not used; compatibility with analyze. - .word32Sbe('glmin') // Not used; compatibility with analyze. - .chars('descrip', 80) // Any text. - .chars('aux_file', 24) // Auxiliary filename. - .word16Sbe('qform_code') // Use the quaternion fields. - .word16Sbe('sform_code') // Use of the affine fields. - .floatbe('quatern_b') // Quaternion b parameter. - .floatbe('quatern_c') // Quaternion c parameter. - .floatbe('quatern_d') // Quaternion d parameter. - .floatbe('qoffset_x') // Quaternion x shift. - .floatbe('qoffset_y') // Quaternion y shift. - .floatbe('qoffset_z') // Quaternion z shift. - .array('srow_x', 4, 'floatbe') // 1st row affine transform - .array('srow_y', 4, 'floatbe') // 2nd row affine transform. - .array('srow_z', 4, 'floatbe') // 3rd row affine transform. - .chars('intent_name', 16) // Name or meaning of the data. - .chars('magic', 4); // Magic string. - } - resolve(); - }); + .then(function() { + if (!me.NiiHdrLE) { + me.NiiHdrLE = Struct() + .word32Sle('sizeof_hdr') // Size of the header. Must be 348 (bytes) + .chars('data_type', 10) // Not used; compatibility with analyze. + .chars('db_name', 18) // Not used; compatibility with analyze. + .word32Sle('extents') // Not used; compatibility with analyze. + .word16Sle('session_error') // Not used; compatibility with analyze. + .word8('regular') // Not used; compatibility with analyze. + .word8('dim_info') // Encoding directions (phase, frequency, slice). + .array('dim', 8, 'word16Sle') // Data array dimensions. + .floatle('intent_p1') // 1st intent parameter. + .floatle('intent_p2') // 2nd intent parameter. + .floatle('intent_p3') // 3rd intent parameter. + .word16Sle('intent_code') // nifti intent. + .word16Sle('datatype') // Data type. + .word16Sle('bitpix') // Number of bits per voxel. + .word16Sle('slice_start') // First slice index. + .array('pixdim', 8, 'floatle') // Grid spacings (unit per dimension). + .floatle('vox_offset') // Offset into a .nii file. + .floatle('scl_slope') // Data scaling, slope. + .floatle('scl_inter') // Data scaling, offset. + .word16Sle('slice_end') // Last slice index. + .word8('slice_code') // Slice timing order. + .word8('xyzt_units') // Units of pixdim[1..4]. + .floatle('cal_max') // Maximum display intensity. + .floatle('cal_min') // Minimum display intensity. + .floatle('slice_duration') // Time for one slice. + .floatle('toffset') // Time axis shift. + .word32Sle('glmax') // Not used; compatibility with analyze. + .word32Sle('glmin') // Not used; compatibility with analyze. + .chars('descrip', 80) // Any text. + .chars('aux_file', 24) // Auxiliary filename. + .word16Sle('qform_code') // Use the quaternion fields. + .word16Sle('sform_code') // Use of the affine fields. + .floatle('quatern_b') // Quaternion b parameter. + .floatle('quatern_c') // Quaternion c parameter. + .floatle('quatern_d') // Quaternion d parameter. + .floatle('qoffset_x') // Quaternion x shift. + .floatle('qoffset_y') // Quaternion y shift. + .floatle('qoffset_z') // Quaternion z shift. + .array('srow_x', 4, 'floatle') // 1st row affine transform + .array('srow_y', 4, 'floatle') // 2nd row affine transform. + .array('srow_z', 4, 'floatle') // 3rd row affine transform. + .chars('intent_name', 16) // Name or meaning of the data. + .chars('magic', 4); // Magic string. + } + if (!me.NiiHdrBE) { + me.NiiHdrBE = Struct() + .word32Sbe('sizeof_hdr') // Size of the header. Must be 348 (bytes) + .chars('data_type', 10) // Not used; compatibility with analyze. + .chars('db_name', 18) // Not used; compatibility with analyze. + .word32Sbe('extents') // Not used; compatibility with analyze. + .word16Sbe('session_error') // Not used; compatibility with analyze. + .word8('regular') // Not used; compatibility with analyze. + .word8('dim_info') // Encoding directions (phase, frequency, slice). + .array('dim', 8, 'word16Sbe') // Data array dimensions. + .floatbe('intent_p1') // 1st intent parameter. + .floatbe('intent_p2') // 2nd intent parameter. + .floatbe('intent_p3') // 3rd intent parameter. + .word16Sbe('intent_code') // nifti intent. + .word16Sbe('datatype') // Data type. + .word16Sbe('bitpix') // Number of bits per voxel. + .word16Sbe('slice_start') // First slice index. + .array('pixdim', 8, 'floatbe') // Grid spacings (unit per dimension). + .floatbe('vox_offset') // Offset into a .nii file. + .floatbe('scl_slope') // Data scaling, slope. + .floatbe('scl_inter') // Data scaling, offset. + .word16Sbe('slice_end') // Last slice index. + .word8('slice_code') // Slice timing order. + .word8('xyzt_units') // Units of pixdim[1..4]. + .floatbe('cal_max') // Maximum display intensity. + .floatbe('cal_min') // Minimum display intensity. + .floatbe('slice_duration') // Time for one slice. + .floatbe('toffset') // Time axis shift. + .word32Sbe('glmax') // Not used; compatibility with analyze. + .word32Sbe('glmin') // Not used; compatibility with analyze. + .chars('descrip', 80) // Any text. + .chars('aux_file', 24) // Auxiliary filename. + .word16Sbe('qform_code') // Use the quaternion fields. + .word16Sbe('sform_code') // Use of the affine fields. + .floatbe('quatern_b') // Quaternion b parameter. + .floatbe('quatern_c') // Quaternion c parameter. + .floatbe('quatern_d') // Quaternion d parameter. + .floatbe('qoffset_x') // Quaternion x shift. + .floatbe('qoffset_y') // Quaternion y shift. + .floatbe('qoffset_z') // Quaternion z shift. + .array('srow_x', 4, 'floatbe') // 1st row affine transform + .array('srow_y', 4, 'floatbe') // 2nd row affine transform. + .array('srow_z', 4, 'floatbe') // 3rd row affine transform. + .chars('intent_name', 16) // Name or meaning of the data. + .chars('magic', 4); // Magic string. + } + resolve(); + }); }); return pr; }, @@ -149,38 +150,38 @@ function MRI() { */ createNifti: function createNifti(dim, pixdim, v2w, data) { - let sizeof_hdr=348; - let dimensions=4; // number of dimension values provided - let spacetimeunits=2+8; // 2=nifti code for millimetres | 8=nifti code for seconds - let datatype=16; // datatype for Float32 data - let vox_offset=352; - let bitsPerVoxel=32; + let sizeof_hdr = 348; + let dimensions = 4; // number of dimension values provided + let spacetimeunits = 2+8; // 2=nifti code for millimetres | 8=nifti code for seconds + let datatype = 16; // datatype for Float32 data + let vox_offset = 352; + let bitsPerVoxel = 32; let newHdr = { sizeof_hdr: sizeof_hdr, - data_type: '', db_name: '', extents: 0, session_error: 0, regular: 0, dim_info: 0, + data_type: '', db_name: '', extents: 0, session_error: 0, regular: 0, dim_info: 0, dim: [3, dim[0], dim[1], dim[2], 1, 1, 1, 1], - intent_p1: 0, intent_p2: 0, intent_p3: 0, intent_code: 0, + intent_p1: 0, intent_p2: 0, intent_p3: 0, intent_code: 0, datatype: datatype, // uchar bitpix: bitsPerVoxel, - slice_start: 0, + slice_start: 0, pixdim: [-1, pixdim[0], pixdim[1], pixdim[2], 0, 1, 1, 1], vox_offset: vox_offset, - scl_slope: 1, scl_inter: 0, slice_end: 0, slice_code: 0, - xyzt_units: 10, - cal_max: 0, cal_min: 0, slice_duration: 0, toffset: 0, - glmax: 0, glmin: 0, - descrip: 'Reorient, 5 January 2018', - aux_file: '', - qform_code: 0, - sform_code: 1, - quatern_b: 0, quatern_c: 0, quatern_d: 0, - qoffset_x: 0, qoffset_y: 0, qoffset_z: 0, + scl_slope: 1, scl_inter: 0, slice_end: 0, slice_code: 0, + xyzt_units: 10, + cal_max: 0, cal_min: 0, slice_duration: 0, toffset: 0, + glmax: 0, glmin: 0, + descrip: 'Reorient, 5 January 2018', + aux_file: '', + qform_code: 0, + sform_code: 1, + quatern_b: 0, quatern_c: 0, quatern_d: 0, + qoffset_x: 0, qoffset_y: 0, qoffset_z: 0, srow_x: [v2w[0][0], v2w[0][1], v2w[0][2], v2w[0][3]], srow_y: [v2w[1][0], v2w[1][1], v2w[1][2], v2w[1][3]], srow_z: [v2w[2][0], v2w[2][1], v2w[2][2], v2w[2][3]], - intent_name: '', - magic: 'n+1' + intent_name: '', + magic: 'n+1' }; me.NiiHdrLE.allocate(); let niihdr = me.NiiHdrLE.buffer(); @@ -320,41 +321,41 @@ function MRI() { me.pixdim = [h.pixdim[1],h.pixdim[2],h.pixdim[3]]; switch (me.datatype) { - case 2: // UCHAR - me.data = new Uint8Array(nii,vox_offset); - break; - case 256: // INT8 - me.data = new Uint8Array(nii,vox_offset); - break; - case 4: // SHORT - if (endianness == 'le') - me.data = new Int16Array(nii,vox_offset); - else - me.data = me.swapInt16(new Int16Array(nii,vox_offset)); - break; - case 8: // INT - if (endianness == 'le') - me.data = new Int32Array(nii,vox_offset); - else - me.data = me.swapInt32(new Int32Array(nii,vox_offset)); - break; - case 16: // FLOAT - if (endianness == 'le') - me.data = new Float32Array(nii,vox_offset); - else - me.data = me.swapFloat32(new Float32Array(nii,vox_offset)); - break; - case 256: // INT8 - me.data = new Int8Array(nii,vox_offset); - break; - case 512: // UINT16 - if (endianness == 'le') - me.data = new Uint16Array(nii,vox_offset); - else - me.data = me.swapUint16(new Uint16Array(nii,vox_offset)); - break; - default: - console.error('Unknown dataType: ' + me.datatype); + case 2: // UCHAR + me.data = new Uint8Array(nii,vox_offset); + break; + // case 256: // INT8 + // me.data = new Uint8Array(nii,vox_offset); + // break; + case 4: // SHORT + if (endianness == 'le') + me.data = new Int16Array(nii,vox_offset); + else + me.data = me.swapInt16(new Int16Array(nii,vox_offset)); + break; + case 8: // INT + if (endianness == 'le') + me.data = new Int32Array(nii,vox_offset); + else + me.data = me.swapInt32(new Int32Array(nii,vox_offset)); + break; + case 16: // FLOAT + if (endianness == 'le') + me.data = new Float32Array(nii,vox_offset); + else + me.data = me.swapFloat32(new Float32Array(nii,vox_offset)); + break; + case 256: // INT8 + me.data = new Int8Array(nii,vox_offset); + break; + case 512: // UINT16 + if (endianness == 'le') + me.data = new Uint16Array(nii,vox_offset); + else + me.data = me.swapUint16(new Uint16Array(nii,vox_offset)); + break; + default: + console.error('Unknown dataType: ' + me.datatype); } }, multMatVec: function multMatVec(m, v) { @@ -429,7 +430,7 @@ function MRI() { /** * @todo Additional transformation functions */ -/* + /* vox2pix: function vox2pix() { }, pix2vox: function pix2vox() {