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,534 +0,0 @@
1
- import cornerstoneTools from "cornerstone-tools";
2
-
3
- const external = cornerstoneTools.external;
4
- const BaseAnnotationTool = cornerstoneTools.importInternal(
5
- "base/BaseAnnotationTool"
6
- );
7
-
8
- // State
9
- const getToolState = cornerstoneTools.getToolState;
10
- const toolStyle = cornerstoneTools.toolStyle;
11
- const toolColors = cornerstoneTools.toolColors;
12
- const getHandleNearImagePoint = cornerstoneTools.importInternal(
13
- "manipulators/getHandleNearImagePoint"
14
- );
15
-
16
- // Drawing
17
- const getNewContext = cornerstoneTools.importInternal("drawing/getNewContext");
18
- const draw = cornerstoneTools.importInternal("drawing/draw");
19
- const drawEllipse = cornerstoneTools.importInternal("drawing/drawEllipse");
20
- const drawHandles = cornerstoneTools.importInternal("drawing/drawHandles");
21
- const drawLinkedTextBox = cornerstoneTools.importInternal(
22
- "drawing/drawLinkedTextBox"
23
- );
24
- const setShadow = cornerstoneTools.importInternal("drawing/setShadow");
25
-
26
- // Util
27
- const calculateSUV = cornerstoneTools.importInternal("util/calculateSUV");
28
- const numbersWithCommas = cornerstoneTools.importInternal(
29
- "util/numbersWithCommas"
30
- );
31
- const { pointInEllipse, calculateEllipseStatistics } =
32
- cornerstoneTools.importInternal("util/ellipseUtils");
33
- const getROITextBoxCoords = cornerstoneTools.importInternal(
34
- "util/getROITextBoxCoords"
35
- );
36
- const throttle = cornerstoneTools.importInternal("util/throttle");
37
- const { ellipticalRoiCursor } =
38
- cornerstoneTools.importInternal("tools/cursors");
39
- const getLogger = cornerstoneTools.importInternal("util/getLogger");
40
- const getPixelSpacing = cornerstoneTools.importInternal("util/getPixelSpacing");
41
- const getModule = cornerstoneTools.getModule;
42
-
43
- const logger = getLogger("tools:annotation:RectangleRoiTool");
44
-
45
- /**
46
- * @public
47
- * @class EllipticalRoiTool
48
- * @memberof Tools.Annotation
49
- * @classdesc Tool for drawing elliptical regions of interest, and measuring
50
- * the statistics of the enclosed pixels.
51
- * @extends Tools.Base.BaseAnnotationTool
52
- */
53
- export default class EllipticalRoiTool extends BaseAnnotationTool {
54
- constructor(props = {}) {
55
- const defaultProps = {
56
- name: "EllipticalRoi",
57
- supportedInteractionTypes: ["Mouse", "Touch"],
58
- configuration: {
59
- // showMinMax: false,
60
- // showHounsfieldUnits: true,
61
- drawHandlesOnHover: false,
62
- hideHandlesIfMoving: false,
63
- renderDashed: false
64
- },
65
- svgCursor: ellipticalRoiCursor
66
- };
67
-
68
- super(props, defaultProps);
69
-
70
- this.throttledUpdateCachedStats = throttle(this.updateCachedStats, 110);
71
- }
72
-
73
- createNewMeasurement(eventData) {
74
- const goodEventData =
75
- eventData && eventData.currentPoints && eventData.currentPoints.image;
76
-
77
- if (!goodEventData) {
78
- logger.error(
79
- `required eventData not supplied to tool ${this.name}'s createNewMeasurement`
80
- );
81
-
82
- return;
83
- }
84
-
85
- return {
86
- computeMeasurements: this.options.computeMeasurements,
87
- visible: true,
88
- active: true,
89
- color: undefined,
90
- invalidated: true,
91
- handles: {
92
- start: {
93
- x: eventData.currentPoints.image.x,
94
- y: eventData.currentPoints.image.y,
95
- highlight: true,
96
- active: false
97
- },
98
- end: {
99
- x: eventData.currentPoints.image.x,
100
- y: eventData.currentPoints.image.y,
101
- highlight: true,
102
- active: true
103
- },
104
- initialRotation: eventData.viewport.rotation,
105
- textBox: {
106
- active: false,
107
- hasMoved: false,
108
- movesIndependently: false,
109
- drawnIndependently: true,
110
- allowedOutsideImage: true,
111
- hasBoundingBox: true
112
- }
113
- }
114
- };
115
- }
116
-
117
- pointNearTool(element, data, coords, interactionType) {
118
- const hasStartAndEndHandles =
119
- data && data.handles && data.handles.start && data.handles.end;
120
-
121
- const validParameters = hasStartAndEndHandles;
122
-
123
- if (!validParameters) {
124
- logger.warn(
125
- `invalid parameters supplied to tool ${this.name}'s pointNearTool`
126
- );
127
- }
128
-
129
- if (!validParameters || data.visible === false) {
130
- return false;
131
- }
132
-
133
- const handleNearImagePoint = getHandleNearImagePoint(
134
- element,
135
- data.handles,
136
- coords,
137
- 6
138
- );
139
-
140
- if (handleNearImagePoint) {
141
- return true;
142
- }
143
-
144
- const distance = interactionType === "mouse" ? 15 : 25;
145
- const startCanvas = external.cornerstone.pixelToCanvas(
146
- element,
147
- data.handles.start
148
- );
149
- const endCanvas = external.cornerstone.pixelToCanvas(
150
- element,
151
- data.handles.end
152
- );
153
-
154
- const minorEllipse = {
155
- left: Math.min(startCanvas.x, endCanvas.x) + distance / 2,
156
- top: Math.min(startCanvas.y, endCanvas.y) + distance / 2,
157
- width: Math.abs(startCanvas.x - endCanvas.x) - distance,
158
- height: Math.abs(startCanvas.y - endCanvas.y) - distance
159
- };
160
-
161
- const majorEllipse = {
162
- left: Math.min(startCanvas.x, endCanvas.x) - distance / 2,
163
- top: Math.min(startCanvas.y, endCanvas.y) - distance / 2,
164
- width: Math.abs(startCanvas.x - endCanvas.x) + distance,
165
- height: Math.abs(startCanvas.y - endCanvas.y) + distance
166
- };
167
-
168
- const pointInMinorEllipse = pointInEllipse(minorEllipse, coords);
169
- const pointInMajorEllipse = pointInEllipse(majorEllipse, coords);
170
-
171
- if (pointInMajorEllipse && !pointInMinorEllipse) {
172
- return true;
173
- }
174
-
175
- return false;
176
- }
177
-
178
- updateCachedStats(image, element, data) {
179
- if (data.computeMeasurements) {
180
- const seriesModule =
181
- external.cornerstone.metaData.get(
182
- "generalSeriesModule",
183
- image.imageId
184
- ) || {};
185
- const modality = seriesModule.modality;
186
- const pixelSpacing = getPixelSpacing(image);
187
-
188
- const stats = _calculateStats(
189
- image,
190
- element,
191
- data.handles,
192
- modality,
193
- pixelSpacing
194
- );
195
-
196
- data.cachedStats = stats;
197
- }
198
- data.invalidated = false;
199
- }
200
-
201
- renderToolData(evt) {
202
- const toolData = getToolState(evt.currentTarget, this.name);
203
-
204
- if (!toolData) {
205
- return;
206
- }
207
-
208
- const eventData = evt.detail;
209
- const { image, element } = eventData;
210
- const lineWidth = toolStyle.getToolWidth();
211
- const lineDash = getModule("globalConfiguration").configuration.lineDash;
212
- const {
213
- handleRadius,
214
- drawHandlesOnHover,
215
- hideHandlesIfMoving,
216
- renderDashed
217
- } = this.configuration;
218
- const context = getNewContext(eventData.canvasContext.canvas);
219
- const { rowPixelSpacing, colPixelSpacing } = getPixelSpacing(image);
220
-
221
- // Meta
222
- const seriesModule =
223
- external.cornerstone.metaData.get("generalSeriesModule", image.imageId) ||
224
- {};
225
-
226
- // Pixel Spacing
227
- const modality = seriesModule.modality;
228
- const hasPixelSpacing = rowPixelSpacing && colPixelSpacing;
229
-
230
- draw(context, context => {
231
- // If we have tool data for this element - iterate over each set and draw it
232
- for (let i = 0; i < toolData.data.length; i++) {
233
- const data = toolData.data[i];
234
-
235
- if (data.visible === false) {
236
- continue;
237
- }
238
-
239
- // Configure
240
- const color = toolColors.getColorIfActive(data);
241
- const handleOptions = {
242
- color,
243
- handleRadius,
244
- drawHandlesIfActive: drawHandlesOnHover,
245
- hideHandlesIfMoving
246
- };
247
-
248
- setShadow(context, this.configuration);
249
-
250
- const ellipseOptions = { color };
251
-
252
- if (renderDashed) {
253
- ellipseOptions.lineDash = lineDash;
254
- }
255
-
256
- // Draw
257
- drawEllipse(
258
- context,
259
- element,
260
- data.handles.start,
261
- data.handles.end,
262
- ellipseOptions,
263
- "pixel",
264
- data.handles.initialRotation
265
- );
266
-
267
- drawHandles(context, eventData, data.handles, handleOptions);
268
-
269
- if (data.computeMeasurements) {
270
- // Update textbox stats
271
- if (data.invalidated === true) {
272
- if (data.cachedStats) {
273
- this.throttledUpdateCachedStats(image, element, data);
274
- } else {
275
- this.updateCachedStats(image, element, data);
276
- }
277
- }
278
-
279
- // Default to textbox on right side of ROI
280
- if (!data.handles.textBox.hasMoved) {
281
- const defaultCoords = getROITextBoxCoords(
282
- eventData.viewport,
283
- data.handles
284
- );
285
-
286
- Object.assign(data.handles.textBox, defaultCoords);
287
- }
288
-
289
- const textBoxAnchorPoints = handles =>
290
- _findTextBoxAnchorPoints(handles.start, handles.end);
291
- const textBoxContent = _createTextBoxContent(
292
- context,
293
- image.color,
294
- data.cachedStats,
295
- modality,
296
- hasPixelSpacing,
297
- this.configuration
298
- );
299
-
300
- data.unit = _getUnit(
301
- modality,
302
- this.configuration.showHounsfieldUnits
303
- );
304
-
305
- drawLinkedTextBox(
306
- context,
307
- element,
308
- data.handles.textBox,
309
- textBoxContent,
310
- data.handles,
311
- textBoxAnchorPoints,
312
- color,
313
- lineWidth,
314
- 10,
315
- true
316
- );
317
- }
318
- }
319
- });
320
- }
321
- }
322
-
323
- /**
324
- *
325
- *
326
- * @param {*} startHandle
327
- * @param {*} endHandle
328
- * @returns {Array.<{x: number, y: number}>}
329
- */
330
- function _findTextBoxAnchorPoints(startHandle, endHandle) {
331
- const { left, top, width, height } = _getEllipseImageCoordinates(
332
- startHandle,
333
- endHandle
334
- );
335
-
336
- return [
337
- {
338
- // Top middle point of ellipse
339
- x: left + width / 2,
340
- y: top
341
- },
342
- {
343
- // Left middle point of ellipse
344
- x: left,
345
- y: top + height / 2
346
- },
347
- {
348
- // Bottom middle point of ellipse
349
- x: left + width / 2,
350
- y: top + height
351
- },
352
- {
353
- // Right middle point of ellipse
354
- x: left + width,
355
- y: top + height / 2
356
- }
357
- ];
358
- }
359
-
360
- function _getUnit(modality, showHounsfieldUnits) {
361
- return modality === "CT" && showHounsfieldUnits !== false ? "HU" : "";
362
- }
363
-
364
- /**
365
- *
366
- *
367
- * @param {*} context
368
- * @param {*} isColorImage
369
- * @param {*} { area, mean, stdDev, min, max, meanStdDevSUV }
370
- * @param {*} modality
371
- * @param {*} hasPixelSpacing
372
- * @param {*} [options={}] - { showMinMax, showHounsfieldUnits }
373
- * @returns {string[]}
374
- */
375
- function _createTextBoxContent(
376
- context,
377
- isColorImage,
378
- { area = 0, mean = 0, stdDev = 0, min = 0, max = 0, meanStdDevSUV = 0 } = {},
379
- modality,
380
- hasPixelSpacing,
381
- options = {}
382
- ) {
383
- const showMinMax = options.showMinMax || false;
384
- const textLines = [];
385
-
386
- // Don't display mean/standardDev for color images
387
- const otherLines = [];
388
-
389
- if (!isColorImage) {
390
- const hasStandardUptakeValues = meanStdDevSUV && meanStdDevSUV.mean !== 0;
391
- const unit = _getUnit(modality, options.showHounsfieldUnits);
392
-
393
- let meanString = `Mean: ${numbersWithCommas(mean.toFixed(2))} ${unit}`;
394
- const stdDevString = `Std Dev: ${numbersWithCommas(
395
- stdDev.toFixed(2)
396
- )} ${unit}`;
397
-
398
- // If this image has SUV values to display, concatenate them to the text line
399
- if (hasStandardUptakeValues) {
400
- const SUVtext = " SUV: ";
401
-
402
- const meanSuvString = `${SUVtext}${numbersWithCommas(
403
- meanStdDevSUV.mean.toFixed(2)
404
- )}`;
405
- const stdDevSuvString = `${SUVtext}${numbersWithCommas(
406
- meanStdDevSUV.stdDev.toFixed(2)
407
- )}`;
408
-
409
- const targetStringLength = Math.floor(
410
- context.measureText(`${stdDevString} `).width
411
- );
412
-
413
- while (context.measureText(meanString).width < targetStringLength) {
414
- meanString += " ";
415
- }
416
-
417
- otherLines.push(`${meanString}${meanSuvString}`);
418
- otherLines.push(`${stdDevString} ${stdDevSuvString}`);
419
- } else {
420
- otherLines.push(`${meanString}`);
421
- otherLines.push(`${stdDevString}`);
422
- }
423
-
424
- if (showMinMax) {
425
- let minString = `Min: ${min} ${unit}`;
426
- const maxString = `Max: ${max} ${unit}`;
427
- const targetStringLength = hasStandardUptakeValues
428
- ? Math.floor(context.measureText(`${stdDevString} `).width)
429
- : Math.floor(context.measureText(`${meanString} `).width);
430
-
431
- while (context.measureText(minString).width < targetStringLength) {
432
- minString += " ";
433
- }
434
-
435
- otherLines.push(`${minString}${maxString}`);
436
- }
437
- }
438
-
439
- textLines.push(_formatArea(area, hasPixelSpacing));
440
- otherLines.forEach(x => textLines.push(x));
441
-
442
- return textLines;
443
- }
444
-
445
- /**
446
- *
447
- *
448
- * @param {*} area
449
- * @param {*} hasPixelSpacing
450
- * @returns {string} The formatted label for showing area
451
- */
452
- function _formatArea(area, hasPixelSpacing) {
453
- // This uses Char code 178 for a superscript 2
454
- const suffix = hasPixelSpacing
455
- ? ` mm${String.fromCharCode(178)}`
456
- : ` px${String.fromCharCode(178)}`;
457
-
458
- return `Area: ${numbersWithCommas(area.toFixed(2))}${suffix}`;
459
- }
460
-
461
- /**
462
- *
463
- *
464
- * @param {*} image
465
- * @param {*} element
466
- * @param {*} handles
467
- * @param {*} modality
468
- * @param {*} pixelSpacing
469
- * @returns {Object} The Stats object
470
- */
471
- function _calculateStats(image, element, handles, modality, pixelSpacing) {
472
- // Retrieve the bounds of the ellipse in image coordinates
473
- const ellipseCoordinates = _getEllipseImageCoordinates(
474
- handles.start,
475
- handles.end
476
- );
477
-
478
- // Retrieve the array of pixels that the ellipse bounds cover
479
- const pixels = external.cornerstone.getPixels(
480
- element,
481
- ellipseCoordinates.left,
482
- ellipseCoordinates.top,
483
- ellipseCoordinates.width,
484
- ellipseCoordinates.height
485
- );
486
-
487
- // Calculate the mean & standard deviation from the pixels and the ellipse details.
488
- const ellipseMeanStdDev = calculateEllipseStatistics(
489
- pixels,
490
- ellipseCoordinates
491
- );
492
-
493
- let meanStdDevSUV;
494
-
495
- if (modality === "PT") {
496
- meanStdDevSUV = {
497
- mean: calculateSUV(image, ellipseMeanStdDev.mean, true) || 0,
498
- stdDev: calculateSUV(image, ellipseMeanStdDev.stdDev, true) || 0
499
- };
500
- }
501
-
502
- // Calculate the image area from the ellipse dimensions and pixel spacing
503
- const area =
504
- Math.PI *
505
- ((ellipseCoordinates.width * (pixelSpacing.colPixelSpacing || 1)) / 2) *
506
- ((ellipseCoordinates.height * (pixelSpacing.rowPixelSpacing || 1)) / 2);
507
-
508
- return {
509
- area: area || 0,
510
- count: ellipseMeanStdDev.count || 0,
511
- mean: ellipseMeanStdDev.mean || 0,
512
- variance: ellipseMeanStdDev.variance || 0,
513
- stdDev: ellipseMeanStdDev.stdDev || 0,
514
- min: ellipseMeanStdDev.min || 0,
515
- max: ellipseMeanStdDev.max || 0,
516
- meanStdDevSUV
517
- };
518
- }
519
-
520
- /**
521
- * Retrieve the bounds of the ellipse in image coordinates
522
- *
523
- * @param {*} startHandle
524
- * @param {*} endHandle
525
- * @returns {{ left: number, top: number, width: number, height: number }}
526
- */
527
- function _getEllipseImageCoordinates(startHandle, endHandle) {
528
- return {
529
- left: Math.round(Math.min(startHandle.x, endHandle.x)),
530
- top: Math.round(Math.min(startHandle.y, endHandle.y)),
531
- width: Math.round(Math.abs(startHandle.x - endHandle.x)),
532
- height: Math.round(Math.abs(startHandle.y - endHandle.y))
533
- };
534
- }