larvitar 1.5.13 → 2.0.0

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 (103) hide show
  1. package/.vscode/settings.json +4 -0
  2. package/README.md +78 -48
  3. package/bundler/webpack.common.js +27 -0
  4. package/bundler/webpack.dev.js +23 -0
  5. package/bundler/webpack.prod.js +19 -0
  6. package/decs.d.ts +12 -0
  7. package/dist/imaging/MetaDataReadable.d.ts +39 -0
  8. package/dist/imaging/MetaDataTypes.d.ts +3488 -0
  9. package/dist/imaging/imageAnonymization.d.ts +12 -0
  10. package/dist/imaging/imageColormaps.d.ts +47 -0
  11. package/dist/imaging/imageContours.d.ts +18 -0
  12. package/dist/imaging/imageIo.d.ts +42 -0
  13. package/dist/imaging/imageLayers.d.ts +56 -0
  14. package/dist/imaging/imageLoading.d.ts +65 -0
  15. package/dist/imaging/imageParsing.d.ts +46 -0
  16. package/dist/imaging/imagePresets.d.ts +43 -0
  17. package/dist/imaging/imageRendering.d.ts +238 -0
  18. package/dist/imaging/imageReslice.d.ts +14 -0
  19. package/dist/imaging/imageStore.d.ts +121 -0
  20. package/dist/imaging/imageTags.d.ts +22 -0
  21. package/dist/imaging/imageTools.d.ts +20 -0
  22. package/dist/imaging/imageUtils.d.ts +165 -0
  23. package/dist/imaging/loaders/commonLoader.d.ts +103 -0
  24. package/dist/imaging/loaders/dicomLoader.d.ts +29 -0
  25. package/dist/imaging/loaders/fileLoader.d.ts +33 -0
  26. package/dist/imaging/loaders/multiframeLoader.d.ts +37 -0
  27. package/dist/imaging/loaders/nrrdLoader.d.ts +112 -0
  28. package/dist/imaging/loaders/resliceLoader.d.ts +15 -0
  29. package/dist/imaging/monitors/memory.d.ts +41 -0
  30. package/dist/imaging/monitors/performance.d.ts +23 -0
  31. package/dist/imaging/parsers/ecg.d.ts +15 -0
  32. package/dist/imaging/parsers/nrrd.d.ts +3 -0
  33. package/dist/imaging/tools/custom/4dSliceScrollTool.d.ts +12 -0
  34. package/dist/imaging/tools/custom/contourTool.d.ts +409 -0
  35. package/dist/imaging/tools/custom/diameterTool.d.ts +18 -0
  36. package/dist/imaging/tools/custom/editMaskTool.d.ts +22 -0
  37. package/dist/imaging/tools/custom/ellipticalRoiOverlayTool.d.ts +45 -0
  38. package/dist/imaging/tools/custom/polygonSegmentationMixin.d.ts +54 -0
  39. package/dist/imaging/tools/custom/polylineScissorsTool.d.ts +11 -0
  40. package/dist/imaging/tools/custom/rectangleRoiOverlayTool.d.ts +45 -0
  41. package/dist/imaging/tools/custom/seedTool.d.ts +0 -0
  42. package/dist/imaging/tools/custom/setLabelMap3D.d.ts +39 -0
  43. package/dist/imaging/tools/custom/thresholdsBrushTool.d.ts +19 -0
  44. package/dist/imaging/tools/default.d.ts +53 -0
  45. package/dist/imaging/tools/interaction.d.ts +30 -0
  46. package/dist/imaging/tools/io.d.ts +38 -0
  47. package/dist/imaging/tools/main.d.ts +81 -0
  48. package/dist/imaging/tools/segmentation.d.ts +125 -0
  49. package/dist/imaging/tools/state.d.ts +17 -0
  50. package/dist/imaging/tools/strategies/eraseFreehand.d.ts +16 -0
  51. package/dist/imaging/tools/strategies/fillFreehand.d.ts +16 -0
  52. package/dist/imaging/tools/strategies/index.d.ts +2 -0
  53. package/dist/index.d.ts +34 -0
  54. package/dist/larvitar.js +89801 -0
  55. package/dist/larvitar.js.map +1 -0
  56. package/imaging/MetaDataReadable.ts +40 -0
  57. package/imaging/MetaDataTypes.ts +3490 -0
  58. package/imaging/dataDictionary.json +5328 -5328
  59. package/imaging/{imageAnonymization.js → imageAnonymization.ts} +41 -13
  60. package/imaging/{imageColormaps.js → imageColormaps.ts} +48 -30
  61. package/imaging/{imageContours.js → imageContours.ts} +24 -22
  62. package/imaging/{imageIo.js → imageIo.ts} +89 -52
  63. package/imaging/{imageLayers.js → imageLayers.ts} +31 -14
  64. package/imaging/{imageLoading.js → imageLoading.ts} +108 -45
  65. package/imaging/{imageParsing.js → imageParsing.ts} +158 -80
  66. package/imaging/{imagePresets.js → imagePresets.ts} +44 -11
  67. package/imaging/imageRendering.ts +1091 -0
  68. package/imaging/{imageReslice.js → imageReslice.ts} +18 -9
  69. package/imaging/imageStore.ts +487 -0
  70. package/imaging/imageTags.ts +609 -0
  71. package/imaging/imageTools.js +2 -1
  72. package/imaging/{imageUtils.js → imageUtils.ts} +211 -701
  73. package/imaging/loaders/{commonLoader.js → commonLoader.ts} +73 -24
  74. package/imaging/loaders/{dicomLoader.js → dicomLoader.ts} +25 -5
  75. package/imaging/loaders/{fileLoader.js → fileLoader.ts} +5 -5
  76. package/imaging/loaders/{multiframeLoader.js → multiframeLoader.ts} +145 -90
  77. package/imaging/loaders/{nrrdLoader.js → nrrdLoader.ts} +230 -64
  78. package/imaging/loaders/{resliceLoader.js → resliceLoader.ts} +51 -20
  79. package/imaging/monitors/{memory.js → memory.ts} +54 -8
  80. package/imaging/monitors/performance.ts +34 -0
  81. package/imaging/parsers/ecg.ts +51 -0
  82. package/imaging/tools/README.md +27 -0
  83. package/imaging/tools/custom/4dSliceScrollTool.js +47 -46
  84. package/imaging/tools/custom/ellipticalRoiOverlayTool.js +534 -0
  85. package/imaging/tools/custom/polylineScissorsTool.js +1 -1
  86. package/imaging/tools/custom/rectangleRoiOverlayTool.js +564 -0
  87. package/imaging/tools/{setLabelMap3D.js → custom/setLabelMap3D.ts} +19 -25
  88. package/imaging/tools/{default.js → default.ts} +114 -30
  89. package/imaging/tools/{interaction.js → interaction.ts} +42 -23
  90. package/imaging/tools/{io.js → io.ts} +47 -31
  91. package/imaging/tools/{main.js → main.ts} +105 -40
  92. package/imaging/tools/{segmentation.js → segmentation.ts} +95 -68
  93. package/imaging/tools/{state.js → state.ts} +7 -12
  94. package/imaging/tools/types.d.ts +243 -0
  95. package/imaging/types.d.ts +197 -0
  96. package/{index.js → index.ts} +43 -14
  97. package/jsdoc.json +1 -1
  98. package/package.json +32 -14
  99. package/tsconfig.json +102 -0
  100. package/imaging/imageRendering.js +0 -860
  101. package/imaging/imageStore.js +0 -322
  102. package/modules/vuex/larvitar.js +0 -187
  103. /package/imaging/tools/{polygonSegmentationMixin.js → custom/polygonSegmentationMixin.js} +0 -0
@@ -21,16 +21,27 @@ import {
21
21
  } from "lodash";
22
22
  import { v4 as uuidv4 } from "uuid";
23
23
  import cornerstone from "cornerstone-core";
24
- import { convertBytes } from "dicom-character-set";
25
24
 
26
25
  // internal libraries
27
26
  import { getDicomImageId } from "./loaders/dicomLoader";
28
27
  import TAG_DICT from "./dataDictionary.json";
29
28
  import { getSeriesDataFromLarvitarManager } from "./loaders/commonLoader";
