Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add wasm jpegls and j2k/htj2k support #910

Merged
merged 1 commit into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# GitHub syntax highlighting
pixi.lock linguist-language=YAML linguist-generated=true
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,10 @@ dist
node_modules
dcm2niix*.js
dcm2niix*.wasm

# pixi environments
.pixi
*.egg-info

*.tar.gz
openjpeg-2.5.3/
4 changes: 2 additions & 2 deletions console/makefile
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ wasm:
emcc -O3 $(UFILES) -lz -s USE_ZLIB -s DEMANGLE_SUPPORT=1 -s EXPORTED_RUNTIME_METHODS='["callMain", "ccall", "cwrap", "FS", "FS_createDataFile", "FS_readFile", "FS_unlink", "allocateUTF8", "getValue", "stringToUTF8", "setValue"]' -s STACK_OVERFLOW_CHECK=2 -s STACK_SIZE=16MB -s ALLOW_MEMORY_GROWTH=1 -s WASM=1 -s EXPORT_ES6=1 -s MODULARIZE=1 -s EXPORTED_FUNCTIONS='["_main", "_malloc", "_free"]' -s FORCE_FILESYSTEM=1 -s INVOKE_RUN=0 -o ../js/src/dcm2niix.js
# STACK_SIZE=16MB is the minimum value found to work with the current codebase when targeting WASM

wasm-jpegls:
emcc -O3 $(JFLAGS) $(UFILES) -lz -s USE_ZLIB -s DEMANGLE_SUPPORT=1 -s EXPORTED_RUNTIME_METHODS='["callMain", "ccall", "cwrap", "FS", "FS_createDataFile", "FS_readFile", "FS_unlink", "allocateUTF8", "getValue", "stringToUTF8", "setValue"]' -s STACK_OVERFLOW_CHECK=2 -s STACK_SIZE=16MB -s ALLOW_MEMORY_GROWTH=1 -s WASM=1 -s EXPORT_ES6=1 -s MODULARIZE=1 -s EXPORTED_FUNCTIONS='["_main", "_malloc", "_free"]' -s FORCE_FILESYSTEM=1 -s INVOKE_RUN=0 -o ../js/src/dcm2niix.jpegls.js
wasm-jpeg:
emcc -O3 $(JFLAGS) $(CFILES) -DUSE_OPENJPEG -I${PIXI_PROJECT_ROOT}/openjpeg-2.5.3/src/lib/openjp2/ -I${PIXI_PROJECT_ROOT}/openjpeg-2.5.3/build/src/lib/openjp2/ -L${PIXI_PROJECT_ROOT}/openjpeg-2.5.3/build/bin/ -lopenjp2 -lz -s USE_ZLIB -s DEMANGLE_SUPPORT=1 -s EXPORTED_RUNTIME_METHODS='["callMain", "ccall", "cwrap", "FS", "FS_createDataFile", "FS_readFile", "FS_unlink", "allocateUTF8", "getValue", "stringToUTF8", "setValue"]' -s STACK_OVERFLOW_CHECK=2 -s STACK_SIZE=16MB -s ALLOW_MEMORY_GROWTH=1 -s WASM=1 -s EXPORT_ES6=1 -s MODULARIZE=1 -s EXPORTED_FUNCTIONS='["_main", "_malloc", "_free"]' -s FORCE_FILESYSTEM=1 -s INVOKE_RUN=0 -o ../js/src/dcm2niix.jpeg.js
# STACK_SIZE=16MB is the minimum value found to work with the current codebase when targeting WASM

28 changes: 28 additions & 0 deletions js/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ The `@niivue/dcm2niix` JavaScript library offers an object oriented API for work
// <input type="file" id="fileInput" webkitdirectory multiple>
import { Dcm2niix } from '@niivue/dcm2niix';

// use the jpeg import to load jpegls and j2k build of dcm2niix
// import { Dcm2niix } from '@niivue/dcm2niix/jpeg';

const dcm2niix = new Dcm2niix();
// call the init() method to load the wasm before processing any data
await dcm2niix.init();
Expand Down Expand Up @@ -66,6 +69,31 @@ npm install /path/to/niivue-dcm2niix.tgz

## Development

### Environment setup

You will need:
- NodeJS/NPM
- Emscripten
- Pixi
- Make/Cmake

