@radicalimaging/static-wado-creator 1.5.0 → 1.6.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +234 -0
  2. package/README.md +1 -1
  3. package/bin/mkdicomweb.mjs +8 -0
  4. package/dist/canvas-xaqc8v6y.node +0 -0
  5. package/dist/index.js +511433 -0
  6. package/lib/DeleteStudy.js +11 -9
  7. package/lib/RejectInstance.js +6 -5
  8. package/lib/StaticWado.js +222 -73
  9. package/lib/createMain.js +3 -3
  10. package/lib/createPart10.js +19 -19
  11. package/lib/createThumbnail.js +163 -0
  12. package/lib/deleteMain.js +2 -2
  13. package/lib/groupMain.js +2 -2
  14. package/lib/index.js +7 -5
  15. package/lib/indexMain.js +2 -2
  16. package/lib/instanceMain.js +3 -2
  17. package/lib/metadataMain.js +2 -2
  18. package/lib/mkdicomwebConfig.js +210 -115
  19. package/lib/model/TagLists.js +13 -4
  20. package/lib/model/uids.js +32 -28
  21. package/lib/operation/InstanceDeduplicate.js +18 -13
  22. package/lib/operation/ScanStudy.js +33 -7
  23. package/lib/operation/StudyData.js +122 -71
  24. package/lib/operation/ThumbnailService.js +44 -36
  25. package/lib/operation/adapter/decodeImage.js +7 -4
  26. package/lib/operation/adapter/getImageInfo.js +23 -6
  27. package/lib/operation/adapter/transcodeImage.js +157 -90
  28. package/lib/operation/extractImageFrames.js +25 -14
  29. package/lib/operation/getDataSet.js +4 -4
  30. package/lib/operation/getEncapsulatedImageFrame.js +16 -4
  31. package/lib/operation/getNumberOfFrames.js +2 -2
  32. package/lib/operation/getVR.js +12 -4
  33. package/lib/operation/getValue.js +42 -65
  34. package/lib/operation/validateMetadata.js +40 -0
  35. package/lib/program/index.js +2 -3
  36. package/lib/rejectMain.js +2 -2
  37. package/lib/serverMain.js +21 -0
  38. package/lib/util/IdCreator.js +25 -8
  39. package/lib/util/adaptProgramOpts.js +1 -1
  40. package/lib/util/compressionOptionParser.js +4 -4
  41. package/lib/util/resultsReport.ts +87 -0
  42. package/lib/writer/CompleteStudyWriter.js +42 -19
  43. package/lib/writer/DeduplicateWriter.js +7 -7
  44. package/lib/writer/ExpandUriPath.js +4 -3
  45. package/lib/writer/HashDataWriter.js +21 -17
  46. package/lib/writer/ImageFrameWriter.js +22 -10
  47. package/lib/writer/MultipartHeader.js +1 -1
  48. package/lib/writer/RawDicomWriter.js +18 -10
  49. package/lib/writer/ThumbnailWriter.js +2 -2
  50. package/lib/writer/VideoWriter.js +23 -34
  51. package/lib/writer/WriteMultipart.js +3 -3
  52. package/lib/writer/WriteStream.js +14 -12
  53. package/package.json +22 -18
  54. package/bin/mkdicomweb.js +0 -9
@@ -1,8 +1,11 @@
1
- const dicomCodec = require("@cornerstonejs/dicom-codec");
2
- const getImageInfo = require("./getImageInfo");
1
+ const dicomCodec = require('@cornerstonejs/dicom-codec');
2
+ const getImageInfo = require('./getImageInfo');
3
3
 
