From 3dc64f4cb8aaef83fc354f8db2bd04d46362eacc Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Sun, 1 Dec 2024 12:42:40 -0500 Subject: [PATCH 01/12] WIP: ITK-Wasm surface generation pipeline Anti-aliased segmentation to surface generation with the aim to make improvements in well-behaved (non-intersecting, well-proportioned) triangles, smooth, reduced sampling artifacts, retains sulci. --- main.js | 424 +++++++------ package-lock.json | 1470 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 + vite.config.js | 14 +- 4 files changed, 1709 insertions(+), 201 deletions(-) diff --git a/main.js b/main.js index 732b2f7..de9ef3f 100644 --- a/main.js +++ b/main.js @@ -1,21 +1,23 @@ -import { Niivue, NVMeshUtilities } from "@niivue/niivue" -import { Niimath } from "@niivue/niimath" +import { Niivue, NVMeshUtilities } from "@niivue/niivue"; +import { Niimath } from "@niivue/niimath"; // import {runInference } from './brainchop-mainthread.js' -import { inferenceModelsList, brainChopOpts } from "./brainchop-parameters.js" -import { isChrome, localSystemDetails } from "./brainchop-telemetry.js" -import MyWorker from "./brainchop-webworker.js?worker" +import { inferenceModelsList, brainChopOpts } from "./brainchop-parameters.js"; +import { isChrome, localSystemDetails } from "./brainchop-telemetry.js"; +import MyWorker from "./brainchop-webworker.js?worker"; +import { antiAliasCuberille } from "@itk-wasm/cuberille"; +import { nii2iwi, iwm2meshCore } from "@niivue/cbor-loader"; async function main() { - const niimath = new Niimath() - await niimath.init() + const niimath = new Niimath(); + await niimath.init(); // const wrapper = await NiiMathWrapper.load() /*smoothCheck.onchange = function () { nv1.setInterpolation(!smoothCheck.checked) }*/ aboutBtn.onclick = function () { const url = "https://github.com/niivue/brain2print"; - window.open(url, '_blank'); - } + window.open(url, "_blank"); + }; /*diagnosticsBtn.onclick = function () { if (diagnosticsString.length < 1) { window.alert('No diagnostic string generated: run a model to create diagnostics') @@ -25,278 +27,312 @@ async function main() { window.alert('Diagnostics copied to clipboard\n' + diagnosticsString) }*/ opacitySlider0.oninput = function () { - nv1.setOpacity(0, opacitySlider0.value / 255) - nv1.updateGLVolume() - } + nv1.setOpacity(0, opacitySlider0.value / 255); + nv1.updateGLVolume(); + }; opacitySlider1.oninput = function () { - if (nv1.volumes.length < 2) return - nv1.setOpacity(1, opacitySlider1.value / 255) - } + if (nv1.volumes.length < 2) return; + nv1.setOpacity(1, opacitySlider1.value / 255); + }; async function ensureConformed() { - let nii = nv1.volumes[0] - let isConformed = ((nii.dims[1] === 256) && (nii.dims[2] === 256) && (nii.dims[3] === 256)) - if ((nii.permRAS[0] !== -1) || (nii.permRAS[1] !== 3) || (nii.permRAS[2] !== -2)) - isConformed = false - if (isConformed) - return - let nii2 = await nv1.conform(nii, false) - await nv1.removeVolume(nv1.volumes[0]) - await nv1.addVolume(nii2) + let nii = nv1.volumes[0]; + let isConformed = + nii.dims[1] === 256 && nii.dims[2] === 256 && nii.dims[3] === 256; + if (nii.permRAS[0] !== -1 || nii.permRAS[1] !== 3 || nii.permRAS[2] !== -2) + isConformed = false; + if (isConformed) return; + let nii2 = await nv1.conform(nii, false); + await nv1.removeVolume(nv1.volumes[0]); + await nv1.addVolume(nii2); } async function closeAllOverlays() { while (nv1.volumes.length > 1) { - await nv1.removeVolume(nv1.volumes[1]) + await nv1.removeVolume(nv1.volumes[1]); } } modelSelect.onchange = async function () { - if (this.selectedIndex < 0) - modelSelect.selectedIndex = 11 - await closeAllOverlays() - await ensureConformed() - let model = inferenceModelsList[this.selectedIndex] - model.isNvidia = false - const rendererInfo = nv1.gl.getExtension('WEBGL_debug_renderer_info') + if (this.selectedIndex < 0) modelSelect.selectedIndex = 11; + await closeAllOverlays(); + await ensureConformed(); + let model = inferenceModelsList[this.selectedIndex]; + model.isNvidia = false; + const rendererInfo = nv1.gl.getExtension("WEBGL_debug_renderer_info"); if (rendererInfo) { - model.isNvidia = nv1.gl.getParameter(rendererInfo.UNMASKED_RENDERER_WEBGL).includes('NVIDIA') - + model.isNvidia = nv1.gl + .getParameter(rendererInfo.UNMASKED_RENDERER_WEBGL) + .includes("NVIDIA"); } - - let opts = brainChopOpts - opts.rootURL = location.href + + let opts = brainChopOpts; + opts.rootURL = location.href; const isLocalhost = Boolean( - window.location.hostname === 'localhost' || - // [::1] is the IPv6 localhost address. - window.location.hostname === '[::1]' || - // 127.0.0.1/8 is considered localhost for IPv4. - window.location.hostname.match( + window.location.hostname === "localhost" || + // [::1] is the IPv6 localhost address. + window.location.hostname === "[::1]" || + // 127.0.0.1/8 is considered localhost for IPv4. + window.location.hostname.match( /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ - ) - ) - if (isLocalhost) - opts.rootURL = location.protocol + '//' + location.host + ) + ); + if (isLocalhost) opts.rootURL = location.protocol + "//" + location.host; if (workerCheck.checked) { - if(typeof(chopWorker) !== "undefined") { - console.log('Unable to start new segmentation: previous call has not completed') - return + if (typeof chopWorker !== "undefined") { + console.log( + "Unable to start new segmentation: previous call has not completed" + ); + return; } - chopWorker = await new MyWorker({ type: "module" }) - let hdr = {datatypeCode: nv1.volumes[0].hdr.datatypeCode, dims: nv1.volumes[0].hdr.dims} - let msg = {opts:opts, modelEntry: model, niftiHeader: hdr, niftiImage: nv1.volumes[0].img} - chopWorker.postMessage(msg) - chopWorker.onmessage = function(event) { - let cmd = event.data.cmd - if (cmd === 'ui') { - if (event.data.modalMessage !== "") { - chopWorker.terminate() - chopWorker = undefined - } - callbackUI(event.data.message, event.data.progressFrac, event.data.modalMessage, event.data.statData) + chopWorker = await new MyWorker({ type: "module" }); + let hdr = { + datatypeCode: nv1.volumes[0].hdr.datatypeCode, + dims: nv1.volumes[0].hdr.dims, + }; + let msg = { + opts: opts, + modelEntry: model, + niftiHeader: hdr, + niftiImage: nv1.volumes[0].img, + }; + chopWorker.postMessage(msg); + chopWorker.onmessage = function (event) { + let cmd = event.data.cmd; + if (cmd === "ui") { + if (event.data.modalMessage !== "") { + chopWorker.terminate(); + chopWorker = undefined; + } + callbackUI( + event.data.message, + event.data.progressFrac, + event.data.modalMessage, + event.data.statData + ); } - if (cmd === 'img') { - chopWorker.terminate() - chopWorker = undefined - callbackImg(event.data.img, event.data.opts, event.data.modelEntry) + if (cmd === "img") { + chopWorker.terminate(); + chopWorker = undefined; + callbackImg(event.data.img, event.data.opts, event.data.modelEntry); } - } + }; } else { - console.log('Only provided with webworker code, see main brainchop github repository for main thread code') + console.log( + "Only provided with webworker code, see main brainchop github repository for main thread code" + ); // runInference(opts, model, nv1.volumes[0].hdr, nv1.volumes[0].img, callbackImg, callbackUI) } - } + }; saveBtn.onclick = function () { - nv1.volumes[1].saveToDisk("Custom.nii") - } + nv1.volumes[1].saveToDisk("Custom.nii"); + }; workerCheck.onchange = function () { - modelSelect.onchange() - } + modelSelect.onchange(); + }; clipCheck.onchange = function () { if (clipCheck.checked) { - nv1.setClipPlane([0, 0, 90]) + nv1.setClipPlane([0, 0, 90]); } else { - nv1.setClipPlane([2, 0, 90]) + nv1.setClipPlane([2, 0, 90]); } - } + }; function doLoadImage() { - opacitySlider0.oninput() + opacitySlider0.oninput(); } async function fetchJSON(fnm) { - const response = await fetch(fnm) - const js = await response.json() - return js + const response = await fetch(fnm); + const js = await response.json(); + return js; } async function callbackImg(img, opts, modelEntry) { - closeAllOverlays() - let overlayVolume = await nv1.volumes[0].clone() - overlayVolume.zeroImage() - overlayVolume.hdr.scl_inter = 0 - overlayVolume.hdr.scl_slope = 1 - overlayVolume.img = new Uint8Array(img) + closeAllOverlays(); + let overlayVolume = await nv1.volumes[0].clone(); + overlayVolume.zeroImage(); + overlayVolume.hdr.scl_inter = 0; + overlayVolume.hdr.scl_slope = 1; + overlayVolume.img = new Uint8Array(img); if (modelEntry.colormapPath) { - let cmap = await fetchJSON(modelEntry.colormapPath) - overlayVolume.setColormapLabel(cmap) + let cmap = await fetchJSON(modelEntry.colormapPath); + overlayVolume.setColormapLabel(cmap); // n.b. most models create indexed labels, but those without colormap mask scalar input - overlayVolume.hdr.intent_code = 1002 // NIFTI_INTENT_LABEL + overlayVolume.hdr.intent_code = 1002; // NIFTI_INTENT_LABEL } else { - let colormap = opts.atlasSelectedColorTable.toLowerCase() - const cmaps = nv1.colormaps() + let colormap = opts.atlasSelectedColorTable.toLowerCase(); + const cmaps = nv1.colormaps(); if (!cmaps.includes(colormap)) { - colormap = 'actc' + colormap = "actc"; } - overlayVolume.colormap = colormap + overlayVolume.colormap = colormap; } - overlayVolume.opacity = opacitySlider1.value / 255 - await nv1.addVolume(overlayVolume) + overlayVolume.opacity = opacitySlider1.value / 255; + await nv1.addVolume(overlayVolume); } async function reportTelemetry(statData) { - if (typeof statData === 'string' || statData instanceof String) { + if (typeof statData === "string" || statData instanceof String) { function strToArray(str) { - const list = JSON.parse(str) - const array = [] + const list = JSON.parse(str); + const array = []; for (const key in list) { - array[key] = list[key] + array[key] = list[key]; } - return array + return array; } - statData = strToArray(statData) + statData = strToArray(statData); } - statData = await localSystemDetails(statData, nv1.gl) - diagnosticsString = ':: Diagnostics can help resolve issues https://github.com/neuroneural/brainchop/issues ::\n' - for (var key in statData){ - diagnosticsString += key + ': ' + statData[key]+'\n' + statData = await localSystemDetails(statData, nv1.gl); + diagnosticsString = + ":: Diagnostics can help resolve issues https://github.com/neuroneural/brainchop/issues ::\n"; + for (var key in statData) { + diagnosticsString += key + ": " + statData[key] + "\n"; } } - function callbackUI(message = "", progressFrac = -1, modalMessage = "", statData = []) { + function callbackUI( + message = "", + progressFrac = -1, + modalMessage = "", + statData = [] + ) { if (message !== "") { - console.log(message) - document.getElementById("location").innerHTML = message + console.log(message); + document.getElementById("location").innerHTML = message; } - if (isNaN(progressFrac)) { //memory issue - memstatus.style.color = "red" - memstatus.innerHTML = "Memory Issue" + if (isNaN(progressFrac)) { + //memory issue + memstatus.style.color = "red"; + memstatus.innerHTML = "Memory Issue"; } else if (progressFrac >= 0) { - modelProgress.value = progressFrac * modelProgress.max + modelProgress.value = progressFrac * modelProgress.max; } if (modalMessage !== "") { - window.alert(modalMessage) + window.alert(modalMessage); } if (Object.keys(statData).length > 0) { - reportTelemetry(statData) + reportTelemetry(statData); } } function handleLocationChange(data) { - document.getElementById("location").innerHTML = "  " + data.string + document.getElementById("location").innerHTML = + "  " + data.string; } let defaults = { backColor: [0.4, 0.4, 0.4, 1], show3Dcrosshair: true, onLocationChange: handleLocationChange, - } + }; createMeshBtn.onclick = function () { - if (nv1.meshes.length > 0) - nv1.removeMesh(nv1.meshes[0]) + if (nv1.meshes.length > 0) nv1.removeMesh(nv1.meshes[0]); if (nv1.volumes.length < 1) { - window.alert("Image not loaded. Drag and drop an image.") + window.alert("Image not loaded. Drag and drop an image."); } else { - remeshDialog.show() + remeshDialog.show(); } - } + }; applyBtn.onclick = async function () { - const niiBuffer = await nv1.saveImage({volumeByIndex: nv1.volumes.length - 1}).buffer - const niiBlob = new Blob([niiBuffer], { type: 'application/octet-stream' }) - const niiFile = new File([niiBlob], 'input.nii') + const niiBuffer = await nv1.saveImage({ + volumeByIndex: nv1.volumes.length - 1, + }).buffer; + const niiBlob = new Blob([niiBuffer], { type: "application/octet-stream" }); + const niiFile = new File([niiBlob], "input.nii"); // get an ImageProcessor instance from niimath // so we can build up the operations we want to perform // based on the UI controls - let image = niimath.image(niiFile) - loadingCircle.classList.remove('hidden') - // initialize the operations object for the niimath mesh function - let ops = { - i: 0.5, - } - //const largestCheckValue = largestCheck.checked - if (largestCheck.checked) { - ops.l = 1 - } - let reduce = Math.min(Math.max(Number(shrinkPct.value) / 100, 0.01), 1) - ops.r = reduce - let smooth = parseFloat(smoothSlide.value) - ops.s = smooth - if (bubbleCheck.checked) { - ops.b = 1 - } + // let image = niimath.image(niiFile); + // loadingCircle.classList.remove("hidden"); + // // initialize the operations object for the niimath mesh function + // let ops = { + // i: 0.5, + // }; + // //const largestCheckValue = largestCheck.checked + // if (largestCheck.checked) { + // ops.l = 1; + // } + // let reduce = Math.min(Math.max(Number(shrinkPct.value) / 100, 0.01), 1); + // ops.r = reduce; + // let smooth = parseFloat(smoothSlide.value); + // ops.s = smooth; + // if (bubbleCheck.checked) { + // ops.b = 1; + // } - let hollowInt = Number(hollowSelect.value ) - if (hollowInt < 0){ - // append the hollow operation to the image processor - // but dont run it yet. - image = image.hollow(0.5, hollowInt) - } + // let hollowInt = Number(hollowSelect.value); + // if (hollowInt < 0) { + // // append the hollow operation to the image processor + // // but dont run it yet. + // image = image.hollow(0.5, hollowInt); + // } + + // let closeFloat = Number(closeMM.value); + // if (isFinite(closeFloat) && closeFloat > 0) { + // // append the close operation to the image processor + // // but dont run it yet. + // image = image.close(0.5, closeFloat, 2 * closeFloat); + // } + // // add the mesh operations + // image = image.mesh(ops); + // console.log("niimath mesh operation", image.commands); + const hdr = nv1.volumes[1].hdr; + const img = nv1.volumes[1].img; + + const itkImage = nii2iwi(hdr, img, false); + itkImage.size = itkImage.size.map(Number); + const { mesh } = await antiAliasCuberille(itkImage); + + const niiMesh = iwm2meshCore(mesh); + console.log(niiMesh); + console.log(nv1); - let closeFloat = Number(closeMM.value) - if ((isFinite(closeFloat)) && (closeFloat > 0)){ - // append the close operation to the image processor - // but dont run it yet. - image = image.close(0.5, closeFloat, 2 * closeFloat) - } - // add the mesh operations - image = image.mesh(ops) - console.log('niimath mesh operation', image.commands) // finally, run the full set of operations - const outFile = await image.run('output.mz3') - const arrayBuffer = await outFile.arrayBuffer() - loadingCircle.classList.add('hidden') - if (nv1.meshes.length > 0) - nv1.removeMesh(nv1.meshes[0]) - await nv1.loadFromArrayBuffer(arrayBuffer, 'output.mz3') - nv1.reverseFaces(0) - } + // const outFile = await image.run("output.mz3"); + // const outFile = await image.run("output.nii"); + // const arrayBuffer = await outFile.arrayBuffer(); + loadingCircle.classList.add("hidden"); + if (nv1.meshes.length > 0) nv1.removeMesh(nv1.meshes[0]); + // await nv1.loadFromArrayBuffer(arrayBuffer, "output.mz3"); + // nv1.reverseFaces(0); + }; saveMeshBtn.onclick = function () { if (nv1.meshes.length < 1) { - window.alert("No mesh open for saving. Use 'Create Mesh'.") + window.alert("No mesh open for saving. Use 'Create Mesh'."); } else { - saveDialog.show() + saveDialog.show(); } - } + }; applySaveBtn.onclick = function () { if (nv1.meshes.length < 1) { - return + return; } - let format = 'obj' + let format = "obj"; if (formatSelect.selectedIndex === 0) { - format = 'mz3' + format = "mz3"; } if (formatSelect.selectedIndex === 2) { - format = 'stl' + format = "stl"; } - const scale = 1 / Number(scaleSelect.value) - const pts = nv1.meshes[0].pts.slice() - for (let i = 0; i < pts.length; i++) - pts[i] *= scale; - NVMeshUtilities.saveMesh(pts, nv1.meshes[0].tris, `mesh.${format}`, true) - } + const scale = 1 / Number(scaleSelect.value); + const pts = nv1.meshes[0].pts.slice(); + for (let i = 0; i < pts.length; i++) pts[i] *= scale; + NVMeshUtilities.saveMesh(pts, nv1.meshes[0].tris, `mesh.${format}`, true); + }; - var diagnosticsString = '' - var chopWorker - let nv1 = new Niivue(defaults) - nv1.attachToCanvas(gl1) - nv1.opts.dragMode = nv1.dragModes.pan - nv1.opts.multiplanarForceRender = true - nv1.opts.yoke3Dto2DZoom = true - nv1.opts.crosshairGap = 11 - await nv1.loadVolumes([{ url: "./t1_crop.nii.gz" }]) + var diagnosticsString = ""; + var chopWorker; + let nv1 = new Niivue(defaults); + nv1.attachToCanvas(gl1); + nv1.opts.dragMode = nv1.dragModes.pan; + nv1.opts.multiplanarForceRender = true; + nv1.opts.yoke3Dto2DZoom = true; + nv1.opts.crosshairGap = 11; + await nv1.loadVolumes([{ url: "./t1_crop.nii.gz" }]); for (let i = 0; i < inferenceModelsList.length; i++) { - var option = document.createElement("option") - option.text = inferenceModelsList[i].modelName - option.value = inferenceModelsList[i].id.toString() - modelSelect.appendChild(option) + var option = document.createElement("option"); + option.text = inferenceModelsList[i].modelName; + option.value = inferenceModelsList[i].id.toString(); + modelSelect.appendChild(option); } - nv1.onImageLoaded = doLoadImage - modelSelect.selectedIndex = -1 - workerCheck.checked = await isChrome() //TODO: Safari does not yet support WebGL TFJS webworkers, test FireFox + nv1.onImageLoaded = doLoadImage; + modelSelect.selectedIndex = -1; + workerCheck.checked = await isChrome(); //TODO: Safari does not yet support WebGL TFJS webworkers, test FireFox // uncomment next two lines to automatically run segmentation when web page is loaded // modelSelect.selectedIndex = 11 // modelSelect.onchange() - } -main() +main(); diff --git a/package-lock.json b/package-lock.json index 8b3f78a..da662dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,8 @@ "name": "niivue-brainchop", "version": "0.1.0", "dependencies": { + "@itk-wasm/cuberille": "^0.1.0", + "@niivue/cbor-loader": "^1.0.0", "@niivue/niimath": "^0.1.1", "@niivue/niivue": "^0.44.2", "@tensorflow/tfjs": "^4.19.0", @@ -17,6 +19,78 @@ "vite": "^5.4.2" } }, + "node_modules/@cbor-extract/cbor-extract-darwin-arm64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-darwin-arm64/-/cbor-extract-darwin-arm64-2.2.0.tgz", + "integrity": "sha512-P7swiOAdF7aSi0H+tHtHtr6zrpF3aAq/W9FXx5HektRvLTM2O89xCyXF3pk7pLc7QpaY7AoaE8UowVf9QBdh3w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@cbor-extract/cbor-extract-darwin-x64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-darwin-x64/-/cbor-extract-darwin-x64-2.2.0.tgz", + "integrity": "sha512-1liF6fgowph0JxBbYnAS7ZlqNYLf000Qnj4KjqPNW4GViKrEql2MgZnAsExhY9LSy8dnvA4C0qHEBgPrll0z0w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@cbor-extract/cbor-extract-linux-arm": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-arm/-/cbor-extract-linux-arm-2.2.0.tgz", + "integrity": "sha512-QeBcBXk964zOytiedMPQNZr7sg0TNavZeuUCD6ON4vEOU/25+pLhNN6EDIKJ9VLTKaZ7K7EaAriyYQ1NQ05s/Q==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@cbor-extract/cbor-extract-linux-arm64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-arm64/-/cbor-extract-linux-arm64-2.2.0.tgz", + "integrity": "sha512-rQvhNmDuhjTVXSPFLolmQ47/ydGOFXtbR7+wgkSY0bdOxCFept1hvg59uiLPT2fVDuJFuEy16EImo5tE2x3RsQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@cbor-extract/cbor-extract-linux-x64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-x64/-/cbor-extract-linux-x64-2.2.0.tgz", + "integrity": "sha512-cWLAWtT3kNLHSvP4RKDzSTX9o0wvQEEAj4SKvhWuOVZxiDAeQazr9A+PSiRILK1VYMLeDml89ohxCnUNQNQNCw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@cbor-extract/cbor-extract-win32-x64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-win32-x64/-/cbor-extract-win32-x64-2.2.0.tgz", + "integrity": "sha512-l2M+Z8DO2vbvADOBNLbbh9y5ST1RY5sqkWOg/58GkUPBYou/cuNZ68SGQ644f1CvZ8kcOxyZtw06+dxWHIoN/w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", @@ -408,6 +482,105 @@ "node": ">=12" } }, + "node_modules/@ipld/car": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@ipld/car/-/car-5.3.3.tgz", + "integrity": "sha512-4vgV5Ml4HCJ2iTx7vYhu0ui+Xxo1HQTtVeYgD+JKd5Wij8TlOFZnxOSickqpLcuf1fdGEStgqVItx15UWfzDYA==", + "dependencies": { + "@ipld/dag-cbor": "^9.0.7", + "cborg": "^4.0.5", + "multiformats": "^13.0.0", + "varint": "^6.0.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@ipld/dag-cbor": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@ipld/dag-cbor/-/dag-cbor-9.2.2.tgz", + "integrity": "sha512-uIEOuruCqKTP50OBWwgz4Js2+LhiBQaxc57cnP71f45b1mHEAo1OCR1Zn/TbvSW/mV1x+JqhacIktkKyaYqhCw==", + "dependencies": { + "cborg": "^4.0.0", + "multiformats": "^13.1.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@ipld/dag-json": { + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/@ipld/dag-json/-/dag-json-10.2.3.tgz", + "integrity": "sha512-itacv1j1hvYgLox2B42Msn70QLzcr0MEo5yGIENuw2SM/lQzq9bmBiMky+kDsIrsqqblKTXcHBZnnmK7D4a6ZQ==", + "dependencies": { + "cborg": "^4.0.0", + "multiformats": "^13.1.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@ipld/dag-pb": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@ipld/dag-pb/-/dag-pb-4.1.3.tgz", + "integrity": "sha512-ueULCaaSCcD+dQga6nKiRr+RSeVgdiYiEPKVUu5iQMNYDN+9osd0KpR3UDd9uQQ+6RWuv9L34SchfEwj7YIbOA==", + "dependencies": { + "multiformats": "^13.1.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@ipld/unixfs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@ipld/unixfs/-/unixfs-3.0.0.tgz", + "integrity": "sha512-Tj3/BPOlnemcZQ2ETIZAO8hqAs9KNzWyX5J9+JCL9jDwvYwjxeYjqJ3v+9DusNvTBmJhZnGVP6ijUHrsuOLp+g==", + "dependencies": { + "@ipld/dag-pb": "^4.0.0", + "@multiformats/murmur3": "^2.1.3", + "@perma/map": "^1.0.2", + "actor": "^2.3.1", + "multiformats": "^13.0.1", + "protobufjs": "^7.1.2", + "rabin-rs": "^2.1.0" + } + }, + "node_modules/@itk-wasm/cuberille": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@itk-wasm/cuberille/-/cuberille-0.1.0.tgz", + "integrity": "sha512-ftbGcnMkEBmIDO2s95AJFXEL9DwnR0XtaH0I0+mAdHo/JggNw5/gKbViGod7TDwm+9Y+ZRXqBaCjGc6372bgWw==", + "dependencies": { + "itk-wasm": "1.0.0-b.184" + } + }, + "node_modules/@itk-wasm/dam": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@itk-wasm/dam/-/dam-1.1.1.tgz", + "integrity": "sha512-7+9L3lrLMKF4y6B6qjs8GqfbpxT0waOJUM14NdMNEA6M+BoBS8fdHREhQHo2s7QMA5O7I+Jv7m+dyqlisGnbdQ==", + "dependencies": { + "axios": "^1.4.0", + "commander": "^10.0.1", + "decompress": "^4.2.1", + "files-from-path": "^1.0.0", + "ipfs-car": "^1.0.0", + "tar": "^6.1.13" + }, + "bin": { + "dam": "cli.js" + } + }, + "node_modules/@itk-wasm/dam/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "engines": { + "node": ">=14" + } + }, "node_modules/@lukeed/csprng": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", @@ -427,6 +600,56 @@ "node": ">=8" } }, + "node_modules/@multiformats/blake2": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@multiformats/blake2/-/blake2-1.0.13.tgz", + "integrity": "sha512-T1Kzya0wjj85CaVeRSpJ858EnSvW1pw94GSitxYf84VsNdv5XYbJ6QG8y26Ft1bVALzrUCmqkQrR53QHSyu6RA==", + "dependencies": { + "blakejs": "^1.1.1", + "multiformats": "^9.5.4" + } + }, + "node_modules/@multiformats/blake2/node_modules/multiformats": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==" + }, + "node_modules/@multiformats/murmur3": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@multiformats/murmur3/-/murmur3-2.1.8.tgz", + "integrity": "sha512-6vId1C46ra3R1sbJUOFCZnsUIveR9oF20yhPmAFxPm0JfrX3/ZRCgP3YDrBzlGoEppOXnA9czHeYc0T9mB6hbA==", + "dependencies": { + "multiformats": "^13.0.0", + "murmurhash3js-revisited": "^3.0.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@multiformats/sha3": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@multiformats/sha3/-/sha3-2.0.17.tgz", + "integrity": "sha512-7ik6pk178qLO2cpNucgf48UnAOBMkq/2H92DP4SprZOJqM9zqbVaKS7XyYW6UvhRsDJ3wi921fYv1ihTtQHLtA==", + "dependencies": { + "js-sha3": "^0.8.0", + "multiformats": "^9.5.4" + } + }, + "node_modules/@multiformats/sha3/node_modules/multiformats": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==" + }, + "node_modules/@niivue/cbor-loader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@niivue/cbor-loader/-/cbor-loader-1.0.0.tgz", + "integrity": "sha512-56YWElTO6NT8EFa9KQ6TlMq393D8hLAAecAS9ACa3MKFd50UkY70eUn0k7P/Vyv4itQin7D6b2ZUaJ4dhK5kUg==", + "dependencies": { + "cbor-x": "^1.6.0", + "nifti-reader-js": "^0.6.8" + } + }, "node_modules/@niivue/niimath": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@niivue/niimath/-/niimath-0.1.1.tgz", @@ -452,6 +675,69 @@ "@rollup/rollup-linux-x64-gnu": "^4.18.1" } }, + "node_modules/@perma/map": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@perma/map/-/map-1.0.3.tgz", + "integrity": "sha512-Bf5njk0fnJGTFE2ETntq0N1oJ6YdCPIpTDn3R3KYZJQdeYSOCNL7mBrFlGnbqav8YQhJA/p81pvHINX9vAtHkQ==", + "dependencies": { + "@multiformats/murmur3": "^2.1.0", + "murmurhash3js-revisited": "^3.0.0" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.21.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.0.tgz", @@ -780,6 +1066,16 @@ "@tensorflow/tfjs-core": "4.19.0" } }, + "node_modules/@thewtex/zstddec": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@thewtex/zstddec/-/zstddec-0.2.1.tgz", + "integrity": "sha512-1yTu7m/qU1nsJy4mCZAB3GAhczsClhw+WIXK0oe598eHcvefH16WLOYN4Uko7K2/Ttz9KEBvvT7WFrZD41ShgA==" + }, + "node_modules/@types/emscripten": { + "version": "1.39.13", + "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.39.13.tgz", + "integrity": "sha512-cFq+fO/isvhvmuP/+Sl4K4jtU6E23DoivtbO4r50e3odaxAiVdbfSYRDdJ4gCdxx+3aRjhphS5ZMwIH4hFy/Cw==" + }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", @@ -832,11 +1128,42 @@ "node": ">=10" } }, + "node_modules/@web3-storage/car-block-validator": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@web3-storage/car-block-validator/-/car-block-validator-1.2.0.tgz", + "integrity": "sha512-KKQ/M5WtpH/JlkX+bQYKzdG4azmSF495T7vpewje2xh7MBh1d94/BLblxCcLM/larWvXDxOkbAyTTdlECAAuUw==", + "dependencies": { + "@multiformats/blake2": "^1.0.13", + "@multiformats/murmur3": "^1.1.3", + "@multiformats/sha3": "^2.0.15", + "multiformats": "9.9.0", + "uint8arrays": "^3.1.1" + } + }, + "node_modules/@web3-storage/car-block-validator/node_modules/@multiformats/murmur3": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@multiformats/murmur3/-/murmur3-1.1.3.tgz", + "integrity": "sha512-wAPLUErGR8g6Lt+bAZn6218k9YQPym+sjszsXL6o4zfxbA22P+gxWZuuD9wDbwL55xrKO5idpcuQUX7/E3oHcw==", + "dependencies": { + "multiformats": "^9.5.4", + "murmurhash3js-revisited": "^3.0.0" + } + }, + "node_modules/@web3-storage/car-block-validator/node_modules/multiformats": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==" + }, "node_modules/@webgpu/types": { "version": "0.1.38", "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.38.tgz", "integrity": "sha512-7LrhVKz2PRh+DD7+S+PVaFd5HxaWQvoMqBbsV9fNJO1pjUs1P8bM2vQVNfk+3URTqbuTI7gkXi0rfsN0IadoBA==" }, + "node_modules/actor": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/actor/-/actor-2.3.1.tgz", + "integrity": "sha512-ST/3wnvcP2tKDXnum7nLCLXm+/rsf8vPocXH2Fre6D8FQwNkGDd4JEitBlXj007VQJfiGYRQvXqwOBZVi+JtRg==" + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -880,6 +1207,149 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, + "node_modules/axios": { + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.8.tgz", + "integrity": "sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bl": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", + "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", + "dependencies": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dependencies": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "node_modules/buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==" + }, + "node_modules/cbor-extract": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cbor-extract/-/cbor-extract-2.2.0.tgz", + "integrity": "sha512-Ig1zM66BjLfTXpNgKpvBePq271BPOvu8MR0Jl080yG7Jsl+wAZunfrwiwA+9ruzm/WEdIV5QF/bjDZTqyAIVHA==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.1.1" + }, + "bin": { + "download-cbor-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@cbor-extract/cbor-extract-darwin-arm64": "2.2.0", + "@cbor-extract/cbor-extract-darwin-x64": "2.2.0", + "@cbor-extract/cbor-extract-linux-arm": "2.2.0", + "@cbor-extract/cbor-extract-linux-arm64": "2.2.0", + "@cbor-extract/cbor-extract-linux-x64": "2.2.0", + "@cbor-extract/cbor-extract-win32-x64": "2.2.0" + } + }, + "node_modules/cbor-x": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/cbor-x/-/cbor-x-1.6.0.tgz", + "integrity": "sha512-0kareyRwHSkL6ws5VXHEf8uY1liitysCVJjlmhaLG+IXLqhSaOO+t63coaso7yjwEzWZzLy8fJo06gZDVQM9Qg==", + "optionalDependencies": { + "cbor-extract": "^2.2.0" + } + }, + "node_modules/cborg": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/cborg/-/cborg-4.2.6.tgz", + "integrity": "sha512-77vo4KlSwfjCIXcyZUVei4l2gdjesSCeYSx4U/Upwix7pcWZq8uw21sVRpjwn7mjEi//ieJPTj1MRWDHmud1Rg==", + "bin": { + "cborg": "lib/bin.js" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -895,6 +1365,14 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -932,6 +1410,11 @@ "node": ">= 0.8" } }, + "node_modules/comlink": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/comlink/-/comlink-4.4.2.tgz", + "integrity": "sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g==" + }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -947,6 +1430,11 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, "node_modules/cssfilter": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz", @@ -964,6 +1452,95 @@ "xss": "1.0.14" } }, + "node_modules/decompress": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz", + "integrity": "sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ==", + "dependencies": { + "decompress-tar": "^4.0.0", + "decompress-tarbz2": "^4.0.0", + "decompress-targz": "^4.0.0", + "decompress-unzip": "^4.0.1", + "graceful-fs": "^4.1.10", + "make-dir": "^1.0.0", + "pify": "^2.3.0", + "strip-dirs": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress-tar": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", + "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", + "dependencies": { + "file-type": "^5.2.0", + "is-stream": "^1.1.0", + "tar-stream": "^1.5.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress-tarbz2": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", + "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", + "dependencies": { + "decompress-tar": "^4.1.0", + "file-type": "^6.1.0", + "is-stream": "^1.1.0", + "seek-bzip": "^1.0.5", + "unbzip2-stream": "^1.0.9" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress-tarbz2/node_modules/file-type": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", + "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress-targz": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", + "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", + "dependencies": { + "decompress-tar": "^4.1.1", + "file-type": "^5.2.0", + "is-stream": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress-unzip": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", + "integrity": "sha512-1fqeluvxgnn86MOh66u8FjbtJpAFv5wgCT9Iw8rcBqQcCo5tO8eiJw7NNTrvt9n4CRBVq7CstiS922oPgyGLrw==", + "dependencies": { + "file-type": "^3.8.0", + "get-stream": "^2.2.0", + "pify": "^2.3.0", + "yauzl": "^2.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress-unzip/node_modules/file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -972,11 +1549,28 @@ "node": ">=0.4.0" } }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/esbuild": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", @@ -1024,11 +1618,62 @@ "node": ">=6" } }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dependencies": { + "pend": "~1.2.0" + } + }, "node_modules/fflate": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==" }, + "node_modules/file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/files-from-path": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/files-from-path/-/files-from-path-1.1.1.tgz", + "integrity": "sha512-M2JDH/0gHqIsdwTnp8IBMWEYUUiHe9ei0ZMTXLxqKFcGxJF4Ki+nicw2k8HP5KGEzPLTyJ81XwLmP8l8rKa6qg==", + "dependencies": { + "graceful-fs": "^4.2.10" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -1042,6 +1687,51 @@ "node": ">= 6" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1065,11 +1755,64 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "integrity": "sha512-AUGhbbemXxrZJRD5cDvKtQxLuYaIbNtDTK8YqupCI393Q2KSTreEsLUN3ZxAWFGiKTzL6nKuzfcIvieflUX9qA==", + "dependencies": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/gl-matrix": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==" }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/hamt-sharding": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/hamt-sharding/-/hamt-sharding-3.0.6.tgz", + "integrity": "sha512-nZeamxfymIWLpVcAN0CRrb7uVq3hCOGj9IcL6NMA6VVCVWqj+h9Jo/SmaWuS92AEDf1thmHsM5D5c70hM3j2Tg==", + "dependencies": { + "sparse-array": "^1.3.1", + "uint8arrays": "^5.0.1" + } + }, + "node_modules/hamt-sharding/node_modules/uint8arrays": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.1.0.tgz", + "integrity": "sha512-vA6nFepEmlSKkMBnLBaUMVvAC4G3CTmO58C12y4sq6WPDOR7mOFYOi7GlrQ4djeSbP6JG9Pv9tJDM97PedRSww==", + "dependencies": { + "multiformats": "^13.0.0" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -1078,6 +1821,111 @@ "node": ">=8" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/interface-blockstore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/interface-blockstore/-/interface-blockstore-5.3.1.tgz", + "integrity": "sha512-nhgrQnz6yUQEqxTFLhlOBurQOy5lWlwCpgFmZ3GTObTVTQS9RZjK/JTozY6ty9uz2lZs7VFJSqwjWAltorJ4Vw==", + "dependencies": { + "interface-store": "^6.0.0", + "multiformats": "^13.2.3" + } + }, + "node_modules/interface-store": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/interface-store/-/interface-store-6.0.2.tgz", + "integrity": "sha512-KSFCXtBlNoG0hzwNa0RmhHtrdhzexp+S+UY2s0rWTBJyfdEIgn6i6Zl9otVqrcFYbYrneBT7hbmHQ8gE0C3umA==" + }, + "node_modules/ipfs-car": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ipfs-car/-/ipfs-car-1.2.0.tgz", + "integrity": "sha512-A++1UesxqwfNv14NmFxr4MHi+vD9rR6SWr87MU9o0315Mzqys48pEefL8rlCAA9cw2qKYeT/ZPYVtqIMAr6U1Q==", + "dependencies": { + "@ipld/car": "^5.1.0", + "@ipld/dag-cbor": "^9.0.0", + "@ipld/dag-json": "^10.0.1", + "@ipld/dag-pb": "^4.0.2", + "@ipld/unixfs": "^3.0.0", + "@web3-storage/car-block-validator": "^1.0.1", + "files-from-path": "^1.0.0", + "ipfs-unixfs-exporter": "^13.0.1", + "multiformats": "^13.0.1", + "sade": "^1.8.1", + "varint": "^6.0.0" + }, + "bin": { + "🚘": "bin.js", + "ipfs-car": "bin.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/ipfs-unixfs": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/ipfs-unixfs/-/ipfs-unixfs-11.2.0.tgz", + "integrity": "sha512-J8FN1qM5nfrDo8sQKQwfj0+brTg1uBfZK2vY9hxci33lcl3BFrsELS9+1+4q/8tO1ASKfxZO8W3Pi2O4sVX2Lg==", + "dependencies": { + "protons-runtime": "^5.5.0", + "uint8arraylist": "^2.4.8" + } + }, + "node_modules/ipfs-unixfs-exporter": { + "version": "13.6.1", + "resolved": "https://registry.npmjs.org/ipfs-unixfs-exporter/-/ipfs-unixfs-exporter-13.6.1.tgz", + "integrity": "sha512-pYPI4oBTWao2//sFzAL0pURyojn79q/u5BuK6L5/nVbVUQVw6DcVP5uB1ySdWlTM2H+0Zlhp9+OL9aJBRIICpg==", + "dependencies": { + "@ipld/dag-cbor": "^9.2.1", + "@ipld/dag-json": "^10.2.2", + "@ipld/dag-pb": "^4.1.2", + "@multiformats/murmur3": "^2.1.8", + "hamt-sharding": "^3.0.6", + "interface-blockstore": "^5.3.0", + "ipfs-unixfs": "^11.0.0", + "it-filter": "^3.1.1", + "it-last": "^3.0.6", + "it-map": "^3.1.1", + "it-parallel": "^3.0.8", + "it-pipe": "^3.0.1", + "it-pushable": "^3.2.3", + "multiformats": "^13.2.3", + "p-queue": "^8.0.1", + "progress-events": "^1.0.1" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -1086,16 +1934,188 @@ "node": ">=8" } }, + "node_modules/is-natural-number": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", + "integrity": "sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ==" + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/it-filter": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/it-filter/-/it-filter-3.1.1.tgz", + "integrity": "sha512-TOXmVuaSkxlLp2hXKoMTra0WMZMKVFxE3vSsbIA+PbADNCBAHhjJ/lM31vBOUTddHMO34Ku++vU8T9PLlBxQtg==", + "dependencies": { + "it-peekable": "^3.0.0" + } + }, + "node_modules/it-last": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/it-last/-/it-last-3.0.6.tgz", + "integrity": "sha512-M4/get95O85u2vWvWQinF8SJUc/RPC5bWTveBTYXvlP2q5TF9Y+QhT3nz+CRCyS2YEc66VJkyl/da6WrJ0wKhw==" + }, + "node_modules/it-map": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/it-map/-/it-map-3.1.1.tgz", + "integrity": "sha512-9bCSwKD1yN1wCOgJ9UOl+46NQtdatosPWzxxUk2NdTLwRPXLh+L7iwCC9QKsbgM60RQxT/nH8bKMqm3H/o8IHQ==", + "dependencies": { + "it-peekable": "^3.0.0" + } + }, + "node_modules/it-merge": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/it-merge/-/it-merge-3.0.5.tgz", + "integrity": "sha512-2l7+mPf85pyRF5pqi0dKcA54E5Jm/2FyY5GsOaN51Ta0ipC7YZ3szuAsH8wOoB6eKY4XsU4k2X+mzPmFBMayEA==", + "dependencies": { + "it-pushable": "^3.2.3" + } + }, + "node_modules/it-parallel": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/it-parallel/-/it-parallel-3.0.8.tgz", + "integrity": "sha512-URLhs6eG4Hdr4OdvgBBPDzOjBeSSmI+Kqex2rv/aAyYClME26RYHirLVhZsZP5M+ZP6M34iRlXk8Wlqtezuqpg==", + "dependencies": { + "p-defer": "^4.0.1" + } + }, + "node_modules/it-peekable": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/it-peekable/-/it-peekable-3.0.5.tgz", + "integrity": "sha512-JWQOGMt6rKiPcY30zUVMR4g6YxkpueTwHVE7CMs/aGqCf4OydM6w+7ZM3PvmO1e0TocjuR4aL8xyZWR46cTqCQ==" + }, + "node_modules/it-pipe": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/it-pipe/-/it-pipe-3.0.1.tgz", + "integrity": "sha512-sIoNrQl1qSRg2seYSBH/3QxWhJFn9PKYvOf/bHdtCBF0bnghey44VyASsWzn5dAx0DCDDABq1hZIuzKmtBZmKA==", + "dependencies": { + "it-merge": "^3.0.0", + "it-pushable": "^3.1.2", + "it-stream-types": "^2.0.1" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/it-pushable": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/it-pushable/-/it-pushable-3.2.3.tgz", + "integrity": "sha512-gzYnXYK8Y5t5b/BnJUr7glfQLO4U5vyb05gPx/TyTw+4Bv1zM9gFk4YsOrnulWefMewlphCjKkakFvj1y99Tcg==", + "dependencies": { + "p-defer": "^4.0.0" + } + }, + "node_modules/it-stream-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/it-stream-types/-/it-stream-types-2.0.2.tgz", + "integrity": "sha512-Rz/DEZ6Byn/r9+/SBCuJhpPATDF9D+dz5pbgSUyBsCDtza6wtNATrz/jz1gDyNanC3XdLboriHnOC925bZRBww==" + }, + "node_modules/itk-wasm": { + "version": "1.0.0-b.184", + "resolved": "https://registry.npmjs.org/itk-wasm/-/itk-wasm-1.0.0-b.184.tgz", + "integrity": "sha512-wmRpOvbG4aPRf51B/VsVj0pZtGmgmI5U8sorYIVW01RQIFqybXoBdHK6AR4d/Wb3MZfFgtWHi++MnpljLORhkg==", + "dependencies": { + "@itk-wasm/dam": "^1.1.1", + "@thewtex/zstddec": "^0.2.1", + "@types/emscripten": "^1.39.10", + "axios": "^1.6.2", + "chalk": "^5.3.0", + "comlink": "^4.4.1", + "commander": "^11.1.0", + "fs-extra": "^11.2.0", + "glob": "^8.1.0", + "markdown-table": "^3.0.3", + "mime-types": "^2.1.35", + "wasm-feature-detect": "^1.6.1" + }, + "bin": { + "itk-wasm": "src/itk-wasm-cli.js" + } + }, + "node_modules/itk-wasm/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/itk-wasm/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "engines": { + "node": ">=16" + } + }, "node_modules/jpeg-lossless-decoder-js": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/jpeg-lossless-decoder-js/-/jpeg-lossless-decoder-js-2.0.7.tgz", "integrity": "sha512-tbZlhFkKmx+JaqVMkq47SKWGuXLkIaV8fTbnhO39dYEnQrSShLGuLCGb0n6ntXjtmk6oAWGiIriWOLwj9od0yQ==" }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" }, + "node_modules/make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/make-dir/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "engines": { + "node": ">=4" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -1115,6 +2135,80 @@ "node": ">= 0.6" } }, + "node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/multiformats": { + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-13.3.1.tgz", + "integrity": "sha512-QxowxTNwJ3r5RMctoGA5p13w5RbRT2QDkoM+yFlqfLiioBp78nhDjnRLvmSBI9+KAqN4VdgOVWM9c0CHd86m3g==" + }, + "node_modules/murmurhash3js-revisited": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/murmurhash3js-revisited/-/murmurhash3js-revisited-3.0.0.tgz", + "integrity": "sha512-/sF3ee6zvScXMb1XFJ8gDsSnY+X8PbOyjIuBhtgis10W2Jx4ZjIhikUCIF9c4gpJxVnQIsPAFrSwTCuAjicP6g==", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -1161,11 +2255,83 @@ } } }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.1.1.tgz", + "integrity": "sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-defer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-4.0.1.tgz", + "integrity": "sha512-Mr5KC5efvAK5VUptYEIopP1bakB85k2IWXaRC0rsh1uwn1L6M0LVml8OIQ4Gudg4oyZakf7FmeRLkMMtZW1i5A==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-queue": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.0.1.tgz", + "integrity": "sha512-NXzu9aQJTAzbBqOt2hwsR63ea7yvxJc0PwN/zobNAudYfb1B7R08SzB4TsLeSbUCuG467NhnoT0oO6w1qRO+BA==", + "dependencies": { + "eventemitter3": "^5.0.1", + "p-timeout": "^6.1.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.3.tgz", + "integrity": "sha512-UJUyfKbwvr/uZSV6btANfb+0t/mOhKV/KXcCUTp8FcQI+v/0d+wXqH4htrW0E4rR6WiEO/EPvUFiV9D5OI4vlw==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/pako": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==" }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" + }, "node_modules/picocolors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", @@ -1173,6 +2339,33 @@ "dev": true, "license": "ISC" }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/postcss": { "version": "8.4.41", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", @@ -1202,6 +2395,99 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/progress-events": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/progress-events/-/progress-events-1.0.1.tgz", + "integrity": "sha512-MOzLIwhpt64KIVN64h1MwdKWiyKFNc/S6BoYKPIVUHFg0/eIEyBulhWCgn678v/4c0ri3FdGuzXymNCv02MUIw==" + }, + "node_modules/protobufjs": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", + "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/protobufjs/node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, + "node_modules/protons-runtime": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-5.5.0.tgz", + "integrity": "sha512-EsALjF9QsrEk6gbCx3lmfHxVN0ah7nG3cY7GySD4xf4g8cr7g543zB88Foh897Sr1RQJ9yDCUsoT1i1H/cVUFA==", + "dependencies": { + "uint8-varint": "^2.0.2", + "uint8arraylist": "^2.4.3", + "uint8arrays": "^5.0.1" + } + }, + "node_modules/protons-runtime/node_modules/uint8arrays": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.1.0.tgz", + "integrity": "sha512-vA6nFepEmlSKkMBnLBaUMVvAC4G3CTmO58C12y4sq6WPDOR7mOFYOi7GlrQ4djeSbP6JG9Pv9tJDM97PedRSww==", + "dependencies": { + "multiformats": "^13.0.0" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/rabin-rs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/rabin-rs/-/rabin-rs-2.1.0.tgz", + "integrity": "sha512-5y72gAXPzIBsAMHcpxZP8eMDuDT98qMP1BqSDHRbHkJJXEgWIN1lA47LxUqzsK6jknOJtgfkQr9v+7qMlFDm6g==" + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/readable-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", @@ -1259,6 +2545,17 @@ "tslib": "^2.1.0" } }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -1283,6 +2580,18 @@ "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" }, + "node_modules/seek-bzip": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz", + "integrity": "sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==", + "dependencies": { + "commander": "^2.8.1" + }, + "bin": { + "seek-bunzip": "bin/seek-bunzip", + "seek-table": "bin/seek-bzip-table" + } + }, "node_modules/source-map-js": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", @@ -1293,6 +2602,11 @@ "node": ">=0.10.0" } }, + "node_modules/sparse-array": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/sparse-array/-/sparse-array-1.3.2.tgz", + "integrity": "sha512-ZT711fePGn3+kQyLuv1fpd3rNSkNF8vd5Kv2D+qnOANeyKs3fx6bUMGWRPvgTTcYV64QMqZKZwcuaQSP3AZ0tg==" + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -1330,6 +2644,14 @@ "node": ">=8" } }, + "node_modules/strip-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", + "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", + "dependencies": { + "is-natural-number": "^4.0.1" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -1341,6 +2663,49 @@ "node": ">=8" } }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "dependencies": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, + "node_modules/to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -1351,11 +2716,84 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, + "node_modules/uint8-varint": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/uint8-varint/-/uint8-varint-2.0.4.tgz", + "integrity": "sha512-FwpTa7ZGA/f/EssWAb5/YV6pHgVF1fViKdW8cWaEarjB8t7NyofSWBdOTyFPaGuUG4gx3v1O3PQ8etsiOs3lcw==", + "dependencies": { + "uint8arraylist": "^2.0.0", + "uint8arrays": "^5.0.0" + } + }, + "node_modules/uint8-varint/node_modules/uint8arrays": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.1.0.tgz", + "integrity": "sha512-vA6nFepEmlSKkMBnLBaUMVvAC4G3CTmO58C12y4sq6WPDOR7mOFYOi7GlrQ4djeSbP6JG9Pv9tJDM97PedRSww==", + "dependencies": { + "multiformats": "^13.0.0" + } + }, + "node_modules/uint8arraylist": { + "version": "2.4.8", + "resolved": "https://registry.npmjs.org/uint8arraylist/-/uint8arraylist-2.4.8.tgz", + "integrity": "sha512-vc1PlGOzglLF0eae1M8mLRTBivsvrGsdmJ5RbK3e+QRvRLOZfZhQROTwH/OfyF3+ZVUg9/8hE8bmKP2CvP9quQ==", + "dependencies": { + "uint8arrays": "^5.0.1" + } + }, + "node_modules/uint8arraylist/node_modules/uint8arrays": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.1.0.tgz", + "integrity": "sha512-vA6nFepEmlSKkMBnLBaUMVvAC4G3CTmO58C12y4sq6WPDOR7mOFYOi7GlrQ4djeSbP6JG9Pv9tJDM97PedRSww==", + "dependencies": { + "multiformats": "^13.0.0" + } + }, + "node_modules/uint8arrays": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.1.tgz", + "integrity": "sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==", + "dependencies": { + "multiformats": "^9.4.2" + } + }, + "node_modules/uint8arrays/node_modules/multiformats": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==" + }, + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/varint": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", + "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" + }, "node_modules/vite": { "version": "5.4.2", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.2.tgz", @@ -1416,6 +2854,11 @@ } } }, + "node_modules/wasm-feature-detect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.8.0.tgz", + "integrity": "sha512-zksaLKM2fVlnB5jQQDqKXXwYHLQUVH9es+5TOOHwGOVJOCeRBCiPjwSg+3tN2AdTCzjgli4jijCH290kXb/zWQ==" + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -1446,6 +2889,11 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, "node_modules/xss": { "version": "1.0.14", "resolved": "https://registry.npmjs.org/xss/-/xss-1.0.14.tgz", @@ -1461,6 +2909,14 @@ "node": ">= 0.10.0" } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -1469,6 +2925,11 @@ "node": ">=10" } }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -1493,6 +2954,15 @@ "engines": { "node": ">=10" } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } } } } diff --git a/package.json b/package.json index 3a21cad..f9c2085 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,8 @@ "preview": "vite preview" }, "dependencies": { + "@itk-wasm/cuberille": "^0.1.0", + "@niivue/cbor-loader": "^1.0.0", "@niivue/niimath": "^0.1.1", "@niivue/niivue": "^0.44.2", "@tensorflow/tfjs": "^4.19.0", diff --git a/vite.config.js b/vite.config.js index 25e5b81..59f3ae4 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,16 +1,16 @@ -import { defineConfig } from 'vite' +import { defineConfig } from "vite"; export default defineConfig({ // root: '.', - base: './', + base: "./", server: { - open: 'index.html', + open: "index.html", }, worker: { - format: 'esm' + format: "esm", }, // exclude @niivue/niimath from optimization optimizeDeps: { - exclude: ['@niivue/niimath'] - } -}) \ No newline at end of file + exclude: ["@niivue/niimath", "@itk-wasm/cuberille"], + }, +}); From d43dbf4bc235c39345ef128dd1abcbe9cc334c4f Mon Sep 17 00:00:00 2001 From: neurolabusc Date: Tue, 3 Dec 2024 09:17:08 -0500 Subject: [PATCH 02/12] Update cbor-loader --- main.js | 63 +++++++++-------------------------------------- package-lock.json | 9 ++++--- package.json | 2 +- 3 files changed, 17 insertions(+), 57 deletions(-) diff --git a/main.js b/main.js index de9ef3f..e371845 100644 --- a/main.js +++ b/main.js @@ -226,67 +226,26 @@ async function main() { } }; applyBtn.onclick = async function () { + const volIdx = nv1.volumes.length - 1 const niiBuffer = await nv1.saveImage({ - volumeByIndex: nv1.volumes.length - 1, + volumeByIndex: volIdx, }).buffer; const niiBlob = new Blob([niiBuffer], { type: "application/octet-stream" }); const niiFile = new File([niiBlob], "input.nii"); - // get an ImageProcessor instance from niimath - // so we can build up the operations we want to perform - // based on the UI controls - // let image = niimath.image(niiFile); - // loadingCircle.classList.remove("hidden"); - // // initialize the operations object for the niimath mesh function - // let ops = { - // i: 0.5, - // }; - // //const largestCheckValue = largestCheck.checked - // if (largestCheck.checked) { - // ops.l = 1; - // } - // let reduce = Math.min(Math.max(Number(shrinkPct.value) / 100, 0.01), 1); - // ops.r = reduce; - // let smooth = parseFloat(smoothSlide.value); - // ops.s = smooth; - // if (bubbleCheck.checked) { - // ops.b = 1; - // } - - // let hollowInt = Number(hollowSelect.value); - // if (hollowInt < 0) { - // // append the hollow operation to the image processor - // // but dont run it yet. - // image = image.hollow(0.5, hollowInt); - // } - - // let closeFloat = Number(closeMM.value); - // if (isFinite(closeFloat) && closeFloat > 0) { - // // append the close operation to the image processor - // // but dont run it yet. - // image = image.close(0.5, closeFloat, 2 * closeFloat); - // } - // // add the mesh operations - // image = image.mesh(ops); - // console.log("niimath mesh operation", image.commands); - const hdr = nv1.volumes[1].hdr; - const img = nv1.volumes[1].img; - + loadingCircle.classList.remove("hidden"); + const hdr = nv1.volumes[volIdx].hdr; + const img = nv1.volumes[volIdx].img; const itkImage = nii2iwi(hdr, img, false); itkImage.size = itkImage.size.map(Number); const { mesh } = await antiAliasCuberille(itkImage); - const niiMesh = iwm2meshCore(mesh); - console.log(niiMesh); - console.log(nv1); - - // finally, run the full set of operations - // const outFile = await image.run("output.mz3"); - // const outFile = await image.run("output.nii"); - // const arrayBuffer = await outFile.arrayBuffer(); loadingCircle.classList.add("hidden"); - if (nv1.meshes.length > 0) nv1.removeMesh(nv1.meshes[0]); - // await nv1.loadFromArrayBuffer(arrayBuffer, "output.mz3"); - // nv1.reverseFaces(0); + while (nv1.meshes.length > 0) { + nv1.removeMesh(nv1.meshes[0]); + } + const meshBuffer = NVMeshUtilities.createMZ3(niiMesh.positions, niiMesh.indices, false) + await nv1.loadFromArrayBuffer(meshBuffer, 'trefoil.mz3') + nv1.reverseFaces(0); }; saveMeshBtn.onclick = function () { if (nv1.meshes.length < 1) { diff --git a/package-lock.json b/package-lock.json index da662dd..2e300af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.0", "dependencies": { "@itk-wasm/cuberille": "^0.1.0", - "@niivue/cbor-loader": "^1.0.0", + "@niivue/cbor-loader": "^1.1.0", "@niivue/niimath": "^0.1.1", "@niivue/niivue": "^0.44.2", "@tensorflow/tfjs": "^4.19.0", @@ -642,9 +642,10 @@ "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==" }, "node_modules/@niivue/cbor-loader": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@niivue/cbor-loader/-/cbor-loader-1.0.0.tgz", - "integrity": "sha512-56YWElTO6NT8EFa9KQ6TlMq393D8hLAAecAS9ACa3MKFd50UkY70eUn0k7P/Vyv4itQin7D6b2ZUaJ4dhK5kUg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@niivue/cbor-loader/-/cbor-loader-1.1.0.tgz", + "integrity": "sha512-ZRQmZlCn7GP98zo3y7WuxxwbhBSVf0u0Ri7h0VdQurRogcO2tSLjADarWebVFPq9w1vbXuvC2xkChsInZeNGvQ==", + "license": "BSD-2-Clause", "dependencies": { "cbor-x": "^1.6.0", "nifti-reader-js": "^0.6.8" diff --git a/package.json b/package.json index f9c2085..edb2d49 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@itk-wasm/cuberille": "^0.1.0", - "@niivue/cbor-loader": "^1.0.0", + "@niivue/cbor-loader": "^1.1.0", "@niivue/niimath": "^0.1.1", "@niivue/niivue": "^0.44.2", "@tensorflow/tfjs": "^4.19.0", From a1e270ca913fe35026e05c101193cb9c563145b0 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Tue, 17 Dec 2024 23:46:30 -0500 Subject: [PATCH 03/12] Repair, smooth, and remesh Make the mesh manifold and smoothed. --- main.js | 16 ++++++++++---- package-lock.json | 54 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + vite.config.js | 2 +- 4 files changed, 68 insertions(+), 5 deletions(-) diff --git a/main.js b/main.js index e371845..bd0b565 100644 --- a/main.js +++ b/main.js @@ -5,6 +5,7 @@ import { inferenceModelsList, brainChopOpts } from "./brainchop-parameters.js"; import { isChrome, localSystemDetails } from "./brainchop-telemetry.js"; import MyWorker from "./brainchop-webworker.js?worker"; import { antiAliasCuberille } from "@itk-wasm/cuberille"; +import { repair, smoothRemesh } from "@itk-wasm/mesh-filters"; import { nii2iwi, iwm2meshCore } from "@niivue/cbor-loader"; async function main() { @@ -237,15 +238,22 @@ async function main() { const img = nv1.volumes[volIdx].img; const itkImage = nii2iwi(hdr, img, false); itkImage.size = itkImage.size.map(Number); - const { mesh } = await antiAliasCuberille(itkImage); - const niiMesh = iwm2meshCore(mesh); + const { mesh } = await antiAliasCuberille(itkImage, { noClosing: true }); + const { outputMesh: repairedMesh } = await repair(mesh); + while (nv1.meshes.length > 0) { + nv1.removeMesh(nv1.meshes[0]); + } + const initialNiiMesh = iwm2meshCore(repairedMesh); + const initialNiiMeshBuffer = NVMeshUtilities.createMZ3(initialNiiMesh.positions, initialNiiMesh.indices, false) + await nv1.loadFromArrayBuffer(initialNiiMeshBuffer, 'trefoil.mz3') + const { outputMesh: smoothedMesh } = await smoothRemesh(repairedMesh, { newtonIterations: 1, numberPoints: 75 }); + const niiMesh = iwm2meshCore(smoothedMesh); loadingCircle.classList.add("hidden"); while (nv1.meshes.length > 0) { nv1.removeMesh(nv1.meshes[0]); } - const meshBuffer = NVMeshUtilities.createMZ3(niiMesh.positions, niiMesh.indices, false) + const meshBuffer = NVMeshUtilities.createMZ3(niiMesh.positions, niiMesh.indices, false) await nv1.loadFromArrayBuffer(meshBuffer, 'trefoil.mz3') - nv1.reverseFaces(0); }; saveMeshBtn.onclick = function () { if (nv1.meshes.length < 1) { diff --git a/package-lock.json b/package-lock.json index 2e300af..12afb99 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "dependencies": { "@itk-wasm/cuberille": "^0.1.0", + "@itk-wasm/mesh-filters": "^0.1.0", "@niivue/cbor-loader": "^1.1.0", "@niivue/niimath": "^0.1.1", "@niivue/niivue": "^0.44.2", @@ -581,6 +582,59 @@ "node": ">=14" } }, + "node_modules/@itk-wasm/mesh-filters": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@itk-wasm/mesh-filters/-/mesh-filters-0.1.0.tgz", + "integrity": "sha512-6ugGkzU1wrnyTPJPItyTfDNfIxkQyTfCCIh2d4czb5esflDV09UZn4+mnSK5Rz9/bp1Q5fZrNnyEv+ocDJjrsg==", + "license": "Apache-2.0", + "dependencies": { + "itk-wasm": "1.0.0-b.183" + } + }, + "node_modules/@itk-wasm/mesh-filters/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@itk-wasm/mesh-filters/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/@itk-wasm/mesh-filters/node_modules/itk-wasm": { + "version": "1.0.0-b.183", + "resolved": "https://registry.npmjs.org/itk-wasm/-/itk-wasm-1.0.0-b.183.tgz", + "integrity": "sha512-B3/W8MqKZ3KOl+96W1CvgAJjOmlqsac7iaEooP98k3yzH04oAsuyh3xZooOxDVNCucEdIj2Zt7lALbdFv+BoPQ==", + "license": "Apache-2.0", + "dependencies": { + "@itk-wasm/dam": "^1.1.1", + "@thewtex/zstddec": "^0.2.1", + "@types/emscripten": "^1.39.10", + "axios": "^1.6.2", + "chalk": "^5.3.0", + "comlink": "^4.4.1", + "commander": "^11.1.0", + "fs-extra": "^11.2.0", + "glob": "^8.1.0", + "markdown-table": "^3.0.3", + "mime-types": "^2.1.35", + "wasm-feature-detect": "^1.6.1" + }, + "bin": { + "itk-wasm": "src/itk-wasm-cli.js" + } + }, "node_modules/@lukeed/csprng": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", diff --git a/package.json b/package.json index edb2d49..7cbcfa2 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "@itk-wasm/cuberille": "^0.1.0", + "@itk-wasm/mesh-filters": "^0.1.0", "@niivue/cbor-loader": "^1.1.0", "@niivue/niimath": "^0.1.1", "@niivue/niivue": "^0.44.2", diff --git a/vite.config.js b/vite.config.js index 59f3ae4..d1c22a5 100644 --- a/vite.config.js +++ b/vite.config.js @@ -11,6 +11,6 @@ export default defineConfig({ }, // exclude @niivue/niimath from optimization optimizeDeps: { - exclude: ["@niivue/niimath", "@itk-wasm/cuberille"], + exclude: ["@niivue/niimath", "@itk-wasm/cuberille", "@itk-wasm/mesh-filters"], }, }); From 258d3d349b5ff2b52cd4d049f33c2e253f9fe7ae Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Tue, 17 Dec 2024 23:54:54 -0500 Subject: [PATCH 04/12] README documentation updates --- README.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 787ab78..fbcdf15 100644 --- a/README.md +++ b/README.md @@ -9,23 +9,23 @@ This is an extension of [brainchop](https://github.com/neuroneural/brainchop) th 1. Open the [live demo](https://niivue.github.io/brain2print/). 2. **Option 1** The web page automatically loads with a default T1 MRI scan. If you want to use this scan, go to step 5. 3. **Option 2** If your T1 MRI scan is in NIfTI format, drag and drop the file onto the web page. -4. **Option 3** If your image is in DICOM format, it may load if you drag and drop the files. If this fails, convert your images with dcm2niix. +4. **Option 3** If your image is in DICOM format, it may load if you drag and drop the files. If this fails, convert your images with [dcm2niix](https://github.com/rordenlab/dcm2niix). 5. Segment your brain scan by choosing a model from the `Segmentation Model` pull-down menu. Not all models with with all graphics cards. The `Tissue GWM (High Acc, Low Mem)` is a good starting point. Hopefully, it will accurately segment your brain into gray matter, white matter and cerebral spinal fluid. 6. Press the `Create Mesh` button and select your preferred settings: - ![settings dialog](Settings.png) - - [Closing](https://en.wikipedia.org/wiki/Closing_(morphology)) removes small crevices and cavities in your mesh which can plague printing. - - Fill bubbles will remove any cavities, this includes large cavities for example the ventricles for a brain scan. + - Fill bubbles will remove any cavities. This includes large cavities such as the brain's ventricles. - The `Largest cluster only` will only extract a single mesh. - - You can choose `Smoothing` to make the surfaces less jagged (note this can create self intersecting triangles that can confound some printers). - - You can choose to `Simplify` [reduce the number of triangles](https://github.com/sp4cerat/Fast-Quadric-Mesh-Simplification) to create smaller files (note this can create self intersecting triangles that can confound some printers). + - You can choose `Smoothing` to make the surfaces less jagged at the expense of computation time. + - You can choose to `Simplify` to reduce the number of triangles and create smaller files. + 7. Once you have set your preferences, press `Apply`. 8. You will see the mesh appear and can interactively view it. If you are unhappy with the result, repeat step 6 with different settings. If you want to print the results, press the `Save Mesh` button. ## How it Works -This web application uses some of the latest browser technologies that allow the tissue segmentation model to run on your local GPU, regardless of the type of GPU. This is possible via the `WebGPU` browser API. Additionally, we leverage `WebAssembly` to run the `niimath` [WASM wrapper](https://www.npmjs.com/package/@niivue/niimath) to turn the tissue segmentation into a 3D mesh. No data ever leaves your machine. +This web application uses some of the latest browser technologies that allow the tissue segmentation model to run on your local GPU, regardless of the type of GPU. This is possible via the `WebGPU` browser API. Additionally, we leverage `WebAssembly` to run the `niimath` [WASM wrapper](https://www.npmjs.com/package/@niivue/niimath) and [ITK-Wasm](https://wasm.itk.org) to turn the tissue segmentation into a 3D mesh. No data ever leaves your machine. ### Developers - Running a Local Live Demo @@ -50,5 +50,4 @@ npm run build - [brainchop](https://github.com/neuroneural/brainchop) - [niivue](https://github.com/niivue/niivue) - [niimath](https://github.com/rordenlab/niimath) - - +- [ITK-Wasm](https://github.com/InsightSoftwareConsortium/ITK-Wasm) From 661400b31fa2f91aab04a41866fed3dc1fa52840 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Wed, 18 Dec 2024 00:29:17 -0500 Subject: [PATCH 05/12] User interface simplifications --- README.md | 2 -- index.html | 35 +++++------------------------------ main.js | 13 +++---------- 3 files changed, 8 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index fbcdf15..391c3f1 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,6 @@ This is an extension of [brainchop](https://github.com/neuroneural/brainchop) th - ![settings dialog](Settings.png) - - Fill bubbles will remove any cavities. This includes large cavities such as the brain's ventricles. - - The `Largest cluster only` will only extract a single mesh. - You can choose `Smoothing` to make the surfaces less jagged at the expense of computation time. - You can choose to `Simplify` to reduce the number of triangles and create smaller files. diff --git a/index.html b/index.html index ba861d2..3c10c0d 100644 --- a/index.html +++ b/index.html @@ -55,46 +55,21 @@
-

