@cornerstonejs/core 1.5.0 → 1.7.0

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 (68) hide show
  1. package/dist/cjs/RenderingEngine/StackViewport.js +43 -75
  2. package/dist/cjs/RenderingEngine/StackViewport.js.map +1 -1
  3. package/dist/cjs/RenderingEngine/Viewport.d.ts +2 -0
  4. package/dist/cjs/RenderingEngine/Viewport.js.map +1 -1
  5. package/dist/cjs/enums/CalibrationTypes.d.ts +10 -0
  6. package/dist/cjs/enums/CalibrationTypes.js +15 -0
  7. package/dist/cjs/enums/CalibrationTypes.js.map +1 -0
  8. package/dist/cjs/enums/Events.d.ts +1 -0
  9. package/dist/cjs/enums/Events.js +1 -0
  10. package/dist/cjs/enums/Events.js.map +1 -1
  11. package/dist/cjs/enums/index.d.ts +2 -1
  12. package/dist/cjs/enums/index.js +3 -1
  13. package/dist/cjs/enums/index.js.map +1 -1
  14. package/dist/cjs/types/CPUIImageData.d.ts +2 -0
  15. package/dist/cjs/types/EventTypes.d.ts +8 -3
  16. package/dist/cjs/types/IImageCalibration.d.ts +11 -0
  17. package/dist/cjs/types/IImageCalibration.js +3 -0
  18. package/dist/cjs/types/IImageCalibration.js.map +1 -0
  19. package/dist/cjs/types/IImageData.d.ts +2 -0
  20. package/dist/cjs/types/index.d.ts +2 -1
  21. package/dist/cjs/utilities/calibratedPixelSpacingMetadataProvider.d.ts +3 -7
  22. package/dist/cjs/utilities/calibratedPixelSpacingMetadataProvider.js.map +1 -1
  23. package/dist/cjs/utilities/imageToWorldCoords.js +4 -1
  24. package/dist/cjs/utilities/imageToWorldCoords.js.map +1 -1
  25. package/dist/cjs/utilities/worldToImageCoords.js +4 -1
  26. package/dist/cjs/utilities/worldToImageCoords.js.map +1 -1
  27. package/dist/esm/RenderingEngine/StackViewport.js +16 -49
  28. package/dist/esm/RenderingEngine/StackViewport.js.map +1 -1
  29. package/dist/esm/RenderingEngine/Viewport.d.ts +2 -0
  30. package/dist/esm/RenderingEngine/Viewport.js.map +1 -1
  31. package/dist/esm/enums/CalibrationTypes.d.ts +10 -0
  32. package/dist/esm/enums/CalibrationTypes.js +12 -0
  33. package/dist/esm/enums/CalibrationTypes.js.map +1 -0
  34. package/dist/esm/enums/Events.d.ts +1 -0
  35. package/dist/esm/enums/Events.js +1 -0
  36. package/dist/esm/enums/Events.js.map +1 -1
  37. package/dist/esm/enums/index.d.ts +2 -1
  38. package/dist/esm/enums/index.js +2 -1
  39. package/dist/esm/enums/index.js.map +1 -1
  40. package/dist/esm/types/CPUIImageData.d.ts +2 -0
  41. package/dist/esm/types/EventTypes.d.ts +8 -3
  42. package/dist/esm/types/IImageCalibration.d.ts +11 -0
  43. package/dist/esm/types/IImageCalibration.js +2 -0
  44. package/dist/esm/types/IImageCalibration.js.map +1 -0
  45. package/dist/esm/types/IImageData.d.ts +2 -0
  46. package/dist/esm/types/index.d.ts +2 -1
  47. package/dist/esm/utilities/calibratedPixelSpacingMetadataProvider.d.ts +3 -7
  48. package/dist/esm/utilities/calibratedPixelSpacingMetadataProvider.js.map +1 -1
  49. package/dist/esm/utilities/imageToWorldCoords.js +4 -1
  50. package/dist/esm/utilities/imageToWorldCoords.js.map +1 -1
  51. package/dist/esm/utilities/worldToImageCoords.js +4 -1
  52. package/dist/esm/utilities/worldToImageCoords.js.map +1 -1
  53. package/dist/umd/index.js +1 -1
  54. package/dist/umd/index.js.map +1 -1
  55. package/package.json +2 -2
  56. package/src/RenderingEngine/StackViewport.ts +28 -97
  57. package/src/RenderingEngine/Viewport.ts +2 -0
  58. package/src/enums/CalibrationTypes.ts +55 -0
  59. package/src/enums/Events.ts +9 -0
  60. package/src/enums/index.ts +2 -0
  61. package/src/types/CPUIImageData.ts +3 -0
  62. package/src/types/EventTypes.ts +23 -2
  63. package/src/types/IImageCalibration.ts +41 -0
  64. package/src/types/IImageData.ts +4 -0
  65. package/src/types/index.ts +2 -0
  66. package/src/utilities/calibratedPixelSpacingMetadataProvider.ts +4 -10
  67. package/src/utilities/imageToWorldCoords.ts +5 -2
  68. package/src/utilities/worldToImageCoords.ts +5 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/core",
