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.
- package/.vscode/settings.json +4 -0
- package/README.md +78 -48
- package/bundler/webpack.common.js +27 -0
- package/bundler/webpack.dev.js +23 -0
- package/bundler/webpack.prod.js +19 -0
- package/decs.d.ts +12 -0
- package/dist/imaging/MetaDataReadable.d.ts +40 -0
- package/dist/imaging/MetaDataTypes.d.ts +3489 -0
- package/dist/imaging/imageAnonymization.d.ts +12 -0
- package/dist/imaging/imageColormaps.d.ts +47 -0
- package/dist/imaging/imageContours.d.ts +18 -0
- package/dist/imaging/imageIo.d.ts +42 -0
- package/dist/imaging/imageLayers.d.ts +56 -0
- package/dist/imaging/imageLoading.d.ts +65 -0
- package/dist/imaging/imageParsing.d.ts +46 -0
- package/dist/imaging/imagePresets.d.ts +43 -0
- package/dist/imaging/imageRendering.d.ts +238 -0
- package/dist/imaging/imageReslice.d.ts +14 -0
- package/dist/imaging/imageStore.d.ts +121 -0
- package/dist/imaging/imageTags.d.ts +22 -0
- package/dist/imaging/imageTools.d.ts +20 -0
- package/dist/imaging/imageUtils.d.ts +165 -0
- package/dist/imaging/loaders/commonLoader.d.ts +103 -0
- package/dist/imaging/loaders/dicomLoader.d.ts +29 -0
- package/dist/imaging/loaders/fileLoader.d.ts +33 -0
- package/dist/imaging/loaders/multiframeLoader.d.ts +37 -0
- package/dist/imaging/loaders/nrrdLoader.d.ts +113 -0
- package/dist/imaging/loaders/resliceLoader.d.ts +15 -0
- package/dist/imaging/monitors/memory.d.ts +41 -0
- package/dist/imaging/monitors/performance.d.ts +23 -0
- package/dist/imaging/parsers/ecg.d.ts +15 -0
- package/dist/imaging/parsers/nrrd.d.ts +3 -0
- package/dist/imaging/tools/custom/4dSliceScrollTool.d.ts +12 -0
- package/dist/imaging/tools/custom/BorderMagnifyTool.d.ts +18 -0
- package/dist/imaging/tools/custom/contourTool.d.ts +409 -0
- package/dist/imaging/tools/custom/diameterTool.d.ts +18 -0
- package/dist/imaging/tools/custom/editMaskTool.d.ts +22 -0
- package/dist/imaging/tools/custom/ellipticalRoiOverlayTool.d.ts +45 -0
- package/dist/imaging/tools/custom/polygonSegmentationMixin.d.ts +54 -0
- package/dist/imaging/tools/custom/polylineScissorsTool.d.ts +11 -0
- package/dist/imaging/tools/custom/rectangleRoiOverlayTool.d.ts +45 -0
- package/dist/imaging/tools/custom/seedTool.d.ts +0 -0
- package/dist/imaging/tools/custom/setLabelMap3D.d.ts +39 -0
- package/dist/imaging/tools/custom/thresholdsBrushTool.d.ts +19 -0
- package/dist/imaging/tools/default.d.ts +53 -0
- package/dist/imaging/tools/interaction.d.ts +30 -0
- package/dist/imaging/tools/io.d.ts +38 -0
- package/dist/imaging/tools/main.d.ts +81 -0
- package/dist/imaging/tools/segmentation.d.ts +125 -0
- package/dist/imaging/tools/state.d.ts +17 -0
- package/dist/imaging/tools/strategies/eraseFreehand.d.ts +16 -0
- package/dist/imaging/tools/strategies/fillFreehand.d.ts +16 -0
- package/dist/imaging/tools/strategies/index.d.ts +2 -0
- package/dist/imaging/waveforms/ecg.d.ts +39 -0
- package/dist/index.d.ts +35 -0
- package/dist/larvitar.js +90104 -0
- package/dist/larvitar.js.map +1 -0
- package/imaging/MetaDataReadable.ts +41 -0
- package/imaging/MetaDataTypes.ts +3491 -0
- package/imaging/dataDictionary.json +5328 -5328
- package/imaging/{imageAnonymization.js → imageAnonymization.ts} +41 -13
- package/imaging/{imageColormaps.js → imageColormaps.ts} +48 -30
- package/imaging/{imageContours.js → imageContours.ts} +24 -22
- package/imaging/{imageIo.js → imageIo.ts} +89 -52
- package/imaging/{imageLayers.js → imageLayers.ts} +31 -14
- package/imaging/{imageLoading.js → imageLoading.ts} +107 -43
- package/imaging/{imageParsing.js → imageParsing.ts} +160 -80
- package/imaging/{imagePresets.js → imagePresets.ts} +44 -11
- package/imaging/imageRendering.ts +1091 -0
- package/imaging/{imageReslice.js → imageReslice.ts} +18 -9
- package/imaging/imageStore.ts +487 -0
- package/imaging/imageTags.ts +609 -0
- package/imaging/imageTools.js +2 -1
- package/imaging/{imageUtils.js → imageUtils.ts} +211 -701
- package/imaging/loaders/{commonLoader.js → commonLoader.ts} +73 -24
- package/imaging/loaders/{dicomLoader.js → dicomLoader.ts} +25 -5
- package/imaging/loaders/{fileLoader.js → fileLoader.ts} +5 -5
- package/imaging/loaders/{multiframeLoader.js → multiframeLoader.ts} +145 -90
- package/imaging/loaders/{nrrdLoader.js → nrrdLoader.ts} +231 -64
- package/imaging/loaders/{resliceLoader.js → resliceLoader.ts} +51 -20
- package/imaging/monitors/{memory.js → memory.ts} +54 -8
- package/imaging/monitors/performance.ts +34 -0
- package/imaging/parsers/ecg.ts +54 -0
- package/imaging/tools/README.md +27 -0
- package/imaging/tools/custom/4dSliceScrollTool.js +47 -46
- package/imaging/tools/custom/BorderMagnifyTool.js +99 -0
- package/imaging/tools/custom/ellipticalRoiOverlayTool.js +534 -0
- package/imaging/tools/custom/polylineScissorsTool.js +1 -1
- package/imaging/tools/custom/rectangleRoiOverlayTool.js +564 -0
- package/imaging/tools/{setLabelMap3D.js → custom/setLabelMap3D.ts} +19 -25
- package/imaging/tools/{default.js → default.ts} +119 -33
- package/imaging/tools/{interaction.js → interaction.ts} +42 -23
- package/imaging/tools/{io.js → io.ts} +47 -31
- package/imaging/tools/{main.js → main.ts} +105 -40
- package/imaging/tools/{segmentation.js → segmentation.ts} +95 -68
- package/imaging/tools/{state.js → state.ts} +7 -12
- package/imaging/tools/types.d.ts +243 -0
- package/imaging/types.d.ts +200 -0
- package/imaging/waveforms/ecg.ts +191 -0
- package/{index.js → index.ts} +53 -14
- package/jsdoc.json +1 -1
- package/package.json +35 -14
- package/tsconfig.json +102 -0
- package/imaging/imageRendering.js +0 -860
- package/imaging/imageStore.js +0 -322
- package/modules/vuex/larvitar.js +0 -187
- /package/imaging/tools/{polygonSegmentationMixin.js → custom/polygonSegmentationMixin.js} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** @module loaders/multiframeLoader
|
|
2
|
-
* @desc This file is a custom
|
|
2
|
+
* @desc This file is a custom DICOM loader for multiframe images
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
// external libraries
|
|
@@ -13,13 +13,20 @@ import {
|
|
|
13
13
|
getLarvitarManager
|
|
14
14
|
} from "./commonLoader";
|
|
15
15
|
import { parseDataSet } from "../imageParsing";
|
|
16
|
+
import type {
|
|
17
|
+
Image,
|
|
18
|
+
ImageFrame,
|
|
19
|
+
LarvitarManager,
|
|
20
|
+
MetaData,
|
|
21
|
+
Series
|
|
22
|
+
} from "../types";
|
|
16
23
|
|
|
17
24
|
// global module variables
|
|
18
25
|
let customImageLoaderCounter = 0;
|
|
19
26
|
|
|
20
27
|
// Local cache used to store multiframe datasets to avoid reading and parsing
|
|
21
28
|
// the whole file to show a single frame.
|
|
22
|
-
let multiframeDatasetCache = null;
|
|
29
|
+
let multiframeDatasetCache: { [key: string]: Series | null } | null = null;
|
|
23
30
|
/*
|
|
24
31
|
* This module provides the following functions to be exported:
|
|
25
32
|
* loadMultiFrameImage(elementId)
|
|
@@ -35,25 +42,26 @@ let multiframeDatasetCache = null;
|
|
|
35
42
|
* @param {String} imageId - ImageId tag
|
|
36
43
|
* @returns {Function} Custom Image Creation Function
|
|
37
44
|
*/
|
|
38
|
-
export const loadMultiFrameImage = function (imageId) {
|
|
45
|
+
export const loadMultiFrameImage = function (imageId: string) {
|
|
39
46
|
let parsedImageId = cornerstoneDICOMImageLoader.wadouri.parseImageId(imageId);
|
|
40
47
|
let rootImageId = parsedImageId.scheme + ":" + parsedImageId.url;
|
|
41
48
|
let imageTracker = getLarvitarImageTracker();
|
|
42
49
|
let seriesId = imageTracker[rootImageId];
|
|
43
|
-
let manager = getLarvitarManager();
|
|
50
|
+
let manager = getLarvitarManager() as LarvitarManager;
|
|
44
51
|
if (multiframeDatasetCache === null) {
|
|
45
52
|
multiframeDatasetCache = {};
|
|
46
53
|
}
|
|
54
|
+
|
|
47
55
|
if (multiframeDatasetCache[rootImageId]) {
|
|
48
56
|
multiframeDatasetCache[rootImageId] = multiframeDatasetCache[rootImageId];
|
|
49
57
|
} else if (manager) {
|
|
50
|
-
multiframeDatasetCache[rootImageId] = manager[seriesId];
|
|
58
|
+
multiframeDatasetCache[rootImageId] = manager[seriesId] as Series;
|
|
51
59
|
} else {
|
|
52
60
|
throw new Error("No multiframe dataset found for seriesId: " + seriesId);
|
|
53
61
|
}
|
|
54
62
|
|
|
55
63
|
let metadata =
|
|
56
|
-
multiframeDatasetCache[rootImageId]
|
|
64
|
+
multiframeDatasetCache[rootImageId]?.instances[imageId].metadata;
|
|
57
65
|
return createCustomImage(rootImageId, imageId, parsedImageId.frame, metadata);
|
|
58
66
|
};
|
|
59
67
|
|
|
@@ -64,65 +72,66 @@ export const loadMultiFrameImage = function (imageId) {
|
|
|
64
72
|
* @param {String} seriesId - SeriesId tag
|
|
65
73
|
* @param {Object} serie - parsed serie object
|
|
66
74
|
*/
|
|
67
|
-
export const buildMultiFrameImage = function (seriesId, serie) {
|
|
75
|
+
export const buildMultiFrameImage = function (seriesId: string, serie: Series) {
|
|
68
76
|
let t0 = performance.now();
|
|
69
77
|
let manager = getLarvitarManager();
|
|
70
78
|
let imageTracker = getLarvitarImageTracker();
|
|
71
|
-
let numberOfFrames =
|
|
72
|
-
|
|
73
|
-
let
|
|
74
|
-
let
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
manager[seriesId] = serie;
|
|
87
|
-
manager[seriesId].imageIds = [];
|
|
88
|
-
manager[seriesId].instances = {};
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
each(range(numberOfFrames), function (frameNumber) {
|
|
92
|
-
let frameImageId = imageId + "?frame=" + frameNumber;
|
|
93
|
-
// EXTRACT MULTIFRAME METADATA (x52009230) Per-frame Functional Groups Sequence
|
|
94
|
-
let frameMetadata = { ...metadata };
|
|
79
|
+
let numberOfFrames = serie.metadata!.numberOfFrames!;
|
|
80
|
+
let frameTime = serie.metadata!.frameTime;
|
|
81
|
+
let frameDelay = serie.metadata!.frameDelay ? serie.metadata!.frameDelay : 0;
|
|
82
|
+
let rWaveTimeVector = serie.metadata!.rWaveTimeVector;
|
|
83
|
+
let sopInstanceUID = serie.metadata!["x00080018"] as string;
|
|
84
|
+
let dataSet = serie.dataSet;
|
|
85
|
+
let imageId = getMultiFrameImageId("multiFrameLoader");
|
|
86
|
+
imageTracker[imageId] = seriesId;
|
|
87
|
+
|
|
88
|
+
// check if manager exists for this seriesId
|
|
89
|
+
if (!manager[seriesId]) {
|
|
90
|
+
manager[seriesId] = serie;
|
|
91
|
+
manager[seriesId].imageIds = [];
|
|
92
|
+
manager[seriesId].instances = {};
|
|
93
|
+
}
|
|
95
94
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
95
|
+
each(range(numberOfFrames as number), function (frameNumber) {
|
|
96
|
+
let frameImageId = imageId + "?frame=" + frameNumber;
|
|
97
|
+
// EXTRACT MULTIFRAME METADATA (x52009230) Per-frame Functional Groups Sequence
|
|
98
|
+
let frameMetadata = { ...serie.metadata! };
|
|
100
99
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
manager[seriesId].modality = metadata["x00080060"];
|
|
105
|
-
manager[seriesId].color = cornerstoneDICOMImageLoader.isColorImage(
|
|
106
|
-
metadata["x00280004"]
|
|
107
|
-
);
|
|
108
|
-
manager[seriesId].isMultiframe = true;
|
|
109
|
-
manager[seriesId].currentImageIdIndex = 0;
|
|
110
|
-
manager[seriesId].numberOfFrames = numberOfFrames;
|
|
111
|
-
manager[seriesId].frameTime = frameTime;
|
|
112
|
-
manager[seriesId].frameDelay = frameDelay;
|
|
113
|
-
manager[seriesId].numberOfImages = undefined;
|
|
114
|
-
manager[seriesId].bytes = serie.bytes;
|
|
115
|
-
manager[seriesId].imageIds.push(frameImageId);
|
|
116
|
-
manager[seriesId].instances[frameImageId] = {
|
|
117
|
-
instanceId: instanceId,
|
|
118
|
-
frame: frameNumber,
|
|
119
|
-
metadata: frameMetadata
|
|
120
|
-
};
|
|
121
|
-
manager[seriesId].dataSet = dataSet;
|
|
122
|
-
manager[seriesId].seriesDescription =
|
|
123
|
-
serie.instances[serie.imageIds[0]].metadata.seriesDescription;
|
|
100
|
+
parseDataSet(dataSet!, frameMetadata, {
|
|
101
|
+
tags: ["x52009230"],
|
|
102
|
+
frameId: frameNumber
|
|
124
103
|
});
|
|
104
|
+
|
|
105
|
+
// TODO-ts REMOVE "AS" WHEN METADATA VALUES ARE TYPED
|
|
106
|
+
// store file references
|
|
107
|
+
const managerSeriesId = manager[seriesId] as Series;
|
|
108
|
+
managerSeriesId.seriesUID = seriesId;
|
|
109
|
+
managerSeriesId.studyUID = serie.metadata!["x0020000d"] as string;
|
|
110
|
+
managerSeriesId.modality = serie.metadata!["x00080060"] as string;
|
|
111
|
+
managerSeriesId.color = cornerstoneDICOMImageLoader.isColorImage(
|
|
112
|
+
serie.metadata!["x00280004"]
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
managerSeriesId.isMultiframe = true;
|
|
116
|
+
managerSeriesId.currentImageIdIndex = 0;
|
|
117
|
+
managerSeriesId.numberOfFrames = numberOfFrames;
|
|
118
|
+
managerSeriesId.frameTime = frameTime;
|
|
119
|
+
managerSeriesId.frameDelay = frameDelay;
|
|
120
|
+
managerSeriesId.rWaveTimeVector = rWaveTimeVector;
|
|
121
|
+
managerSeriesId.numberOfImages = undefined;
|
|
122
|
+
managerSeriesId.bytes = serie.bytes;
|
|
123
|
+
managerSeriesId.imageIds.push(frameImageId);
|
|
124
|
+
managerSeriesId.instanceUIDs[sopInstanceUID] = imageId;
|
|
125
|
+
managerSeriesId.instances[frameImageId] = {
|
|
126
|
+
instanceId: sopInstanceUID,
|
|
127
|
+
frame: frameNumber,
|
|
128
|
+
metadata: frameMetadata
|
|
129
|
+
};
|
|
130
|
+
managerSeriesId.dataSet = dataSet || null;
|
|
131
|
+
managerSeriesId.seriesDescription = serie.metadata!
|
|
132
|
+
.seriesDescription as string;
|
|
125
133
|
});
|
|
134
|
+
|
|
126
135
|
let t1 = performance.now();
|
|
127
136
|
console.log(`Call to buildMultiFrameImage took ${t1 - t0} milliseconds.`);
|
|
128
137
|
};
|
|
@@ -134,7 +143,7 @@ export const buildMultiFrameImage = function (seriesId, serie) {
|
|
|
134
143
|
* @param {String} customLoaderName The custom loader name
|
|
135
144
|
* @return {String} the custom image id
|
|
136
145
|
*/
|
|
137
|
-
export const getMultiFrameImageId = function (customLoaderName) {
|
|
146
|
+
export const getMultiFrameImageId = function (customLoaderName: string) {
|
|
138
147
|
let imageId = customLoaderName + "://" + customImageLoaderCounter;
|
|
139
148
|
customImageLoaderCounter++;
|
|
140
149
|
return imageId;
|
|
@@ -146,20 +155,26 @@ export const getMultiFrameImageId = function (customLoaderName) {
|
|
|
146
155
|
* @function clearMultiFrameCache
|
|
147
156
|
* @param {String} seriesId - SeriesId tag
|
|
148
157
|
*/
|
|
149
|
-
export const clearMultiFrameCache = function (seriesId) {
|
|
158
|
+
export const clearMultiFrameCache = function (seriesId: string) {
|
|
150
159
|
each(multiframeDatasetCache, function (image, imageId) {
|
|
160
|
+
if (!image) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
151
163
|
if (seriesId == image.seriesUID || !seriesId) {
|
|
152
164
|
if (image.dataSet) {
|
|
165
|
+
// @ts-ignore: modify external type ?
|
|
153
166
|
image.dataSet.byteArray = null;
|
|
154
167
|
}
|
|
155
168
|
image.dataSet = null;
|
|
156
169
|
image.elements = null;
|
|
157
170
|
each(image.instances, function (instance) {
|
|
171
|
+
// @ts-ignore: is needed to clear the cache ?
|
|
158
172
|
instance.metadata = null;
|
|
159
173
|
});
|
|
174
|
+
// @ts-ignore: is needed to clear the cache ?
|
|
160
175
|
image.instances = null;
|
|
161
|
-
multiframeDatasetCache[imageId] = null;
|
|
162
|
-
delete multiframeDatasetCache[imageId];
|
|
176
|
+
multiframeDatasetCache![imageId] = null;
|
|
177
|
+
delete multiframeDatasetCache![imageId];
|
|
163
178
|
}
|
|
164
179
|
});
|
|
165
180
|
if (!seriesId) {
|
|
@@ -179,8 +194,13 @@ export const clearMultiFrameCache = function (seriesId) {
|
|
|
179
194
|
* @param {Object} dataSet dataset object
|
|
180
195
|
* @returns {Object} custom image object
|
|
181
196
|
*/
|
|
182
|
-
let createCustomImage = function (
|
|
183
|
-
|
|
197
|
+
let createCustomImage = function (
|
|
198
|
+
id: string,
|
|
199
|
+
imageId: string,
|
|
200
|
+
frameIndex: number,
|
|
201
|
+
metadata?: MetaData
|
|
202
|
+
) {
|
|
203
|
+
let options: { [key: string]: any } = {}; //TODO-ts change any to proper type when available
|
|
184
204
|
// always preScale the pixel array unless it is asked not to
|
|
185
205
|
options.preScale = {
|
|
186
206
|
enabled:
|
|
@@ -189,10 +209,20 @@ let createCustomImage = function (id, imageId, frameIndex, metadata) {
|
|
|
189
209
|
: false
|
|
190
210
|
};
|
|
191
211
|
|
|
192
|
-
|
|
212
|
+
if (multiframeDatasetCache === null || !multiframeDatasetCache[id]) {
|
|
213
|
+
throw new Error("No multiframe dataset found for id: " + id);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
let dataSet = (multiframeDatasetCache as { [key: string]: Series })[id]
|
|
217
|
+
.dataSet;
|
|
218
|
+
|
|
219
|
+
if (!dataSet) {
|
|
220
|
+
throw new Error("No dataset found for id: " + id);
|
|
221
|
+
}
|
|
222
|
+
|
|
193
223
|
let pixelDataElement = dataSet.elements.x7fe00010;
|
|
194
224
|
// Extract pixelData of the required frame
|
|
195
|
-
let pixelData;
|
|
225
|
+
let pixelData: number[];
|
|
196
226
|
try {
|
|
197
227
|
if (pixelDataElement.encapsulatedPixelData) {
|
|
198
228
|
pixelData = cornerstoneDICOMImageLoader.wadouri.getEncapsulatedImageFrame(
|
|
@@ -206,14 +236,17 @@ let createCustomImage = function (id, imageId, frameIndex, metadata) {
|
|
|
206
236
|
);
|
|
207
237
|
}
|
|
208
238
|
} catch (error) {
|
|
209
|
-
|
|
239
|
+
throw new Error("No pixel data for id: " + id);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (!metadata) {
|
|
243
|
+
throw new Error("No metadata for id: " + id);
|
|
210
244
|
}
|
|
211
245
|
|
|
212
246
|
let imageFrame = getImageFrame(metadata, dataSet);
|
|
213
247
|
let transferSyntax = dataSet.string("x00020010");
|
|
214
248
|
|
|
215
249
|
let canvas = window.document.createElement("canvas");
|
|
216
|
-
|
|
217
250
|
// Get the scaling parameters from the metadata
|
|
218
251
|
if (options.preScale.enabled) {
|
|
219
252
|
const scalingParameters = cornerstoneDICOMImageLoader.getScalingParameters(
|
|
@@ -237,8 +270,8 @@ let createCustomImage = function (id, imageId, frameIndex, metadata) {
|
|
|
237
270
|
options
|
|
238
271
|
);
|
|
239
272
|
|
|
240
|
-
let promise = new Promise((resolve, reject) => {
|
|
241
|
-
decodePromise.then(function handleDecodeResponse(imageFrame) {
|
|
273
|
+
let promise: Promise<Image> = new Promise((resolve, reject) => {
|
|
274
|
+
decodePromise.then(function handleDecodeResponse(imageFrame: ImageFrame) {
|
|
242
275
|
// This function uses the pixelData received as argument without manipulating
|
|
243
276
|
// them: if the image is compressed, the decompress function should be called
|
|
244
277
|
// before creating the custom image object (like the multiframe case).
|
|
@@ -260,35 +293,43 @@ let createCustomImage = function (id, imageId, frameIndex, metadata) {
|
|
|
260
293
|
);
|
|
261
294
|
}
|
|
262
295
|
|
|
263
|
-
let image = {
|
|
296
|
+
let image: Partial<Image> = {
|
|
264
297
|
imageId: imageId,
|
|
265
298
|
color: cornerstoneDICOMImageLoader.isColorImage(
|
|
266
299
|
imageFrame.photometricInterpretation
|
|
267
300
|
),
|
|
268
|
-
columnPixelSpacing: pixelSpacing
|
|
301
|
+
columnPixelSpacing: (pixelSpacing as number[])[1]
|
|
302
|
+
? (pixelSpacing as number[])[1]
|
|
303
|
+
: (pixelSpacing as number), // check for specific spacing value
|
|
269
304
|
columns: imageFrame.columns,
|
|
270
|
-
data: dataSet,
|
|
305
|
+
data: dataSet ? dataSet : undefined,
|
|
271
306
|
height: imageFrame.rows,
|
|
272
307
|
floatPixelData: undefined,
|
|
273
|
-
intercept: rescaleIntercept
|
|
308
|
+
intercept: (rescaleIntercept as number)
|
|
309
|
+
? (rescaleIntercept as number)
|
|
310
|
+
: 0,
|
|
274
311
|
invert: imageFrame.photometricInterpretation === "MONOCHROME1",
|
|
275
312
|
minPixelValue: imageFrame.smallestPixelValue,
|
|
276
313
|
maxPixelValue: imageFrame.largestPixelValue,
|
|
277
314
|
render: undefined, // set below
|
|
278
|
-
rowPixelSpacing: pixelSpacing
|
|
315
|
+
rowPixelSpacing: (pixelSpacing as number[])[0]
|
|
316
|
+
? (pixelSpacing as number[])[0]
|
|
317
|
+
: (pixelSpacing as number), // check for specific spacing value
|
|
279
318
|
rows: imageFrame.rows,
|
|
280
319
|
sizeInBytes: getSizeInBytes(),
|
|
281
|
-
slope: rescaleSlope ? rescaleSlope : 1,
|
|
320
|
+
slope: (rescaleSlope as number) ? (rescaleSlope as number) : 1,
|
|
282
321
|
width: imageFrame.columns,
|
|
283
|
-
windowCenter: windowCenter,
|
|
284
|
-
windowWidth: windowWidth,
|
|
322
|
+
windowCenter: windowCenter as number,
|
|
323
|
+
windowWidth: windowWidth as number,
|
|
285
324
|
decodeTimeInMS: undefined, // TODO
|
|
286
|
-
loadTimeInMS: undefined
|
|
287
|
-
render: undefined
|
|
325
|
+
loadTimeInMS: undefined // TODO
|
|
288
326
|
};
|
|
289
327
|
// add function to return pixel data
|
|
290
328
|
image.getPixelData = function () {
|
|
291
|
-
|
|
329
|
+
if (imageFrame.pixelData === undefined) {
|
|
330
|
+
throw new Error("No pixel data for image " + imageId);
|
|
331
|
+
}
|
|
332
|
+
return Array.from(imageFrame.pixelData);
|
|
292
333
|
};
|
|
293
334
|
|
|
294
335
|
// convert color space if not isJPEGBaseline8BitColor
|
|
@@ -305,6 +346,10 @@ let createCustomImage = function (id, imageId, frameIndex, metadata) {
|
|
|
305
346
|
|
|
306
347
|
let context = canvas.getContext("2d");
|
|
307
348
|
|
|
349
|
+
if (!context) {
|
|
350
|
+
throw new Error("Unable to get canvas context");
|
|
351
|
+
}
|
|
352
|
+
|
|
308
353
|
let imageData = context.createImageData(
|
|
309
354
|
imageFrame.columns,
|
|
310
355
|
imageFrame.rows
|
|
@@ -319,10 +364,13 @@ let createCustomImage = function (id, imageId, frameIndex, metadata) {
|
|
|
319
364
|
// Setup the renderer
|
|
320
365
|
if (image.color) {
|
|
321
366
|
image.getCanvas = function () {
|
|
322
|
-
canvas.height = image.rows;
|
|
323
|
-
canvas.width = image.columns;
|
|
367
|
+
canvas.height = image.rows || 0;
|
|
368
|
+
canvas.width = image.columns || 0;
|
|
324
369
|
let context = canvas.getContext("2d");
|
|
325
|
-
context
|
|
370
|
+
if (!context) {
|
|
371
|
+
throw new Error("Unable to get canvas context");
|
|
372
|
+
}
|
|
373
|
+
context.putImageData(imageFrame.imageData!, 0, 0);
|
|
326
374
|
return canvas;
|
|
327
375
|
};
|
|
328
376
|
}
|
|
@@ -342,7 +390,12 @@ let createCustomImage = function (id, imageId, frameIndex, metadata) {
|
|
|
342
390
|
if (image.color) {
|
|
343
391
|
image.windowWidth = 255;
|
|
344
392
|
image.windowCenter = 128;
|
|
345
|
-
} else
|
|
393
|
+
} else if (
|
|
394
|
+
image.maxPixelValue &&
|
|
395
|
+
image.minPixelValue &&
|
|
396
|
+
image.slope &&
|
|
397
|
+
image.intercept
|
|
398
|
+
) {
|
|
346
399
|
let maxVoi = image.maxPixelValue * image.slope + image.intercept;
|
|
347
400
|
let minVoi = image.minPixelValue * image.slope + image.intercept;
|
|
348
401
|
image.windowWidth = maxVoi - minVoi;
|
|
@@ -350,7 +403,7 @@ let createCustomImage = function (id, imageId, frameIndex, metadata) {
|
|
|
350
403
|
}
|
|
351
404
|
}
|
|
352
405
|
|
|
353
|
-
resolve(image);
|
|
406
|
+
resolve(image as Image);
|
|
354
407
|
}, reject);
|
|
355
408
|
});
|
|
356
409
|
|
|
@@ -367,14 +420,16 @@ let createCustomImage = function (id, imageId, frameIndex, metadata) {
|
|
|
367
420
|
* @function setPixelDataType
|
|
368
421
|
* @param {Object} imageFrame The Id of the image
|
|
369
422
|
*/
|
|
370
|
-
const setPixelDataType = function (imageFrame) {
|
|
423
|
+
const setPixelDataType = function (imageFrame: ImageFrame) {
|
|
371
424
|
if (imageFrame.bitsAllocated === 16) {
|
|
372
425
|
if (imageFrame.pixelRepresentation === 0) {
|
|
373
|
-
imageFrame.pixelData = new Uint16Array(
|
|
426
|
+
imageFrame.pixelData = new Uint16Array(
|
|
427
|
+
imageFrame.pixelData as Uint16Array
|
|
428
|
+
);
|
|
374
429
|
} else {
|
|
375
|
-
imageFrame.pixelData = new Int16Array(imageFrame.pixelData);
|
|
430
|
+
imageFrame.pixelData = new Int16Array(imageFrame.pixelData as Int16Array);
|
|
376
431
|
}
|
|
377
432
|
} else {
|
|
378
|
-
imageFrame.pixelData = new Uint8Array(imageFrame.pixelData);
|
|
433
|
+
imageFrame.pixelData = new Uint8Array(imageFrame.pixelData as Uint8Array);
|
|
379
434
|
}
|
|
380
435
|
};
|