- - -

-

- -

-

- - -

-

- - -

- - + +

diff --git a/main.js b/main.js index bd0b565..77dcd0d 100644 --- a/main.js +++ b/main.js @@ -11,10 +11,6 @@ import { nii2iwi, iwm2meshCore } from "@niivue/cbor-loader"; async function main() { const niimath = new Niimath(); await niimath.init(); - // const wrapper = await NiiMathWrapper.load() - /*smoothCheck.onchange = function () { - nv1.setInterpolation(!smoothCheck.checked) - }*/ aboutBtn.onclick = function () { const url = "https://github.com/niivue/brain2print"; window.open(url, "_blank"); @@ -228,11 +224,6 @@ async function main() { }; applyBtn.onclick = async function () { const volIdx = nv1.volumes.length - 1 - const niiBuffer = await nv1.saveImage({ - volumeByIndex: volIdx, - }).buffer; - const niiBlob = new Blob([niiBuffer], { type: "application/octet-stream" }); - const niiFile = new File([niiBlob], "input.nii"); loadingCircle.classList.remove("hidden"); const hdr = nv1.volumes[volIdx].hdr; const img = nv1.volumes[volIdx].img; @@ -246,7 +237,9 @@ async function main() { const initialNiiMesh = iwm2meshCore(repairedMesh); const initialNiiMeshBuffer = NVMeshUtilities.createMZ3(initialNiiMesh.positions, initialNiiMesh.indices, false) await nv1.loadFromArrayBuffer(initialNiiMeshBuffer, 'trefoil.mz3') - const { outputMesh: smoothedMesh } = await smoothRemesh(repairedMesh, { newtonIterations: 1, numberPoints: 75 }); + const smooth = parseInt(smoothSlide.value) + const shrink = parseFloat(shrinkPct.value) + const { outputMesh: smoothedMesh } = await smoothRemesh(repairedMesh, { newtonIterations: smooth, numberPoints: shrink }); const niiMesh = iwm2meshCore(smoothedMesh); loadingCircle.classList.add("hidden"); while (nv1.meshes.length > 0) { From 742a5f9c611f063a012f0f73f2851fcd91804951 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Wed, 18 Dec 2024 15:07:54 -0500 Subject: [PATCH 06/12] UI presentation tweaks --- index.html | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index 3c10c0d..748d5a3 100644 --- a/index.html +++ b/index.html @@ -10,6 +10,8 @@
+ +   @@ -18,16 +20,23 @@   +
+ +          +
+ +        +
  @@ -69,7 +78,7 @@

- +

From ae9aafdc08289d8f0c5bce9287fc431a14782b6b Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Wed, 18 Dec 2024 15:23:20 -0500 Subject: [PATCH 07/12] Disable buttons when not valid, provide mesh processing feedback --- index.html | 7 ++++--- main.js | 9 +++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 748d5a3..13f8b65 100644 --- a/index.html +++ b/index.html @@ -27,14 +27,14 @@   - +  
   - +   - +  
@@ -43,6 +43,7 @@   +
diff --git a/main.js b/main.js index 77dcd0d..e4d8c5b 100644 --- a/main.js +++ b/main.js @@ -161,6 +161,8 @@ async function main() { } overlayVolume.opacity = opacitySlider1.value / 255; await nv1.addVolume(overlayVolume); + saveBtn.disabled = false + createMeshBtn.disabled = false } async function reportTelemetry(statData) { if (typeof statData === "string" || statData instanceof String) { @@ -225,10 +227,13 @@ async function main() { applyBtn.onclick = async function () { const volIdx = nv1.volumes.length - 1 loadingCircle.classList.remove("hidden"); + meshProcessingMsg.classList.remove("hidden") + meshProcessingMsg.textContent = "Generating mesh from segmentation" const hdr = nv1.volumes[volIdx].hdr; const img = nv1.volumes[volIdx].img; const itkImage = nii2iwi(hdr, img, false); itkImage.size = itkImage.size.map(Number); + const { mesh } = await antiAliasCuberille(itkImage, { noClosing: true }); const { outputMesh: repairedMesh } = await repair(mesh); while (nv1.meshes.length > 0) { @@ -237,11 +242,15 @@ async function main() { const initialNiiMesh = iwm2meshCore(repairedMesh); const initialNiiMeshBuffer = NVMeshUtilities.createMZ3(initialNiiMesh.positions, initialNiiMesh.indices, false) await nv1.loadFromArrayBuffer(initialNiiMeshBuffer, 'trefoil.mz3') + saveMeshBtn.disabled = false + + meshProcessingMsg.textContent = "Smoothing and remeshing" const smooth = parseInt(smoothSlide.value) const shrink = parseFloat(shrinkPct.value) const { outputMesh: smoothedMesh } = await smoothRemesh(repairedMesh, { newtonIterations: smooth, numberPoints: shrink }); const niiMesh = iwm2meshCore(smoothedMesh); loadingCircle.classList.add("hidden"); + meshProcessingMsg.classList.add("hidden"); while (nv1.meshes.length > 0) { nv1.removeMesh(nv1.meshes[0]); } From 65969f056372f2f6db32602c97f62dcee0c029d7 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Wed, 18 Dec 2024 15:44:47 -0500 Subject: [PATCH 08/12] Keep largest mesh component We could switch to niimath once https://github.com/rordenlab/niimath/pull/34 has been merged, if desired. --- main.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/main.js b/main.js index e4d8c5b..42ab370 100644 --- a/main.js +++ b/main.js @@ -5,7 +5,7 @@ import { inferenceModelsList, brainChopOpts } from "./brainchop-parameters.js"; import { isChrome, localSystemDetails } from "./brainchop-telemetry.js"; import MyWorker from "./brainchop-webworker.js?worker"; import { antiAliasCuberille } from "@itk-wasm/cuberille"; -import { repair, smoothRemesh } from "@itk-wasm/mesh-filters"; +import { repair, smoothRemesh, keepLargestComponent } from "@itk-wasm/mesh-filters"; import { nii2iwi, iwm2meshCore } from "@niivue/cbor-loader"; async function main() { @@ -235,11 +235,14 @@ async function main() { itkImage.size = itkImage.size.map(Number); const { mesh } = await antiAliasCuberille(itkImage, { noClosing: true }); + meshProcessingMsg.textContent = "Generating manifold" const { outputMesh: repairedMesh } = await repair(mesh); + meshProcessingMsg.textContent = "Keep largest mesh component" + const { outputMesh: largestOnly } = await keepLargestComponent(repairedMesh) while (nv1.meshes.length > 0) { nv1.removeMesh(nv1.meshes[0]); } - const initialNiiMesh = iwm2meshCore(repairedMesh); + const initialNiiMesh = iwm2meshCore(largestOnly); const initialNiiMeshBuffer = NVMeshUtilities.createMZ3(initialNiiMesh.positions, initialNiiMesh.indices, false) await nv1.loadFromArrayBuffer(initialNiiMeshBuffer, 'trefoil.mz3') saveMeshBtn.disabled = false @@ -247,7 +250,7 @@ async function main() { meshProcessingMsg.textContent = "Smoothing and remeshing" const smooth = parseInt(smoothSlide.value) const shrink = parseFloat(shrinkPct.value) - const { outputMesh: smoothedMesh } = await smoothRemesh(repairedMesh, { newtonIterations: smooth, numberPoints: shrink }); + const { outputMesh: smoothedMesh } = await smoothRemesh(largestOnly, { newtonIterations: smooth, numberPoints: shrink }); const niiMesh = iwm2meshCore(smoothedMesh); loadingCircle.classList.add("hidden"); meshProcessingMsg.classList.add("hidden"); From 82049ebe3dbabd0b0aa748c3c2f19ace4e8c2c7d Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Wed, 18 Dec 2024 15:53:00 -0500 Subject: [PATCH 09/12] Update Settings.png --- Settings.png | Bin 5737 -> 11473 bytes 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 Settings.png diff --git a/Settings.png b/Settings.png old mode 100644 new mode 100755 index 41a9cf6130a2e7bf23beec37970cffc6321a8f00..95f00ce5553deea2c9287d4fbbdac576fd998e70 GIT binary patch literal 11473 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 literal 5737 zcmZu#WmFVgx1M2Ss2KsNVL(DcV(3Od8isD9l#*_w!x==nLAp}`0YT{)K_rKi?k*7| zL_nF#``!EJ{nq_))>-GAwf9;3+0Q;}pC?*JO9e^{Ck6ljP^7A&9smFY-VPc<(Ctok z2M`GW;I-*!7%1UzxSN}szkmP!`Sa)c`ughX>hkjP_wU~q7Z<;N{W?ECKRY`+Jv}`+ zIr;hX=gtZ4`1ttf=;+6fABTsB-@ku9I5^nf-{0HY+uhyW+1c6N-rm~U+T7gS*w~oc z{JFlqzP7fuy1Kfuva-CqytK5`w}x9>TwGXKn4h1Yo12@Ro$Xr0&CJY9Pft%xO?~_J zZE|w5d-`Z%Vq$!Jd~9rNbaZrNWCV-F4i66x4Gj$r4h{?q^!N9djpF+H`g(hNzkKFMt7{`~nf27~G9>gw$5%=vQO(b3V~-rm;M*3#0_+}zyM)YRD6`03N9j~_oa zG&F>_j%*@EhNKa3H^X5%j zT3TvqYD!8*1g@uKo(P+iEbrcHq^5x6W(9n>Okl^6pprD|@z`%fj0DpgfKR-WTUtb>|A8&7O zx^SGAmzSrfr-z4!ySqCT3g_nLCga!c>gwv^;_}F+)!EtE$;rvl(b2)d!QS59&d!e3 zXPw4p>-qENHa0dOpFh^t)&L)zm6esHrRB3{&nzq~%+1YBO-)TqOrAV>Vr*<|WMpJ$ zXlP(yps%m5r>Cc@tE;1lq%-x3V}dwX)ONr!#e?L5 zzENK1=$@IuRKRF0M&&*s2oEjGL`Hb$|D6=Vye*}|@xY5X0(MV9gY8W-Ptq2?B6p+5 zub4KmcS%7kT7jx92s{p3NZ>srZAi-JJwo|+3-G&OgyxIGS&!6=ATbmhZOGAnYnWx+ z_O=IqT?{rE^*){R0#?T)-jFq;?jHML>>FIXxMikTVN8}SwTOT6BHa#Cf6AWIh!-WZ zw}w^1sJw~taTh;Kt+D}{W#usP`Pj?b&`_YIYY;TGb7KCp{JMLWfuFux2o*)-=K=0| zd<;+&xKB?W2A-c^QxWorg7#vADVm2_9xX`V^FZtL-FQ4bt11taJ!3Tpgq?x`xo4ez z`EHlHj-pl4bff{Z<2svm>`7Sq(x~7A=ztw%tE+h zHMknO1fGWrgCsB_cA%+`b8}9;^o@$v#H4_MMF+TU;~ysuc+{Fn1KNcboYVtpej+}E z_kvcuSd*rDO&(Cy3iYpb0K3QvL;~H%-R#N9dhY>V;FUD5z;xT)4;zXc0QY(9K##KS zSW=5UD2qP(aY8psv}$4fh>;*^+Eun@8X_w~M)bYZ;=s`+c}13TD2{x}T*(36Je;f( zwVYHAfAU!vF#1yh5PdM;%!|R?tGS~y=32OM6#|J{4uYuG`?WqV3T1b3>qtabG*82HZ!41IfF?W_c=#v3YhP;NfdQzw zpQ5EA0N!J}GOsi>OvH~uaG6(>1Zg{afC9`d8FZsY@Mg6Fk@@k!Ujp#P2AM0aYD}2# z#07Xvk2LxbfSwtJyd)6Z_M`Jhd!xPZ#H-=6a>xV64LJaUfNQfKMb5K+Ox7WkE!jhS zUmdR%MjpukdHfNMA<{bcvm^?$Iyby~RVi-ZxY_&a+$F3){uv~!E(}SUhbG_RZ7D+# zhen80%aPT5@3w?SJ!I`h`D=0fo9=|9xhoWe_$LK&@}cWw(nHrpR0h|Df?<)C7{OA3 z19AZm-3T>A>}#|fJgOu2>KF#wdoeUquK~6*x^CYoXI|j}sx0-OFAm7Nx~Y$qsW1$`|QpgVSC+|j|FZ}VNHRM#*%#^<@o4I5-;gRF>z)gr$D zatz$+VSL`)WIN82&|GV-q>+niFIu}X;{?v(-pU+Kc2M+*dL^(W;)OfwlCO8eN?JWF zG1gp=73}s_xDKX5i(i=A=mv7d>UfB(&uhAz(!a3b>AQ3DgatlgA_B@szDv`m*pl*Y zzzH{)T*KB)bPis3+m*kdv!tSw`DH~>;`}(X?@I&k9r)~8^r4^*q5lXFyS2TIp?r%M zF^eHG1*Qp>FUST-Q<|FczZu$%N}KUXJLkvHDMk8o(w#_RItUy%#KZ{7QCOH0=-?8M zfA~Ur*7>@-)MD`-=y2Q^Ng8D8&9JK~+?}NAN zLMFHGO5lrQ*_jgK@CNq?e;4l~2(6jUaPa($qT8IHkv^qC6oB*x@uR>Y)Bc=2fRTq7 zf4UFgmrw%@s1|S-3UU(4h1@yGypM)3CgeYfT&)!ULIw^8T3Hs3Mkz+A{?}ti7!vwx zfn@2=FZ&M4vWZl~4(ghT#^Sz47lLjgB~%e0bXtGo1?zMD%JP|dO#~>=#o0klyoeMx z(8OnsDwugw0VRzdDYRlpU zU|}=uY8yeY*SSGR&I+dg z9XS2;dMV^{RqmdcPVK`ggI_-b7`I|nEtLsOO0al4Z1p18_V=Cms;zQ^uc;y4Db)q2 zNW!66Rfk!X?op3{kD7g=qIg{78!qcN`v1iOGQw_gB_aQ_RqSfj1E^<=9XnXDlm#DM zD!{GUblp?WtTjH|jf%1|(E%wpB?*&BDcK0XJFJPUS8tXOa*%Mv7`xfzyNw-S+g4){ zPx6zTIl<9SeUvG4^CQ2o{d#E^O~ujDFIPNF8(CTPGgON)iI0i7W>>JOudjgMe{GlY|4}CRuJm+Q-R=h=_lT5kHK4-JX{Q>Of0iDK`ufQ>ZCFBBRT* zv2q8atG7A?1p4TfU@BSGJY`k8-%5HiB8&VivF5R#+P^Q=vkFRmkbm(1;eSd|Ehwf-t?lL@yZ$IDd>$60@XK zAQtA2oO{?oehZz+*I-M*zu>XqEpm$aU152_mRMl31*}}#F;Ozv+f2^@q#^a4m77aTmiqyu%R}B1l6MnSMNVTGgWKzWbao`io9YUH2boG+EXE0qa zQ=8-#>tu;=6{8{v9pk`ynA#anx;ImytvdGO$WZ%~UFm`C2?w?~VwCeRpr(f`wC( z=eQ64s8swTJDhH&*SkUT@80gS!a!o^)zGt>GnK^S-!FaSHjEQ1Uoqmg!wOdZz>4J7 zUvOVV>v}odXdN)U1jYa?^;k1bxzU}X3;jEsSXvb=_#;UKib^jA%mj>4!G%dD;N{&Qd9!lc-o zxhtuTonu-Wz~S@J3VS+JovT=gs|{+hiKZ2CU4CtX!z4JbWZDt2a4h}ibf z&j7N^#Ru(OR@UX>M-5b^4)D}95Jp)O0VLxsQP!Za- zBXPjgx995vEQ;J^f^J)gd8iHY4X=M&UiukT!b@n0-bSl(GZ*GRr*e?p%Sw;-2QgcH zI?P=XTDv{BQ4tSStv9qcvhTniA%NgB%hYjM(OStsvBI6I?vs)JD+a24 zWk0q|7pb?1^UrTgpAZ#x(5isMd<>2`;Db5 zVV9LE6fDo!7($8u)#!)s(#Lxh z^;QJnXZG7!(uo190to%n=gP_14m;|5z)T0ouFlBlsQ(M!~Eqz~p=|M!7(4qQ-wj#!%JeOt~bu{BqGpaneSb_sy~Vx(>efF4WxsAw*%| zxLz+)po^8Dxu#C@KK|IYpz>KcA8|`uWYeAIr(zDbw?wbVO6XupFoESgN(4!RgKnTF zU)aV-Heq1pPvbQ-JD$hY@0b!D&mAp^V}~0G-vhZKfHoh#lDwvuv9}VT95g(fl9`OM zMp4AU2k~C{&)n{3(ZU8y@5ib$?4gsZ6sLgJ{=hrw_VGeeIGY zsGW#8)P-6BcwbtlznDdjB1TZHGJdb zFiWO7*%75csr;&gBAT7?yH=E&MCS3+fepZxR&5Z~yya;Y-UZaPW)KiVYXcwu?&_L9 zK$1m>C=vcATqGY@vT$tmE`K3S|F}Im=4q~qbokSxz9&mn=!An1IESSm%1e1Idj=0P zRec}fp?Gg4I9CWg^(r49O`Gx*@>V_7Ujl>DW$JU0y-o4`ZjOGNYEg*)YDLQw%q#7F zUECzi%Wh%}Zxf#TPd291Bc}=l8^xdzK;l53O(scNGuR!I%e;q0`CXU$j*#+OQuYhb zjm4fiMDi1#>{dZRDkhSo@HZd#6?_GNTQ7doOu6=QXMYPRUhLGoWH=%`L|Df;2pA_y zblZE@*sKu;46XhHk-*~2xwKH$nwXB6a;taIn<-AVq|X|+s7oA)71HeJlHQ`U*V1|p zPFlC75`MaB&Y>zrDBSP+-QMovL8)`;g%3yRGOO7nkkzBgQIVh{O$@MM+CLa|OZj|e zT?mGHWfV_B*^{A!De;43k^{G}a^0P!C*ORGGNbaI%h5!q7S=~2x5;=*I3ujE$L zv!TJG_+G>zAaR}2gR{b;IPlQc#)>yO*9z)9=1$%81v-uLmwy0>+6n)+SRhAhyh=}r zzj4+<@KJwPw@w32IYj)wi?uXxv^Rgyqt`$yrc!9!(n<1xVmf86i2aqI&d*5yJ%$*+ z@MQGw$39OvuflK~_*<)aGLYft?rotrj8?X*cWAf^a3NyIloUZbZY;8df+pb&Wy%zr zZQS4=V<7rw;Hd-L{O~*QWT{85mTZ+9sl@2* z7Ee4bti3~auvuX_d$I!Ee3Z~B|9rTu>pETP0W$9;`_Zr-#P)b6#b7Lp>{$|3AT*!J0n_ZId<;@81K{Qu=VyDv3_WAjv!kov4OHIw4&7+~TF2b)< zH*+Bp&H1fA!?$Xo>rctIEIy=3ZY|6|*LkQjx%)Hb;R-ufGcgY4I z=l--hex~Q4(@3NEH|fjlqrqm&u1tISCk+*4_)YzM`en;d+hZyub5@1lDc!Q6@AntU z&osV4zO4L}a;b^gu!~DJ$X87oW@Sfm4NzQp8n$1X?Gd%Ha$bFXh_r}18V+LpK>`60 zR{{q{J8^$SZ*&FgisdKXPPp^moNGI-FOOk3^U0%k!q-1n|3}^`!r(y0g0#9f19%O$ P+8Y3=q@`FRZyEMKT4S&@ From f73583d36ef2162f99f95078369303842941e965 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Wed, 18 Dec 2024 16:07:44 -0500 Subject: [PATCH 10/12] Use vendored ITK-Wasm wasm modules These are fetched on-demand in web workers from JsDelivr by default. --- main.js | 18 ++- package-lock.json | 353 +++++++++++++++++++++++++++++++++++++++++++++- package.json | 3 +- vite.config.js | 10 ++ 4 files changed, 380 insertions(+), 4 deletions(-) diff --git a/main.js b/main.js index 42ab370..4d54812 100644 --- a/main.js +++ b/main.js @@ -4,10 +4,24 @@ import { Niimath } from "@niivue/niimath"; import { inferenceModelsList, brainChopOpts } from "./brainchop-parameters.js"; import { isChrome, localSystemDetails } from "./brainchop-telemetry.js"; import MyWorker from "./brainchop-webworker.js?worker"; -import { antiAliasCuberille } from "@itk-wasm/cuberille"; -import { repair, smoothRemesh, keepLargestComponent } from "@itk-wasm/mesh-filters"; +import { + antiAliasCuberille, + setPipelinesBaseUrl as setCuberillePipelinesUrl +} from "@itk-wasm/cuberille"; +import { + repair, + smoothRemesh, + keepLargestComponent, + setPipelinesBaseUrl as setMeshFiltersPipelinesUrl, +} from "@itk-wasm/mesh-filters"; import { nii2iwi, iwm2meshCore } from "@niivue/cbor-loader"; +// Use local, vendored WebAssembly module assets +const viteBaseUrl = import.meta.env.BASE_URL +const pipelinesBaseUrl = new URL(`${viteBaseUrl}pipelines`, document.location.origin).href +setCuberillePipelinesUrl(pipelinesBaseUrl) +setMeshFiltersPipelinesUrl(pipelinesBaseUrl) + async function main() { const niimath = new Niimath(); await niimath.init(); diff --git a/package-lock.json b/package-lock.json index 12afb99..f7d2c70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,8 @@ "gl-matrix": "^3.4.3" }, "devDependencies": { - "vite": "^5.4.2" + "vite": "^5.4.2", + "vite-plugin-static-copy": "^2.2.0" } }, "node_modules/@cbor-extract/cbor-extract-darwin-arm64": { @@ -730,6 +731,44 @@ "@rollup/rollup-linux-x64-gnu": "^4.18.1" } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@perma/map": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@perma/map/-/map-1.0.3.tgz", @@ -1241,6 +1280,20 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -1296,6 +1349,19 @@ } ] }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bl": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", @@ -1318,6 +1384,19 @@ "balanced-match": "^1.0.0" } }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -1420,6 +1499,31 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -1678,6 +1782,33 @@ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", @@ -1710,6 +1841,19 @@ "node": ">=18" } }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/follow-redirects": { "version": "1.15.9", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", @@ -1846,6 +1990,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -1981,6 +2138,29 @@ "progress-events": "^1.0.1" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -1989,11 +2169,34 @@ "node": ">=8" } }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-natural-number": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", "integrity": "sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ==" }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -2171,6 +2374,30 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -2324,6 +2551,16 @@ "node-gyp-build-optional-packages-test": "build-test.js" } }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -2394,6 +2631,19 @@ "dev": true, "license": "ISC" }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -2511,6 +2761,27 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/rabin-rs": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/rabin-rs/-/rabin-rs-2.1.0.tgz", @@ -2543,6 +2814,19 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", @@ -2556,6 +2840,17 @@ "node": ">=0.10.0" } }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rollup": { "version": "4.21.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.0.tgz", @@ -2592,6 +2887,30 @@ "fsevents": "~2.3.2" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -2761,6 +3080,19 @@ "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -2909,6 +3241,25 @@ } } }, + "node_modules/vite-plugin-static-copy": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-2.2.0.tgz", + "integrity": "sha512-ytMrKdR9iWEYHbUxs6x53m+MRl4SJsOSoMu1U1+Pfg0DjPeMlsRVx3RR5jvoonineDquIue83Oq69JvNsFSU5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.3", + "fast-glob": "^3.2.11", + "fs-extra": "^11.1.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0" + } + }, "node_modules/wasm-feature-detect": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.8.0.tgz", diff --git a/package.json b/package.json index 7cbcfa2..04ef63d 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "gl-matrix": "^3.4.3" }, "devDependencies": { - "vite": "^5.4.2" + "vite": "^5.4.2", + "vite-plugin-static-copy": "^2.2.0" } } diff --git a/vite.config.js b/vite.config.js index d1c22a5..8394a46 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,4 +1,5 @@ import { defineConfig } from "vite"; +import { viteStaticCopy } from 'vite-plugin-static-copy' export default defineConfig({ // root: '.', @@ -13,4 +14,13 @@ export default defineConfig({ optimizeDeps: { exclude: ["@niivue/niimath", "@itk-wasm/cuberille", "@itk-wasm/mesh-filters"], }, + plugins: [ + // put lazy loaded JavaScript and Wasm bundles in dist directory + viteStaticCopy({ + targets: [ + { src: 'node_modules/@itk-wasm/cuberille/dist/pipelines/*.{js,wasm,wasm.zst}', dest: 'pipelines' }, + { src: 'node_modules/@itk-wasm/mesh-filters/dist/pipelines/*.{js,wasm,wasm.zst}', dest: 'pipelines' }, + ], + }) + ], }); From 652a164bcc57d5e4ced2604931ddad38dd9b856b Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Wed, 18 Dec 2024 16:13:08 -0500 Subject: [PATCH 11/12] Use a high maximumHoleArea Ensure we have no surface holes. --- main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.js b/main.js index 4d54812..8b01a2b 100644 --- a/main.js +++ b/main.js @@ -250,7 +250,7 @@ async function main() { const { mesh } = await antiAliasCuberille(itkImage, { noClosing: true }); meshProcessingMsg.textContent = "Generating manifold" - const { outputMesh: repairedMesh } = await repair(mesh); + const { outputMesh: repairedMesh } = await repair(mesh, { maximumHoleArea: 50.0 }); meshProcessingMsg.textContent = "Keep largest mesh component" const { outputMesh: largestOnly } = await keepLargestComponent(repairedMesh) while (nv1.meshes.length > 0) { From f80b90353d843cbf1544e966757feb0abdf4ed47 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Wed, 18 Dec 2024 16:13:30 -0500 Subject: [PATCH 12/12] README typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 391c3f1..026da43 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ This is an extension of [brainchop](https://github.com/neuroneural/brainchop) th 2. **Option 1** The web page automatically loads with a default T1 MRI scan. If you want to use this scan, go to step 5. 3. **Option 2** If your T1 MRI scan is in NIfTI format, drag and drop the file onto the web page. 4. **Option 3** If your image is in DICOM format, it may load if you drag and drop the files. If this fails, convert your images with [dcm2niix](https://github.com/rordenlab/dcm2niix). -5. Segment your brain scan by choosing a model from the `Segmentation Model` pull-down menu. Not all models with with all graphics cards. The `Tissue GWM (High Acc, Low Mem)` is a good starting point. Hopefully, it will accurately segment your brain into gray matter, white matter and cerebral spinal fluid. +5. Segment your brain scan by choosing a model from the `Segmentation Model` pull-down menu. Not all models work with all graphics cards. The `Tissue GWM (High Acc, Low Mem)` is a good starting point. Hopefully, it will accurately segment your brain into gray matter, white matter and cerebral spinal fluid. 6. Press the `Create Mesh` button and select your preferred settings: - ![settings dialog](Settings.png)