29
+ import type {
30
+ CustomDataSet,
31
+ MetaData,
32
+ ReslicedInstance,
33
+ Series
34
+ } from "./types";
35
+ import { getTagValue } from "./imageTags";
36
+ import { MetaDataTypes } from "./MetaDataTypes";
30
37
 
31
38
  // global module variables
32
39
  // variables used to manage the reslice functionality
33
- const resliceTable = {
40
+ const resliceTable: {
41
+ [key: string]: {
42
+ [key: string]: [number, number, number];
43
+ };
44
+ } = {
34
45
  sagittal: { coronal: [-2, 1, 0], axial: [-2, 0, -1] },
35
46
  coronal: { sagittal: [2, 1, -0], axial: [0, 2, -1] },
36
47
  axial: { sagittal: [1, -2, -0], coronal: [0, -2, 1] }
@@ -43,7 +54,6 @@ const resliceTable = {
43
54
  * getMaxPixelValue(defaultValue, pixelData)
44
55
  * getPixelRepresentation(dataset)
45
56
  * getTypedArrayFromDataType(dataType)
46
- * getPixelTypedArray(dataset, pixelDataElement)
47
57
  * getSortedStack(seriesData, sortPriorities, returnSuccessMethod)
48
58
  * getSortedUIDs(seriesData)
49
59
  * randomId()
@@ -52,7 +62,6 @@ const resliceTable = {
52
62
  * getCmprMetadata(reslicedSeriesId, imageLoaderName, header)
53
63
  * getReslicedPixeldata(imageId, originalData, reslicedData)
54
64
  * getDistanceBetweenSlices(seriesData, sliceIndex1, sliceIndex2)
55
- * parseTag(dataSet, propertyName, element)
56
65
  * isElement(o)
57
66
  * getImageMetadata(dataSet, imageId)
58
67
  */
@@ -70,7 +79,9 @@ const resliceTable = {
70
79
  * @function getNormalOrientation
71
80
  * @param {Array} el - The image_orientation dicom tag
72
81
  */
73
- export const getNormalOrientation = function (el) {
82
+ export const getNormalOrientation = function (
83
+ el: [number, number, number, number, number, number]
84
+ ) {
74
85
  let a = [el[0], el[1], el[2]];
75
86
  let b = [el[3], el[4], el[5]];
76
87
 
@@ -90,7 +101,10 @@ export const getNormalOrientation = function (el) {
90
101
  * @param {Number} value - The min value
91
102
  * @param {Array} pixelData - Pixel data array
92
103
  */
93
- export const getMinPixelValue = function (value, pixelData) {
104
+ export const getMinPixelValue = function (
105
+ value: number,
106
+ pixelData: Uint16Array
107
+ ) {
94
108
  if (value !== undefined) {
95
109
  return value;
96
110
  }
@@ -110,7 +124,10 @@ export const getMinPixelValue = function (value, pixelData) {
110
124
  * @param {Number} value - The max value
111
125
  * @param {Array} pixelData - Pixel data array
112
126
  */
113
- export const getMaxPixelValue = function (value, pixelData) {
127
+ export const getMaxPixelValue = function (
128
+ value: string,
129
+ pixelData: Uint16Array
130
+ ) {
114
131
  if (value !== undefined) {
115
132
  return value;
116
133
  }
@@ -131,7 +148,7 @@ export const getMaxPixelValue = function (value, pixelData) {
131
148
  * @param {Object} dataSet - The dataset
132
149
  * @returns {String} The pixel representation in the form Sint / Uint + bytelength
133
150
  */
134
- export const getPixelRepresentation = function (dataSet) {
151
+ export const getPixelRepresentation = function (dataSet: CustomDataSet) {
135
152
  if (dataSet.repr) {
136
153
  return dataSet.repr;
137
154
  } else {
@@ -156,50 +173,17 @@ export const getPixelRepresentation = function (dataSet) {
156
173
  * @param {Object} dataType - The data type
157
174
  * @returns {TypedArray} The typed array
158
175
  */
159
- export const getTypedArrayFromDataType = function (dataType) {
160
- let repr = dataType.toLowerCase();
176
+ export const getTypedArrayFromDataType = function (dataType: string) {
177
+ let repr = dataType.toLowerCase() as keyof typeof TYPES_TO_TYPEDARRAY;
161
178
  let typedArray = has(TYPES_TO_TYPEDARRAY, repr)
162
179
  ? TYPES_TO_TYPEDARRAY[repr]
163
180
  : null;
164
181
  if (!typedArray) {
165
- console.error("invalida data type: ", dataType);
182
+ console.error("invalid data type: ", dataType);
166
183
  }
167
184
  return typedArray;
168
185
  };
169
186
 
170
- /**
171
- * Create and return a typed array from the pixel data
172
- * @instance
173
- * @function getPixelTypedArray
174
- * @param {Object} dataSet - The cornerstone serie object
175
- * @param {Object} pixelDataElement - The dataset metadata (dataSet.elements.x7fe00010)
176
- * @returns {TypedArray} The pixel array as proper typed array
177
- */
178
- export const getPixelTypedArray = function (dataSet, pixelDataElement) {
179
- let buffer = dataSet.byteArray.buffer;
180
- let offset = pixelDataElement.dataOffset;
181
- let r = getPixelRepresentation(dataSet);
182
- let typedArray = getTypedArrayFromDataType(r);
183
- switch (typedArray) {
184
- case Uint16Array:
185
- length = pixelDataElement.length / 2;
186
- break;
187
- case Int16Array:
188
- length = pixelDataElement.length / 2;
189
- break;
190
- case Uint32Array:
191
- length = pixelDataElement.length / 4;
192
- break;
193
- case Int32Array:
194
- length = pixelDataElement.length / 4;
195
- break;
196
- default:
197
- length = pixelDataElement.length;
198
- break;
199
- }
200
- return new typedArray(buffer, offset, length);
201
- };
202
-
203
187
  /**
204
188
  * Sort the array of images ids of a series trying with:
205
189
  * - content time order, if the series has cardiacNumberOfImages tag > 1
@@ -214,31 +198,30 @@ export const getPixelTypedArray = function (dataSet, pixelDataElement) {
214
198
  * @return {Object} The sorted stack
215
199
  */
216
200
  export const getSortedStack = function (
217
- seriesData,
218
- sortPriorities,
219
- returnSuccessMethod
201
+ seriesData: Series,
202
+ sortPriorities: Array<"imagePosition" | "contentTime" | "instanceNumber">,
203
+ returnSuccessMethod: boolean
220
204
  ) {
221
- let tryToSort = function (data, methods) {
205
+ let tryToSort = function (
206
+ data: Series,
207
+ methods: typeof sortPriorities
208
+ ): string[] {
222
209
  if (isEmpty(methods)) {
223
210
  if (returnSuccessMethod === true) {
224
- return sorted;
211
+ return sorted!;
225
212
  } else {
226
- return sorted;
213
+ return sorted!;
227
214
  }
228
215
  }
229
216
 
230
217
  let sortMethod = methods.shift();
231
- try {
232
- var sorted = sortBy(data.imageIds, function (imageId) {
233
- return sortStackCallback(data, imageId, sortMethod);
234
- });
235
- if (returnSuccessMethod === true) {
236
- return sorted;
237
- } else {
238
- return sorted;
239
- }
240
- } catch (ex) {
241
- return tryToSort(data, methods);
218
+ var sorted = sortBy(data.imageIds, function (imageId: string) {
219
+ return sortStackCallback(data, imageId, sortMethod!);
220
+ });
221
+ if (returnSuccessMethod === true) {
222
+ return sorted;
223
+ } else {
224
+ return sorted;
242
225
  }
243
226
  };
244
227
 
@@ -254,10 +237,11 @@ export const getSortedStack = function (
254
237
  * @param {Object} seriesData - The dataset
255
238
  * @return {Object} The sorted instanceUIDs
256
239
  */
257
- export const getSortedUIDs = function (seriesData) {
258
- let instanceUIDs = {};
259
- forEach(seriesData.imageIds, function (imageId) {
260
- instanceUIDs[seriesData.instances[imageId].metadata.instanceUID] = imageId;
240
+ export const getSortedUIDs = function (seriesData: Series) {
241
+ let instanceUIDs: { [key: string]: string } = {};
242
+ forEach(seriesData.imageIds, function (imageId: string) {
243
+ let instanceUID = seriesData.instances[imageId].metadata.instanceUID!;
244
+ instanceUIDs[instanceUID] = imageId;
261
245
  });
262
246
  return instanceUIDs;
263
247
  };
@@ -281,35 +265,53 @@ export const randomId = function () {
281
265
  * @param {Bool} isArray - True if tag value is an array
282
266
  * @return {Number} - Tag mean value
283
267
  */
284
- export const getMeanValue = function (series, tag, isArray) {
285
- let meanValue = isArray ? [] : 0;
286
-
287
- forEach(series.imageIds, function (imageId) {
288
- const tagValue = series.instances[imageId].metadata[tag];
289
- if (tagValue.length === 2) {
290
- meanValue[0] = meanValue[0] ? meanValue[0] + tagValue[0] : tagValue[0];
291
- meanValue[1] = meanValue[1] ? meanValue[1] + tagValue[1] : tagValue[1];
292
- } else if (tagValue.length === 3) {
293
- meanValue[0] = meanValue[0] ? meanValue[0] + tagValue[0] : tagValue[0];
294
- meanValue[1] = meanValue[1] ? meanValue[1] + tagValue[1] : tagValue[1];
295
- meanValue[2] = meanValue[2] ? meanValue[2] + tagValue[2] : tagValue[2];
296
- } else if (tagValue.length === 6) {
297
- meanValue[0] = meanValue[0] ? meanValue[0] + tagValue[0] : tagValue[0];
298
- meanValue[1] = meanValue[1] ? meanValue[1] + tagValue[1] : tagValue[1];
299
- meanValue[2] = meanValue[2] ? meanValue[2] + tagValue[2] : tagValue[2];
300
- meanValue[3] = meanValue[3] ? meanValue[3] + tagValue[3] : tagValue[3];
301
- meanValue[4] = meanValue[4] ? meanValue[4] + tagValue[4] : tagValue[4];
302
- meanValue[5] = meanValue[5] ? meanValue[5] + tagValue[5] : tagValue[5];
268
+ export const getMeanValue = function (
269
+ series: Series,
270
+ tag: keyof MetaData,
271
+ isArray: boolean
272
+ ) {
273
+ let meanValue = isArray ? ([] as number[]) : (0 as number);
274
+
275
+ forEach(series.imageIds, function (imageId: string) {
276
+ let tagValue = series.instances[imageId].metadata[
277
+ tag
278
+ ] as MetaData[typeof tag];
279
+ if (Array.isArray(tagValue)) {
280
+ tagValue; //exclude array of metadatatypes
281
+ meanValue = meanValue as number[];
282
+
283
+ if (tagValue.length === 2) {
284
+ tagValue = tagValue as [number, number];
285
+ meanValue[0] = meanValue[0] ? meanValue[0] + tagValue[0] : tagValue[0];
286
+ meanValue[1] = meanValue[1] ? meanValue[1] + tagValue[1] : tagValue[1];
287
+ } else if (tagValue.length === 3) {
288
+ tagValue = tagValue as [number, number, number];
289
+ meanValue[0] = meanValue[0] ? meanValue[0] + tagValue[0] : tagValue[0];
290
+ meanValue[1] = meanValue[1] ? meanValue[1] + tagValue[1] : tagValue[1];
291
+ meanValue[2] = meanValue[2] ? meanValue[2] + tagValue[2] : tagValue[2];
292
+ } else if (tagValue.length === 6) {
293
+ tagValue = tagValue as [number, number, number, number, number, number];
294
+ meanValue[0] = meanValue[0] ? meanValue[0] + tagValue[0] : tagValue[0];
295
+ meanValue[1] = meanValue[1] ? meanValue[1] + tagValue[1] : tagValue[1];
296
+ meanValue[2] = meanValue[2] ? meanValue[2] + tagValue[2] : tagValue[2];
297
+ meanValue[3] = meanValue[3] ? meanValue[3] + tagValue[3] : tagValue[3];
298
+ meanValue[4] = meanValue[4] ? meanValue[4] + tagValue[4] : tagValue[4];
299
+ meanValue[5] = meanValue[5] ? meanValue[5] + tagValue[5] : tagValue[5];
300
+ }
303
301
  } else {
302
+ meanValue = meanValue as number;
303
+ tagValue = parseFloat(tagValue as string);
304
304
  meanValue += tagValue;
305
305
  }
306
306
  });
307
307
 
308
308
  if (isArray) {
309
+ meanValue = meanValue as number[];
309
310
  for (let i = 0; i < meanValue.length; i++) {
310
311
  meanValue[i] /= series.imageIds.length;
311
312
  }
312
313
  } else {
314
+ meanValue = meanValue as number;
313
315
  meanValue /= series.imageIds.length;
314
316
  }
315
317
  return meanValue;
@@ -327,11 +329,11 @@ export const getMeanValue = function (series, tag, isArray) {
327
329
  * @return {Object} - Cornerstone series object, filled only with metadata
328
330
  */
329
331
  export const getReslicedMetadata = function (
330
- reslicedSeriesId,
331
- fromOrientation,
332
- toOrientation,
333
- seriesData,
334
- imageLoaderName
332
+ reslicedSeriesId: string,
333
+ fromOrientation: "axial" | "coronal" | "sagittal",
334
+ toOrientation: "axial" | "coronal" | "sagittal",
335
+ seriesData: Series,
336
+ imageLoaderName: string
335
337
  ) {
336
338
  // get reslice metadata and apply the reslice algorithm
337
339
  let permuteTable = resliceTable[fromOrientation][toOrientation];
@@ -340,20 +342,20 @@ export const getReslicedMetadata = function (
340
342
  });
341
343
 
342
344
  // orthogonal reslice algorithm
343
- let reslicedImageIds = [];
344
- let reslicedInstances = {};
345
+ let reslicedImageIds: string[] = [];
346
+ let reslicedInstances: { [key: string]: ReslicedInstance } = {};
345
347
 
346
348
  let sampleMetadata = seriesData.instances[seriesData.imageIds[0]].metadata;
347
349
 
348
350
  let fromSize = [
349
- sampleMetadata.x00280011,
350
- sampleMetadata.x00280010,
351
+ sampleMetadata.x00280011!,
352
+ sampleMetadata.x00280010!,
351
353
  seriesData.imageIds.length
352
354
  ];
353
355
  let toSize = permuteValues(permuteAbsTable, fromSize);
354
356
  let fromSpacing = spacingArray(seriesData, sampleMetadata);
355
- let toSpacing = permuteValues(permuteAbsTable, fromSpacing);
356
- let reslicedIOP = getReslicedIOP(sampleMetadata.x00200037, permuteTable);
357
+ let toSpacing = permuteValues(permuteAbsTable, fromSpacing as number[]);
358
+ let reslicedIOP = getReslicedIOP(sampleMetadata.x00200037!, permuteTable);
357
359
 
358
360
  for (let f = 0; f < toSize[2]; f++) {
359
361
  let reslicedImageId = getDicomImageId(imageLoaderName);
@@ -361,16 +363,16 @@ export const getReslicedMetadata = function (
361
363
 
362
364
  let instanceId = uuidv4();
363
365
  let reslicedIPP = getReslicedIPP(
364
- sampleMetadata.x00200032,
365
- sampleMetadata.x00200037,
366
+ sampleMetadata.x00200032 as [number, number, number],
367
+ sampleMetadata.x00200037!,
366
368
  reslicedIOP,
367
369
  permuteTable,
368
370
  f,
369
371
  fromSize,
370
372
  toSize,
371
- fromSpacing
373
+ fromSpacing as number[]
372
374
  );
373
- let metadata = extend(clone(sampleMetadata), {
375
+ let metadata: MetaData = extend(clone(sampleMetadata), {
374
376
  // pixel representation
375
377
  x00280100: sampleMetadata.x00280100,
376
378
  x00280103: sampleMetadata.x00280103,
@@ -413,12 +415,10 @@ export const getReslicedMetadata = function (
413
415
  // new image orientation
414
416
  x00200037: reslicedIOP,
415
417
  // new image position
416
- x00200032: reslicedIPP,
417
- x00280106: sampleMetadata.x00280106,
418
- x00280107: sampleMetadata.x00280107
418
+ x00200032: reslicedIPP
419
419
  });
420
420
 
421
- // set human readable metadata
421
+ // set human readable metadata.
422
422
  metadata.seriesUID = reslicedSeriesId;
423
423
  metadata.rows = metadata.x00280010;
424
424
  metadata.cols = metadata.x00280011;
@@ -454,12 +454,12 @@ export const getReslicedMetadata = function (
454
454
  * @return {Object} - Cornerstone series object, filled only with metadata
455
455
  */
456
456
  export const getCmprMetadata = function (
457
- reslicedSeriesId,
458
- imageLoaderName,
459
- header
457
+ reslicedSeriesId: string,
458
+ imageLoaderName: string,
459
+ header: any // TODO-ts : type
460
460
  ) {
461
- let reslicedImageIds = [];
462
- let reslicedInstances = {};
461
+ let reslicedImageIds: string[] = [];
462
+ let reslicedInstances: { [key: string]: ReslicedInstance } = {};
463
463
 
464
464
  for (let f = 0; f < header.frames_number; f++) {
465
465
  let reslicedImageId = getDicomImageId(imageLoaderName);
@@ -467,7 +467,7 @@ export const getCmprMetadata = function (
467
467
 
468
468
  let instanceId = uuidv4();
469
469
 
470
- let metadata = {
470
+ let metadata: MetaData = {
471
471
  // pixel representation
472
472
  x00280100: header.repr,
473
473
  // Bits Allocated
@@ -477,7 +477,7 @@ export const getCmprMetadata = function (
477
477
  x00280011: header.cols, // cols
478
478
  // resliced series spacing
479
479
  x00280030: [header.spacing[1], header.spacing[0]],
480
- x00180050: [header.distance_btw_slices],
480
+ x00180050: [header.distance_btw_slices] as number[],
481
481
  // remove min and max pixelvalue from metadata before calling the createCustomImage function:
482
482
  // need to recalculate the min and max pixel values on the new instance pixelData
483
483
  x00280106: undefined,
@@ -506,8 +506,8 @@ export const getCmprMetadata = function (
506
506
  // data needed to obtain a good rendering
507
507
  x00281050: [header.wwwl[1] / 2], // [wl]
508
508
  x00281051: [header.wwwl[0]], // [ww]
509
- x00281052: [header.intercept],
510
- x00281053: [header.slope],
509
+ x00281052: header.intercept,
510
+ x00281053: header.slope,
511
511
  // new image orientation (IOP)
512
512
  x00200037: header.iop ? header.iop.slice(f * 6, (f + 1) * 6) : null,
513
513
  // new image position (IPP)
@@ -536,27 +536,30 @@ export const getCmprMetadata = function (
536
536
  * @return {Object} - A single resliced slice pixel array
537
537
  */
538
538
  export const getReslicedPixeldata = function (
539
- imageId,
540
- originalData,
541
- reslicedData
539
+ imageId: string,
540
+ originalData: Series,
541
+ reslicedData: Series
542
542
  ) {
543
543
  // resliced metadata must be already available
544
- let reslicedInstance = reslicedData.instances[imageId];
544
+ let reslicedInstance = reslicedData.instances[imageId] as ReslicedInstance;
545
545
  let reslicedMetadata = reslicedInstance.metadata;
546
+ if (!reslicedInstance.permuteTable) {
547
+ throw new Error("Resliced permuteTable not available");
548
+ }
546
549
  let permuteAbsTable = reslicedInstance.permuteTable.map(function (v) {
547
550
  return Math.abs(v);
548
551
  });
549
552
 
550
553
  // compute resliced series pixelData, use the correct typedarray
551
- let rows = reslicedMetadata.x00280010;
552
- let cols = reslicedMetadata.x00280011;
553
- let reslicedSlice = getTypedArray(reslicedMetadata, rows * cols);
554
+ let rows = reslicedMetadata.x00280010 as number;
555
+ let cols = reslicedMetadata.x00280011 as number;
556
+ let reslicedSlice = getTypedArray(reslicedMetadata as any, rows * cols); // TODO-ts : type of reslicedMetadata?
554
557
 
555
558
  let frame = indexOf(reslicedData.imageIds, imageId);
556
559
  let originalInstance = originalData.instances[originalData.imageIds[0]];
557
- let fromCols = originalInstance.metadata.x00280011;
560
+ let fromCols = originalInstance.metadata.x00280011 as number;
558
561
 
559
- function getPixelValue(ijf) {
562
+ function getPixelValue(ijf: [number, number, number]) {
560
563
  let i = ijf[0];
561
564
  let j = ijf[1];
562
565
  let f = ijf[2];
@@ -577,7 +580,7 @@ export const getReslicedPixeldata = function (
577
580
 
578
581
  for (let j = 0; j < rows; j++) {
579
582
  for (let i = 0; i < cols; i++) {
580
- let ijf = [0, 0, 0];
583
+ let ijf: [number, number, number] = [0, 0, 0];
581
584
  ijf[permuteAbsTable[0]] = i;
582
585
  ijf[permuteAbsTable[1]] = j;
583
586
  ijf[permuteAbsTable[2]] = frame;
@@ -607,9 +610,9 @@ export const getReslicedPixeldata = function (
607
610
  * @return {Number} - The distance value
608
611
  */
609
612
  export const getDistanceBetweenSlices = function (
610
- seriesData,
611
- sliceIndex1,
612
- sliceIndex2
613
+ seriesData: Series,
614
+ sliceIndex1: number,
615
+ sliceIndex2: number
613
616
  ) {
614
617
  if (seriesData.imageIds.length <= 1) {
615
618
  return 0;
@@ -618,12 +621,8 @@ export const getDistanceBetweenSlices = function (
618
621
  let imageId1 = seriesData.imageIds[sliceIndex1];
619
622
  let instance1 = seriesData.instances[imageId1];
620
623
  let metadata1 = instance1.metadata;
621
- let imageOrientation = metadata1.imageOrientation
622
- ? metadata1.imageOrientation
623
- : metadata1.x00200037;
624
- let imagePosition = metadata1.imagePosition
625
- ? metadata1.imagePosition
626
- : metadata1.x00200032;
624
+ let imageOrientation = metadata1.x00200037;
625
+ let imagePosition = metadata1.x00200032 as [number, number, number];
627
626
 
628
627
  if (imageOrientation && imagePosition) {
629
628
  let normal = getNormalOrientation(imageOrientation);
@@ -635,223 +634,17 @@ export const getDistanceBetweenSlices = function (
635
634
  let imageId2 = seriesData.imageIds[sliceIndex2];
636
635
  let instance2 = seriesData.instances[imageId2];
637
636
  let metadata2 = instance2.metadata;
638
- let imagePosition2 = metadata2.imagePosition
639
- ? metadata2.imagePosition
640
- : metadata2.x00200032;
637
+ let imagePosition2 = metadata2.x00200032!;
641
638
 
642
639
  let d2 =
643
640
  normal[0] * imagePosition2[0] +
644
641
  normal[1] * imagePosition2[1] +
645
- normal[2] * imagePosition2[2];
642
+ normal[2] * imagePosition2[2]!;
646
643
 
647
644
  return Math.abs(d1 - d2);
648
645
  }
649
646
  };
650
647
 
651
- /**
652
- * Parse a DICOM Tag according to its type
653
- * @instance
654
- * @function parseTag
655
- * @param {Object} dataSet - The parsed dataset object from dicom parser
656
- * @param {String} propertyName - The tag name
657
- * @param {Object} element - The parsed dataset element
658
- * @return {String} - The DICOM Tag value
659
- */
660
- export const parseTag = function (dataSet, propertyName, element) {
661
- // GET VR
662
- var tagData = dataSet.elements[propertyName] || {};
663
- var vr = tagData.vr;
664
- if (!vr) {
665
- // use dicom dict to get VR
666
- var tag = getDICOMTag(propertyName);
667
- if (tag && tag.vr) {
668
- vr = tag.vr;
669
- } else {
670
- return element;
671
- }
672
- }
673
-
674
- var value;
675
-
676
- if (isStringVr(vr)) {
677
- // We ask the dataset to give us the element's data in string form.
678
- // Most elements are strings but some aren't so we do a quick check
679
- // to make sure it actually has all ascii characters so we know it is
680
- // reasonable to display it.
681
- var str = dataSet.string(propertyName);
682
- if (str === undefined) {
683
- return undefined;
684
- } else {
685
- // the string will be undefined if the element is present but has no data
686
- // (i.e. attribute is of type 2 or 3) so we only display the string if it has
687
- // data. Note that the length of the element will be 0 to indicate "no data"
688
- // so we don't put anything here for the value in that case.
689
- value = str;
690
- }
691
-
692
- // A string of characters representing an Integer in base-10 (decimal),
693
- // shall contain only the characters 0 - 9, with an optional leading "+" or "-".
694
- // It may be padded with leading and/or trailing spaces. Embedded spaces
695
- // are not allowed. The integer, n, represented shall be in the range:
696
- // -231 <= n <= (231 - 1).
697
- if (vr === "IS") {
698
- value = parseInt(value);
699
- }
700
- // A string of characters representing either a fixed point number
701
- // or a floating point number. A fixed point number shall contain only
702
- // the characters 0-9 with an optional leading "+" or "-" and an optional "."
703
- // to mark the decimal point. A floating point number shall be conveyed
704
- // as defined in ANSI X3.9, with an "E" or "e" to indicate the start
705
- // of the exponent. Decimal Strings may be padded with leading or trailing spaces.
706
- // Embedded spaces are not allowed.
707
- else if (vr === "DS") {
708
- value = value.split("\\").map(Number);
709
- if (propertyName == "x00281050" || propertyName == "x00281051") {
710
- value = value.length > 0 ? value[0] : value;
711
- } else {
712
- value = value.length == 1 ? value[0] : value;
713
- }
714
- }
715
- // A string of characters of the format YYYYMMDD; where YYYY shall contain year,
716
- // MM shall contain the month, and DD shall contain the day,
717
- // interpreted as a date of the Gregorian calendar system.
718
- else if (vr === "DA") {
719
- value = parseDateTag(value, false);
720
- }
721
- // A concatenated date-time character string in the format:
722
- // YYYYMMDDHHMMSS.FFFFFF
723
- else if (vr === "DT") {
724
- value = parseDateTimeTag(value);
725
- }
726
- // A string of characters of the format HHMMSS.FFFFFF; where HH contains hours
727
- // (range "00" - "23"), MM contains minutes (range "00" - "59"),
728
- // SS contains seconds (range "00" - "60"), and FFFFFF contains a fractional
729
- // part of a second as small as 1 millionth of a second (range "000000" - "999999").
730
- else if (vr === "TM") {
731
- value = parseTimeTag(value);
732
- }
733
- // Specific Character Set (0008,0005) identifies the Character Set that expands or
734
- // replaces the Basic Graphic Set (ISO 646) for values of Data Elements that have
735
- // Value Representation of SH, LO, ST, PN, LT, UC or UT.
736
- // If the Attribute Specific Character Set (0008,0005) is not present or has only
737
- // a single value, Code Extension techniques are not used. Defined Terms for the
738
- // Attribute Specific Character Set (0008,0005), when single valued, are derived
739
- // from the International Registration Number as per ISO 2375
740
- // (e.g., ISO_IR 100 for Latin alphabet No. 1).
741
- // See https://github.com/radialogica/dicom-character-set
742
- else if (
743
- vr == "PN" ||
744
- vr == "SH" ||
745
- vr == "LO" ||
746
- vr == "ST" ||
747
- vr == "LT" ||
748
- vr == "UC" ||
749
- vr == "UT"
750
- ) {
751
- // get character set
752
- let characterSet = dataSet.string("x00080005");
753
- if (characterSet) {
754
- let data = dataSet.elements[propertyName];
755
- let arr = new Uint8Array(
756
- dataSet.byteArray.buffer,
757
- data.dataOffset,
758
- data.length
759
- );
760
- value = convertBytes(characterSet, arr, {
761
- vr: vr
762
- });
763
- arr = null;
764
- }
765
- if (vr == "PN") {
766
- // PatientName tag value is: "LastName^FirstName^MiddleName".
767
- // Spaces inside each name component are permitted. If you don't know
768
- // any of the three components, just leave it empty.
769
- // Actually you may even append a name prefix (^professor) and
770
- // a name suffix (^senior) so you have a maximum of 5 components.
771
- value = parsePatientNameTag(value);
772
- }
773
- value = value.replace(/\0/g, ""); // remove null char (\u0000)
774
- }
775
- // A string of characters with one of the following formats
776
- // -- nnnD, nnnW, nnnM, nnnY; where nnn shall contain the number of days for D,
777
- // weeks for W, months for M, or years for Y.
778
- else if (vr == "AS") {
779
- value = parseAgeTag(value);
780
- }
781
-
782
- // A string of characters with leading or trailing spaces (20H) being non-significant.
783
- else if (vr === "CS") {
784
- if (propertyName === "x00041500") {
785
- value = parseDICOMFileIDTag(value);
786
- } else {
787
- value = value.split("\\").join(", ");
788
- }
789
- }
790
- } else if (vr === "US") {
791
- value = dataSet.uint16(propertyName);
792
- } else if (vr === "SS") {
793
- value = dataSet.int16(propertyName);
794
- } else if (vr === "US|SS") {
795
- value = dataSet.int16(propertyName);
796
- } else if (vr === "UL") {
797
- value = dataSet.uint32(propertyName);
798
- } else if (vr === "SL") {
799
- value = dataSet.int32(propertyName);
800
- } else if (vr == "FD") {
801
- value = dataSet.double(propertyName);
802
- } else if (vr == "FL") {
803
- value = dataSet.float(propertyName);
804
- } else if (
805
- vr === "OB" ||
806
- vr === "OW" ||
807
- vr === "OW|OB" ||
808
- vr === "US|OW" ||
809
- vr === "UN" ||
810
- vr === "OF" ||
811
- vr === "UT"
812
- ) {
813
- // If it is some other length and we have no string
814
- if (element.length === 2) {
815
- value =
816
- "binary data of length " +
817
- element.length +
818
- " as uint16: " +
819
- dataSet.uint16(propertyName);
820
- } else if (element.length === 4) {
821
- value =
822
- "binary data of length " +
823
- element.length +
824
- " as uint32: " +
825
- dataSet.uint32(propertyName);
826
- } else {
827
- value = "binary data of length " + element.length + " and VR " + vr;
828
- }
829
- } else if (vr === "AT") {
830
- var group = dataSet.uint16(propertyName, 0);
831
- if (group) {
832
- var groupHexStr = ("0000" + group.toString(16)).substr(-4);
833
- var elm = dataSet.uint16(propertyName, 1);
834
- var elmHexStr = ("0000" + elm.toString(16)).substr(-4);
835
- value = "x" + groupHexStr + elmHexStr;
836
- } else {
837
- value = "";
838
- }
839
- } else if (vr === "SQ") {
840
- // parse the nested tags
841
- var subTags = map(element, function (obj) {
842
- return map(obj, function (v, k) {
843
- return parseTag(dataSet, k, v);
844
- });
845
- });
846
-
847
- value = subTags;
848
- } else {
849
- // If it is some other length and we have no string
850
- value = "no display code for VR " + vr;
851
- }
852
- return value;
853
- };
854
-
855
648
  /**
856
649
  * @instance
857
650
  * @function getImageMetadata
@@ -859,7 +652,10 @@ export const parseTag = function (dataSet, propertyName, element) {
859
652
  * @param {String} instanceUID - The SOPInstanceUID
860
653
  * @return {Array} - List of metadata objects: tag, name and value
861
654
  */
862
- export const getImageMetadata = function (seriesId, instanceUID) {
655
+ export const getImageMetadata = function (
656
+ seriesId: string,
657
+ instanceUID: string
658
+ ) {
863
659
  const seriesData = getSeriesDataFromLarvitarManager(seriesId);
864
660
  if (seriesData === undefined || seriesData === null) {
865
661
  console.log(`Invalid Series ID: ${seriesId}`);
@@ -873,14 +669,15 @@ export const getImageMetadata = function (seriesId, instanceUID) {
873
669
 
874
670
  let metadata = seriesData.instances[imageId].metadata;
875
671
  // get elements from metadata where the key starts with x and is length 7
876
- let metadata_keys = filter(keys(metadata), function (key) {
877
- return key.length === 9 && key[0] === "x";
878
- });
672
+ let metadata_keys = Object.keys(metadata);
879
673
  // loop metadata using metadata_keys and return list of key value pairs
880
- let metadata_list = map(metadata_keys, function (key) {
674
+ let metadata_list = map(metadata_keys, function (key: string) {
881
675
  // if value is a dictionary return empty string
676
+ let KEY = key as keyof MetaDataTypes;
882
677
  const value =
883
- metadata[key] && metadata[key].constructor == Object ? "" : metadata[key];
678
+ metadata[KEY] && metadata[KEY]!.constructor == Object
679
+ ? ""
680
+ : metadata[KEY];
884
681
  // convert key removing x and adding comma at position 4
885
682
  const tagKey = (
886
683
  "(" +
@@ -889,7 +686,14 @@ export const getImageMetadata = function (seriesId, instanceUID) {
889
686
  key.slice(5) +
890
687
  ")"
891
688
  ).toUpperCase();
892
- const name = TAG_DICT[tagKey] ? TAG_DICT[tagKey].name : "";
689
+
690
+ if (!Object.keys(TAG_DICT).includes(tagKey)) {
691
+ console.debug(`Invalid tag key: ${tagKey}`);
692
+ }
693
+ // force type to keyof typeof TAG_DICT after having checked that it is a valid key
694
+ const name = TAG_DICT[tagKey as keyof typeof TAG_DICT]
695
+ ? TAG_DICT[tagKey as keyof typeof TAG_DICT].name
696
+ : "";
893
697
  return {
894
698
  tag: tagKey,
895
699
  name: name,
@@ -911,34 +715,31 @@ export const getImageMetadata = function (seriesId, instanceUID) {
911
715
  * @param {String} method - Orientation target
912
716
  * @return {Number} - The sorting value (float)
913
717
  */
914
- let sortStackCallback = function (seriesData, imageId, method) {
718
+ let sortStackCallback = function (
719
+ seriesData: Series,
720
+ imageId: string,
721
+ method: "instanceNumber" | "contentTime" | "imagePosition"
722
+ ) {
915
723
  switch (method) {
916
724
  case "instanceNumber":
917
- var instanceNumber = seriesData.instances[imageId].metadata.x00200013;
918
- instanceNumber = parseInt(instanceNumber);
725
+ var instanceNumber = seriesData.instances[imageId].metadata.x00200013!;
919
726
  return instanceNumber;
920
727
 
921
728
  case "contentTime":
922
729
  return seriesData.instances[imageId].metadata.x00080033;
923
730
 
924
731
  case "imagePosition":
925
- var p = seriesData.instances[imageId].metadata.imagePosition;
926
-
927
- p = map(p, function (value) {
928
- return parseFloat(value);
929
- });
930
-
931
- var o = seriesData.instances[imageId].metadata.imageOrientation;
932
- o = map(o, function (value) {
933
- return parseFloat(value);
934
- });
732
+ let p = seriesData.instances[imageId].metadata.imagePosition!;
733
+ let pStr = p?.map(String);
734
+ let o = seriesData.instances[imageId].metadata.imageOrientation!;
735
+ let oStr = o?.map(String);
935
736
 
936
- var v1, v2, v3;
737
+ var v1, v2, v3: number;
937
738
  v1 = o[0] * o[0] + o[3] * o[3];
938
739
  v2 = o[1] * o[1] + o[4] * o[4];
939
740
  v3 = o[2] * o[2] + o[5] * o[5];
940
741
 
941
- var sortIndex;
742
+ var sortIndex = -1;
942
743
  if (v1 <= v2 && v2 <= v3) {
943
744
  sortIndex = 0;
944
745
  }
@@ -948,89 +749,17 @@ let sortStackCallback = function (seriesData, imageId, method) {
948
749
  if (v3 <= v1 && v3 <= v2) {
949
750
  sortIndex = 2;
950
751
  }
752
+
753
+ if (!sortIndex) {
754
+ throw new Error("Invalid sort index");
755
+ }
756
+
951
757
  return p[sortIndex];
952
758
  default:
953
759
  break;
954
760
  }
955
761
  };
956
762
 
957
- /**
958
- * Get the dicom tag code from dicom image
959
- * @instance
960
- * @function getDICOMTagCode
961
- * @param {String} dicomTag - The original DICOM tag code
962
- * @return {String} - The human readable DICOM tag code
963
- */
964
- let getDICOMTagCode = function (code) {
965
- let re = /x(\w{4})(\w{4})/;
966
- let result = re.exec(code);
967
- if (!result) {
968
- return code;
969
- }
970
- let newCode = "(" + result[1] + "," + result[2] + ")";
971
- newCode = newCode.toUpperCase();
972
- return newCode;
973
- };
974
-
975
- /**
976
- * Get the dicom tag from dicom tag code
977
- * @instance
978
- * @function getDICOMTag
979
- * @param {String} dicomTagCode - The original DICOM tag code
980
- * @return {String} - The human readable DICOM tag
981
- */
982
- let getDICOMTag = function (code) {
983
- let newCode = getDICOMTagCode(code);
984
- let tag = TAG_DICT[newCode];
985
- return tag;
986
- };
987
-
988
- /**
989
- * Convert date from dicom tag
990
- * @instance
991
- * @function formatDate
992
- * @param {Date} dicomDate - A date from a DICOM tag
993
- * @return {String} - The human readable date
994
- */
995
- let formatDate = function (date) {
996
- let yyyy = date.slice(0, 4);
997
- let mm = date.slice(4, 6);
998
- let dd = date.slice(6, 8);
999
- return (
1000
- yyyy + "-" + (mm[1] ? mm : "0" + mm[0]) + "-" + (dd[1] ? dd : "0" + dd[0])
1001
- );
1002
- };
1003
-
1004
- /**
1005
- * Convert datetime from dicom tag
1006
- * @instance
1007
- * @function formatDateTime
1008
- * @param {Date} dicomDateTime - A dateTime from a DICOM tag
1009
- * @return {String} - The human readable dateTime
1010
- */
1011
- let formatDateTime = function (date) {
1012
- let yyyy = date.slice(0, 4);
1013
- let mm = date.slice(4, 6);
1014
- let dd = date.slice(6, 8);
1015
- let hh = date.slice(8, 10);
1016
- let m = date.slice(10, 12);
1017
- let ss = date.slice(12, 14);
1018
-
1019
- return (
1020
- yyyy +
1021
- "-" +
1022
- (mm[1] ? mm : "0" + mm[0]) +
1023
- "-" +
1024
- (dd[1] ? dd : "0" + dd[0]) +
1025
- "/" +
1026
- hh +
1027
- ":" +
1028
- m +
1029
- ":" +
1030
- ss
1031
- );
1032
- };
1033
-
1034
763
  /**
1035
764
  * Generate a random number and convert it to base 36 (0-9a-z)
1036
765
  * @instance
@@ -1049,7 +778,7 @@ let rand = function () {
1049
778
  * @param {Array} sourceArray - The source array
1050
779
  * @return {Array} - The converted array
1051
780
  */
1052
- let permuteValues = function (convertArray, sourceArray) {
781
+ let permuteValues = function (convertArray: number[], sourceArray: number[]) {
1053
782
  let outputArray = new Array(convertArray.length);
1054
783
  for (let i = 0; i < convertArray.length; i++) {
1055
784
  outputArray[i] = sourceArray[convertArray[i]];
@@ -1065,7 +794,7 @@ let permuteValues = function (convertArray, sourceArray) {
1065
794
  * @param {Number} x - The number to check
1066
795
  * @return {Boolean} - Is negative boolean response
1067
796
  */
1068
- let isNegativeSign = function (x) {
797
+ let isNegativeSign = function (x: number) {
1069
798
  return 1 / x !== 1 / Math.abs(x);
1070
799
  };
1071
800
 
@@ -1077,9 +806,12 @@ let isNegativeSign = function (x) {
1077
806
  * @param {Number} size - The size of the array
1078
807
  * @return {Array} - The typed array
1079
808
  */
1080
- let getTypedArray = function (tags, size) {
809
+ let getTypedArray = function (tags: CustomDataSet, size: number) {
1081
810
  let r = getPixelRepresentation(tags);
1082
811
  let typedArray = getTypedArrayFromDataType(r);
812
+ if (!typedArray) {
813
+ throw new Error("Invalid typed array");
814
+ }
1083
815
  return new typedArray(size);
1084
816
  };
1085
817
 
@@ -1091,7 +823,10 @@ let getTypedArray = function (tags, size) {
1091
823
  * @param {Array} permuteTable - The matrix transformation
1092
824
  * @return {Array} - The resliced image orientation array
1093
825
  */
1094
- let getReslicedIOP = function (iop, permuteTable) {
826
+ let getReslicedIOP = function (
827
+ iop: [number, number, number, number, number, number],
828
+ permuteTable: number[]
829
+ ) {
1095
830
  if (!iop) {
1096
831
  return null;
1097
832
  }
@@ -1126,29 +861,29 @@ let getReslicedIOP = function (iop, permuteTable) {
1126
861
  * @return {Array} - The resliced image position array
1127
862
  */
1128
863
  let getReslicedIPP = function (
1129
- ipp,
1130
- iop,
1131
- reslicedIOP,
1132
- permuteTable,
1133
- imageIndex,
1134
- fromSize,
1135
- toSize,
1136
- fromSpacing
864
+ ipp: [number, number, number],
865
+ iop: [number, number, number, number, number, number],
866
+ reslicedIOP: [number, number, number, number, number, number],
867
+ permuteTable: number[],
868
+ imageIndex: number,
869
+ fromSize: number[],
870
+ toSize: number[],
871
+ fromSpacing: number[]
1137
872
  ) {
1138
873
  // compute resliced ipp
1139
874
  let reslicedIPP = [];
1140
875
 
1141
- // iop data
876
+ // iop data types??
1142
877
  let u = iop.slice(0, 3);
1143
878
  let v = iop.slice(3, 6);
1144
879
  let w = getNormalOrientation(iop);
1145
- let absW = map(w, function (v) {
880
+ let absW = map(w, function (v: number) {
1146
881
  return Math.abs(v);
1147
882
  });
1148
883
  let majorOriginalIndex = indexOf(absW, max(absW));
1149
884
 
1150
885
  let normalReslicedIop = getNormalOrientation(reslicedIOP);
1151
- normalReslicedIop = map(normalReslicedIop, function (v) {
886
+ normalReslicedIop = map(normalReslicedIop, function (v: number) {
1152
887
  return Math.abs(v);
1153
888
  });
1154
889
 
@@ -1161,10 +896,11 @@ let getReslicedIPP = function (
1161
896
  if (isNegativeSign(permuteTable[1])) {
1162
897
  ipp = ipp.map(function (val, i) {
1163
898
  return val + fromSize[2] * fromSpacing[2] * w[i];
1164
- });
899
+ }) as [number, number, number];
1165
900
  }
1166
901
 
1167
- let spacing, versor;
902
+ let spacing: number;
903
+ let versor: number[];
1168
904
  // to sagittal
1169
905
  if (majorIndex == 0) {
1170
906
  // original x spacing
@@ -1203,7 +939,7 @@ let getReslicedIPP = function (
1203
939
  return val + index * spacing * versor[i];
1204
940
  });
1205
941
 
1206
- return reslicedIPP;
942
+ return reslicedIPP as [number, number, number];
1207
943
  };
1208
944
 
1209
945
  /**
@@ -1214,9 +950,12 @@ let getReslicedIPP = function (
1214
950
  * @param {Array} reslicedIPP - The resliced image position array
1215
951
  * @return {Array} - The slice location as normal orientation vector
1216
952
  */
1217
- let getReslicedSliceLocation = function (reslicedIOP, reslicedIPP) {
953
+ let getReslicedSliceLocation = function (
954
+ reslicedIOP: [number, number, number, number, number, number],
955
+ reslicedIPP: [number, number, number]
956
+ ) {
1218
957
  let normalReslicedIop = getNormalOrientation(reslicedIOP);
1219
- normalReslicedIop = map(normalReslicedIop, function (v) {
958
+ normalReslicedIop = map(normalReslicedIop, function (v: number) {
1220
959
  return Math.abs(v);
1221
960
  });
1222
961
 
@@ -1232,22 +971,23 @@ let getReslicedSliceLocation = function (reslicedIOP, reslicedIPP) {
1232
971
  * @param {Object} sampleMetadata - The medatata object
1233
972
  * @return {Array} - The spacing array
1234
973
  */
1235
- let spacingArray = function (seriesData, sampleMetadata) {
974
+ let spacingArray = function (
975
+ seriesData: Series,
976
+ sampleMetadata: MetaDataTypes
977
+ ) {
1236
978
  // the spacingArray is as follows:
1237
979
  // [0]: column pixelSpacing value (x00280030[1])
1238
980
  // [1]: row pixelSpacing value (x00280030[0])
1239
981
  // [2]: distance between slices, given the series imageOrientationPatient and
1240
982
  // imagePositionPatient of the first two slices
1241
983
 
1242
- let distanceBetweenSlices = sampleMetadata.x00180050
1243
- ? sampleMetadata.x00180050
984
+ let distanceBetweenSlices = sampleMetadata["x00180050"]
985
+ ? sampleMetadata["x00180050"]
1244
986
  : getDistanceBetweenSlices(seriesData, 0, 1);
1245
987
 
1246
- return [
1247
- sampleMetadata.x00280030[1],
1248
- sampleMetadata.x00280030[0],
1249
- distanceBetweenSlices
1250
- ];
988
+ let spacing = sampleMetadata.x00280030!;
989
+
990
+ return [spacing[1], spacing[0], distanceBetweenSlices as number];
1251
991
  };
1252
992
 
1253
993
  /**
@@ -1258,7 +998,10 @@ let spacingArray = function (seriesData, sampleMetadata) {
1258
998
  * @param {Array} sourceArray - The source array
1259
999
  * @return {Array} - The permuted array array
1260
1000
  */
1261
- let permuteSignedArrays = function (convertArray, sourceArray) {
1001
+ let permuteSignedArrays = function (
1002
+ convertArray: number[],
1003
+ sourceArray: number[][]
1004
+ ) {
1262
1005
  let outputArray = new Array(convertArray.length);
1263
1006
  for (let i = 0; i < convertArray.length; i++) {
1264
1007
  let sourceIndex = Math.abs(convertArray[i]);
@@ -1274,239 +1017,6 @@ let permuteSignedArrays = function (convertArray, sourceArray) {
1274
1017
  return outputArray;
1275
1018
  };
1276
1019
 
1277
- /**
1278
- * Check if argument is a valid Date Object
1279
- * @instance
1280
- * @function isValidDate
1281
- * @param {Date} d - The date object to be checked
1282
- * @return {Boolean} - Boolean result
1283
- */
1284
- const isValidDate = function (d) {
1285
- return d instanceof Date && !isNaN(d);
1286
- };
1287
-
1288
- /**
1289
- * Check if argument is a string of concatenated vrs
1290
- * @instance
1291
- * @function isStringVr
1292
- * @param {String} vr - The string to be checked
1293
- * @return {Boolean} - Boolean result
1294
- */
1295
- const isStringVr = function (vr) {
1296
- // vr can be a string of concatenated vrs
1297
- vr = vr || "";
1298
- vr = vr.split("|")[0];
1299
-
1300
- if (
1301
- vr === "AT" ||
1302
- vr === "FL" ||
1303
- vr === "FD" ||
1304
- vr === "OB" ||
1305
- vr === "OF" ||
1306
- vr === "OW" ||
1307
- vr === "SI" ||
1308
- vr === "SQ" ||
1309
- vr === "SS" ||
1310
- vr === "UL" ||
1311
- vr === "US"
1312
- ) {
1313
- return false;
1314
- }
1315
- return true;
1316
- };
1317
-
1318
- /**
1319
- * Parse a dicom date tag into human readable format
1320
- * @instance
1321
- * @function parseDateTag
1322
- * @param {String} tagValue - The string to be parsed
1323
- * @return {String} - The parsed result
1324
- */
1325
- const parseDateTag = function (tagValue) {
1326
- if (!tagValue) return;
1327
- let year = tagValue.substring(0, 4);
1328
- let month = tagValue.substring(4, 6);
1329
- let day = tagValue.substring(6, 8);
1330
- let date = new Date(year, month - 1, day);
1331
- if (isValidDate(date) === true) {
1332
- return date.toISOString();
1333
- } else {
1334
- return tagValue;
1335
- }
1336
- };
1337
-
1338
- /**
1339
- * Parse a dicom datetime tag into human readable format
1340
- * @instance
1341
- * @function parseDateTimeTag
1342
- * @param {String} tagValue - The string to be parsed
1343
- * @return {String} - The parsed result
1344
- */
1345
- const parseDateTimeTag = function (tagValue) {
1346
- if (!tagValue) return;
1347
- let year = tagValue.substring(0, 4);
1348
- let month = tagValue.substring(4, 6);
1349
- let day = tagValue.substring(6, 8);
1350
- let hour = tagValue.substring(8, 10);
1351
- let min = tagValue.substring(10, 12);
1352
- let sec = tagValue.substring(12, 14);
1353
- let msec = tagValue.substring(15, 21);
1354
- let date = new Date(year, month - 1, day, hour, min, sec, msec);
1355
- if (isValidDate(date) === true) {
1356
- return date.toISOString();
1357
- } else {
1358
- return tagValue;
1359
- }
1360
- };
1361
-
1362
- /**
1363
- * Parse a dicom time tag into human readable format
1364
- * @instance
1365
- * @function parseTimeTag
1366
- * @param {String} tagValue - The string to be parsed
1367
- * @return {String} - The parsed result
1368
- */
1369
- const parseTimeTag = function (tagValue) {
1370
- if (!tagValue) return;
1371
- let hour = tagValue.substring(0, 2);
1372
- let min = tagValue.substring(2, 4);
1373
- let sec = tagValue.substring(4, 6);
1374
- let msec = tagValue.substring(7, 13) ? tagValue.substring(7, 13) : "0";
1375
- let result = hour + ":" + min + ":" + sec + "." + msec;
1376
- return result;
1377
- };
1378
-
1379
- /**
1380
- * Parse a dicom patient tag into human readable format
1381
- * @instance
1382
- * @function parsePatientNameTag
1383
- * @param {String} tagValue - The string to be parsed
1384
- * @return {String} - The parsed result
1385
- */
1386
- const parsePatientNameTag = function (tagValue) {
1387
- if (!tagValue) return;
1388
- return tagValue.replace(/\^/gi, " ");
1389
- };
1390
-
1391
- /**
1392
- * Parse a dicom age tag into human readable format
1393
- * @instance
1394
- * @function parseAgeTag
1395
- * @param {String} tagValue - The string to be parsed
1396
- * @return {String} - The parsed result
1397
- */
1398
- const parseAgeTag = function (tagValue) {
1399
- if (!tagValue) return;
1400
- let regs = /(\d{3})(D|W|M|Y)/gim.exec(tagValue);
1401
- if (regs) {
1402
- return parseInt(regs[1]) + " " + regs[2];
1403
- }
1404
- };
1405
-
1406
- /**
1407
- * Parse a dicom fileID tag into human readable format
1408
- * @instance
1409
- * @function parseDICOMFileIDTag
1410
- * @param {String} tagValue - The string to be parsed
1411
- * @return {String} - The parsed result
1412
- */
1413
- const parseDICOMFileIDTag = function (tagValue) {
1414
- // The DICOM File Service does not specify any "separator" between
1415
- // the Components of the File ID. This is a Value Representation issue that
1416
- // may be addressed in a specific manner by each Media Format Layer.
1417
- // In DICOM IODs, File ID Components are generally handled as multiple
1418
- // Values and separated by "backslashes".
1419
- // There is no requirement that Media Format Layers use this separator.
1420
- if (!tagValue) return;
1421
- return tagValue.split("\\").join(path.sep);
1422
- };
1423
-
1424
- /**
1425
- * Extract tag value according to its value rapresentation, see
1426
- * {@link http://dicom.nema.org/dicom/2013/output/chtml/part05/sect_6.2.html}
1427
- * @instance
1428
- * @function getTagValue
1429
- * @param {Object} dataSet - the dataset
1430
- * @param {String} tag - the desired tag key
1431
- * @return {Number | Array | String} - the desired tag value
1432
- */
1433
- const getTagValue = function (dataSet, tag) {
1434
- // tag value rapresentation
1435
- if (!getDICOMTag(tag)) {
1436
- return null;
1437
- }
1438
- let vr = getDICOMTag(tag).vr;
1439
-
1440
- // parse value according to vr map
1441
- let vrParsingMap = {
1442
- // Date
1443
- // string of characters of the format YYYYMMDD; where YYYY shall contain year,
1444
- // MM shall contain the month, and DD shall contain the day,
1445
- // interpreted as a date of the Gregorian calendar system.
1446
- DA: function () {
1447
- let dateString = dataSet.string(tag);
1448
- return dateString ? formatDate(dateString) : "";
1449
- },
1450
- // Decimal String
1451
- // A string of characters representing either a fixed point number
1452
- // or a floating point number.
1453
- DS: function () {
1454
- let array = dataSet.string(tag)
1455
- ? dataSet.string(tag).split("\\").map(Number)
1456
- : null;
1457
- if (!array) {
1458
- return null;
1459
- }
1460
- return array.length === 1 ? array[0] : array;
1461
- },
1462
- // Date Time
1463
- // A concatenated date-time character string in the format:
1464
- // YYYYMMDDHHMMSS.FFFFFF&ZZXX
1465
- DT: function () {
1466
- let dateString = dataSet.string(tag);
1467
- return formatDateTime(dateString);
1468
- },
1469
- // Person Name
1470
- // A character string encoded using a 5 component convention.
1471
- // The character code 5CH (the BACKSLASH "\" in ISO-IR 6) shall
1472
- // not be present, as it is used as the delimiter between values
1473
- // in multiple valued data elements. The string may be padded
1474
- // with trailing spaces. For human use, the five components
1475
- // in their order of occurrence are: family name complex,
1476
- // given name complex, middle name, name prefix, name suffix.
1477
- PN: function () {
1478
- let pn = dataSet.string(tag) ? dataSet.string(tag).split("^") : null;
1479
- if (!pn) {
1480
- return null;
1481
- }
1482
-
1483
- let pns = [pn[3], pn[0], pn[1], pn[2], pn[4]];
1484
- return pns.join(" ").trim();
1485
- },
1486
- // Signed Short
1487
- // Signed binary integer 16 bits long in 2's complement form
1488
- SS: function () {
1489
- return dataSet.uint16(tag);
1490
- },
1491
- // Unique Identifier
1492
- // A character string containing a UID that is used to uniquely
1493
- // identify a wide letiety of items. The UID is a series of numeric
1494
- // components separated by the period "." character.
1495
- UI: function () {
1496
- return dataSet.string(tag);
1497
- },
1498
- // Unsigned Short
1499
- // Unsigned binary integer 16 bits long.
1500
- US: function () {
1501
- return dataSet.uint16(tag);
1502
- },
1503
- "US|SS": function () {
1504
- return dataSet.uint16(tag);
1505
- }
1506
- };
1507
- return vrParsingMap[vr] ? vrParsingMap[vr]() : dataSet.string(tag);
1508
- };
1509
-
1510
1020
  /**
1511
1021
  * Object used to convert data type to typed array
1512
1022
  * @object
@@ -1558,7 +1068,7 @@ const TYPES_TO_TYPEDARRAY = {
1558
1068
  * @param {Object} o - The div tag
1559
1069
  * @return {Boolean} - True if is an element otherwise returns False
1560
1070
  */
1561
- export const isElement = function (o) {
1071
+ export const isElement = function (o: any) {
1562
1072
  return typeof HTMLElement === "object"
1563
1073
  ? o instanceof HTMLElement //DOM2
1564
1074
  : o &&