larvitar 2.0.5 → 2.0.7

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 (77) hide show
  1. package/README.md +2 -2
  2. package/dist/imaging/imageRendering.d.ts +1 -71
  3. package/dist/imaging/imageStore.d.ts +5 -0
  4. package/dist/imaging/loaders/commonLoader.d.ts +4 -4
  5. package/dist/imaging/loaders/nrrdLoader.d.ts +1 -51
  6. package/dist/larvitar.js +13 -1
  7. package/dist/larvitar.js.map +1 -1
  8. package/imaging/tools/types.d.ts +19 -19
  9. package/imaging/types.d.ts +110 -2
  10. package/package.json +7 -2
  11. package/.github/workflows/build-docs.yml +0 -59
  12. package/.github/workflows/codeql-analysis.yml +0 -71
  13. package/.github/workflows/deploy.yml +0 -37
  14. package/.vscode/settings.json +0 -4
  15. package/CODE_OF_CONDUCT.md +0 -76
  16. package/MIGRATION.md +0 -25
  17. package/bundler/webpack.common.js +0 -27
  18. package/bundler/webpack.dev.js +0 -23
  19. package/bundler/webpack.prod.js +0 -19
  20. package/decs.d.ts +0 -12
  21. package/dist/imaging/MetaDataReadable.d.ts +0 -41
  22. package/dist/imaging/MetaDataTypes.d.ts +0 -3489
  23. package/imaging/dataDictionary.json +0 -21866
  24. package/imaging/imageAnonymization.ts +0 -135
  25. package/imaging/imageColormaps.ts +0 -217
  26. package/imaging/imageContours.ts +0 -196
  27. package/imaging/imageIo.ts +0 -251
  28. package/imaging/imageLayers.ts +0 -121
  29. package/imaging/imageLoading.ts +0 -299
  30. package/imaging/imageParsing.ts +0 -444
  31. package/imaging/imagePresets.ts +0 -156
  32. package/imaging/imageRendering.ts +0 -1091
  33. package/imaging/imageReslice.ts +0 -87
  34. package/imaging/imageStore.ts +0 -487
  35. package/imaging/imageTags.ts +0 -609
  36. package/imaging/imageTools.js +0 -708
  37. package/imaging/imageUtils.ts +0 -1079
  38. package/imaging/loaders/commonLoader.ts +0 -275
  39. package/imaging/loaders/dicomLoader.ts +0 -66
  40. package/imaging/loaders/fileLoader.ts +0 -71
  41. package/imaging/loaders/multiframeLoader.ts +0 -435
  42. package/imaging/loaders/nrrdLoader.ts +0 -630
  43. package/imaging/loaders/resliceLoader.ts +0 -205
  44. package/imaging/monitors/memory.ts +0 -151
  45. package/imaging/monitors/performance.ts +0 -34
  46. package/imaging/parsers/ecg.ts +0 -54
  47. package/imaging/parsers/nrrd.js +0 -485
  48. package/imaging/tools/custom/4dSliceScrollTool.js +0 -146
  49. package/imaging/tools/custom/BorderMagnifyTool.js +0 -99
  50. package/imaging/tools/custom/contourTool.js +0 -1884
  51. package/imaging/tools/custom/diameterTool.js +0 -141
  52. package/imaging/tools/custom/editMaskTool.js +0 -141
  53. package/imaging/tools/custom/ellipticalRoiOverlayTool.js +0 -534
  54. package/imaging/tools/custom/polygonSegmentationMixin.js +0 -245
  55. package/imaging/tools/custom/polylineScissorsTool.js +0 -59
  56. package/imaging/tools/custom/rectangleRoiOverlayTool.js +0 -564
  57. package/imaging/tools/custom/seedTool.js +0 -342
  58. package/imaging/tools/custom/setLabelMap3D.ts +0 -242
  59. package/imaging/tools/custom/thresholdsBrushTool.js +0 -161
  60. package/imaging/tools/default.ts +0 -594
  61. package/imaging/tools/interaction.ts +0 -266
  62. package/imaging/tools/io.ts +0 -229
  63. package/imaging/tools/main.ts +0 -427
  64. package/imaging/tools/segmentation.ts +0 -532
  65. package/imaging/tools/segmentations.md +0 -38
  66. package/imaging/tools/state.ts +0 -74
  67. package/imaging/tools/strategies/eraseFreehand.js +0 -76
  68. package/imaging/tools/strategies/fillFreehand.js +0 -79
  69. package/imaging/tools/strategies/index.js +0 -2
  70. package/imaging/waveforms/ecg.ts +0 -191
  71. package/index.ts +0 -431
  72. package/jsdoc.json +0 -52
  73. package/rollup.config.js +0 -51
  74. package/template/.gitkeep +0 -0
  75. package/tsconfig.json +0 -102
  76. /package/imaging/{MetaDataReadable.ts → MetaDataReadable.d.ts} +0 -0
  77. /package/imaging/{MetaDataTypes.ts → MetaDataTypes.d.ts} +0 -0
