larvitar 2.0.4 → 2.0.6

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 (72) hide show
  1. package/README.md +2 -2
  2. package/dist/larvitar.js +5 -3
  3. package/dist/larvitar.js.map +1 -1
  4. package/package.json +6 -2
  5. package/.github/workflows/build-docs.yml +0 -59
  6. package/.github/workflows/codeql-analysis.yml +0 -71
  7. package/.github/workflows/deploy.yml +0 -37
  8. package/.vscode/settings.json +0 -4
  9. package/CODE_OF_CONDUCT.md +0 -76
  10. package/MIGRATION.md +0 -25
  11. package/bundler/webpack.common.js +0 -27
  12. package/bundler/webpack.dev.js +0 -23
  13. package/bundler/webpack.prod.js +0 -19
  14. package/decs.d.ts +0 -12
  15. package/imaging/MetaDataReadable.ts +0 -42
  16. package/imaging/MetaDataTypes.ts +0 -3491
  17. package/imaging/dataDictionary.json +0 -21866
  18. package/imaging/imageAnonymization.ts +0 -135
  19. package/imaging/imageColormaps.ts +0 -217
  20. package/imaging/imageContours.ts +0 -196
  21. package/imaging/imageIo.ts +0 -251
  22. package/imaging/imageLayers.ts +0 -121
  23. package/imaging/imageLoading.ts +0 -299
  24. package/imaging/imageParsing.ts +0 -444
  25. package/imaging/imagePresets.ts +0 -156
  26. package/imaging/imageRendering.ts +0 -1091
  27. package/imaging/imageReslice.ts +0 -87
  28. package/imaging/imageStore.ts +0 -487
  29. package/imaging/imageTags.ts +0 -609
  30. package/imaging/imageTools.js +0 -708
  31. package/imaging/imageUtils.ts +0 -1079
  32. package/imaging/loaders/commonLoader.ts +0 -275
  33. package/imaging/loaders/dicomLoader.ts +0 -66
  34. package/imaging/loaders/fileLoader.ts +0 -71
  35. package/imaging/loaders/multiframeLoader.ts +0 -435
  36. package/imaging/loaders/nrrdLoader.ts +0 -630
  37. package/imaging/loaders/resliceLoader.ts +0 -205
  38. package/imaging/monitors/memory.ts +0 -151
  39. package/imaging/monitors/performance.ts +0 -34
  40. package/imaging/parsers/ecg.ts +0 -54
  41. package/imaging/parsers/nrrd.js +0 -485
  42. package/imaging/tools/README.md +0 -27
  43. package/imaging/tools/custom/4dSliceScrollTool.js +0 -146
  44. package/imaging/tools/custom/BorderMagnifyTool.js +0 -99
  45. package/imaging/tools/custom/contourTool.js +0 -1884
  46. package/imaging/tools/custom/diameterTool.js +0 -141
  47. package/imaging/tools/custom/editMaskTool.js +0 -141
  48. package/imaging/tools/custom/ellipticalRoiOverlayTool.js +0 -534
  49. package/imaging/tools/custom/polygonSegmentationMixin.js +0 -245
  50. package/imaging/tools/custom/polylineScissorsTool.js +0 -59
  51. package/imaging/tools/custom/rectangleRoiOverlayTool.js +0 -564
  52. package/imaging/tools/custom/seedTool.js +0 -342
  53. package/imaging/tools/custom/setLabelMap3D.ts +0 -242
  54. package/imaging/tools/custom/thresholdsBrushTool.js +0 -161
  55. package/imaging/tools/default.ts +0 -594
  56. package/imaging/tools/interaction.ts +0 -266
  57. package/imaging/tools/io.ts +0 -229
  58. package/imaging/tools/main.ts +0 -424
  59. package/imaging/tools/segmentation.ts +0 -532
  60. package/imaging/tools/segmentations.md +0 -38
  61. package/imaging/tools/state.ts +0 -74
  62. package/imaging/tools/strategies/eraseFreehand.js +0 -76
  63. package/imaging/tools/strategies/fillFreehand.js +0 -79
  64. package/imaging/tools/strategies/index.js +0 -2
  65. package/imaging/tools/types.d.ts +0 -243
  66. package/imaging/types.d.ts +0 -200
  67. package/imaging/waveforms/ecg.ts +0 -191
  68. package/index.ts +0 -431
  69. package/jsdoc.json +0 -52
  70. package/rollup.config.js +0 -51
  71. package/template/.gitkeep +0 -0
  72. package/tsconfig.json +0 -102
@@ -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
- };