3
- "version": "1.5.0",
3
+ "version": "1.7.0",
4
4
  "description": "",
5
5
  "main": "dist/umd/index.js",
6
6
  "types": "dist/esm/index.d.ts",
@@ -44,5 +44,5 @@
44
44
  "type": "individual",
45
45
  "url": "https://ohif.org/donate"
46
46
  },
47
- "gitHead": "cbfe5342099f46b69109d34e09a0a733ca7c897d"
47
+ "gitHead": "757fe06aab211f0bd506c40f262264e90290b702"
48
48
  }
@@ -10,7 +10,6 @@ import vtkColorTransferFunction from '@kitware/vtk.js/Rendering/Core/ColorTransf
10
10
  import * as metaData from '../metaData';
11
11
  import Viewport from './Viewport';
12
12
  import eventTarget from '../eventTarget';
13
- import Events from '../enums/Events';
14
13
  import {
15
14
  triggerEvent,
16
15
  isEqual,
@@ -41,6 +40,7 @@ import {
41
40
  VolumeActor,
42
41
  Mat3,
43
42
  ColormapRegistration,
43
+ IImageCalibration,
44
44
  } from '../types';
45
45
  import { ViewportInput } from '../types/IViewport';
46
46
  import drawImageSync from './helpers/cpuFallback/drawImageSync';
@@ -48,8 +48,13 @@ import { getColormap } from './helpers/cpuFallback/colors/index';
48
48
 
49
49
  import { loadAndCacheImage } from '../loaders/imageLoader';
50
50
  import imageLoadPoolManager from '../requestPool/imageLoadPoolManager';
51
- import InterpolationType from '../enums/InterpolationType';
52
- import VOILUTFunctionType from '../enums/VOILUTFunctionType';
51
+ import {
52
+ InterpolationType,
53
+ RequestType,
54
+ Events,
55
+ CalibrationTypes,
56
+ VOILUTFunctionType,
57
+ } from '../enums';
53
58
  import canvasToPixel from './helpers/cpuFallback/rendering/canvasToPixel';
54
59
  import pixelToCanvas from './helpers/cpuFallback/rendering/pixelToCanvas';
55
60
  import getDefaultViewport from './helpers/cpuFallback/rendering/getDefaultViewport';
@@ -59,7 +64,6 @@ import resize from './helpers/cpuFallback/rendering/resize';
59
64
  import resetCamera from './helpers/cpuFallback/rendering/resetCamera';
60
65
  import { Transform } from './helpers/cpuFallback/rendering/transform';
61
66
  import { getConfiguration, getShouldUseCPURendering } from '../init';
62
- import RequestType from '../enums/RequestType';
63
67
  import {
64
68
  StackViewportNewStackEventDetail,
65
69
  StackViewportScrollEventDetail,
@@ -91,8 +95,10 @@ interface ImageDataMetaData {
91
95
  }
92
96
  // TODO This needs to be exposed as its published to consumers.
93
97
  type CalibrationEvent = {
94
- rowScale: number;
95
- columnScale: number;
98
+ rowScale?: number;
99
+ columnScale?: number;
100
+ scale: number;
101
+ calibration: IImageCalibration;
96
102
  };
97
103
 
98
104
  type SetVOIOptions = {
@@ -411,6 +417,7 @@ class StackViewport extends Viewport implements IStackViewport {
411
417
  metadata: { Modality: this.modality },
412
418
  scaling: this.scaling,
413
419
  hasPixelSpacing: this.hasPixelSpacing,
420
+ calibration: this.calibration,
414
421
  preScale: {
415
422
  ...this.csImage.preScale,
416
423
  },
@@ -452,6 +459,7 @@ class StackViewport extends Viewport implements IStackViewport {
452
459
  },
453
460
  scalarData: this.cpuImagePixelData,
454
461
  hasPixelSpacing: this.hasPixelSpacing,
462
+ calibration: this.calibration,
455
463
  preScale: {
456
464
  ...this.csImage.preScale,
457
465
  },
@@ -558,6 +566,7 @@ class StackViewport extends Viewport implements IStackViewport {
558
566
  const voiLUTFunctionEnum = this._getValidVOILUTFunction(voiLUTFunction);
559
567
  this.VOILUTFunction = voiLUTFunctionEnum;
560
568
 
569
+ this.calibration = null;
561
570
  let imagePlaneModule = this._getImagePlaneModule(imageId);
562
571
 
563
572
  if (!this.useCPURendering) {
@@ -591,89 +600,19 @@ class StackViewport extends Viewport implements IStackViewport {
591
600
  * @returns modified imagePlaneModule with the calibrated spacings
592
601
  */
593
602
  private calibrateIfNecessary(imageId, imagePlaneModule) {
594
- const calibratedPixelSpacing = metaData.get(
595
- 'calibratedPixelSpacing',
596
- imageId
597
- );
598
-
599
- if (!calibratedPixelSpacing) {
600
- return imagePlaneModule;
601
- }
602
-
603
- const {
604
- rowPixelSpacing: calibratedRowSpacing,
605
- columnPixelSpacing: calibratedColumnSpacing,
606
- } = calibratedPixelSpacing;
603
+ const calibration = metaData.get('calibratedPixelSpacing', imageId);
604
+ const isUpdated = this.calibration !== calibration;
605
+ const { scale } = calibration || {};
606
+ this.hasPixelSpacing = scale > 0 || imagePlaneModule.rowPixelSpacing > 0;
607
+ imagePlaneModule.calibration = calibration;
607
608
 
608
- // Todo: This is necessary in general, but breaks an edge case when an image
609
- // is calibrated to some other spacing, and it gets calibrated BACK to the
610
- // original spacing.
611
- if (
612
- imagePlaneModule.rowPixelSpacing === calibratedRowSpacing &&
613
- imagePlaneModule.columnPixelSpacing === calibratedColumnSpacing
614
- ) {
615
- return imagePlaneModule;
616
- }
609
+ if (!isUpdated) return imagePlaneModule;
617
610
 
618
- // Check if there is already an actor
619
- const imageDataMetadata = this.getImageData();
620
-
621
- // If no actor (first load) and calibration matches the dicom header
622
- if (
623
- !imageDataMetadata &&
624
- imagePlaneModule.rowPixelSpacing === calibratedRowSpacing &&
625
- imagePlaneModule.columnPixelSpacing === calibratedColumnSpacing
626
- ) {
627
- return imagePlaneModule;
628
- }
629
-
630
- // If no actor (first load) and calibration doesn't match headers
631
- // -> needs calibration
632
- if (
633
- !imageDataMetadata &&
634
- (imagePlaneModule.rowPixelSpacing !== calibratedRowSpacing ||
635
- imagePlaneModule.columnPixelSpacing !== calibratedColumnSpacing)
636
- ) {
637
- this._publishCalibratedEvent = true;
638
-
639
- this._calibrationEvent = <CalibrationEvent>{
640
- rowScale: calibratedRowSpacing / imagePlaneModule.rowPixelSpacing,
641
- columnScale:
642
- calibratedColumnSpacing / imagePlaneModule.columnPixelSpacing,
643
- };
644
-
645
- // modify the calibration object to store the actual updated values applied
646
- calibratedPixelSpacing.appliedSpacing = calibratedPixelSpacing;
647
- // This updates the render copy
648
- imagePlaneModule.rowPixelSpacing = calibratedRowSpacing;
649
- imagePlaneModule.columnPixelSpacing = calibratedColumnSpacing;
650
- return imagePlaneModule;
651
- }
652
-
653
- // If there is already an actor, check if calibration is needed for the current actor
654
- const { imageData } = imageDataMetadata;
655
- const [columnPixelSpacing, rowPixelSpacing] = imageData.getSpacing();
656
-
657
- // modify the calibration object to store the actual updated values applied
658
- calibratedPixelSpacing.appliedSpacing = calibratedPixelSpacing;
659
- imagePlaneModule.rowPixelSpacing = calibratedRowSpacing;
660
- imagePlaneModule.columnPixelSpacing = calibratedColumnSpacing;
661
-
662
- // If current actor spacing matches the calibrated spacing
663
- if (
664
- rowPixelSpacing === calibratedRowSpacing &&
665
- columnPixelSpacing === calibratedPixelSpacing
666
- ) {
667
- // No calibration is required
668
- return imagePlaneModule;
669
- }
670
-
671
- // Calibration is required
611
+ this.calibration = calibration;
672
612
  this._publishCalibratedEvent = true;
673
-
674
613
  this._calibrationEvent = <CalibrationEvent>{
675
- rowScale: calibratedRowSpacing / rowPixelSpacing,
676
- columnScale: calibratedColumnSpacing / columnPixelSpacing,
614
+ scale,
615
+ calibration,
677
616
  };
678
617
 
679
618
  return imagePlaneModule;
@@ -2717,28 +2656,20 @@ class StackViewport extends Viewport implements IStackViewport {
2717
2656
  imageId
2718
2657
  );
2719
2658
 
2659
+ this.calibration ||= imagePlaneModule.calibration;
2660
+
2720
2661
  const newImagePlaneModule: ImagePlaneModule = {
2721
2662
  ...imagePlaneModule,
2722
2663
  };
2723
2664
 
2724
- if (calibratedPixelSpacing?.appliedSpacing) {
2725
- // Over-ride the image plane module spacing, as the measurement data
2726
- // has already been created with the calibrated spacing provided from
2727
- // down below inside calibrateIfNecessary
2728
- const { rowPixelSpacing, columnPixelSpacing } =
2729
- calibratedPixelSpacing.appliedSpacing;
2730
- newImagePlaneModule.rowPixelSpacing = rowPixelSpacing;
2731
- newImagePlaneModule.columnPixelSpacing = columnPixelSpacing;
2732
- }
2733
-
2734
2665
  if (!newImagePlaneModule.columnPixelSpacing) {
2735
2666
  newImagePlaneModule.columnPixelSpacing = 1;
2736
- this.hasPixelSpacing = false;
2667
+ this.hasPixelSpacing = this.calibration?.scale > 0;
2737
2668
  }
2738
2669
 
2739
2670
  if (!newImagePlaneModule.rowPixelSpacing) {
2740
2671
  newImagePlaneModule.rowPixelSpacing = 1;
2741
- this.hasPixelSpacing = false;
2672
+ this.hasPixelSpacing = this.calibration?.scale > 0;
2742
2673
  }
2743
2674
 
2744
2675
  if (!newImagePlaneModule.columnCosines) {
@@ -27,6 +27,7 @@ import type {
27
27
  import type { ViewportInput, IViewport } from '../types/IViewport';
28
28
  import type { vtkSlabCamera } from './vtkClasses/vtkSlabCamera';
29
29
  import { getConfiguration } from '../init';
30
+ import IImageCalibration from '../types/IImageCalibration';
30
31
 
31
32
  /**
32
33
  * An object representing a single viewport, which is a camera
@@ -74,6 +75,7 @@ class Viewport implements IViewport {
74
75
  /** A flag representing if viewport methods should fire events or not */
75
76
  readonly suppressEvents: boolean;
76
77
  protected hasPixelSpacing = true;
78
+ protected calibration: IImageCalibration;
77
79
  /** The camera that is initially defined on the reset for
78
80
  * the relative pan/zoom
79
81
  */
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Defines the calibration types available. These define how the units
3
+ * for measurements are specified.
4
+ */
5
+ export enum CalibrationTypes {
6
+ /**
7
+ * Not applicable means the units are directly defind by the underlying
8
+ * hardware, such as CT and MR volumetric displays, so no special handling
9
+ * or notification is required.
10
+ */
11
+ NOT_APPLICABLE = '',
12
+ /**
13
+ * ERMF is estimated radiographic magnification factor. This defines how
14
+ * much the image is magnified at the detector as opposed to the location in
15
+ * the body of interest. This occurs because the radiation beam is expanding
16
+ * and effectively magnifies the image on the detector compared to where the
17
+ * point of interest in the body is.
18
+ * This suggests that measurements can be partially trusted, but the user
19
+ * still needs to be aware that different depths within the body have differing
20
+ * ERMF values, so precise measurements would still need to be manually calibrated.
21
+ */
22
+ ERMF = 'ERMF',
23
+ /**
24
+ * User calibration means that the user has provided a custom calibration
25
+ * specifying how large the image data is. This type can occur on
26
+ * volumetric images, eg for scout images that might have invalid spacing
27
+ * tags.
28
+ */
29
+ USER = 'User',
30
+ /**
31
+ * A projection calibration means the raw detector size, without any
32
+ * ERMF applied, meaning that the size in the body cannot be trusted and
33
+ * that a calibration should be applied.
34
+ * This is different from Error in that there is simply no magnification
35
+ * factor applied as opposed to having multiple, inconsistent magnification
36
+ * factors.
37
+ */
38
+ PROJECTION = 'Proj',
39
+ /**
40
+ * A region calibration is used for other types of images, typically
41
+ * ultrasouunds where the distance in the image may mean something other than
42
+ * physical distance, such as mV or Hz or some other measurement values.
43
+ */
44
+ REGION = 'Region',
45
+ /**
46
+ * Error is used to define mismatches between various units, such as when
47
+ * there are two different ERMF values specified. This is an indication to
48
+ * NOT trust the measurement values but to manually calibrate.
49
+ */
50
+ ERROR = 'Error',
51
+ /** Uncalibrated image */
52
+ UNCALIBRATED = 'Uncalibrated',
53
+ }
54
+
55
+ export default CalibrationTypes;
@@ -75,6 +75,15 @@ enum Events {
75
75
  * and see what event detail is included in {@link EventTypes.ImageVolumeModifiedEventDetail | ImageVolumeModified Event Detail }
76
76
  */
77
77
  IMAGE_VOLUME_MODIFIED = 'CORNERSTONE_IMAGE_VOLUME_MODIFIED',
78
+ /**
79
+ * Triggers on the eventTarget when the image volume loading is completed and all
80
+ * frames are loaded and inserted into a volume.
81
+ *
82
+ * Make use of {@link EventTypes.ImageVolumeLoadingCompletedEvent | ImageVolumeLoadingCompleted Event Type } for typing your
83
+ * event listeners for IMAGE_VOLUME_LOADING_COMPLETED event, and see what event detail is included
84
+ * in {@link EventTypes.ImageVolumeLoadingCompletedEventDetail | ImageVolumeLoadingCompleted Event Detail }
85
+ */
86
+ IMAGE_VOLUME_LOADING_COMPLETED = 'CORNERSTONE_IMAGE_VOLUME_LOADING_COMPLETED',
78
87
  /**
79
88
  * Triggers on the eventTarget when the image has successfully loaded by imageLoaders
80
89
  *
@@ -9,11 +9,13 @@ import GeometryType from './GeometryType';
9
9
  import ContourType from './ContourType';
10
10
  import VOILUTFunctionType from './VOILUTFunctionType';
11
11
  import DynamicOperatorType from './DynamicOperatorType';
12
+ import CalibrationTypes from './CalibrationTypes';
12
13
  import ViewportStatus from './ViewportStatus';
13
14
 
14
15
  export {
15
16
  Events,
16
17
  BlendModes,
18
+ CalibrationTypes,
17
19
  InterpolationType,
18
20
  RequestType,
19
21
  ViewportType,
@@ -1,4 +1,5 @@
1
1
  import { Point3, Scaling, Mat3, PixelDataTypedArray } from '../types';
2
+ import IImageCalibration from './IImageCalibration';
2
3
 
3
4
  type CPUImageData = {
4
5
  worldToIndex?: (point: Point3) => Point3;
@@ -24,6 +25,8 @@ type CPUIImageData = {
24
25
  scaling: Scaling;
25
26
  /** whether the image has pixel spacing and it is not undefined */
26
27
  hasPixelSpacing?: boolean;
28
+ calibration?: IImageCalibration;
29
+
27
30
  /** preScale object */
28
31
  preScale?: {
29
32
  /** boolean flag to indicate whether the image has been scaled */
@@ -10,6 +10,7 @@ import type { VOIRange } from './voi';
10
10
  import type VOILUTFunctionType from '../enums/VOILUTFunctionType';
11
11
  import type ViewportStatus from '../enums/ViewportStatus';
12
12
  import type DisplayArea from './displayArea';
13
+ import IImageCalibration from './IImageCalibration';
13
14
 
14
15
  /**
15
16
  * CAMERA_MODIFIED Event's data
@@ -110,6 +111,16 @@ type ImageVolumeModifiedEventDetail = {
110
111
  FrameOfReferenceUID: string;
111
112
  };
112
113
 
114
+ /**
115
+ * IMAGE_VOLUME_LOADING_COMPLETED Event's data
116
+ */
117
+ type ImageVolumeLoadingCompletedEventDetail = {
118
+ /** the loaded volume */
119
+ volumeId: string;
120
+ /** FrameOfReferenceUID where the volume belongs to */
121
+ FrameOfReferenceUID: string;
122
+ };
123
+
113
124
  /**
114
125
  * IMAGE_LOADED Event's data
115
126
  */
@@ -228,8 +239,8 @@ type ImageSpacingCalibratedEventDetail = {
228
239
  viewportId: string;
229
240
  renderingEngineId: string;
230
241
  imageId: string;
231
- rowScale: number;
232
- columnScale: number;
242
+ /** calibration contains the scaling information as well as other calibration info */
243
+ calibration: IImageCalibration;
233
244
  imageData: vtkImageData;
234
245
  worldToIndex: mat4;
235
246
  };
@@ -307,6 +318,14 @@ type ImageRenderedEvent = CustomEventType<ElementEnabledEventDetail>;
307
318
  */
308
319
  type ImageVolumeModifiedEvent = CustomEventType<ImageVolumeModifiedEventDetail>;
309
320
 
321
+ /**
322
+ * IMAGE_VOLUME_LOADING_COMPLETED Event type
323
+ * This event is fired when a volume is fully loaded, means all the frames
324
+ * are loaded and cached.
325
+ */
326
+ type ImageVolumeLoadingCompletedEvent =
327
+ CustomEventType<ImageVolumeLoadingCompletedEventDetail>;
328
+
310
329
  /**
311
330
  * IMAGE_LOADED Event type
312
331
  */
@@ -400,6 +419,8 @@ export type {
400
419
  ImageRenderedEvent,
401
420
  ImageVolumeModifiedEvent,
402
421
  ImageVolumeModifiedEventDetail,
422
+ ImageVolumeLoadingCompletedEvent,
423
+ ImageVolumeLoadingCompletedEventDetail,
403
424
  ImageLoadedEvent,
404
425
  ImageLoadedEventDetail,
405
426
  ImageLoadedFailedEventDetail,
@@ -0,0 +1,41 @@
1
+ import CalibrationTypes from '../enums/CalibrationTypes';
2
+
3
+ /**
4
+ * IImageCalibration is an object that stores information about the type
5
+ * of image calibration.
6
+ */
7
+ export interface IImageCalibration {
8
+ /**
9
+ * The pixel spacing for the image, in mm between pixel centers
10
+ * These are not required, and are deprecated in favour of getting the original
11
+ * image spacing and then applying the transforms. The values here should
12
+ * be identical to original spacing.
13
+ */
14
+ rowPixelSpacing?: number;
15
+ columnPixelSpacing?: number;
16
+ /** The scaling of measurement values relative to the base pixel spacing (1 if not specified) */
17
+ scale?: number;
18
+ /**
19
+ * The calibration aspect ratio for non-square calibrations.
20
+ * This is the aspect ratio similar to the scale above that applies when
21
+ * the viewport is displaying non-square image pixels as square screen pixels.
22
+ *
23
+ * Defaults to 1 if not specified, and is also 1 if the Viewport has squared
24
+ * up the image pixels so that they are displayed as a square.
25
+ * Not well handled currently as this needs to be incorporated into
26
+ * tools when doing calculations.
27
+ */
28
+ aspect?: number;
29
+ /** The type of the pixel spacing, distinguishing between various
30
+ * types projection (CR/DX/MG) spacing and volumetric spacing (the type is
31
+ * an empty string as it doesn't get a suffix, but this distinguishes it
32
+ * from other types)
33
+ */
34
+ type: CalibrationTypes;
35
+ /** A tooltip which can be used to explain the calibration information */
36
+ tooltip?: string;
37
+ /** The DICOM defined ultrasound regions. Used for non-distance spacing units. */
38
+ sequenceOfUltrasoundRegions?: Record<string, unknown>[];
39
+ }
40
+
41
+ export default IImageCalibration;
@@ -1,5 +1,6 @@
1
1
  import type { vtkImageData } from '@kitware/vtk.js/Common/DataModel/ImageData';
2
2
  import { Point3, Scaling, Mat3 } from '../types';
3
+ import IImageCalibration from './IImageCalibration';
3
4
 
4
5
  /**
5
6
  * IImageData of an image, which stores actual scalarData and metaData about the image.
@@ -24,6 +25,9 @@ interface IImageData {
24
25
  scaling?: Scaling;
25
26
  /** whether the image has pixel spacing and it is not undefined */
26
27
  hasPixelSpacing?: boolean;
28
+
29
+ calibration?: IImageCalibration;
30
+
27
31
  /** preScale object */
28
32
  preScale?: {
29
33
  /** boolean flag to indicate whether the image has been scaled */
@@ -30,6 +30,7 @@ import type Plane from './Plane';
30
30
  import type IStreamingImageVolume from './IStreamingImageVolume';
31
31
  import type ViewportInputOptions from './ViewportInputOptions';
32
32
  import type IImageData from './IImageData';
33
+ import type IImageCalibration from './IImageCalibration';
33
34
  import type CPUIImageData from './CPUIImageData';
34
35
  import type { CPUImageData } from './CPUIImageData';
35
36
  import type IImage from './IImage';
@@ -102,6 +103,7 @@ export type {
102
103
  IStreamingImageVolume,
103
104
  IImage,
104
105
  IImageData,
106
+ IImageCalibration,
105
107
  CPUIImageData,
106
108
  CPUImageData,
107
109
  EventTypes,
@@ -1,13 +1,7 @@
1
1
  import imageIdToURI from './imageIdToURI';
2
+ import { IImageCalibration } from '../types';
2
3
 
3
- export type CalibratedPixelValue = {
4
- rowPixelSpacing: number;
5
- columnPixelSpacing: number;
6
- // These values get updated by the viewport after the change to record the applied value
7
- appliedSpacing?: CalibratedPixelValue;
8
- };
9
-
10
- const state: Record<string, CalibratedPixelValue> = {}; // Calibrated pixel spacing per imageId
4
+ const state: Record<string, IImageCalibration> = {}; // Calibrated pixel spacing per imageId
11
5
 
12
6
  /**
13
7
  * Simple metadataProvider object to store metadata for calibrated spacings.
@@ -20,7 +14,7 @@ const metadataProvider = {
20
14
  * @param imageId - the imageId for the metadata to store
21
15
  * @param payload - the payload composed of new calibrated pixel spacings
22
16
  */
23
- add: (imageId: string, payload: CalibratedPixelValue): void => {
17
+ add: (imageId: string, payload: IImageCalibration): void => {
24
18
  const imageURI = imageIdToURI(imageId);
25
19
  state[imageURI] = payload;
26
20
  },
@@ -31,7 +25,7 @@ const metadataProvider = {
31
25
  * @param imageId - the imageId to enquire about
32
26
  * @returns the calibrated pixel spacings for the imageId if it exists, otherwise undefined
33
27
  */
34
- get: (type: string, imageId: string): CalibratedPixelValue => {
28
+ get: (type: string, imageId: string): IImageCalibration => {
35
29
  if (type === 'calibratedPixelSpacing') {
36
30
  const imageURI = imageIdToURI(imageId);
37
31
  return state[imageURI];
@@ -23,12 +23,15 @@ export default function imageToWorldCoords(
23
23
 
24
24
  const {
25
25
  columnCosines,
26
- columnPixelSpacing,
27
26
  rowCosines,
28
- rowPixelSpacing,
29
27
  imagePositionPatient: origin,
30
28
  } = imagePlaneModule;
31
29
 
30
+ let { columnPixelSpacing, rowPixelSpacing } = imagePlaneModule;
31
+ // Use ||= to convert null and 0 as well as undefined to 1
32
+ columnPixelSpacing ||= 1;
33
+ rowPixelSpacing ||= 1;
34
+
32
35
  // calculate the image coordinates in the world space
33
36
  const imageCoordsInWorld = vec3.create();
34
37
 
@@ -27,14 +27,15 @@ function worldToImageCoords(
27
27
 
28
28
  const {
29
29
  columnCosines,
30
- columnPixelSpacing,
31
30
  rowCosines,
32
- rowPixelSpacing,
33
31
  imagePositionPatient: origin,
34
- rows,
35
- columns,
36
32
  } = imagePlaneModule;
37
33
 
34
+ let { columnPixelSpacing, rowPixelSpacing } = imagePlaneModule;
35
+ // Use ||= to convert null and 0 as well as undefined to 1
36
+ columnPixelSpacing ||= 1;
37
+ rowPixelSpacing ||= 1;
38
+
38
39
  // The origin is the image position patient, but since image coordinates start
39
40
  // from [0,0] for the top left hand of the first pixel, and the origin is at the
40
41
  // center of the first pixel, we need to account for this.