|
| 1 | +// src/index.js |
| 2 | +var Dcm2niix = class { |
| 3 | + constructor() { |
| 4 | + this.worker = null; |
| 5 | + } |
| 6 | + init() { |
| 7 | + this.worker = new Worker(new URL("./worker.js", import.meta.url), { type: "module" }); |
| 8 | + return new Promise((resolve, reject) => { |
| 9 | + this.worker.onmessage = (event) => { |
| 10 | + if (event.data && event.data.type === "ready") { |
| 11 | + resolve(true); |
| 12 | + } |
| 13 | + }; |
| 14 | + this.worker.onerror = (error) => { |
| 15 | + reject(new Error(`Worker failed to load: ${error.message}`)); |
| 16 | + }; |
| 17 | + }); |
| 18 | + } |
| 19 | + input(fileList) { |
| 20 | + return new Processor({ worker: this.worker, fileList }); |
| 21 | + } |
| 22 | +}; |
| 23 | +var Processor = class { |
| 24 | + constructor({ worker, fileList }) { |
| 25 | + this.worker = worker; |
| 26 | + this.fileList = fileList; |
| 27 | + this.commands = []; |
| 28 | + } |
| 29 | + _addCommand(cmd, ...args) { |
| 30 | + this.commands.push(cmd, ...args.map(String)); |
| 31 | + return this; |
| 32 | + } |
| 33 | + // --version |
| 34 | + version() { |
| 35 | + return this._addCommand("--version"); |
| 36 | + } |
| 37 | + // -1..-9 gz compression level (1=fastest..9=smallest, default 6) |
| 38 | + compressionLevel(level) { |
| 39 | + return this._addCommand(`-${level}`); |
| 40 | + } |
| 41 | + // -a adjacent DICOMs (images from same series always in same folder) for faster conversion (n/y, default n) |
| 42 | + a(value) { |
| 43 | + return this._addCommand("-a", value); |
| 44 | + } |
| 45 | + // alias for -a |
| 46 | + adjacent(value) { |
| 47 | + return this.a(value); |
| 48 | + } |
| 49 | + // -b BIDS sidecar (y/n/o [o=only: no NIfTI], default y) |
| 50 | + b(value) { |
| 51 | + return this._addCommand("-b", value); |
| 52 | + } |
| 53 | + // alias for -b |
| 54 | + bids(value) { |
| 55 | + return this.b(value); |
| 56 | + } |
| 57 | + // -ba BIDS anonymize (y/n, default y) |
| 58 | + ba(value) { |
| 59 | + return this._addCommand("-ba", value); |
| 60 | + } |
| 61 | + // alias for -ba |
| 62 | + bidsAnonymize(value) { |
| 63 | + return this.ba(value); |
| 64 | + } |
| 65 | + // -c comment stored as NIfTI aux_file (up to 24 characters) |
| 66 | + c(value) { |
| 67 | + return this._addCommand("-c", value); |
| 68 | + } |
| 69 | + // alias for -c |
| 70 | + comment(value) { |
| 71 | + return this.c(value); |
| 72 | + } |
| 73 | + // -d directory search depth (0..9, default 5) |
| 74 | + // Note: not used in browser/wasm since file list is a flat list |
| 75 | + d(value) { |
| 76 | + return this._addCommand("-d", value); |
| 77 | + } |
| 78 | + // alias for -d |
| 79 | + directorySearchDepth(value) { |
| 80 | + return this.d(value); |
| 81 | + } |
| 82 | + // export as NRRD (y) or MGH (o) or JSON/JNIfTI (j) or BJNIfTI (b) instead of NIfTI (y/n/o/j/b, default n) |
| 83 | + e(value) { |
| 84 | + return this._addCommand("-e", value); |
| 85 | + } |
| 86 | + // alias for -e |
| 87 | + exportFormat(value) { |
| 88 | + return this.e(value); |
| 89 | + } |
| 90 | + // -f : filename (%a=antenna (coil) name, %b=basename, %c=comments, %d=description, |
| 91 | + // %e=echo number, %f=folder name, %g=accession number, %i=ID of patient, %j=seriesInstanceUID, |
| 92 | + // %k=studyInstanceUID, %m=manufacturer, %n=name of patient, %o=mediaObjectInstanceUID, |
| 93 | + // %p=protocol, %r=instance number, %s=series number, %t=time, %u=acquisition number, |
| 94 | + // %v=vendor, %x=study ID; %z=sequence name; |
| 95 | + // |
| 96 | + // default '%f_%p_%t_%s') |
| 97 | + f(value) { |
| 98 | + return this._addCommand("-f", value); |
| 99 | + } |
| 100 | + // alias for -f |
| 101 | + filenameformat(value) { |
| 102 | + return this.f(value); |
| 103 | + } |
| 104 | + // -i : ignore derived, localizer and 2D images (y/n, default n) |
| 105 | + i(value) { |
| 106 | + return this._addCommand("-i", value); |
| 107 | + } |
| 108 | + // alias for -i |
| 109 | + ignoreDerived(value) { |
| 110 | + return this.i(value); |
| 111 | + } |
| 112 | + // -l : losslessly scale 16-bit integers to use dynamic range (y/n/o [yes=scale, no=no, but uint16->int16, o=original], default o) |
| 113 | + l(value) { |
| 114 | + return this._addCommand("-l", value); |
| 115 | + } |
| 116 | + // alias for -l |
| 117 | + losslessScale(value) { |
| 118 | + return this.l(value); |
| 119 | + } |
| 120 | + // -m : merge 2D slices from same series regardless of echo, exposure, etc. (n/y or 0/1/2, default 2) [no, yes, auto] |
| 121 | + m(value) { |
| 122 | + return this._addCommand("-m", value); |
| 123 | + } |
| 124 | + // alias for -m |
| 125 | + merge2DSlices(value) { |
| 126 | + return this.m(value); |
| 127 | + } |
| 128 | + // -n : only convert this series CRC number - can be used up to 16 times (default convert all) |
| 129 | + n(value) { |
| 130 | + return this._addCommand("-n", value); |
| 131 | + } |
| 132 | + // alias for -n |
| 133 | + seriesCRC(value) { |
| 134 | + return this.n(value); |
| 135 | + } |
| 136 | + // -o : output directory (omit to save to input folder) |
| 137 | + // o(value){ |
| 138 | + // return this._addCommand('-o', value); |
| 139 | + // } |
| 140 | + // alias for -o |
| 141 | + // outputDirectory(value){ |
| 142 | + // return this.o(value); |
| 143 | + // } |
| 144 | + // -p : Philips precise float (not display) scaling (y/n, default y) |
| 145 | + p(value) { |
| 146 | + return this._addCommand("-p", value); |
| 147 | + } |
| 148 | + // alias for -p |
| 149 | + philipsPreciseFloat(value) { |
| 150 | + return this.p(value); |
| 151 | + } |
| 152 | + // -q : only search directory for DICOMs (y/l/n, default y) [y=show number of DICOMs found, l=additionally list DICOMs found, n=no] |
| 153 | + q(value) { |
| 154 | + return this._addCommand("-q", value); |
| 155 | + } |
| 156 | + // alias for -q |
| 157 | + searchDirectory(value) { |
| 158 | + return this.q(value); |
| 159 | + } |
| 160 | + // -r : rename instead of convert DICOMs (y/n, default n) |
| 161 | + r(value) { |
| 162 | + return this._addCommand("-r", value); |
| 163 | + } |
| 164 | + // alias for -r |
| 165 | + renameOnly(value) { |
| 166 | + return this.r(value); |
| 167 | + } |
| 168 | + // -s : single file mode, do not convert other images in folder (y/n, default n) |
| 169 | + s(value) { |
| 170 | + return this._addCommand("-s", value); |
| 171 | + } |
| 172 | + // alias for -s |
| 173 | + singleFileMode(value) { |
| 174 | + return this.s(value); |
| 175 | + } |
| 176 | + // -v : verbose (n/y or 0/1/2, default 0) [no, yes, logorrheic] |
| 177 | + v(value) { |
| 178 | + return this._addCommand("-v", value); |
| 179 | + } |
| 180 | + // alias for -v |
| 181 | + verbose(value) { |
| 182 | + return this.v(value); |
| 183 | + } |
| 184 | + // -w : write behavior for name conflicts (0,1,2, default 2: 0=skip duplicates, 1=overwrite, 2=add suffix) |
| 185 | + w(value) { |
| 186 | + return this._addCommand("-w", value); |
| 187 | + } |
| 188 | + // alias for -w |
| 189 | + writeBehavior(value) { |
| 190 | + return this.w(value); |
| 191 | + } |
| 192 | + // -x : crop 3D acquisitions (y/n/i, default n, use 'i'gnore to neither crop nor rotate 3D acquisitions) |
| 193 | + x(value) { |
| 194 | + return this._addCommand("-x", value); |
| 195 | + } |
| 196 | + // alias for -x |
| 197 | + crop(value) { |
| 198 | + return this.x(value); |
| 199 | + } |
| 200 | + // -z : gz compress images (y/o/i/n/3, default n) [y=pigz, o=optimal pigz, i=internal:miniz, n=no, 3=no,3D] |
| 201 | + z(value) { |
| 202 | + return this._addCommand("-z", value); |
| 203 | + } |
| 204 | + // alias for -z |
| 205 | + gzip(value) { |
| 206 | + return this.z(value); |
| 207 | + } |
| 208 | + // --big-endian : byte order (y/n/o, default o) [y=big-end, n=little-end, o=optimal/native] |
| 209 | + bigEndian(value) { |
| 210 | + return this._addCommand("--big-endian", value); |
| 211 | + } |
| 212 | + // --ignore_trigger_times : disregard values in 0018,1060 and 0020,9153 |
| 213 | + ignoreTriggerTimes() { |
| 214 | + return this._addCommand("--ignore_trigger_times"); |
| 215 | + } |
| 216 | + // --terse : omit filename post-fixes (can cause overwrites) |
| 217 | + terse() { |
| 218 | + return this._addCommand("--terse"); |
| 219 | + } |
| 220 | + // --xml : Slicer format features |
| 221 | + xml() { |
| 222 | + return this._addCommand("--xml"); |
| 223 | + } |
| 224 | + async run() { |
| 225 | + return new Promise((resolve, reject) => { |
| 226 | + this.worker.onmessage = (e) => { |
| 227 | + if (e.data.type === "error") { |
| 228 | + reject(new Error(e.data.message)); |
| 229 | + } else { |
| 230 | + const { convertedFiles, exitCode } = e.data; |
| 231 | + if (exitCode === 0 || exitCode === 3) { |
| 232 | + resolve(convertedFiles); |
| 233 | + } else { |
| 234 | + reject(new Error(`dcm2niix processing failed with exit code ${exitCode}`)); |
| 235 | + } |
| 236 | + } |
| 237 | + }; |
| 238 | + const args = [...this.commands]; |
| 239 | + if (this.worker === null) { |
| 240 | + reject(new Error("Worker not initialized. Did you await the init() method?")); |
| 241 | + } |
| 242 | + const filesWithRelativePaths = Array.from(this.fileList).map((file) => ({ |
| 243 | + file, |
| 244 | + webkitRelativePath: file.webkitRelativePath || "" |
| 245 | + })); |
| 246 | + this.worker.postMessage({ fileList: filesWithRelativePaths, cmd: args }); |
| 247 | + }); |
| 248 | + } |
| 249 | +}; |
| 250 | +export { |
| 251 | + Dcm2niix |
| 252 | +}; |
0 commit comments