@niivue/vox-loader
Version:
A MagicaVoxel vox image loader to be used with the NiiVue useLoader method
94 lines (91 loc) • 3.07 kB
JavaScript
// src/vox2nii.ts
import * as fs from "fs/promises";
import path from "path";
import { fileURLToPath } from "url";
// src/lib/loader.ts
import readVox from "vox-reader";
import * as nifti from "nifti-reader-js";
async function vox2nii(inBuffer, isVerbose = true) {
try {
let byteArray;
if (inBuffer instanceof Uint8Array) {
byteArray = inBuffer;
} else if (inBuffer instanceof ArrayBuffer) {
byteArray = new Uint8Array(inBuffer);
} else {
throw new Error("Unsupported input type: Expected Uint8Array or ArrayBuffer.");
}
console.log("here");
const vox = readVox(byteArray);
if (!vox || !vox.size || !vox.xyzi?.values || !vox.rgba?.values) {
throw new Error("Invalid or empty MagicaVoxel file.");
}
const { x: width, y: height, z: depth } = vox.size;
if (isVerbose) {
console.log(`Loaded MagicaVoxel: ${width}x${height}x${depth}`);
}
const voxelData = new Uint8Array(width * height * depth * 4).fill(0);
for (const voxel of vox.xyzi.values) {
const { x, y, z, i } = voxel;
const color = vox.rgba.values[i];
if (color) {
const index = (x + y * width + z * width * height) * 4;
voxelData[index] = color.r;
voxelData[index + 1] = color.g;
voxelData[index + 2] = color.b;
voxelData[index + 3] = color.a;
}
}
const hdr = new nifti.NIFTI1();
hdr.littleEndian = true;
hdr.dims[0] = 3;
hdr.dims[1] = width;
hdr.dims[2] = height;
hdr.dims[3] = depth;
hdr.datatypeCode = 2304;
hdr.numBitsPerVoxel = 32;
hdr.pixDims = [1, 1, 1, 1, 1, 0, 0, 0];
hdr.vox_offset = 352;
hdr.scl_slope = 1;
hdr.scl_inter = 0;
hdr.qform_code = 0;
hdr.sform_code = 0;
hdr.magic = "n+1";
const hdrBuffer = hdr.toArrayBuffer();
const niftiData = new Uint8Array(hdrBuffer.byteLength + voxelData.byteLength);
niftiData.set(new Uint8Array(hdrBuffer), 0);
niftiData.set(voxelData, hdrBuffer.byteLength);
return niftiData;
} catch (error) {
throw error;
}
}
// src/vox2nii.ts
import { performance } from "perf_hooks";
var __filename = fileURLToPath(import.meta.url);
var __dirname = path.dirname(__filename);
if (process.argv.length < 3) {
console.error("Usage: node vox2nii.js <input.vox>");
process.exit(1);
}
var inputFile = process.argv[2];
var outputFile = inputFile.replace(/\.vox$/, ".nii");
async function convertVoxToNifti() {
try {
const startTime = performance.now();
const buffer = await fs.readFile(inputFile);
let niftiData = await vox2nii(buffer);
await fs.writeFile(outputFile, Buffer.from(niftiData.buffer));
console.log(`Saved NIfTI file: ${outputFile}`);
console.log(`Converted to ${outputFile} in ${performance.now() - startTime}ms`);
} catch (error) {
if (error instanceof Error) {
console.error("Error processing file:", error.message);
} else {
console.error("Error processing file:", String(error));
}
}
}
convertVoxToNifti();
//# sourceMappingURL=vox2nii.js.map