0
# JavaScript API
1
2
Browser-based DICOM to NIfTI conversion using WebAssembly. The JavaScript API provides an object-oriented interface for converting medical imaging data directly in the browser without requiring server uploads.
3
4
## Installation
5
6
```bash
7
npm install @niivue/dcm2niix
8
```
9
10
For JPEG-LS and JPEG2000 support:
11
12
```bash
13
npm install @niivue/dcm2niix
14
# Then import from the jpeg build
15
```
16
17
## Core Imports
18
19
Standard import (basic JPEG support):
20
21
```javascript
22
import { Dcm2niix } from '@niivue/dcm2niix';
23
```
24
25
Enhanced import (JPEG-LS and JPEG2000 support):
26
27
```javascript
28
import { Dcm2niix } from '@niivue/dcm2niix/jpeg';
29
```
30
31
## Basic Usage
32
33
```javascript
34
import { Dcm2niix } from '@niivue/dcm2niix';
35
36
// Initialize converter
37
const dcm2niix = new Dcm2niix();
38
await dcm2niix.init();
39
40
// Setup file input handler
41
const fileInput = document.getElementById('fileInput'); // with webkitdirectory and multiple attributes
42
fileInput.addEventListener('change', async (event) => {
43
const files = event.target.files;
44
45
try {
46
const convertedFiles = await dcm2niix
47
.input(files)
48
.bids('y') // Generate BIDS sidecar
49
.verbose('y') // Enable verbose output
50
.gzip('y') // Compress output
51
.run();
52
53
// Process converted files
54
convertedFiles.forEach(file => {
55
console.log(`Converted: ${file.name} (${file.type})`);
56
// Create download link, display in viewer, etc.
57
});
58
} catch (error) {
59
console.error('Conversion failed:', error.message);
60
}
61
});
62
```
63
64
## Capabilities
65
66
### Dcm2niix Class
67
68
Main class for DICOM to NIfTI conversion in the browser.
69
70
```javascript { .api }
71
/**
72
* Main dcm2niix conversion class
73
*/
74
class Dcm2niix {
75
constructor();
76
77
/**
78
* Initialize WebAssembly worker
79
* @returns Promise that resolves when worker is ready
80
*/
81
init(): Promise<boolean>;
82
83
/**
84
* Create processor for file input
85
* @param fileList - Files from input element or file array
86
* @returns Processor instance for chaining options
87
*/
88
input(fileList: FileList | File[]): Processor;
89
90
/**
91
* Create processor for webkit directory input
92
* @param fileList - Files from webkitdirectory input
93
* @returns Processor instance for chaining options
94
*/
95
inputFromWebkitDirectory(fileList: FileList | File[]): Processor;
96
97
/**
98
* Create processor for drag-and-drop files
99
* @param items - DataTransferItem array from drop event
100
* @returns Processor instance for chaining options
101
*/
102
inputFromDropItems(items: DataTransferItem[]): Processor;
103
}
104
```
105
106
**Usage Example:**
107
108
```javascript
109
const dcm2niix = new Dcm2niix();
110
111
// Initialize (required before use)
112
await dcm2niix.init();
113
114
// Handle different input sources
115
const processor1 = dcm2niix.input(fileInputElement.files);
116
const processor2 = dcm2niix.inputFromWebkitDirectory(directoryFiles);
117
const processor3 = dcm2niix.inputFromDropItems(dropEvent.dataTransfer.items);
118
```
119
120
### Processor Class
121
122
Handles conversion configuration and execution. All configuration methods return the processor instance for method chaining.
123
124
```javascript { .api }
125
/**
126
* Conversion processor with chainable configuration methods
127
*/
128
class Processor {
129
/**
130
* Execute the conversion
131
* @returns Promise resolving to array of converted files
132
*/
133
run(): Promise<File[]>;
134
135
// === Core Options ===
136
137
/**
138
* BIDS sidecar generation
139
* @param value - 'y'=generate, 'n'=no sidecar, 'o'=only sidecar (no NIfTI)
140
*/
141
b(value: 'y' | 'n' | 'o'): Processor;
142
bids(value: 'y' | 'n' | 'o'): Processor;
143
144
/**
145
* Verbosity level
146
* @param value - 'n'/'0'=quiet, 'y'/'1'=verbose, '2'=very verbose
147
*/
148
v(value: 'n' | 'y' | '0' | '1' | '2'): Processor;
149
verbose(value: 'n' | 'y' | '0' | '1' | '2'): Processor;
150
151
/**
152
* Compression options
153
* @param value - 'y'=pigz, 'o'=optimal, 'i'=internal, 'n'=none, '3'=no 3D
154
*/
155
z(value: 'y' | 'o' | 'i' | 'n' | '3'): Processor;
156
gzip(value: 'y' | 'o' | 'i' | 'n' | '3'): Processor;
157
158
// === Format Options ===
159
160
/**
161
* Export format selection
162
* @param value - 'y'=NRRD, 'o'=MGH, 'j'=JSON, 'b'=BJNIfTI, 'n'=NIfTI
163
*/
164
e(value: 'y' | 'n' | 'o' | 'j' | 'b'): Processor;
165
exportFormat(value: 'y' | 'n' | 'o' | 'j' | 'b'): Processor;
166
167
/**
168
* Filename format with DICOM field placeholders
169
* @param format - Format string with %placeholders
170
*/
171
f(format: string): Processor;
172
filenameformat(format: string): Processor;
173
174
// === Processing Options ===
175
176
/**
177
* Adjacent DICOMs for faster conversion
178
* @param value - 'y'=assume same folder, 'n'=search subdirectories
179
*/
180
a(value: 'y' | 'n'): Processor;
181
adjacent(value: 'y' | 'n'): Processor;
182
183
/**
184
* Ignore derived, localizer and 2D images
185
* @param value - 'y'=ignore, 'n'=include all
186
*/
187
i(value: 'y' | 'n'): Processor;
188
ignoreDerived(value: 'y' | 'n'): Processor;
189
190
/**
191
* Merge 2D slices from same series
192
* @param value - 'n'/'0'=no merge, 'y'/'1'=force merge, '2'=auto merge
193
*/
194
m(value: 'n' | 'y' | '0' | '1' | '2'): Processor;
195
merge2DSlices(value: 'n' | 'y' | '0' | '1' | '2'): Processor;
196
197
/**
198
* Single file mode
199
* @param value - 'y'=process only one file, 'n'=process all files
200
*/
201
s(value: 'y' | 'n'): Processor;
202
singleFileMode(value: 'y' | 'n'): Processor;
203
204
// === Data Processing ===
205
206
/**
207
* Lossless 16-bit integer scaling
208
* @param value - 'y'=scale, 'n'=uint16->int16, 'o'=preserve original
209
*/
210
l(value: 'y' | 'n' | 'o'): Processor;
211
losslessScale(value: 'y' | 'n' | 'o'): Processor;
212
213
/**
214
* Philips precise float scaling
215
* @param value - 'y'=precise float, 'n'=display scaling
216
*/
217
p(value: 'y' | 'n'): Processor;
218
philipsPreciseFloat(value: 'y' | 'n'): Processor;
219
220
/**
221
* Crop 3D acquisitions
222
* @param value - 'y'=crop, 'n'=no crop, 'i'=ignore (no crop/rotate)
223
*/
224
x(value: 'y' | 'n' | 'i'): Processor;
225
crop(value: 'y' | 'n' | 'i'): Processor;
226
227
// === Metadata Options ===
228
229
/**
230
* Comment for NIfTI aux_file field
231
* @param comment - Text comment (up to 24 characters)
232
*/
233
c(comment: string): Processor;
234
comment(comment: string): Processor;
235
236
/**
237
* BIDS anonymization
238
* @param value - 'y'=anonymize BIDS, 'n'=include patient details
239
*/
240
ba(value: 'y' | 'n'): Processor;
241
bidsAnonymize(value: 'y' | 'n'): Processor;
242
243
// === Advanced Options ===
244
245
/**
246
* Compression level for gzip
247
* @param level - Compression level 1-9 (1=fastest, 9=smallest)
248
*/
249
compressionLevel(level: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9): Processor;
250
251
/**
252
* Directory search depth
253
* @param depth - Search depth 0-9
254
*/
255
d(depth: number): Processor;
256
directorySearchDepth(depth: number): Processor;
257
258
/**
259
* Convert specific series by CRC number
260
* @param crc - Series CRC number to convert
261
*/
262
n(crc: number): Processor;
263
seriesCRC(crc: number): Processor;
264
265
/**
266
* Search directory behavior
267
* @param value - 'y'=show count, 'l'=list files, 'n'=no search
268
*/
269
q(value: 'y' | 'l' | 'n'): Processor;
270
searchDirectory(value: 'y' | 'l' | 'n'): Processor;
271
272
/**
273
* Rename instead of convert
274
* @param value - 'y'=rename only, 'n'=convert
275
*/
276
r(value: 'y' | 'n'): Processor;
277
renameOnly(value: 'y' | 'n'): Processor;
278
279
/**
280
* Write behavior for name conflicts
281
* @param behavior - 0=skip, 1=overwrite, 2=add suffix
282
*/
283
w(behavior: 0 | 1 | 2): Processor;
284
writeBehavior(behavior: 0 | 1 | 2): Processor;
285
286
/**
287
* Byte order
288
* @param value - 'y'=big-endian, 'n'=little-endian, 'o'=optimal/native
289
*/
290
bigEndian(value: 'y' | 'n' | 'o'): Processor;
291
292
/**
293
* Ignore trigger times
294
*/
295
ignoreTriggerTimes(): Processor;
296
297
/**
298
* Omit filename post-fixes
299
*/
300
terse(): Processor;
301
302
/**
303
* Slicer format features
304
*/
305
xml(): Processor;
306
307
/**
308
* Show version information
309
*/
310
version(): Processor;
311
}
312
```
313
314
## Advanced Usage Examples
315
316
### File Input Handling
317
318
```javascript
319
import { Dcm2niix } from '@niivue/dcm2niix';
320
321
const dcm2niix = new Dcm2niix();
322
await dcm2niix.init();
323
324
// Directory input with webkitdirectory
325
const directoryInput = document.getElementById('dirInput');
326
directoryInput.addEventListener('change', async (event) => {
327
const files = event.target.files;
328
const results = await dcm2niix.inputFromWebkitDirectory(files).run();
329
console.log('Converted files:', results);
330
});
331
332
// Drag and drop handling
333
const dropZone = document.getElementById('dropZone');
334
dropZone.addEventListener('drop', async (event) => {
335
event.preventDefault();
336
const items = event.dataTransfer.items;
337
338
// Set custom relative paths for drop events
339
const filesWithPaths = [];
340
for (let item of items) {
341
const file = item.getAsFile();
342
if (file) {
343
file._webkitRelativePath = file.name; // Custom property for worker
344
filesWithPaths.push(file);
345
}
346
}
347
348
const results = await dcm2niix.inputFromDropItems(filesWithPaths).run();
349
});
350
```
351
352
### Complex Conversion Pipeline
353
354
```javascript
355
// Advanced conversion with multiple options
356
const results = await dcm2niix
357
.input(files)
358
.verbose('2') // Maximum verbosity
359
.bids('y') // Generate BIDS sidecar
360
.bidsAnonymize('y') // Anonymize BIDS output
361
.gzip('o') // Optimal compression
362
.compressionLevel(9) // Maximum compression
363
.filenameformat('%p_%t_%s') // Custom filename format
364
.ignoreDerived('y') // Skip derived images
365
.merge2DSlices('2') // Auto-merge 2D slices
366
.losslessScale('y') // Scale 16-bit data
367
.crop('y') // Crop 3D acquisitions
368
.comment('Processed by web app') // Add comment
369
.run();
370
371
// Process results by file type
372
results.forEach(file => {
373
if (file.name.endsWith('.nii.gz')) {
374
console.log('NIfTI file:', file.name);
375
// Display in viewer, trigger download, etc.
376
} else if (file.name.endsWith('.json')) {
377
console.log('BIDS sidecar:', file.name);
378
// Parse JSON metadata
379
} else if (file.name.endsWith('.bval') || file.name.endsWith('.bvec')) {
380
console.log('DTI file:', file.name);
381
// Handle diffusion data
382
}
383
});
384
```
385
386
### Error Handling
387
388
```javascript
389
try {
390
const results = await dcm2niix
391
.input(files)
392
.bids('y')
393
.run();
394
395
if (results.length === 0) {
396
console.warn('No files were converted - check input files');
397
}
398
399
} catch (error) {
400
if (error.message.includes('exit code')) {
401
// dcm2niix processing error
402
const exitCode = error.message.match(/exit code (\d+)/)?.[1];
403
switch (exitCode) {
404
case '2':
405
console.error('No valid DICOM files found');
406
break;
407
case '4':
408
console.error('Corrupt DICOM file encountered');
409
break;
410
default:
411
console.error('Conversion failed:', error.message);
412
}
413
} else if (error.message.includes('Worker')) {
414
console.error('WebAssembly initialization failed:', error.message);
415
} else {
416
console.error('Unexpected error:', error.message);
417
}
418
}
419
```
420
421
### Filename Format Placeholders
422
423
When using the `filenameformat()` method, these placeholders are available:
424
425
```javascript
426
dcm2niix
427
.input(files)
428
.filenameformat('%p_%t_%s_%e') // protocol_time_series_echo
429
.run();
430
```
431
432
Available placeholders:
433
- `%a` - Antenna (coil) name
434
- `%b` - Basename
435
- `%c` - Comments
436
- `%d` - Description
437
- `%e` - Echo number
438
- `%f` - Folder name
439
- `%g` - Accession number
440
- `%i` - Patient ID
441
- `%j` - Series Instance UID
442
- `%k` - Study Instance UID
443
- `%m` - Manufacturer
444
- `%n` - Patient name
445
- `%o` - Media Object Instance UID
446
- `%p` - Protocol name
447
- `%r` - Instance number
448
- `%s` - Series number
449
- `%t` - Time
450
- `%u` - Acquisition number
451
- `%v` - Vendor
452
- `%x` - Study ID
453
- `%z` - Sequence name
454
455
## Types
456
457
```typescript { .api }
458
/**
459
* File input types supported by dcm2niix
460
*/
461
type FileInput = FileList | File[] | DataTransferItem[];
462
463
/**
464
* Boolean option values
465
*/
466
type BooleanOption = 'y' | 'n';
467
468
/**
469
* Verbosity levels
470
*/
471
type VerbosityLevel = 'n' | 'y' | '0' | '1' | '2';
472
473
/**
474
* Compression options
475
*/
476
type CompressionOption = 'y' | 'o' | 'i' | 'n' | '3';
477
478
/**
479
* Export format options
480
*/
481
type ExportFormat = 'y' | 'n' | 'o' | 'j' | 'b';
482
483
/**
484
* Merge options for 2D slices
485
*/
486
type MergeOption = 'n' | 'y' | '0' | '1' | '2';
487
488
/**
489
* Scaling options for 16-bit data
490
*/
491
type ScalingOption = 'y' | 'n' | 'o';
492
493
/**
494
* Crop options for 3D data
495
*/
496
type CropOption = 'y' | 'n' | 'i';
497
498
/**
499
* Byte order options
500
*/
501
type ByteOrderOption = 'y' | 'n' | 'o';
502
503
/**
504
* Search directory options
505
*/
506
type SearchOption = 'y' | 'l' | 'n';
507
508
/**
509
* Write behavior for file conflicts
510
*/
511
type WriteBehavior = 0 | 1 | 2;
512
513
/**
514
* Compression levels
515
*/
516
type CompressionLevel = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
517
518
/**
519
* Conversion result extends File with guaranteed properties
520
*/
521
interface ConversionResult extends File {
522
readonly name: string; // Output filename
523
readonly type: string; // MIME type based on extension
524
readonly size: number; // File size in bytes
525
}
526
```
527
528
## Browser Compatibility
529
530
The JavaScript API requires:
531
- **WebAssembly**: Supported in all modern browsers
532
- **Web Workers**: For background processing
533
- **File API**: For file input handling
534
- **ES6 Modules**: For import/export syntax
535
536
Minimum browser versions:
537
- Chrome 57+
538
- Firefox 52+
539
- Safari 11+
540
- Edge 16+