4
- async function decodeImage(imageFrame, dataset, transferSyntaxUid) {
5
- const imageInfo = getImageInfo(dataset);
4
+ function decodeImage(imageFrame, dataset, instance, transferSyntaxUid) {
5
+ const imageInfo = getImageInfo(dataset, instance);
6
+ if (imageFrame && !imageFrame.length) {
7
+ imageFrame = new Uint8Array(imageFrame);
8
+ }
6
9
  return dicomCodec.decode(imageFrame, imageInfo, transferSyntaxUid);
7
10
  }
8
11
 
@@ -1,12 +1,29 @@
1
+ const { Tags } = require('@radicalimaging/static-wado-util');
1
2
  /**
2
3
  * Minimum image info data to be used on transcode process by dicom-codec api.
3
4
  */
4
- function getImageInfo(dataSet) {
5
- const rows = dataSet.uint16("x00280010");
6
- const columns = dataSet.uint16("x00280011");
7
- const bitsAllocated = dataSet.uint16("x00280100");
8
- const samplesPerPixel = dataSet.uint16("x00280002");
9
- const pixelRepresentation = dataSet.uint16("x00280103") || 0; // not yet being used.
5
+ function getImageInfo(dataSet, instance) {
6
+ if (instance) {
7
+ const rows = Tags.getValue(instance, Tags.Rows);
8
+ const columns = Tags.getValue(instance, Tags.Columns);
9
+ const bitsAllocated = Tags.getValue(instance, Tags.BitsAllocated);
10
+ const samplesPerPixel = Tags.getValue(instance, Tags.SamplesPerPixel);
11
+ const pixelRepresentation = Tags.getValue(instance, Tags.PixelRepresentation) || 0; // not yet being used.
12
+
13
+ return {
14
+ bitsAllocated,
15
+ samplesPerPixel,
16
+ rows, // Number with the image rows/height
17
+ columns, // Number with the image columns/width,
18
+ signed: pixelRepresentation === 1,
19
+ pixelRepresentation,
20
+ };
21
+ }
22
+ const rows = dataSet.uint16('x00280010');
23
+ const columns = dataSet.uint16('x00280011');
24
+ const bitsAllocated = dataSet.uint16('x00280100');
25
+ const samplesPerPixel = dataSet.uint16('x00280002');
26
+ const pixelRepresentation = dataSet.uint16('x00280103') || 0; // not yet being used.
10
27
 
11
28
  return {
12
29
  bitsAllocated,
@@ -1,8 +1,8 @@
1
- const dicomCodec = require("@cornerstonejs/dicom-codec");
2
- const { Tags, replicate } = require("@radicalimaging/static-wado-util");
3
- const getImageInfo = require("./getImageInfo");
1
+ const dicomCodec = require('@cornerstonejs/dicom-codec');
2
+ const { Tags, replicate } = require('@radicalimaging/static-wado-util');
3
+ const getImageInfo = require('./getImageInfo');
4
4
 
5
- dicomCodec.setConfig("verbose: false");
5
+ dicomCodec.setConfig('verbose: false');
6
6
 
7
7
  const transcodeOp = {
8
8
  none: 0,
@@ -11,88 +11,117 @@ const transcodeOp = {
11
11
  transcode: 3, // decode and then encode
12
12
  };
13
13
 
14
+ const jpegBeforeEncode = (options, encoder) => {
15
+ const quality = options.quality ?? 99;
16
+ // First value is to encode as reversible lossless colour
17
+ return encoder => {
18
+ console.log('Calling setQuality', quality, !!encoder.setQuality);
19
+ encoder.setQuality(quality);
20
+ };
21
+ };
22
+
23
+ const jlsBeforeEncode = options => {
24
+ const delta = (options.delta ?? lossy) ? 3 : 0;
25
+ return encoder => encoder.setNearLossless(delta);
26
+ };
27
+
28
+ const htj2kBeforeEncode = options => {
29
+ const { lossy } = options;
30
+ const quality = lossy === true ? 0.002 : -1;
31
+ return encoder => encoder.setQuality(!lossy, quality);
32
+ };
33
+
14
34
  /**
15
35
  * Static mapping for transcoding decoder destination names/uids - currently only lei, jls and jls-lossy appear to work.
16
36
  */
17
37
  const transcodeDestinationMap = {
18
38
  lei: {
19
- transferSyntaxUid: "1.2.840.10008.1.2.1",
39
+ transferSyntaxUid: '1.2.840.10008.1.2.1',
20
40
  transcodeOp: transcodeOp.none,
21
41
  },
22
42
  jls: {
23
- transferSyntaxUid: "1.2.840.10008.1.2.4.80",
43
+ transferSyntaxUid: '1.2.840.10008.1.2.4.80',
24
44
  transcodeOp: transcodeOp.encode,
45
+ beforeEncode: jlsBeforeEncode.bind(null, { lossy: false }),
25
46
  },
26
- "jls-lossy": {
27
- transferSyntaxUid: "1.2.840.10008.1.2.4.81",
47
+ 'jls-lossy': {
48
+ transferSyntaxUid: '1.2.840.10008.1.2.4.81',
28
49
  transcodeOp: transcodeOp.encode,
50
+ beforeEncode: jlsBeforeEncode.bind(null, { lossy: true, delta: 3 }),
29
51
  },
30
52
  jp2: {
31
- transferSyntaxUid: "1.2.840.10008.1.2.4.90",
53
+ transferSyntaxUid: '1.2.840.10008.1.2.4.90',
32
54
  transcodeOp: transcodeOp.encode,
33
55
  },
34
- "jp2-lossy": {
35
- transferSyntaxUid: "1.2.840.10008.1.2.4.91",
56
+ 'jp2-lossy': {
57
+ transferSyntaxUid: '1.2.840.10008.1.2.4.91',
36
58
  transcodeOp: transcodeOp.encode,
37
59
  },
38
60
  jhc: {
39
- transferSyntaxUid: "1.2.840.10008.1.2.4.202",
61
+ transferSyntaxUid: '1.2.840.10008.1.2.4.201',
62
+ transcodeOp: transcodeOp.encode,
63
+ beforeEncode: htj2kBeforeEncode({}),
64
+ },
65
+ 'jhc-lossy': {
66
+ transferSyntaxUid: '1.2.840.10008.1.2.4.202',
40
67
  transcodeOp: transcodeOp.encode,
68
+ beforeEncode: htj2kBeforeEncode({ lossy: true }),
41
69
  },
42
70
  jpeg: {
43
- transferSyntaxUid: "1.2.840.10008.1.2.4.50",
71
+ transferSyntaxUid: '1.2.840.10008.1.2.4.50',
44
72
  transcodeOp: transcodeOp.encode,
73
+ // beforeEncode: jpegBeforeEncode({}),
45
74
  },
46
75
  };
47
76
 
48
77
  const transcodeSourceMap = {
49
- "1.2.840.10008.1.2": {
78
+ '1.2.840.10008.1.2': {
50
79
  transcodeOp: transcodeOp.decode,
51
- alias: "uncompressed",
80
+ alias: 'uncompressed',
52
81
  },
53
- "1.2.840.10008.1.2.1": {
82
+ '1.2.840.10008.1.2.1': {
54
83
  transcodeOp: transcodeOp.none,
55
- alias: "uncompressed",
84
+ alias: 'uncompressed',
56
85
  },
57
- "1.2.840.10008.1.2.2": {
86
+ '1.2.840.10008.1.2.2': {
58
87
  transcodeOp: transcodeOp.decode,
59
- alias: "uncompressed",
88
+ alias: 'uncompressed',
60
89
  },
61
- "1.2.840.10008.1.2.4.50": {
90
+ '1.2.840.10008.1.2.4.50': {
62
91
  transcodeOp: transcodeOp.decode,
63
- alias: "jpeg",
92
+ alias: 'jpeg',
64
93
  },
65
- "1.2.840.10008.1.2.4.57": {
94
+ '1.2.840.10008.1.2.4.57': {
66
95
  transcodeOp: transcodeOp.decode,
67
- alias: "jls",
96
+ alias: 'jls',
68
97
  },
69
- "1.2.840.10008.1.2.4.70": {
98
+ '1.2.840.10008.1.2.4.70': {
70
99
  transcodeOp: transcodeOp.decode,
71
- alias: "jpll",
100
+ alias: 'jpll',
72
101
  },
73
- "1.2.840.10008.1.2.4.80": {
102
+ '1.2.840.10008.1.2.4.80': {
74
103
  transcodeOp: transcodeOp.decode,
75
- alias: "jls",
104
+ alias: 'jls',
76
105
  },
77
- "1.2.840.10008.1.2.4.90": {
106
+ '1.2.840.10008.1.2.4.90': {
78
107
  transcodeOp: transcodeOp.decode,
79
- alias: "jp2",
108
+ alias: 'jp2',
80
109
  },
81
- "1.2.840.10008.1.2.4.91": {
110
+ '1.2.840.10008.1.2.4.91': {
82
111
  transcodeOp: transcodeOp.decode,
83
- alias: "jp2",
112
+ alias: 'jp2',
84
113
  },
85
- "3.2.840.10008.1.2.4.96": {
114
+ '3.2.840.10008.1.2.4.96': {
86
115
  transcodeOp: transcodeOp.decode,
87
- alias: "jhc",
116
+ alias: 'jhc',
88
117
  },
89
- "1.2.840.10008.1.2.4.202": {
118
+ '1.2.840.10008.1.2.4.202': {
90
119
  transcodeOp: transcodeOp.decode,
91
- alias: "jhc",
120
+ alias: 'jhc',
92
121
  },
93
- "1.2.840.10008.1.2.5": {
122
+ '1.2.840.10008.1.2.5': {
94
123
  transcodeOp: transcodeOp.decode,
95
- alias: "rle",
124
+ alias: 'rle',
96
125
  },
97
126
  };
98
127
 
@@ -103,11 +132,10 @@ const transcodeSourceMap = {
103
132
  * @returns A partial transcoder definition. Otherwise it returns undefined.
104
133
  */
105
134
  function getDestinationTranscoder(id) {
106
- const destinationTranscoderEntry = Object.entries(transcodeDestinationMap).find(([key, value]) => key === id || value.transferSyntaxUid === id);
107
- if (destinationTranscoderEntry) {
108
- return destinationTranscoderEntry[1];
109
- }
110
- return undefined;
135
+ const destinationTranscoderEntry =
136
+ transcodeDestinationMap[id] ||
137
+ Object.values(transcodeDestinationMap).find(value => value.transferSyntaxUid === id);
138
+ return destinationTranscoderEntry;
111
139
  }
112
140
 
113
141
  /**
@@ -116,7 +144,11 @@ function getDestinationTranscoder(id) {
116
144
  * @param {*} transferSyntaxUid
117
145
  * @returns
118
146
  */
119
- function getTranscoder(transferSyntaxUid, { contentType: greyContentType, colorContentType }, samplesPerPixel) {
147
+ function getTranscoder(
148
+ transferSyntaxUid,
149
+ { contentType: greyContentType, colorContentType },
150
+ samplesPerPixel
151
+ ) {
120
152
  const contentType = samplesPerPixel === 3 ? colorContentType : greyContentType;
121
153
  const sourceTranscoder = transcodeSourceMap[transferSyntaxUid];
122
154
  const destinationTranscoder = getDestinationTranscoder(contentType);
@@ -126,8 +158,9 @@ function getTranscoder(transferSyntaxUid, { contentType: greyContentType, colorC
126
158
 
127
159
  return {
128
160
  transferSyntaxUid: destinationTranscoder.transferSyntaxUid,
129
- transcodeOp: sourceTranscoder.transcodeOp | destinationTranscoder.transcodeOp, // eslint-disable-line no-bitwise
161
+ transcodeOp: sourceTranscoder.transcodeOp | destinationTranscoder.transcodeOp,
130
162
  alias: sourceTranscoder.alias,
163
+ beforeEncode: destinationTranscoder.beforeEncode,
131
164
  };
132
165
  }
133
166
 
@@ -140,7 +173,7 @@ function shouldTranscodeImageFrame(id, options, samplesPerPixel) {
140
173
  const { recompress: recompressGrey, recompressColor } = options;
141
174
  const recompress = samplesPerPixel === 3 ? recompressColor : recompressGrey;
142
175
  if (!recompress) {
143
- console.verbose("Not transcoding because recompress not set");
176
+ console.verbose('Not transcoding because recompress not set');
144
177
  return false;
145
178
  }
146
179
 
@@ -148,12 +181,21 @@ function shouldTranscodeImageFrame(id, options, samplesPerPixel) {
148
181
  const transcoder = getTranscoder(transferSyntaxUid, options, samplesPerPixel);
149
182
  const validTranscoder = transcoder && transcoder.transferSyntaxUid;
150
183
  if (!validTranscoder) {
151
- console.verbose("Not transcoding because no decoder found for", transferSyntaxUid, samplesPerPixel);
184
+ console.verbose(
185
+ 'Not transcoding because no decoder found for',
186
+ transferSyntaxUid,
187
+ samplesPerPixel
188
+ );
152
189
  return false;
153
190
  }
154
- const validRecompress = recompress.includes("true") || recompress.includes(transcoder.alias);
191
+ const validRecompress = recompress.includes('true') || recompress.includes(transcoder.alias);
155
192
  if (!validRecompress) {
156
- console.verbose("Not transcoding because recompress", recompress, "does not include", transcoder.alias);
193
+ console.verbose(
194
+ 'Not transcoding because recompress',
195
+ recompress,
196
+ 'does not include',
197
+ transcoder.alias
198
+ );
157
199
  return false;
158
200
  }
159
201
 
@@ -175,8 +217,12 @@ function shouldThumbUseTranscoded(id, options) {
175
217
  function isValidTranscoder() {
176
218
  const { transferSyntaxUid } = id;
177
219
  // Ignore the samples per pixel for thumbnails
178
- const transcoder = getTranscoder(transferSyntaxUid, options, "thumbnail");
179
- const result = transcoder && transcoder.transferSyntaxUid && options.recompress.includes(transcoder.alias) && options.recompressThumb.includes(transcoder.alias);
220
+ const transcoder = getTranscoder(transferSyntaxUid, options, 'thumbnail');
221
+ const result =
222
+ transcoder &&
223
+ transcoder.transferSyntaxUid &&
224
+ options.recompress.includes(transcoder.alias) &&
225
+ options.recompressThumb.includes(transcoder.alias);
180
226
 
181
227
  return result;
182
228
  }
@@ -184,21 +230,12 @@ function shouldThumbUseTranscoded(id, options) {
184
230
  return isValidTranscoder();
185
231
  }
186
232
 
187
- function transcodeLog(options, msg, error = "") {
233
+ function transcodeLog(options, msg, error = '') {
188
234
  if (options.verbose) {
189
235
  console.log(`\x1b[34m${msg}\x1b[0m`, error);
190
236
  }
191
237
  }
192
238
 
193
- const beforeEncode = (options, encoder) => {
194
- const lossy = !!options.lossy;
195
- const quality = lossy ? 0.002 : -1;
196
- const delta = lossy ? 3 : 0;
197
- // First value is to encode as reversible lossless colour
198
- encoder.setQuality?.(!lossy, quality);
199
- encoder.setNearLossless?.(delta);
200
- };
201
-
202
239
  function scale(imageFrame, imageInfo) {
203
240
  const { rows, columns, bitsPerPixel, pixelRepresentation, samplesPerPixel } = imageInfo;
204
241
  let ArrayConstructor = Float32Array;
@@ -243,12 +280,13 @@ function scale(imageFrame, imageInfo) {
243
280
  async function generateLossyImage(id, decoded, options) {
244
281
  if (!options.alternate) return;
245
282
  if (!decoded?.imageFrame) return;
283
+ console.verbose('Writing alternate thumbnail');
246
284
 
247
285
  try {
248
286
  let { imageFrame, imageInfo } = decoded;
249
287
  const lossyId = {
250
288
  ...id,
251
- imageFrameRootPath: id.imageFrameRootPath.replace("frames", options.alternateName),
289
+ imageFrameRootPath: id.imageFrameRootPath.replace('frames', options.alternateName),
252
290
  transferSyntaxUid: transcodeDestinationMap.jhc.transferSyntaxUid,
253
291
  };
254
292
 
@@ -263,31 +301,40 @@ async function generateLossyImage(id, decoded, options) {
263
301
  imageInfo = scaled.imageInfo;
264
302
  }
265
303
 
266
- if (options.alternate === "jls") {
267
- lossyId.transferSyntaxUid = transcodeDestinationMap["jls-lossy"].transferSyntaxUid;
268
- } else if (options.alternate === "jlsLossless") {
304
+ if (options.alternate === 'jls') {
305
+ lossyId.transferSyntaxUid = transcodeDestinationMap['jls-lossy'].transferSyntaxUid;
306
+ } else if (options.alternate === 'jlsLossless') {
269
307
  lossyId.transferSyntaxUid = transcodeDestinationMap.jls.transferSyntaxUid;
270
308
  lossy = false;
271
- } else if (options.alternate === "jhcLossless") {
309
+ } else if (options.alternate === 'jhcLossless') {
272
310
  lossy = false;
273
311
  }
274
312
 
275
313
  const encodeOptions = {
276
- beforeEncode: beforeEncode.bind(null, {
277
- lossy,
278
- }),
314
+ beforeEncode: transcodeDestinationMap[options.alternate]?.beforeEncode,
279
315
  };
280
- const lossyEncoding = await dicomCodec.encode(imageFrame, imageInfo, lossyId.transferSyntaxUid, encodeOptions);
281
- console.log("Encoded alternate", lossyId.transferSyntaxUid, "of size", lossyEncoding.imageFrame.length);
282
- // eslint-disable-next-line consistent-return
316
+
317
+ const lossyEncoding = await dicomCodec.encode(
318
+ imageFrame,
319
+ imageInfo,
320
+ lossyId.transferSyntaxUid,
321
+ encodeOptions
322
+ );
323
+ console.verbose(
324
+ 'Encoded alternate',
325
+ lossyId.transferSyntaxUid,
326
+ 'of size',
327
+ lossyEncoding.imageFrame.length
328
+ );
329
+
283
330
  return { id: lossyId, imageFrame: lossyEncoding.imageFrame };
284
331
  } catch (e) {
285
- console.warn("Unable to create alternate:", e);
332
+ console.warn('Unable to create alternate:', e);
286
333
  }
287
334
  }
288
335
 
289
336
  function isPalette(dataSet) {
290
- return dataSet.string(Tags.RawPhotometricInterpretation) === "PALETTE COLOR";
337
+ return dataSet.string(Tags.RawPhotometricInterpretation) === 'PALETTE COLOR';
291
338
  }
292
339
 
293
340
  /**
@@ -305,8 +352,12 @@ async function transcodeImageFrame(id, targetIdSrc, imageFrame, dataSet, options
305
352
  let result = {};
306
353
 
307
354
  const samplesPerPixel = dataSet.uint16(Tags.RawSamplesPerPixel);
308
- const planarConfiguration = dataSet.uint16("x00280006");
309
- if (!shouldTranscodeImageFrame(id, options, samplesPerPixel) || planarConfiguration === 1 || isPalette(dataSet)) {
355
+ const planarConfiguration = dataSet.uint16('x00280006');
356
+ if (
357
+ !shouldTranscodeImageFrame(id, options, samplesPerPixel) ||
358
+ planarConfiguration === 1 ||
359
+ isPalette(dataSet)
360
+ ) {
310
361
  console.verbose("Shouldn't transcode");
311
362
  return {
312
363
  id,
@@ -319,7 +370,7 @@ async function transcodeImageFrame(id, targetIdSrc, imageFrame, dataSet, options
319
370
 
320
371
  // Don't transcode if not required
321
372
  if (targetId.transferSyntaxUid !== transcoder.transferSyntaxUid && !options.forceTranscode) {
322
- console.verbose("Image is already in", targetId.transferSyntaxUid, "not transcoding");
373
+ console.verbose('Image is already in', targetId.transferSyntaxUid, 'not transcoding');
323
374
  return {
324
375
  id,
325
376
  imageFrame,
@@ -327,33 +378,49 @@ async function transcodeImageFrame(id, targetIdSrc, imageFrame, dataSet, options
327
378
  };
328
379
  }
329
380
 
330
- console.verbose("Transcoding to", transcoder.transferSyntaxUid);
381
+ console.verbose('Transcoding to', transcoder.transferSyntaxUid);
331
382
 
332
383
  const imageInfo = getImageInfo(dataSet);
333
384
  let done = false;
334
- let processResultMsg = "";
385
+ let processResultMsg = '';
335
386
  const encodeOptions = {
336
- beforeEncode: beforeEncode.bind(null, {
337
- lossy: options.lossy,
338
- }),
387
+ beforeEncode: transcoder.beforeEncode,
339
388
  };
340
389
  let decoded;
341
390
 
342
391
  try {
343
392
  switch (transcoder.transcodeOp) {
344
393
  case transcodeOp.transcode:
345
- transcodeLog(options, `Full transcoding image from \x1b[43m${id.transferSyntaxUid}\x1b[0m to \x1b[43m${targetId.transferSyntaxUid}\x1b[0m`);
394
+ transcodeLog(
395
+ options,
396
+ `Full transcoding image from \x1b[43m${id.transferSyntaxUid}\x1b[0m to \x1b[43m${targetId.transferSyntaxUid}\x1b[0m`
397
+ );
346
398
 
347
399
  decoded = await dicomCodec.decode(imageFrame, imageInfo, id.transferSyntaxUid);
348
- result = await dicomCodec.encode(decoded.imageFrame, decoded.imageInfo, targetId.transferSyntaxUid, encodeOptions);
349
-
350
- console.log("transcoded image to", targetId.transferSyntaxUid, "of size", result.imageFrame.length);
400
+ result = await dicomCodec.encode(
401
+ decoded.imageFrame,
402
+ decoded.imageInfo,
403
+ targetId.transferSyntaxUid,
404
+ encodeOptions
405
+ );
406
+
407
+ console.verbose(
408
+ 'transcoded image to',
409
+ targetId.transferSyntaxUid,
410
+ 'of size',
411
+ result.imageFrame.length
412
+ );
351
413
  processResultMsg = `Transcoding finished`;
352
414
  break;
353
415
  case transcodeOp.encode:
354
416
  transcodeLog(options, `Encoding image to \x1b[43m${targetId.transferSyntaxUid}\x1b[0m`);
355
417
 
356
- result = await dicomCodec.encode(imageFrame, imageInfo, targetId.transferSyntaxUid, encodeOptions);
418
+ result = await dicomCodec.encode(
419
+ imageFrame,
420
+ imageInfo,
421
+ targetId.transferSyntaxUid,
422
+ encodeOptions
423
+ );
357
424
 
358
425
  processResultMsg = `Encoding finished`;
359
426
  break;
@@ -364,12 +431,12 @@ async function transcodeImageFrame(id, targetIdSrc, imageFrame, dataSet, options
364
431
  processResultMsg = `Decoding finished`;
365
432
  break;
366
433
  default:
367
- processResultMsg = "";
434
+ processResultMsg = '';
368
435
  }
369
436
 
370
437
  done = !!result.imageFrame;
371
438
  } catch (e) {
372
- transcodeLog(options, "Failed to transcode image", e);
439
+ transcodeLog(options, 'Failed to transcode image', e);
373
440
  }
374
441
 
375
442
  // recover transfer syntax
@@ -379,7 +446,7 @@ async function transcodeImageFrame(id, targetIdSrc, imageFrame, dataSet, options
379
446
 
380
447
  // log final message only if resultMsg is present
381
448
  if (processResultMsg) {
382
- processResultMsg += done ? " successfully" : " unsuccessfully";
449
+ processResultMsg += done ? ' successfully' : ' unsuccessfully';
383
450
  transcodeLog(options, processResultMsg);
384
451
  }
385
452
 
@@ -437,7 +504,7 @@ function transcodeMetadata(metadata, id, options) {
437
504
 
438
505
  if (result[Tags.AvailableTransferSyntaxUID]) {
439
506
  Tags.setValue(result, Tags.AvailableTransferSyntaxUID, transcodedId.transferSyntaxUid);
440
- console.verbose("Apply available tsuid", transcodeId.transferSyntaxUid);
507
+ console.verbose('Apply available tsuid', transcodeId.transferSyntaxUid);
441
508
  }
442
509
 
443
510
  return result;
@@ -1,17 +1,18 @@
1
- const { Stats } = require("@radicalimaging/static-wado-util");
1
+ const { Stats } = require('@radicalimaging/static-wado-util');
2
2
 
3
- const getNumberOfFrames = require("./getNumberOfFrames");
4
- const getUncompressedImageFrame = require("./getUncompressedImageFrame");
5
- const getEncapsulatedImageFrame = require("./getEncapsulatedImageFrame");
6
- const { isVideo } = require("../writer/VideoWriter");
3
+ const getNumberOfFrames = require('./getNumberOfFrames');
4
+ const getUncompressedImageFrame = require('./getUncompressedImageFrame');
5
+ const getEncapsulatedImageFrame = require('./getEncapsulatedImageFrame');
6
+ const { isVideo } = require('../writer/VideoWriter');
7
7
 
8
- const areFramesAreFragmented = (attr, numberOfFrames) => attr.encapsulatedPixelData && numberOfFrames != attr.fragments.length;
8
+ const areFramesAreFragmented = (attr, numberOfFrames) =>
9
+ attr.encapsulatedPixelData && numberOfFrames != attr.fragments.length;
9
10
 
10
- const getFrameSize = (dataSet) => {
11
- const rows = dataSet.uint16("x00280010");
12
- const columns = dataSet.uint16("x00280011");
13
- const samplesPerPixel = dataSet.uint16("x00280002");
14
- const bitsAllocated = dataSet.uint16("x00280100");
11
+ const getFrameSize = dataSet => {
12
+ const rows = dataSet.uint16('x00280010');
13
+ const columns = dataSet.uint16('x00280011');
14
+ const samplesPerPixel = dataSet.uint16('x00280002');
15
+ const bitsAllocated = dataSet.uint16('x00280100');
15
16
  return (rows * columns * samplesPerPixel * bitsAllocated) / 8;
16
17
  };
17
18
 
@@ -30,11 +31,21 @@ const extractImageFrames = async (dataSet, attr, vr, callback) => {
30
31
 
31
32
  for (let frameIndex = 0; frameIndex < numberOfFrames; frameIndex++) {
32
33
  if (attr.encapsulatedPixelData) {
33
- const compressedFrame = getEncapsulatedImageFrame(dataSet, attr, frameIndex, framesAreFragmented);
34
+ const compressedFrame = getEncapsulatedImageFrame(
35
+ dataSet,
36
+ attr,
37
+ frameIndex,
38
+ framesAreFragmented
39
+ );
34
40
  BulkDataURI = await callback.imageFrame(compressedFrame, { dataSet });
35
- Stats.OverallStats.add("Image Write", `Write image frame ${frameIndex + 1}`, 5000);
41
+ Stats.OverallStats.add('Image Write', `Write image frame ${frameIndex + 1}`, 5000);
36
42
  } else {
37
- const uncompressedFrame = getUncompressedImageFrame(dataSet, attr, frameIndex, uncompressedFrameSize);
43
+ const uncompressedFrame = getUncompressedImageFrame(
44
+ dataSet,
45
+ attr,
46
+ frameIndex,
47
+ uncompressedFrameSize
48
+ );
38
49
  BulkDataURI = await callback.imageFrame(uncompressedFrame, { dataSet });
39
50
  }
40
51
  }
@@ -1,6 +1,6 @@
1
- const { Tags } = require("@radicalimaging/static-wado-util");
2
- const getVR = require("./getVR");
3
- const getValue = require("./getValue");
1
+ const { Tags } = require('@radicalimaging/static-wado-util');
2
+ const getVR = require('./getVR');
3
+ const getValue = require('./getValue');
4
4
 
5
5
  /**
6
6
  * Get dataset.
@@ -28,7 +28,7 @@ async function getDataSet(dataSet, callback, optionsOrig, parentAttr = undefined
28
28
  options = { ...options, SpecificCharacterSet };
29
29
  }
30
30
  const attr = dataSet.elements[tag];
31
- /* eslint-disable-next-line no-use-before-define */
31
+
32
32
  await attributeToJS(metadata, tag, dataSet, attr, callback, options, parentAttr);
33
33
  }
34
34
  if (metadata[Tags.TransferSyntaxUID]) {
@@ -1,4 +1,4 @@
1
- const dicomParser = require("dicom-parser");
1
+ const dicomParser = require('dicom-parser');
2
2
 
3
3
  /**
4
4
  * Function to deal with extracting an image frame from an encapsulated data set.
@@ -12,12 +12,24 @@ const getEncapsulatedImageFrame = (dataSet, attr, frameIndex, framesAreFragmente
12
12
 
13
13
  // Empty basic offset table
14
14
  if (framesAreFragmented) {
15
- const basicOffsetTable = dicomParser.createJPEGBasicOffsetTable(dataSet, dataSet.elements.x7fe00010);
15
+ const basicOffsetTable = dicomParser.createJPEGBasicOffsetTable(
16
+ dataSet,
17
+ dataSet.elements.x7fe00010
18
+ );
16
19
 
17
- return dicomParser.readEncapsulatedImageFrame(dataSet, dataSet.elements.x7fe00010, frameIndex, basicOffsetTable);
20
+ return dicomParser.readEncapsulatedImageFrame(
21
+ dataSet,
22
+ dataSet.elements.x7fe00010,
23
+ frameIndex,
24
+ basicOffsetTable
25
+ );
18
26
  }
19
27
 
20
- return dicomParser.readEncapsulatedPixelDataFromFragments(dataSet, dataSet.elements.x7fe00010, frameIndex);
28
+ return dicomParser.readEncapsulatedPixelDataFromFragments(
29
+ dataSet,
30
+ dataSet.elements.x7fe00010,
31
+ frameIndex
32
+ );
21
33
  };
22
34
 
23
35
  module.exports = getEncapsulatedImageFrame;
@@ -1,6 +1,6 @@
1
- const getNumberOfFrames = (dataSet) => {
1
+ const getNumberOfFrames = dataSet => {
2
2
  if (dataSet.elements.x00280008) {
3
- const numberOfFramesString = dataSet.string("x00280008");
3
+ const numberOfFramesString = dataSet.string('x00280008');
4
4
  if (numberOfFramesString.length === 0) {
5
5
  return 1;
6
6
  }
@@ -1,16 +1,24 @@
1
- const { dataDictionary } = require("@radicalimaging/static-wado-util");
1
+ const { dataDictionary } = require('@radicalimaging/static-wado-util');
2
2
 
3
- const getVR = (attr) => {
3
+ const nullVrTags = new Set();
4
+ nullVrTags.add('FFFEE00D');
5
+
6
+ const getVR = attr => {
4
7
  if (attr.vr) {
5
8
  return attr.vr;
6
9
  }
7
10
  // lookup the vr using the data dictionary
8
11
  const tag = attr.tag.substring(1).toUpperCase();
9
12
  const dataDictAttr = dataDictionary[tag];
10
- if (dataDictAttr) {
13
+ if (dataDictAttr?.vr) {
11
14
  return dataDictAttr.vr;
12
15
  }
13
- return undefined;
16
+ if (nullVrTags.has(tag)) {
17
+ return null;
18
+ }
19
+
20
+ console.log('Unknown VR', tag, attr, dataDictAttr);
21
+ return 'UN';
14
22
  };
15
23
 
16
24
  module.exports = getVR;