-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
implement object oriented JS lib of niimath wasm
- Loading branch information
Showing
16 changed files
with
891 additions
and
159 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,5 +3,7 @@ | |
/bin/ | ||
/src/niimath | ||
niimath | ||
/dist | ||
/node_modules | ||
dist | ||
node_modules | ||
niimath.js | ||
niimath.wasm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
# @niivue/niimath | ||
|
||
`@niivue/niimath` is a JavaScript + WASM library for performing mathemetical operations on NIFTI files. This library is intended to be **used in the browser**, not in a Node.js environment. | ||
|
||
> All image processing operations are performed using the WASM build of [niimath](https://github.com/rordenlab/niimath), making it much faster than a pure JavaScript implementation. The image processing takes place in a separate worker thread, so it won't block the main thread in your application. | ||
## Usage | ||
|
||
The `@niivue/niimath` JavaScript library offers an object oriented API for working with the `niimath` CLI. Since `niimath` is a CLI tool, the API implemented in `@niivue/niimath` is just a wrapper around the CLI options and arguments. | ||
|
||
### example | ||
|
||
For example, the [difference of gaussian](https://www.biorxiv.org/content/biorxiv/early/2022/09/17/2022.09.14.507937.full.pdf) command `niimath input.nii -dog 2 3.2 output.nii` can be executed using the following `@niivue/niimath` JavaScript code: | ||
|
||
```javascript | ||
import { Niimath } from '@niivue/niimath'; | ||
|
||
const niimath = new Niimath(); | ||
|
||
// 1. selectedFile is a browser File object | ||
// 2. note the use of the final run() method to execute the command. | ||
// 3. note the use of await. The run method returns a promise that resolves to the output file if the command is successful. | ||
const outFile = await niimath.image(selectedFile).dog(2, 3.2).run(); | ||
``` | ||
|
||
## Installation | ||
|
||
To install `@niivue/niimath` in your project, run the following command: | ||
|
||
```bash | ||
# TODO: publish to npm | ||
# npm install @niivue/niimath | ||
``` | ||
|
||
### To install a local build of the library | ||
|
||
Fist, `cd` into the `js` directory of the `niimath` repository. | ||
|
||
```bash | ||
# from niimath root directory | ||
cd js | ||
``` | ||
|
||
To install a local build of the library, run the following command: | ||
|
||
```bash | ||
npm run build | ||
``` | ||
|
||
Then, install the library using the following command: | ||
|
||
```bash | ||
npm pack # will create a .tgz file in the root directory | ||
``` | ||
|
||
Then, install the `@niivue/niimath` library in your application locally using the following command: | ||
|
||
```bash | ||
npm install /path/to/niivue-niimath.tgz | ||
``` | ||
|
||
## Development | ||
|
||
First `cd` into the `js` directory of the `niimath` repository. | ||
|
||
```bash | ||
# from niimath root directory | ||
cd js | ||
``` | ||
|
||
To install the dependencies, run the following command: | ||
|
||
```bash | ||
npm install | ||
``` | ||
|
||
To build the library, run the following command | ||
|
||
```bash | ||
npm run build | ||
``` | ||
|
||
To run the tests, run the following command: | ||
|
||
```bash | ||
npm run test | ||
``` | ||
|
||
### Test using a simple demo | ||
|
||
To test that the `@niivue/niimath` library is working correctly, you can run the following command: | ||
|
||
```bash | ||
npm run demo | ||
``` | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
const esbuild = require('esbuild'); | ||
const fs = require('fs'); | ||
|
||
esbuild.build({ | ||
entryPoints: ['./src/index.js'], | ||
outfile: './dist/index.js', | ||
bundle: true, | ||
format: 'esm', | ||
target: ['es2020'], | ||
minify: false, | ||
define: { | ||
'process.env.NODE_ENV': '"production"', | ||
}, | ||
}).then(() => { | ||
// copy worker.js, niimath.wasm, niimath.js to dist folder | ||
// (they do not require any processing by esbuild). | ||
// Technically, none of the files in the src folder require processing by esbuild, | ||
// but it does allow minification (optional), and ES version target specification if needed. | ||
// In the future, if we use Typescript, we can use esbuild to transpile the Typescript to JS. | ||
fs.copyFileSync('./src/worker.js', './dist/worker.js'); | ||
fs.copyFileSync('./src/niimath.wasm', './dist/niimath.wasm'); | ||
fs.copyFileSync('./src/niimath.js', './dist/niimath.js'); | ||
console.log('Build completed!'); | ||
}).catch(() => process.exit(1)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
|
||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>Niimath WASM Demo</title> | ||
</head> | ||
|
||
<body> | ||
<h1>Niimath WASM Demo</h1> | ||
<input type="file" id="fileInput"> | ||
<button id="processButton" disabled>Process Image</button> | ||
<p id="status">Please select a NIfTI image file to process.</p> | ||
<a id="downloadLink" style="display: none;">Download Processed Image</a> | ||
|
||
<script type="module"> | ||
import { Niimath } from './dist/index.js'; | ||
const niimath = new Niimath(); | ||
const fileInput = document.getElementById('fileInput'); | ||
const processButton = document.getElementById('processButton'); | ||
const status = document.getElementById('status'); | ||
const downloadLink = document.getElementById('downloadLink'); | ||
|
||
let selectedFile = null; | ||
|
||
fileInput.addEventListener('change', async (event) => { | ||
selectedFile = event.target.files[0]; | ||
if (selectedFile) { | ||
processButton.disabled = false; | ||
status.textContent = `Selected file: ${selectedFile.name}`; | ||
} else { | ||
processButton.disabled = true; | ||
status.textContent = 'Please select a NIfTI image file to process.'; | ||
} | ||
}); | ||
|
||
processButton.addEventListener('click', async () => { | ||
if (!selectedFile) return; | ||
|
||
status.textContent = 'Processing...'; | ||
processButton.disabled = true; | ||
|
||
try { | ||
|
||
const outFile = await niimath.image(selectedFile) | ||
.dog(2, 3.2) | ||
.run(); | ||
|
||
// Create a download link for the processed file | ||
const url = URL.createObjectURL(outFile); | ||
downloadLink.href = url; | ||
downloadLink.download = 'processed_image.nii.gz'; | ||
downloadLink.style.display = 'block'; | ||
downloadLink.textContent = 'Download Processed Image'; | ||
|
||
status.textContent = 'Processing complete!'; | ||
} catch (error) { | ||
console.error('Processing failed:', error); | ||
status.textContent = 'Processing failed. Please check the console for details.'; | ||
} finally { | ||
processButton.disabled = false; | ||
} | ||
}); | ||
</script> | ||
</body> | ||
|
||
</html> |
Oops, something went wrong.