[Pixi](https://prefix.dev/) is used to create the environment for building the WASM port of `dcm2niix`. To install pixi, follow their instructions.

> Note: on macos-arm64, you can get emscripten using homebrew since there is not yet a native arm64 version of emscripten on conda-forge (which is where pixi searches for packages).

### Building dcm2niix WASM

```bash
pixi run wasm
```

### clean up after build

```bash
pixi run clean
```

### If doing things manually
First `cd` into the `js` directory of the `dcm2niix` repository.

```bash
Expand Down
10 changes: 5 additions & 5 deletions js/esbuild.config.jpegls.js → js/esbuild.config.jpeg.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ const esbuild = require('esbuild');
const fs = require('fs');

esbuild.build({
entryPoints: ['./src/index.jpegls.js'],
outfile: './dist/index.jpegls.js',
entryPoints: ['./src/index.jpeg.js'],
outfile: './dist/index.jpeg.js',
bundle: true,
format: 'esm',
target: ['es2020'],
Expand All @@ -17,8 +17,8 @@ esbuild.build({
// 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.jpegls.js', './dist/worker.jpegls.js');
fs.copyFileSync('./src/dcm2niix.jpegls.wasm', './dist/dcm2niix.jpegls.wasm');
fs.copyFileSync('./src/dcm2niix.jpegls.js', './dist/dcm2niix.jpegls.js');
fs.copyFileSync('./src/worker.jpeg.js', './dist/worker.jpeg.js');
fs.copyFileSync('./src/dcm2niix.jpeg.wasm', './dist/dcm2niix.jpeg.wasm');
fs.copyFileSync('./src/dcm2niix.jpeg.js', './dist/dcm2niix.jpeg.js');
console.log('Build completed!');
}).catch(() => process.exit(1));
6 changes: 3 additions & 3 deletions js/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ <h1>dcm2niix WASM Demo</h1>
<a id="downloadLink" style="display: none;">Download Processed Image(s)</a>

<script type="module">
import { Dcm2niix } from './dist/index.js';
// import { Dcm2niix } from './dist/index.js';
// use below line for jpegls version
// import { Dcm2niix } from './dist/index.jpegls.js';
import { Dcm2niix } from './dist/index.jpeg.js';

const fileInput = document.getElementById('fileInput');
const processButton = document.getElementById('processButton');
Expand Down Expand Up @@ -52,7 +52,7 @@ <h1>dcm2niix WASM Demo</h1>
}
const dcm2niix = new Dcm2niix();
await dcm2niix.init()
const resultFileList = await dcm2niix.inputFromDropItems(files).run()
const resultFileList = await dcm2niix.inputFromDropItems(files).v().run()

resultFileList.forEach((resultFile, index) => {
let url = URL.createObjectURL(resultFile);
Expand Down
4 changes: 2 additions & 2 deletions js/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 7 additions & 6 deletions js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,20 @@
".": {
"import": "./dist/index.js"
},
"./with-jpegls": {
"import": "./dist/index.jpegls.js"
"./jpeg": {
"import": "./dist/index.jpeg.js"
}
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "node esbuild.config.js && node esbuild.config.jpegls.js",
"build": "node esbuild.config.js && node esbuild.config.jpeg.js",
"makeWasm": "make wasm -C ../console",
"makeWasmJpegls": "JPEGLS=1 make wasm-jpegls -C ../console",
"makeWasmJpeg": "JPEGLS=1 make wasm-jpeg -C ../console",
"fixWasmJs": "node scripts/pre-build.js -i src/dcm2niix.js -o src/dcm2niix.js",
"fixWasmJsJpegls": "node scripts/pre-build.js -i src/dcm2niix.jpegls.js -o src/dcm2niix.jpegls.js",
"prebuild": "npm run makeWasm && npm run makeWasmJpegls && npm run fixWasmJs && npm run fixWasmJsJpegls",
"fixWasmJsJpeg": "node scripts/pre-build.js -i src/dcm2niix.jpeg.js -o src/dcm2niix.jpeg.js",
"prebuild": "npm run makeWasm && npm run makeWasmJpeg && npm run fixWasmJs && npm run fixWasmJsJpeg",
"demo": "npm run build && npx http-server .",
"demo-no-build": "npx http-server .",
"pub": "npm run build && npm publish --access public"
},
"keywords": [
Expand Down
2 changes: 1 addition & 1 deletion js/src/index.jpegls.js → js/src/index.jpeg.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export class Dcm2niix {
}

init() {
this.worker = new Worker(new URL('./worker.jpegls.js', import.meta.url), { type: 'module' });
this.worker = new Worker(new URL('./worker.jpeg.js', import.meta.url), { type: 'module' });
return new Promise((resolve, reject) => {
// handle worker ready message.
// This gets reassigned in the run() method,
Expand Down
2 changes: 1 addition & 1 deletion js/src/worker.jpegls.js → js/src/worker.jpeg.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// The worker is of type "module" so that it can use ES6 module syntax.
// Importantly, the emscripten code must be compiled with: -s EXPORT_ES6=1 -s MODULARIZE=1.
// This allows proper module bundlers to import the worker and wasm properly with code splitting.
import Module from './dcm2niix.jpegls.js';
import Module from './dcm2niix.jpeg.js';

// initialise an instance of the Emscripten Module so that
// it is ready when the worker receives a message.
Expand Down
Loading
Loading