larvitar 1.5.14 → 2.0.2

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 (107) 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 +40 -0
  8. package/dist/imaging/MetaDataTypes.d.ts +3489 -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 +113 -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/BorderMagnifyTool.d.ts +18 -0
  35. package/dist/imaging/tools/custom/contourTool.d.ts +409 -0
  36. package/dist/imaging/tools/custom/diameterTool.d.ts +18 -0
  37. package/dist/imaging/tools/custom/editMaskTool.d.ts +22 -0
  38. package/dist/imaging/tools/custom/ellipticalRoiOverlayTool.d.ts +45 -0
  39. package/dist/imaging/tools/custom/polygonSegmentationMixin.d.ts +54 -0
  40. package/dist/imaging/tools/custom/polylineScissorsTool.d.ts +11 -0
  41. package/dist/imaging/tools/custom/rectangleRoiOverlayTool.d.ts +45 -0
  42. package/dist/imaging/tools/custom/seedTool.d.ts +0 -0
  43. package/dist/imaging/tools/custom/setLabelMap3D.d.ts +39 -0
  44. package/dist/imaging/tools/custom/thresholdsBrushTool.d.ts +19 -0
  45. package/dist/imaging/tools/default.d.ts +53 -0
  46. package/dist/imaging/tools/interaction.d.ts +30 -0
  47. package/dist/imaging/tools/io.d.ts +38 -0
  48. package/dist/imaging/tools/main.d.ts +81 -0
  49. package/dist/imaging/tools/segmentation.d.ts +125 -0
  50. package/dist/imaging/tools/state.d.ts +17 -0
  51. package/dist/imaging/tools/strategies/eraseFreehand.d.ts +16 -0
  52. package/dist/imaging/tools/strategies/fillFreehand.d.ts +16 -0
  53. package/dist/imaging/tools/strategies/index.d.ts +2 -0
  54. package/dist/imaging/waveforms/ecg.d.ts +39 -0
  55. package/dist/index.d.ts +35 -0
  56. package/dist/larvitar.js +90104 -0
  57. package/dist/larvitar.js.map +1 -0
  58. package/imaging/MetaDataReadable.ts +41 -0
  59. package/imaging/MetaDataTypes.ts +3491 -0
  60. package/imaging/dataDictionary.json +5328 -5328
  61. package/imaging/{imageAnonymization.js → imageAnonymization.ts} +41 -13
  62. package/imaging/{imageColormaps.js → imageColormaps.ts} +48 -30
  63. package/imaging/{imageContours.js → imageContours.ts} +24 -22
  64. package/imaging/{imageIo.js → imageIo.ts} +89 -52
  65. package/imaging/{imageLayers.js → imageLayers.ts} +31 -14
  66. package/imaging/{imageLoading.js → imageLoading.ts} +107 -43
  67. package/imaging/{imageParsing.js → imageParsing.ts} +160 -80
  68. package/imaging/{imagePresets.js → imagePresets.ts} +44 -11
  69. package/imaging/imageRendering.ts +1091 -0
  70. package/imaging/{imageReslice.js → imageReslice.ts} +18 -9
  71. package/imaging/imageStore.ts +487 -0
  72. package/imaging/imageTags.ts +609 -0
  73. package/imaging/imageTools.js +2 -1
  74. package/imaging/{imageUtils.js → imageUtils.ts} +211 -701
  75. package/imaging/loaders/{commonLoader.js → commonLoader.ts} +73 -24
  76. package/imaging/loaders/{dicomLoader.js → dicomLoader.ts} +25 -5
  77. package/imaging/loaders/{fileLoader.js → fileLoader.ts} +5 -5
  78. package/imaging/loaders/{multiframeLoader.js → multiframeLoader.ts} +145 -90
  79. package/imaging/loaders/{nrrdLoader.js → nrrdLoader.ts} +231 -64
  80. package/imaging/loaders/{resliceLoader.js → resliceLoader.ts} +51 -20
  81. package/imaging/monitors/{memory.js → memory.ts} +54 -8
  82. package/imaging/monitors/performance.ts +34 -0
  83. package/imaging/parsers/ecg.ts +54 -0
  84. package/imaging/tools/README.md +27 -0
  85. package/imaging/tools/custom/4dSliceScrollTool.js +47 -46
  86. package/imaging/tools/custom/BorderMagnifyTool.js +99 -0
  87. package/imaging/tools/custom/ellipticalRoiOverlayTool.js +534 -0
  88. package/imaging/tools/custom/polylineScissorsTool.js +1 -1
  89. package/imaging/tools/custom/rectangleRoiOverlayTool.js +564 -0
  90. package/imaging/tools/{setLabelMap3D.js → custom/setLabelMap3D.ts} +19 -25
  91. package/imaging/tools/{default.js → default.ts} +119 -33
  92. package/imaging/tools/{interaction.js → interaction.ts} +42 -23
  93. package/imaging/tools/{io.js → io.ts} +47 -31
  94. package/imaging/tools/{main.js → main.ts} +105 -40
  95. package/imaging/tools/{segmentation.js → segmentation.ts} +95 -68
  96. package/imaging/tools/{state.js → state.ts} +7 -12
  97. package/imaging/tools/types.d.ts +243 -0
  98. package/imaging/types.d.ts +200 -0
  99. package/imaging/waveforms/ecg.ts +191 -0
  100. package/{index.js → index.ts} +53 -14
  101. package/jsdoc.json +1 -1
  102. package/package.json +35 -14
  103. package/tsconfig.json +102 -0
  104. package/imaging/imageRendering.js +0 -860
  105. package/imaging/imageStore.js +0 -322
  106. package/modules/vuex/larvitar.js +0 -187
  107. /package/imaging/tools/{polygonSegmentationMixin.js → custom/polygonSegmentationMixin.js} +0 -0