@@ -1,435 +0,0 @@
1
- /** @module loaders/multiframeLoader
2
- * @desc This file is a custom DICOM loader for multiframe images
3
- */
4
-
5
- // external libraries
6
- import { default as cornerstoneDICOMImageLoader } from "cornerstone-wado-image-loader";
7
- import { each, range } from "lodash";
8
-
9
- // internal libraries
10
- import {
11
- getImageFrame,
12
- getLarvitarImageTracker,
13
- getLarvitarManager
14
- } from "./commonLoader";
15
- import { parseDataSet } from "../imageParsing";
16
- import type {
17
- Image,
18
- ImageFrame,
19
- LarvitarManager,
20
- MetaData,
21
- Series
22
- } from "../types";
23
-
24
- // global module variables
25
- let customImageLoaderCounter = 0;
26
-
27
- // Local cache used to store multiframe datasets to avoid reading and parsing
28
- // the whole file to show a single frame.
29
- let multiframeDatasetCache: { [key: string]: Series | null } | null = null;
30
- /*
31
- * This module provides the following functions to be exported:
32
- * loadMultiFrameImage(elementId)
33
- * buildMultiFrameImage(seriesId, serie)
34
- * getMultiFrameImageId(customLoaderName)
35
- * clearMultiFrameCache()
36
- */
37
-
38
- /**
39
- * Custom MultiFrame Loader Function
40
- * @export
41
- * @function loadMultiFrameImage
42
- * @param {String} imageId - ImageId tag
43
- * @returns {Function} Custom Image Creation Function
44
- */
45
- export const loadMultiFrameImage = function (imageId: string) {
46
- let parsedImageId = cornerstoneDICOMImageLoader.wadouri.parseImageId(imageId);
47
- let rootImageId = parsedImageId.scheme + ":" + parsedImageId.url;
48
- let imageTracker = getLarvitarImageTracker();
49
- let seriesId = imageTracker[rootImageId];
50
- let manager = getLarvitarManager() as LarvitarManager;
51
- if (multiframeDatasetCache === null) {
52
- multiframeDatasetCache = {};
53
- }
54
-
55
- if (multiframeDatasetCache[rootImageId]) {
56
- multiframeDatasetCache[rootImageId] = multiframeDatasetCache[rootImageId];
57
- } else if (manager) {
58
- multiframeDatasetCache[rootImageId] = manager[seriesId] as Series;
59
- } else {
60
- throw new Error("No multiframe dataset found for seriesId: " + seriesId);
61
- }
62
-
63
- let metadata =
64
- multiframeDatasetCache[rootImageId]?.instances[imageId].metadata;
65
- return createCustomImage(rootImageId, imageId, parsedImageId.frame, metadata);
66
- };
67
-
68
- /**
69
- * Build the multiframe layout in the larvitar Manager
70
- * @export
71
- * @function buildMultiFrameImage
72
- * @param {String} seriesId - SeriesId tag
73
- * @param {Object} serie - parsed serie object
74
- */
75
- export const buildMultiFrameImage = function (seriesId: string, serie: Series) {
76
- let t0 = performance.now();
77
- let manager = getLarvitarManager();
78
- let imageTracker = getLarvitarImageTracker();
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
- }
94
-
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! };
99
-
100
- parseDataSet(dataSet!, frameMetadata, {
101
- tags: ["x52009230"],
102
- frameId: frameNumber
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;
133
- });
134
-
135
- let t1 = performance.now();
136
- console.log(`Call to buildMultiFrameImage took ${t1 - t0} milliseconds.`);
137
- };
138
-
139
- /**
140
- * Get the custom imageId from custom loader
141
- * @instance
142
- * @function getMultiFrameImageId
143
- * @param {String} customLoaderName The custom loader name
144
- * @return {String} the custom image id
145
- */
146
- export const getMultiFrameImageId = function (customLoaderName: string) {
147
- let imageId = customLoaderName + "://" + customImageLoaderCounter;
148
- customImageLoaderCounter++;
149
- return imageId;
150
- };
151
-
152
- /**
153
- * Clear the multiframe cache
154
- * @instance
155
- * @function clearMultiFrameCache
156
- * @param {String} seriesId - SeriesId tag
157
- */
158
- export const clearMultiFrameCache = function (seriesId: string) {
159
- each(multiframeDatasetCache, function (image, imageId) {
160
- if (!image) {
161
- return;
162
- }
163
- if (seriesId == image.seriesUID || !seriesId) {
164
- if (image.dataSet) {
165
- // @ts-ignore: modify external type ?
166
- image.dataSet.byteArray = null;
167
- }
168
- image.dataSet = null;
169
- image.elements = null;
170
- each(image.instances, function (instance) {
171
- // @ts-ignore: is needed to clear the cache ?
172
- instance.metadata = null;
173
- });
174
- // @ts-ignore: is needed to clear the cache ?
175
- image.instances = null;
176
- multiframeDatasetCache![imageId] = null;
177
- delete multiframeDatasetCache![imageId];
178
- }
179
- });
180
- if (!seriesId) {
181
- multiframeDatasetCache = null;
182
- }
183
- };
184
-
185
- /* Internal module functions */
186
-
187
- /**
188
- * Create the custom image object for cornerstone from custom image
189
- * @instance
190
- * @function createCustomImage
191
- * @param {String} imageId The Id of the image
192
- * @param {Object} metadata the metadata object
193
- * @param {Object} pixelData pixel data object
194
- * @param {Object} dataSet dataset object
195
- * @returns {Object} custom image object
196
- */
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
204
- // always preScale the pixel array unless it is asked not to
205
- options.preScale = {
206
- enabled:
207
- options.preScale && options.preScale.enabled !== undefined
208
- ? options.preScale.enabled
209
- : false
210
- };
211
-
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
-
223
- let pixelDataElement = dataSet.elements.x7fe00010;
224
- // Extract pixelData of the required frame
225
- let pixelData: number[];
226
- try {
227
- if (pixelDataElement.encapsulatedPixelData) {
228
- pixelData = cornerstoneDICOMImageLoader.wadouri.getEncapsulatedImageFrame(
229
- dataSet,
230
- frameIndex
231
- );
232
- } else {
233
- pixelData = cornerstoneDICOMImageLoader.wadouri.getUncompressedImageFrame(
234
- dataSet,
235
- frameIndex
236
- );
237
- }
238
- } catch (error) {
239
- throw new Error("No pixel data for id: " + id);
240
- }
241
-
242
- if (!metadata) {
243
- throw new Error("No metadata for id: " + id);
244
- }
245
-
246
- let imageFrame = getImageFrame(metadata, dataSet);
247
- let transferSyntax = dataSet.string("x00020010");
248
-
249
- let canvas = window.document.createElement("canvas");
250
- // Get the scaling parameters from the metadata
251
- if (options.preScale.enabled) {
252
- const scalingParameters = cornerstoneDICOMImageLoader.getScalingParameters(
253
- cornerstone.metaData,
254
- imageId
255
- );
256
-
257
- if (scalingParameters) {
258
- options.preScale = {
259
- ...options.preScale,
260
- scalingParameters
261
- };
262
- }
263
- }
264
-
265
- const decodePromise = cornerstoneDICOMImageLoader.decodeImageFrame(
266
- imageFrame,
267
- transferSyntax,
268
- pixelData,
269
- canvas,
270
- options
271
- );
272
-
273
- let promise: Promise<Image> = new Promise((resolve, reject) => {
274
- decodePromise.then(function handleDecodeResponse(imageFrame: ImageFrame) {
275
- // This function uses the pixelData received as argument without manipulating
276
- // them: if the image is compressed, the decompress function should be called
277
- // before creating the custom image object (like the multiframe case).
278
- setPixelDataType(imageFrame);
279
-
280
- let pixelSpacing = metadata.x00280030 ? metadata.x00280030 : 1.0;
281
- let rescaleIntercept = metadata.x00281052;
282
- let rescaleSlope = metadata.x00281053;
283
- let windowCenter = metadata.x00281050;
284
- let windowWidth = metadata.x00281051;
285
-
286
- function getSizeInBytes() {
287
- let bytesPerPixel = Math.round(imageFrame.bitsAllocated / 8);
288
- return (
289
- imageFrame.rows *
290
- imageFrame.columns *
291
- bytesPerPixel *
292
- imageFrame.samplesPerPixel
293
- );
294
- }
295
-
296
- let image: Partial<Image> = {
297
- imageId: imageId,
298
- color: cornerstoneDICOMImageLoader.isColorImage(
299
- imageFrame.photometricInterpretation
300
- ),
301
- columnPixelSpacing: (pixelSpacing as number[])[1]
302
- ? (pixelSpacing as number[])[1]
303
- : (pixelSpacing as number), // check for specific spacing value
304
- columns: imageFrame.columns,
305
- data: dataSet ? dataSet : undefined,
306
- height: imageFrame.rows,
307
- floatPixelData: undefined,
308
- intercept: (rescaleIntercept as number)
309
- ? (rescaleIntercept as number)
310
- : 0,
311
- invert: imageFrame.photometricInterpretation === "MONOCHROME1",
312
- minPixelValue: imageFrame.smallestPixelValue,
313
- maxPixelValue: imageFrame.largestPixelValue,
314
- render: undefined, // set below
315
- rowPixelSpacing: (pixelSpacing as number[])[0]
316
- ? (pixelSpacing as number[])[0]
317
- : (pixelSpacing as number), // check for specific spacing value
318
- rows: imageFrame.rows,
319
- sizeInBytes: getSizeInBytes(),
320
- slope: (rescaleSlope as number) ? (rescaleSlope as number) : 1,
321
- width: imageFrame.columns,
322
- windowCenter: windowCenter as number,
323
- windowWidth: windowWidth as number,
324
- decodeTimeInMS: undefined, // TODO
325
- loadTimeInMS: undefined // TODO
326
- };
327
- // add function to return pixel data
328
- image.getPixelData = function () {
329
- if (imageFrame.pixelData === undefined) {
330
- throw new Error("No pixel data for image " + imageId);
331
- }
332
- return Array.from(imageFrame.pixelData);
333
- };
334
-
335
- // convert color space if not isJPEGBaseline8BitColor
336
- let isJPEGBaseline8BitColor =
337
- cornerstoneDICOMImageLoader.isJPEGBaseline8BitColor(
338
- imageFrame,
339
- transferSyntax
340
- );
341
-
342
- if (image.color && !isJPEGBaseline8BitColor) {
343
- // setup the canvas context
344
- canvas.height = imageFrame.rows;
345
- canvas.width = imageFrame.columns;
346
-
347
- let context = canvas.getContext("2d");
348
-
349
- if (!context) {
350
- throw new Error("Unable to get canvas context");
351
- }
352
-
353
- let imageData = context.createImageData(
354
- imageFrame.columns,
355
- imageFrame.rows
356
- );
357
-
358
- cornerstoneDICOMImageLoader.convertColorSpace(imageFrame, imageData);
359
-
360
- imageFrame.imageData = imageData;
361
- imageFrame.pixelData = imageData.data;
362
- }
363
-
364
- // Setup the renderer
365
- if (image.color) {
366
- image.getCanvas = function () {
367
- canvas.height = image.rows || 0;
368
- canvas.width = image.columns || 0;
369
- let context = canvas.getContext("2d");
370
- if (!context) {
371
- throw new Error("Unable to get canvas context");
372
- }
373
- context.putImageData(imageFrame.imageData!, 0, 0);
374
- return canvas;
375
- };
376
- }
377
-
378
- // calculate min/max if not supplied
379
- if (
380
- image.minPixelValue === undefined ||
381
- image.maxPixelValue === undefined
382
- ) {
383
- let minMax = cornerstoneDICOMImageLoader.getMinMax(pixelData);
384
- image.minPixelValue = minMax.min;
385
- image.maxPixelValue = minMax.max;
386
- }
387
-
388
- // set the ww/wc to cover the dynamic range of the image if no values are supplied
389
- if (image.windowCenter === undefined || image.windowWidth === undefined) {
390
- if (image.color) {
391
- image.windowWidth = 255;
392
- image.windowCenter = 128;
393
- } else if (
394
- image.maxPixelValue &&
395
- image.minPixelValue &&
396
- image.slope &&
397
- image.intercept
398
- ) {
399
- let maxVoi = image.maxPixelValue * image.slope + image.intercept;
400
- let minVoi = image.minPixelValue * image.slope + image.intercept;
401
- image.windowWidth = maxVoi - minVoi;
402
- image.windowCenter = (maxVoi + minVoi) / 2;
403
- }
404
- }
405
-
406
- resolve(image as Image);
407
- }, reject);
408
- });
409
-
410
- // Return an object containing the Promise to cornerstone so it can setup callbacks to be
411
- // invoked asynchronously for the success/resolve and failure/reject scenarios.
412
- return {
413
- promise
414
- };
415
- };
416
-
417
- /**
418
- * This is an override of the cornerstoneDICOMImageLoader setPixelDataType function
419
- * @instance
420
- * @function setPixelDataType
421
- * @param {Object} imageFrame The Id of the image
422
- */
423
- const setPixelDataType = function (imageFrame: ImageFrame) {
424
- if (imageFrame.bitsAllocated === 16) {
425
- if (imageFrame.pixelRepresentation === 0) {
426
- imageFrame.pixelData = new Uint16Array(
427
- imageFrame.pixelData as Uint16Array
428
- );
429
- } else {
430
- imageFrame.pixelData = new Int16Array(imageFrame.pixelData as Int16Array);
431
- }
432
- } else {
433
- imageFrame.pixelData = new Uint8Array(imageFrame.pixelData as Uint8Array);
434
- }
435
- };