@@ -7,6 +7,7 @@
7
7
  import sha256 from "crypto-js/sha256";
8
8
  import Hex from "crypto-js/enc-hex";
9
9
  import { forEach } from "lodash";
10
+ import { Instance, MetaData, Series } from "./types";
10
11
 
11
12
  const SH = [
12
13
  "x00080050" // Accession Number,
@@ -111,43 +112,70 @@ const TAGS = [
111
112
  * @param {Object} series - Cornerstone series object
112
113
  * @returns {Object} anonymized_series: Cornerstone anonymized series object
113
114
  */
114
- export const anonymize = function (series) {
115
- forEach(series.instances, function (instance) {
115
+ export const anonymize = function (series: Series) {
116
+ forEach(series.instances, function (instance: Instance) {
116
117
  forEach(TAGS, function (tag) {
117
118
  if (tag in instance.metadata) {
118
- let anonymized_value = sha256(instance.metadata[tag]).toString(Hex);
119
+ let tag_meta = tag as keyof MetaData;
120
+
121
+ let anonymized_value = sha256(
122
+ (instance.metadata[tag_meta] || "").toString()
123
+ ).toString(Hex);
124
+
119
125
  // Patient Tag Anonymization
120
- if (tag === "x00100010") {
121
- instance.metadata[tag] =
126
+ if (tag_meta === "x00100010") {
127
+ instance.metadata[tag_meta] =
122
128
  "Anonymized^" + anonymized_value.substring(0, 6);
123
129
  }
124
130
  // Short string
125
- else if (SH.includes(tag) === true) {
126
- instance.metadata[tag] = anonymized_value.substring(0, 16);
131
+ else if (tag_meta === "x00080050") {
132
+ instance.metadata[tag_meta] = anonymized_value.substring(0, 16);
127
133
  }
128
134
  // Required, empty if unknown
129
- else if (OPTIONAL.includes(tag) === true) {
130
- instance.metadata[tag] = "";
135
+ /*else if (OPTIONAL.includes(tag) === true) {
136
+ tag_meta = tag as keyof MetaData;
137
+ instance.metadata[tag_meta] = "";
138
+ }*/
139
+ else if (tag_meta === "x00100030") {
140
+ instance.metadata[tag_meta] = "";
141
+ } else if (tag_meta === "x00080090") {
142
+ instance.metadata[tag_meta] = "";
143
+ } else if (tag_meta === "x00100020") {
144
+ instance.metadata[tag_meta] = "";
145
+ } else if (tag_meta === "x00100040") {
146
+ instance.metadata[tag_meta] = "";
147
+ } else if (tag_meta === "x00200010") {
148
+ instance.metadata[tag_meta] = "";
131
149
  }
132
150
  // Optional
133
151
  else if (REMOVE.includes(tag) === true) {
134
- delete instance.metadata[tag];
152
+ //tag_meta = tag as keyof MetaData;
153
+ delete instance.metadata[tag_meta];
135
154
  }
136
155
  // Default sha256
137
156
  else {
138
- instance.metadata[tag] = anonymized_value;
157
+ tag_meta = tag as keyof MetaData;
158
+ if (instance.metadata[tag_meta] === "string") {
159
+ instance.metadata[tag_meta] = anonymized_value as any;
160
+ }
161
+ //TODO-ts: check if this case has to be applied only on strings
162
+ //or also on numbers and if any type could be correct to force solution
163
+ //or find another solution
139
164
  }
140
165
  }
141
166
  });
167
+
142
168
  instance.metadata["x00120062"] = "YES"; // Patient Identity Removed Attribute
143
169
  instance.metadata.seriesUID = instance.metadata["x0020000e"];
144
170
  instance.metadata.instanceUID = instance.metadata["x00080018"];
145
171
  instance.metadata.studyUID = instance.metadata["x0020000d"];
146
172
  instance.metadata.accessionNumber = instance.metadata["x00080050"];
147
173
  instance.metadata.studyDescription = instance.metadata["x00081030"];
148
- instance.metadata.patientName = instance.metadata["x00100010"];
174
+ instance.metadata.patientName = instance.metadata["x00100010"] as string;
149
175
  instance.metadata.patientBirthdate = instance.metadata["x00100030"];
150
- instance.metadata.seriesDescription = instance.metadata["x0008103e"];
176
+ instance.metadata.seriesDescription = instance.metadata[
177
+ "x0008103e"
178
+ ] as string;
151
179
  instance.metadata.anonymized = true;
152
180
  });
153
181
 
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import cornerstone from "cornerstone-core";
7
+ import { EnabledElementLayer } from "cornerstone-core";
7
8
  import { each } from "lodash";
8
9
 
9
10
  /*
@@ -33,8 +34,12 @@ export function getColormapsList() {
33
34
  * @param {String} colormapName - the new colormap name
34
35
  * @param {Array} colors - array containing 255 rgb colors (ie [[r,g,b], [r,g,b], ...])
35
36
  */
36
- export function addColorMap(colormapId, colormapName, colors) {
37
- const colormap = cornerstone.colors.getColormap(colormapId);
37
+ export function addColorMap(
38
+ colormapId: string,
39
+ colormapName: string,
40
+ colors: Array<Array<number>>
41
+ ) {
42
+ const colormap = cornerstone.colors.getColormap(colormapId, null);
38
43
  colormap.setColorSchemeName(colormapName);
39
44
  let noc = colors.length;
40
45
  colormap.setNumberOfColors(noc);
@@ -54,31 +59,35 @@ export function addColorMap(colormapId, colormapName, colors) {
54
59
  * @param {HTMLCanvasElement} canvas - target canvas
55
60
  * @param {String} colormapId - the colormap name
56
61
  */
57
- export function fillPixelData(canvas, colormapId) {
62
+ export function fillPixelData(canvas: HTMLCanvasElement, colormapId: string) {
58
63
  const ctx = canvas.getContext("2d");
59
64
  const height = canvas.height;
60
65
  const width = canvas.width;
61
- const colorbar = ctx.createImageData(width, height);
62
-
63
- const colormap = cornerstone.colors.getColormap(colormapId);
64
- const lookupTable = colormap.createLookupTable();
65
- // Set the min and max values then the lookup table
66
- // will be able to return the right color for this range
67
- lookupTable.setTableRange(0, width);
68
-
69
- // Update the colorbar pixel by pixel
70
- for (let col = 0; col < width; col++) {
71
- const color = lookupTable.mapValue(col);
72
-
73
- for (let row = 0; row < height; row++) {
74
- const pixel = (col + row * width) * 4;
75
- colorbar.data[pixel] = color[0];
76
- colorbar.data[pixel + 1] = color[1];
77
- colorbar.data[pixel + 2] = color[2];
78
- colorbar.data[pixel + 3] = color[3];
66
+ if (ctx) {
67
+ const colorbar = ctx.createImageData(width, height);
68
+ const colormap = cornerstone.colors.getColormap(colormapId, {});
69
+ const lookupTable = colormap.createLookupTable();
70
+
71
+ // Set the min and max values then the lookup table
72
+ // will be able to return the right color for this range
73
+ lookupTable.setTableRange(0, width);
74
+
75
+ // Update the colorbar pixel by pixel
76
+ for (let col = 0; col < width; col++) {
77
+ const color = lookupTable.mapValue(col);
78
+
79
+ for (let row = 0; row < height; row++) {
80
+ const pixel = (col + row * width) * 4;
81
+ colorbar.data[pixel] = color[0];
82
+ colorbar.data[pixel + 1] = color[1];
83
+ colorbar.data[pixel + 2] = color[2];
84
+ colorbar.data[pixel + 3] = color[3];
85
+ }
79
86
  }
87
+ ctx.putImageData(colorbar, 0, 0);
88
+ } else {
89
+ console.error("No context found for canvas", canvas);
80
90
  }
81
- ctx.putImageData(colorbar, 0, 0);
82
91
  }
83
92
 
84
93
  /**
@@ -88,21 +97,30 @@ export function fillPixelData(canvas, colormapId) {
88
97
  * @param {String} colormapId - the colormap name
89
98
  * @param {Array} viewportNames - List of viewports where to apply preset
90
99
  */
91
- export function applyColorMap(colormapId, viewportNames) {
100
+ export function applyColorMap(
101
+ colormapId: string,
102
+ viewportNames?: Array<string>
103
+ ) {
92
104
  // for retro-compatibility
93
105
  if (!viewportNames) {
94
106
  viewportNames = cornerstone.getEnabledElements().map(e => e.element.id);
95
107
  }
96
- let colormap = cornerstone.colors.getColormap(colormapId);
108
+ let colormap = cornerstone.colors.getColormap(colormapId, {});
97
109
 
98
110
  each(viewportNames, viewportName => {
99
111
  let element = document.getElementById(viewportName);
100
- let enabledElement;
112
+
113
+ if (!element) {
114
+ console.error("No element with id:", viewportName);
115
+ return;
116
+ }
117
+
118
+ let enabledElement: EnabledElementLayer;
101
119
 
102
120
  try {
103
121
  enabledElement = cornerstone.getEnabledElement(element);
104
122
  } catch {
105
- console.warn("No enabledElement with id", viewportName);
123
+ console.error("No enabledElement with id", viewportName);
106
124
  return;
107
125
  }
108
126
 
@@ -125,11 +143,11 @@ export function applyColorMap(colormapId, viewportNames) {
125
143
  /**
126
144
  * Converts an HSV (Hue, Saturation, Value) color to RGB (Red, Green, Blue) color value
127
145
  * @param {Number} hue A number representing the hue color value
128
- * @param {any} sat A number representing the saturation color value
129
- * @param {any} val A number representing the value color value
130
- * @returns {Numberp[]} An RGB color array
146
+ * @param {Number} sat A number representing the saturation color value
147
+ * @param {Number} val A number representing the value color value
148
+ * @returns {Number[]} An RGB color array
131
149
  */
132
- export function HSVToRGB(hue, sat, val) {
150
+ export function HSVToRGB(hue: number, sat: number, val: number) {
133
151
  if (hue > 1) {
134
152
  throw new Error("HSVToRGB expects hue < 1");
135
153
  }
@@ -5,6 +5,8 @@
5
5
 
6
6
  // external libraries
7
7
  import { each, range } from "lodash";
8
+ import { vec2 } from "cornerstone-core";
9
+ import { Contours } from "./types";
8
10
 
9
11
  /*
10
12
  * This module provides the following functions to be exported:
@@ -22,15 +24,15 @@ import { each, range } from "lodash";
22
24
  * @returns {Number} Number of array elements consumed
23
25
  */
24
26
  export const parseContours = function (
25
- contoursData,
26
- pointBatchSize,
27
- segmentationName,
28
- viewports
27
+ contoursData: { [key: string]: Uint8Array }, // TODO-ts: check if this is correct @mronzoni
28
+ pointBatchSize: number,
29
+ segmentationName: string,
30
+ viewports: Array<string>
29
31
  ) {
30
- let contours = {};
32
+ let contours: Contours = {};
31
33
  each(viewports, viewport => {
32
- contour[viewport] = {};
33
- contour[viewport][segmentationName] = [];
34
+ contours[viewport] = {};
35
+ contours[viewport][segmentationName] = [];
34
36
  let points = contoursData[viewport];
35
37
 
36
38
  if (!points) {
@@ -70,15 +72,15 @@ export const parseContours = function (
70
72
  * @param {Array} data - Raw data (array of pixel values)
71
73
  */
72
74
  const populateContoursObject = function (
73
- pointBatchSize,
74
- contours,
75
- lineNumber,
76
- sliceNumber,
77
- segmentationName,
78
- viewport,
79
- data
75
+ pointBatchSize: number,
76
+ contours: Contours,
77
+ lineNumber: number,
78
+ sliceNumber: number,
79
+ segmentationName: string,
80
+ viewport: string,
81
+ data: Uint8Array
80
82
  ) {
81
- let coords = [];
83
+ let coords: Array<{ x: number; y: number; lines: Array<vec2> }> = [];
82
84
 
83
85
  for (let i = 0; i < data.length; i += pointBatchSize) {
84
86
  let xy = data.slice(i, pointBatchSize + i);
@@ -134,11 +136,11 @@ const populateContoursObject = function (
134
136
  * @returns {Number} Number of array elements consumed
135
137
  */
136
138
  const extractSlicePoints = function (
137
- contours,
138
- pointBatchSize,
139
- slicePoints,
140
- segmentationName,
141
- viewport
139
+ contours: Contours,
140
+ pointBatchSize: number,
141
+ slicePoints: Uint8Array, // TODO-ts: check if this is correct @mronzoni
142
+ segmentationName: string,
143
+ viewport: string
142
144
  ) {
143
145
  // read slice number and number of lines for current slice, then remove from array
144
146
  let sliceNumber = slicePoints[0];
@@ -152,12 +154,12 @@ const extractSlicePoints = function (
152
154
 
153
155
  let numberOfPoints = 0;
154
156
  contours[viewport][segmentationName][sliceNumber] = {
155
- lines: []
157
+ lines: [] as vec2[][]
156
158
  };
157
159
 
158
160
  if (numberOfLines) {
159
161
  // for each line
160
- each(range(numberOfLines), function (l) {
162
+ each(range(numberOfLines), function (l: number) {
161
163
  // get number of points for current line
162
164
  let numberOfPointsPerLine = slicePoints[0];
163
165
  // compute coordinates size
@@ -11,10 +11,11 @@ import {
11
11
  getMeanValue,
12
12
  getDistanceBetweenSlices,
13
13
  getTypedArrayFromDataType
14
- } from "./imageUtils.js";
15
- import { larvitar_store } from "./imageStore";
14
+ } from "./imageUtils";
15
+ import store from "./imageStore";
16
16
  import { parse } from "./parsers/nrrd";
17
17
  import { checkMemoryAllocation } from "./monitors/memory";
18
+ import { Series, Header, Volume, TypedArray } from "./types";
18
19
 
19
20
  /*
20
21
  * This module provides the following functions to be exported:
@@ -30,41 +31,50 @@ import { checkMemoryAllocation } from "./monitors/memory";
30
31
  * @param {Object} series - Cornerstone series object
31
32
  * @returns {Object} header: image metadata
32
33
  */
33
- export const buildHeader = function (series) {
34
- let header = {};
35
- header.volume = {};
36
- header.volume.imageIds = series.imageIds;
37
- header.volume.seriesId =
38
- series.instances[series.imageIds[0]].metadata.seriesUID;
39
- header.volume.rows =
34
+ export const buildHeader = function (series: Series) {
35
+ let header: Partial<Header> = {};
36
+
37
+ forEach(series.imageIds, function (imageId: string) {
38
+ header[imageId] = series.instances[imageId].metadata;
39
+ });
40
+
41
+ let volume: Partial<Volume> = {};
42
+
43
+ volume.imageIds = series.imageIds;
44
+ volume.seriesId = series.instances[series.imageIds[0]].metadata.seriesUID;
45
+ volume.rows =
40
46
  series.instances[series.imageIds[0]].metadata.rows ||
41
47
  series.instances[series.imageIds[0]].metadata.x00280010;
42
- header.volume.cols =
48
+ volume.cols =
43
49
  series.instances[series.imageIds[0]].metadata.cols ||
44
50
  series.instances[series.imageIds[0]].metadata.x00280011;
45
- header.volume.slope = series.instances[series.imageIds[0]].metadata.slope;
46
- header.volume.repr = series.instances[series.imageIds[0]].metadata.repr;
47
- header.volume.intercept =
48
- series.instances[series.imageIds[0]].metadata.intercept;
49
- header.volume.imagePosition =
50
- series.instances[series.imageIds[0]].metadata.imagePosition;
51
- header.volume.numberOfSlices = series.imageIds.length;
52
-
53
- header.volume.imageOrientation = getMeanValue(
51
+ volume.slope = series.instances[series.imageIds[0]].metadata.slope as number;
52
+ volume.repr = series.instances[series.imageIds[0]].metadata.repr as string;
53
+ volume.intercept = series.instances[series.imageIds[0]].metadata
54
+ .intercept as number;
55
+ volume.imagePosition = series.instances[series.imageIds[0]].metadata
56
+ .imagePosition as [number, number];
57
+ volume.numberOfSlices = series.imageIds.length;
58
+
59
+ // @ts-ignore
60
+ volume.imageOrientation = getMeanValue(
54
61
  series,
55
62
  "imageOrientation",
56
63
  true
57
- );
64
+ ) as number[];
58
65
 
59
- header.volume.pixelSpacing = getMeanValue(series, "pixelSpacing", true);
60
- // header.volume.maxPixelValue = getMeanValue(series, "maxPixelValue", false);
61
- // header.volume.minPixelValue = getMeanValue(series, "minPixelValue", false);
62
- header.volume.sliceThickness = getDistanceBetweenSlices(series, 0, 1);
66
+ // @ts-ignore
67
+ volume.pixelSpacing = getMeanValue(series, "pixelSpacing", true) as [
68
+ number,
69
+ number
70
+ ];
71
+ // volume.maxPixelValue = getMeanValue(series, "maxPixelValue", false);
72
+ // volume.minPixelValue = getMeanValue(series, "minPixelValue", false);
73
+ volume.sliceThickness = getDistanceBetweenSlices(series, 0, 1);
63
74
 
64
- forEach(series.imageIds, function (imageId) {
65
- header[imageId] = series.instances[imageId].metadata;
66
- });
67
- return header;
75
+ header.volume = volume as Volume;
76
+
77
+ return header as Header;
68
78
  };
69
79
 
70
80
  /**
@@ -74,12 +84,12 @@ export const buildHeader = function (series) {
74
84
  * @returns {Promise} A promise which will resolve to a pixel data array or fail if an error occurs
75
85
  */
76
86
 
77
- export const getCachedPixelData = function (imageId) {
87
+ export const getCachedPixelData = function (imageId: string) {
78
88
  let cachedImage = find(cornerstone.imageCache.cachedImages, [
79
89
  "imageId",
80
90
  imageId
81
91
  ]);
82
- let promise = new Promise((resolve, reject) => {
92
+ let promise = new Promise<number[]>((resolve, reject) => {
83
93
  if (cachedImage && cachedImage.image) {
84
94
  resolve(cachedImage.image.getPixelData());
85
95
  } else {
@@ -99,37 +109,48 @@ export const getCachedPixelData = function (imageId) {
99
109
  * @param {Bool} useSeriesData - Flag to force using "series" data instead of cached ones
100
110
  * @returns {Array} Contiguous pixel array
101
111
  */
102
- export const buildData = function (series, useSeriesData) {
112
+ export const buildData = function (series: Series, useSeriesData: boolean) {
103
113
  if (checkMemoryAllocation(series.bytes)) {
104
114
  let t0 = performance.now();
105
115
  let repr = series.instances[series.imageIds[0]].metadata.repr;
106
116
  let rows =
107
- series.instances[series.imageIds[0]].metadata.rows ||
108
- series.instances[series.imageIds[0]].metadata.x00280010;
117
+ (series.instances[series.imageIds[0]].metadata.rows as number) ||
118
+ (series.instances[series.imageIds[0]].metadata.x00280010 as number);
109
119
  let cols =
110
- series.instances[series.imageIds[0]].metadata.cols ||
111
- series.instances[series.imageIds[0]].metadata.x00280011;
120
+ (series.instances[series.imageIds[0]].metadata.cols as number) ||
121
+ (series.instances[series.imageIds[0]].metadata.x00280011 as number);
112
122
  let len = rows * cols * series.imageIds.length;
113
123
 
114
- let typedArray = getTypedArrayFromDataType(repr);
124
+ if (!repr) {
125
+ throw new Error("Image representation metadata not found");
126
+ }
127
+
128
+ let typedArray = getTypedArrayFromDataType(repr as string);
129
+
130
+ if (!typedArray) {
131
+ throw new Error("Image representation not supported");
132
+ }
133
+
115
134
  let data = new typedArray(len);
116
135
  let offsetData = 0;
117
136
 
118
137
  // use input data or cached data
119
138
  if (useSeriesData) {
120
- forEach(series.imageIds, function (imageId) {
139
+ forEach(series.imageIds, function (imageId: string) {
121
140
  const sliceData = series.instances[imageId].pixelData;
122
- data.set(sliceData, offsetData);
123
- offsetData += sliceData.length;
141
+ if (sliceData) {
142
+ data.set(sliceData, offsetData);
143
+ offsetData += sliceData.length;
144
+ }
124
145
  });
125
146
  let t1 = performance.now();
126
147
  console.log(`Call to buildData took ${t1 - t0} milliseconds.`);
127
148
  return data;
128
149
  } else {
129
- larvitar_store.addSeriesIds(series.seriesUID, series.imageIds);
150
+ store.addSeriesId(series.seriesUID, series.imageIds);
130
151
  let image_counter = 0;
131
- forEach(series.imageIds, function (imageId) {
132
- getCachedPixelData(imageId).then(sliceData => {
152
+ forEach(series.imageIds, function (imageId: string) {
153
+ getCachedPixelData(imageId).then((sliceData: number[]) => {
133
154
  data.set(sliceData, offsetData);
134
155
  offsetData += sliceData.length;
135
156
  image_counter += 1;
@@ -154,26 +175,42 @@ export const buildData = function (series, useSeriesData) {
154
175
  * @param {Function} resolve - Promise resolve function
155
176
  * @param {Function} reject - Promise reject function
156
177
  */
157
- export const buildDataAsync = function (series, time, resolve, reject) {
178
+ export const buildDataAsync = function (
179
+ series: Series,
180
+ time: number,
181
+ resolve: (response: TypedArray) => void,
182
+ reject: (response: string) => void
183
+ ) {
158
184
  const memoryAllocation = checkMemoryAllocation(series.bytes);
185
+
159
186
  if (memoryAllocation) {
160
187
  let t0 = performance.now();
161
188
  let repr = series.instances[series.imageIds[0]].metadata.repr;
162
189
  let rows =
163
- series.instances[series.imageIds[0]].metadata.rows ||
164
- series.instances[series.imageIds[0]].metadata.x00280010;
190
+ (series.instances[series.imageIds[0]].metadata.rows as number) ||
191
+ (series.instances[series.imageIds[0]].metadata.x00280010 as number);
165
192
  let cols =
166
- series.instances[series.imageIds[0]].metadata.cols ||
167
- series.instances[series.imageIds[0]].metadata.x00280011;
193
+ (series.instances[series.imageIds[0]].metadata.cols as number) ||
194
+ (series.instances[series.imageIds[0]].metadata.x00280011 as number);
168
195
  let len = rows * cols * series.imageIds.length;
169
- let typedArray = getTypedArrayFromDataType(repr);
196
+
197
+ if (!repr) {
198
+ throw new Error("Image representation metadata not found");
199
+ }
200
+
201
+ let typedArray = getTypedArrayFromDataType(repr as string);
202
+
203
+ if (!typedArray) {
204
+ throw new Error("Image representation not supported");
205
+ }
206
+
170
207
  let data = new typedArray(len);
171
208
  let offsetData = 0;
172
209
 
173
210
  let imageIds = series.imageIds.slice();
174
- larvitar_store.addSeriesIds(series.seriesUID, series.imageIds);
211
+ store.addSeriesId(series.seriesUID, series.imageIds);
175
212
 
176
- function runFillPixelData(data) {
213
+ function runFillPixelData(data: TypedArray) {
177
214
  let imageId = imageIds.shift();
178
215
  if (imageId) {
179
216
  getCachedPixelData(imageId).then(sliceData => {
@@ -207,8 +244,8 @@ export const buildDataAsync = function (series, time, resolve, reject) {
207
244
  * @param {ArrayBuffer} bufferArray - buffer array from nrrd file
208
245
  * @returns {Array} Parsed pixel data array
209
246
  */
210
- export const importNRRDImage = function (bufferArray) {
247
+ export const importNRRDImage = function (bufferArray: ArrayBuffer) {
211
248
  // get the data
212
- let volume = parse(bufferArray, {});
249
+ let volume = parse(bufferArray, { headerOnly: false });
213
250
  return volume;
214
251
  };
@@ -8,6 +8,7 @@ import cornerstone from "cornerstone-core";
8
8
 
9
9
  // internal libraries
10
10
  import { isElement } from "./imageUtils";
11
+ import { Series } from "./types";
11
12
 
12
13
  /*
13
14
  * This module provides the following functions to be exported:
@@ -25,17 +26,20 @@ import { isElement } from "./imageUtils";
25
26
  * @param {Object} options - layer options {opacity:float, colormap: str}
26
27
  * @returns {Object} Cornerstone layer object
27
28
  */
28
- export const buildLayer = function (series, tag, options) {
29
- let layerOptions = options ? options : {};
29
+ export const buildLayer = function (
30
+ series: Series,
31
+ tag: string,
32
+ options: { opacity: number; colormap: string }
33
+ ) {
30
34
  let layer = {
31
35
  imageIds: series.imageIds,
32
36
  currentImageIdIndex: Math.floor(series.imageIds.length / 2),
33
37
  options: {
34
38
  name: tag,
35
- opacity: layerOptions.opacity ? layerOptions.opacity : 1.0,
39
+ opacity: options?.opacity ? options?.opacity : 1.0,
36
40
  visible: true,
37
41
  viewport: {
38
- colormap: layerOptions.colormap ? layerOptions.colormap : "gray"
42
+ colormap: options?.colormap ? options?.colormap : "gray"
39
43
  }
40
44
  }
41
45
  };
@@ -47,18 +51,28 @@ export const buildLayer = function (series, tag, options) {
47
51
  * @instance
48
52
  * @function updateLayer
49
53
  * @param {String} elementId - The html div id used for rendering or its DOM HTMLElement
50
- * @param {Object} layer - The cornestone object layer
54
+ * @param {string} layer - The layer id
51
55
  * @param {Object} options - The new layer's options
52
56
  */
53
- export const updateLayer = function (elementId, layerId, options) {
57
+ export const updateLayer = function (
58
+ elementId: string | HTMLElement,
59
+ layerId: string,
60
+ options: { opacity: number; colormap: string }
61
+ ) {
54
62
  let element = isElement(elementId)
55
- ? elementId
56
- : document.getElementById(elementId);
63
+ ? (elementId as HTMLElement)
64
+ : document.getElementById(elementId as string);
57
65
  if (!element) {
58
66
  console.log("not element");
59
67
  return;
60
68
  }
61
69
  let layer = cornerstone.getLayer(element, layerId);
70
+ if (!layer.options) {
71
+ layer["options"] = {};
72
+ }
73
+ if (!layer.viewport) {
74
+ layer["viewport"] = {};
75
+ }
62
76
  layer.options.opacity =
63
77
  options.opacity != null ? options.opacity : layer.options.opacity;
64
78
  layer.viewport.colormap = options.colormap
@@ -74,10 +88,10 @@ export const updateLayer = function (elementId, layerId, options) {
74
88
  * @param {String} elementId - The html div id used for rendering or its DOM HTMLElement
75
89
  * @returns {Object} layer - The active layer object
76
90
  */
77
- export const getActiveLayer = function (elementId) {
91
+ export const getActiveLayer = function (elementId: string | HTMLElement) {
78
92
  let element = isElement(elementId)
79
- ? elementId
80
- : document.getElementById(elementId);
93
+ ? (elementId as HTMLElement)
94
+ : document.getElementById(elementId as string);
81
95
  if (!element) {
82
96
  console.log("not element");
83
97
  return;
@@ -92,10 +106,13 @@ export const getActiveLayer = function (elementId) {
92
106
  * @param {String} elementId - The html div id used for rendering or its DOM HTMLElement
93
107
  * @param {String} layerId - The id of the layer
94
108
  */
95
- export const setActiveLayer = function (elementId, layerId) {
109
+ export const setActiveLayer = function (
110
+ elementId: string | HTMLElement,
111
+ layerId: string
112
+ ) {
96
113
  let element = isElement(elementId)
97
- ? elementId
98
- : document.getElementById(elementId);
114
+ ? (elementId as HTMLElement)
115
+ : document.getElementById(elementId as string);
99
116
  if (!element) {
100
117
  console.log("not element");
101
118
  return;