@cornerstonejs/core 1.32.2 → 1.33.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 (163) hide show
  1. package/dist/cjs/RenderingEngine/StackViewport.d.ts +24 -3
  2. package/dist/cjs/RenderingEngine/StackViewport.js +47 -31
  3. package/dist/cjs/RenderingEngine/StackViewport.js.map +1 -1
  4. package/dist/cjs/RenderingEngine/helpers/addImageSlicesToViewports.d.ts +3 -0
  5. package/dist/cjs/RenderingEngine/helpers/addImageSlicesToViewports.js +33 -0
  6. package/dist/cjs/RenderingEngine/helpers/addImageSlicesToViewports.js.map +1 -0
  7. package/dist/cjs/RenderingEngine/helpers/index.d.ts +2 -1
  8. package/dist/cjs/RenderingEngine/helpers/index.js +3 -1
  9. package/dist/cjs/RenderingEngine/helpers/index.js.map +1 -1
  10. package/dist/cjs/cache/cache.d.ts +2 -1
  11. package/dist/cjs/cache/cache.js +11 -0
  12. package/dist/cjs/cache/cache.js.map +1 -1
  13. package/dist/cjs/index.d.ts +2 -2
  14. package/dist/cjs/index.js +2 -1
  15. package/dist/cjs/index.js.map +1 -1
  16. package/dist/cjs/loaders/imageLoader.d.ts +21 -1
  17. package/dist/cjs/loaders/imageLoader.js +97 -1
  18. package/dist/cjs/loaders/imageLoader.js.map +1 -1
  19. package/dist/cjs/loaders/volumeLoader.d.ts +2 -2
  20. package/dist/cjs/loaders/volumeLoader.js +6 -28
  21. package/dist/cjs/loaders/volumeLoader.js.map +1 -1
  22. package/dist/cjs/types/IImage.d.ts +1 -0
  23. package/dist/cjs/types/IStackInput.d.ts +12 -0
  24. package/dist/cjs/types/IStackInput.js +3 -0
  25. package/dist/cjs/types/IStackInput.js.map +1 -0
  26. package/dist/cjs/types/IStackViewport.d.ts +3 -0
  27. package/dist/cjs/types/PixelDataTypedArray.d.ts +1 -0
  28. package/dist/cjs/types/index.d.ts +3 -2
  29. package/dist/cjs/utilities/genericMetadataProvider.d.ts +6 -0
  30. package/dist/cjs/utilities/genericMetadataProvider.js +23 -0
  31. package/dist/cjs/utilities/genericMetadataProvider.js.map +1 -0
  32. package/dist/cjs/utilities/getBufferConfiguration.d.ts +9 -0
  33. package/dist/cjs/utilities/getBufferConfiguration.js +47 -0
  34. package/dist/cjs/utilities/getBufferConfiguration.js.map +1 -0
  35. package/dist/cjs/utilities/getTargetVolumeAndSpacingInNormalDir.d.ts +1 -1
  36. package/dist/cjs/utilities/getTargetVolumeAndSpacingInNormalDir.js +4 -4
  37. package/dist/cjs/utilities/getTargetVolumeAndSpacingInNormalDir.js.map +1 -1
  38. package/dist/cjs/utilities/getVolumeSliceRangeInfo.d.ts +1 -1
  39. package/dist/cjs/utilities/getVolumeSliceRangeInfo.js +2 -2
  40. package/dist/cjs/utilities/getVolumeSliceRangeInfo.js.map +1 -1
  41. package/dist/cjs/utilities/getVolumeViewportScrollInfo.d.ts +1 -1
  42. package/dist/cjs/utilities/getVolumeViewportScrollInfo.js +2 -2
  43. package/dist/cjs/utilities/getVolumeViewportScrollInfo.js.map +1 -1
  44. package/dist/cjs/utilities/index.d.ts +7 -1
  45. package/dist/cjs/utilities/index.js +13 -1
  46. package/dist/cjs/utilities/index.js.map +1 -1
  47. package/dist/cjs/utilities/isValidVolume.d.ts +2 -0
  48. package/dist/cjs/utilities/isValidVolume.js +35 -0
  49. package/dist/cjs/utilities/isValidVolume.js.map +1 -0
  50. package/dist/cjs/utilities/makeVolumeMetadata.d.ts +2 -0
  51. package/dist/cjs/utilities/makeVolumeMetadata.js +55 -0
  52. package/dist/cjs/utilities/makeVolumeMetadata.js.map +1 -0
  53. package/dist/cjs/utilities/sortImageIdsAndGetSpacing.d.ts +9 -0
  54. package/dist/cjs/utilities/sortImageIdsAndGetSpacing.js +82 -0
  55. package/dist/cjs/utilities/sortImageIdsAndGetSpacing.js.map +1 -0
  56. package/dist/cjs/utilities/updateVTKImageDataWithCornerstoneImage.d.ts +4 -0
  57. package/dist/cjs/utilities/updateVTKImageDataWithCornerstoneImage.js +27 -0
  58. package/dist/cjs/utilities/updateVTKImageDataWithCornerstoneImage.js.map +1 -0
  59. package/dist/esm/RenderingEngine/StackViewport.js +46 -32
  60. package/dist/esm/RenderingEngine/StackViewport.js.map +1 -1
  61. package/dist/esm/RenderingEngine/helpers/addImageSlicesToViewports.js +20 -0
  62. package/dist/esm/RenderingEngine/helpers/addImageSlicesToViewports.js.map +1 -0
  63. package/dist/esm/RenderingEngine/helpers/index.js +2 -1
  64. package/dist/esm/RenderingEngine/helpers/index.js.map +1 -1
  65. package/dist/esm/cache/cache.js +11 -0
  66. package/dist/esm/cache/cache.js.map +1 -1
  67. package/dist/esm/index.js +2 -2
  68. package/dist/esm/index.js.map +1 -1
  69. package/dist/esm/loaders/imageLoader.js +94 -1
  70. package/dist/esm/loaders/imageLoader.js.map +1 -1
  71. package/dist/esm/loaders/volumeLoader.js +7 -29
  72. package/dist/esm/loaders/volumeLoader.js.map +1 -1
  73. package/dist/esm/types/IStackInput.js +2 -0
  74. package/dist/esm/types/IStackInput.js.map +1 -0
  75. package/dist/esm/utilities/genericMetadataProvider.js +20 -0
  76. package/dist/esm/utilities/genericMetadataProvider.js.map +1 -0
  77. package/dist/esm/utilities/getBufferConfiguration.js +44 -0
  78. package/dist/esm/utilities/getBufferConfiguration.js.map +1 -0
  79. package/dist/esm/utilities/getTargetVolumeAndSpacingInNormalDir.js +4 -4
  80. package/dist/esm/utilities/getTargetVolumeAndSpacingInNormalDir.js.map +1 -1
  81. package/dist/esm/utilities/getVolumeSliceRangeInfo.js +2 -2
  82. package/dist/esm/utilities/getVolumeSliceRangeInfo.js.map +1 -1
  83. package/dist/esm/utilities/getVolumeViewportScrollInfo.js +2 -2
  84. package/dist/esm/utilities/getVolumeViewportScrollInfo.js.map +1 -1
  85. package/dist/esm/utilities/index.js +7 -1
  86. package/dist/esm/utilities/index.js.map +1 -1
  87. package/dist/esm/utilities/isValidVolume.js +29 -0
  88. package/dist/esm/utilities/isValidVolume.js.map +1 -0
  89. package/dist/esm/utilities/makeVolumeMetadata.js +52 -0
  90. package/dist/esm/utilities/makeVolumeMetadata.js.map +1 -0
  91. package/dist/esm/utilities/sortImageIdsAndGetSpacing.js +79 -0
  92. package/dist/esm/utilities/sortImageIdsAndGetSpacing.js.map +1 -0
  93. package/dist/esm/utilities/updateVTKImageDataWithCornerstoneImage.js +24 -0
  94. package/dist/esm/utilities/updateVTKImageDataWithCornerstoneImage.js.map +1 -0
  95. package/dist/types/RenderingEngine/StackViewport.d.ts +24 -3
  96. package/dist/types/RenderingEngine/StackViewport.d.ts.map +1 -1
  97. package/dist/types/RenderingEngine/helpers/addImageSlicesToViewports.d.ts +4 -0
  98. package/dist/types/RenderingEngine/helpers/addImageSlicesToViewports.d.ts.map +1 -0
  99. package/dist/types/RenderingEngine/helpers/index.d.ts +2 -1
  100. package/dist/types/RenderingEngine/helpers/index.d.ts.map +1 -1
  101. package/dist/types/cache/cache.d.ts +2 -1
  102. package/dist/types/cache/cache.d.ts.map +1 -1
  103. package/dist/types/index.d.ts +2 -2
  104. package/dist/types/index.d.ts.map +1 -1
  105. package/dist/types/loaders/imageLoader.d.ts +21 -1
  106. package/dist/types/loaders/imageLoader.d.ts.map +1 -1
  107. package/dist/types/loaders/volumeLoader.d.ts +2 -2
  108. package/dist/types/loaders/volumeLoader.d.ts.map +1 -1
  109. package/dist/types/types/IImage.d.ts +1 -0
  110. package/dist/types/types/IImage.d.ts.map +1 -1
  111. package/dist/types/types/IStackInput.d.ts +13 -0
  112. package/dist/types/types/IStackInput.d.ts.map +1 -0
  113. package/dist/types/types/IStackViewport.d.ts +3 -0
  114. package/dist/types/types/IStackViewport.d.ts.map +1 -1
  115. package/dist/types/types/PixelDataTypedArray.d.ts +1 -0
  116. package/dist/types/types/PixelDataTypedArray.d.ts.map +1 -1
  117. package/dist/types/types/index.d.ts +3 -2
  118. package/dist/types/types/index.d.ts.map +1 -1
  119. package/dist/types/utilities/genericMetadataProvider.d.ts +7 -0
  120. package/dist/types/utilities/genericMetadataProvider.d.ts.map +1 -0
  121. package/dist/types/utilities/getBufferConfiguration.d.ts +10 -0
  122. package/dist/types/utilities/getBufferConfiguration.d.ts.map +1 -0
  123. package/dist/types/utilities/getTargetVolumeAndSpacingInNormalDir.d.ts +1 -1
  124. package/dist/types/utilities/getTargetVolumeAndSpacingInNormalDir.d.ts.map +1 -1
  125. package/dist/types/utilities/getVolumeSliceRangeInfo.d.ts +1 -1
  126. package/dist/types/utilities/getVolumeSliceRangeInfo.d.ts.map +1 -1
  127. package/dist/types/utilities/getVolumeViewportScrollInfo.d.ts +1 -1
  128. package/dist/types/utilities/getVolumeViewportScrollInfo.d.ts.map +1 -1
  129. package/dist/types/utilities/index.d.ts +7 -1
  130. package/dist/types/utilities/index.d.ts.map +1 -1
  131. package/dist/types/utilities/isValidVolume.d.ts +3 -0
  132. package/dist/types/utilities/isValidVolume.d.ts.map +1 -0
  133. package/dist/types/utilities/makeVolumeMetadata.d.ts +3 -0
  134. package/dist/types/utilities/makeVolumeMetadata.d.ts.map +1 -0
  135. package/dist/types/utilities/sortImageIdsAndGetSpacing.d.ts +10 -0
  136. package/dist/types/utilities/sortImageIdsAndGetSpacing.d.ts.map +1 -0
  137. package/dist/types/utilities/updateVTKImageDataWithCornerstoneImage.d.ts +5 -0
  138. package/dist/types/utilities/updateVTKImageDataWithCornerstoneImage.d.ts.map +1 -0
  139. package/dist/umd/index.js +1 -1
  140. package/dist/umd/index.js.map +1 -1
  141. package/package.json +2 -2
  142. package/src/RenderingEngine/StackViewport.ts +77 -52
  143. package/src/RenderingEngine/helpers/addImageSlicesToViewports.ts +54 -0
  144. package/src/RenderingEngine/helpers/index.ts +2 -0
  145. package/src/cache/cache.ts +22 -0
  146. package/src/index.ts +2 -0
  147. package/src/loaders/imageLoader.ts +202 -2
  148. package/src/loaders/volumeLoader.ts +18 -27
  149. package/src/types/IImage.ts +2 -0
  150. package/src/types/IStackInput.ts +30 -0
  151. package/src/types/IStackViewport.ts +10 -3
  152. package/src/types/PixelDataTypedArray.ts +8 -0
  153. package/src/types/index.ts +8 -1
  154. package/src/utilities/genericMetadataProvider.ts +43 -0
  155. package/src/utilities/getBufferConfiguration.ts +69 -0
  156. package/src/utilities/getTargetVolumeAndSpacingInNormalDir.ts +9 -5
  157. package/src/utilities/getVolumeSliceRangeInfo.ts +10 -2
  158. package/src/utilities/getVolumeViewportScrollInfo.ts +5 -2
  159. package/src/utilities/index.ts +12 -0
  160. package/src/utilities/isValidVolume.ts +59 -0
  161. package/src/utilities/makeVolumeMetadata.ts +87 -0
  162. package/src/utilities/sortImageIdsAndGetSpacing.ts +174 -0
  163. package/src/utilities/updateVTKImageDataWithCornerstoneImage.ts +38 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/core",
3
- "version": "1.32.2",
3
+ "version": "1.33.0",
4
4
  "description": "",
5
5
  "main": "src/index.ts",
6
6
  "types": "dist/types/index.d.ts",
@@ -47,5 +47,5 @@
47
47
  "type": "individual",
48
48
  "url": "https://ohif.org/donate"
49
49
  },
50
- "gitHead": "c6c2dfdee7f3b1137fae77d9154809267076dc87"
50
+ "gitHead": "bcfcf24cacbc6d230a3ddc722823d5ecc05cbb6d"
51
51
  }
@@ -21,6 +21,7 @@ import {
21
21
  isImageActor,
22
22
  actorIsA,
23
23
  colormap as colormapUtils,
24
+ updateVTKImageDataWithCornerstoneImage,
24
25
  imageRetrieveMetadataProvider,
25
26
  } from '../utilities';
26
27
  import type {
@@ -44,6 +45,7 @@ import type {
44
45
  Mat3,
45
46
  ColormapPublic,
46
47
  IImageCalibration,
48
+ IStackInput,
47
49
  IImagesLoader,
48
50
  ImageLoadListener,
49
51
  } from '../types';
@@ -1489,7 +1491,7 @@ class StackViewport extends Viewport implements IStackViewport, IImagesLoader {
1489
1491
  * @returns image metadata: bitsAllocated, number of components, origin,
1490
1492
  * direction, dimensions, spacing, number of voxels.
1491
1493
  */
1492
- private _getImageDataMetadata(image: IImage): ImageDataMetaData {
1494
+ public getImageDataMetadata(image: IImage): ImageDataMetaData {
1493
1495
  // TODO: Creating a single image should probably not require a metadata provider.
1494
1496
  // We should define the minimum we need to display an image and it should live on
1495
1497
  // the Image object itself. Additional stuff (e.g. pixel spacing, direction, origin, etc)
@@ -1582,21 +1584,14 @@ class StackViewport extends Viewport implements IStackViewport, IImagesLoader {
1582
1584
  };
1583
1585
  }
1584
1586
 
1585
- /**
1586
- * Creates vtkImagedata based on the image object, it creates
1587
- * and empty scalar data for the image based on the metadata
1588
- * tags (e.g., bitsAllocated)
1589
- *
1590
- * @param image - cornerstone Image object
1591
- */
1592
- private _createVTKImageData({
1587
+ createVTKImageData({
1593
1588
  origin,
1594
1589
  direction,
1595
1590
  dimensions,
1596
1591
  spacing,
1597
1592
  numComps,
1598
1593
  pixelArray,
1599
- }): void {
1594
+ }) {
1600
1595
  const values = new pixelArray.constructor(pixelArray.length);
1601
1596
 
1602
1597
  // Todo: I guess nothing should be done for use16bit?
@@ -1606,13 +1601,39 @@ class StackViewport extends Viewport implements IStackViewport, IImagesLoader {
1606
1601
  values: values,
1607
1602
  });
1608
1603
 
1609
- this._imageData = vtkImageData.newInstance();
1604
+ const imageData = vtkImageData.newInstance();
1610
1605
 
1611
- this._imageData.setDimensions(dimensions);
1612
- this._imageData.setSpacing(spacing);
1613
- this._imageData.setDirection(direction);
1614
- this._imageData.setOrigin(origin);
1615
- this._imageData.getPointData().setScalars(scalarArray);
1606
+ imageData.setDimensions(dimensions);
1607
+ imageData.setSpacing(spacing);
1608
+ imageData.setDirection(direction);
1609
+ imageData.setOrigin(origin);
1610
+ imageData.getPointData().setScalars(scalarArray);
1611
+
1612
+ return imageData;
1613
+ }
1614
+ /**
1615
+ * Creates vtkImagedata based on the image object, it creates
1616
+ * empty scalar data for the image based on the metadata
1617
+ * tags (e.g., bitsAllocated)
1618
+ *
1619
+ * @param image - cornerstone Image object
1620
+ */
1621
+ private _createVTKImageData({
1622
+ origin,
1623
+ direction,
1624
+ dimensions,
1625
+ spacing,
1626
+ numComps,
1627
+ pixelArray,
1628
+ }): void {
1629
+ this._imageData = this.createVTKImageData({
1630
+ origin,
1631
+ direction,
1632
+ dimensions,
1633
+ spacing,
1634
+ numComps,
1635
+ pixelArray,
1636
+ });
1616
1637
  }
1617
1638
 
1618
1639
  /**
@@ -1750,40 +1771,7 @@ class StackViewport extends Viewport implements IStackViewport, IImagesLoader {
1750
1771
 
1751
1772
  // Update the pixel data in the vtkImageData object with the pixelData
1752
1773
  // from the loaded Cornerstone image
1753
- this._updatePixelData(image);
1754
- }
1755
-
1756
- private _updatePixelData(image: IImage) {
1757
- const pixelData = image.getPixelData();
1758
- const scalars = this._imageData.getPointData().getScalars();
1759
- const scalarData = scalars.getData() as
1760
- | Uint8Array
1761
- | Float32Array
1762
- | Uint16Array
1763
- | Int16Array;
1764
-
1765
- // if the color image is loaded with CPU previously, it loads it
1766
- // with RGBA, and here we need to remove the A channel from the
1767
- // pixel data.
1768
- if (image.color && image.rgba) {
1769
- const newPixelData = new Uint8Array(image.columns * image.rows * 3);
1770
- for (let i = 0; i < image.columns * image.rows; i++) {
1771
- newPixelData[i * 3] = pixelData[i * 4];
1772
- newPixelData[i * 3 + 1] = pixelData[i * 4 + 1];
1773
- newPixelData[i * 3 + 2] = pixelData[i * 4 + 2];
1774
- }
1775
- // modify the image object to have the correct pixel data for later
1776
- // use.
1777
- image.rgba = false;
1778
- image.getPixelData = () => newPixelData;
1779
- scalarData.set(newPixelData);
1780
- } else {
1781
- scalarData.set(pixelData);
1782
- }
1783
-
1784
- // Trigger modified on the VTK Object so the texture is updated
1785
- // TODO: evaluate directly changing things with texSubImage3D later
1786
- this._imageData.modified();
1774
+ updateVTKImageDataWithCornerstoneImage(this._imageData, image);
1787
1775
  }
1788
1776
 
1789
1777
  /**
@@ -2117,7 +2105,7 @@ class StackViewport extends Viewport implements IStackViewport, IImagesLoader {
2117
2105
  };
2118
2106
 
2119
2107
  private _updateToDisplayImageCPU(image: IImage) {
2120
- const metadata = this._getImageDataMetadata(image) as ImageDataMetaData;
2108
+ const metadata = this.getImageDataMetadata(image) as ImageDataMetaData;
2121
2109
 
2122
2110
  const viewport = getDefaultViewport(
2123
2111
  this.canvas,
@@ -2159,6 +2147,43 @@ class StackViewport extends Viewport implements IStackViewport, IImagesLoader {
2159
2147
  );
2160
2148
  }
2161
2149
 
2150
+ /**
2151
+ * This method is used to add images to the stack viewport.
2152
+ * It takes an array of stack inputs, each containing an imageId and an actor UID.
2153
+ * For each stack input, it retrieves the image from the cache and creates a VTK image data object.
2154
+ * It then creates an actor mapper for the image data and adds it to the list of actors.
2155
+ * Finally, it sets the actors for the stack viewport.
2156
+ *
2157
+ * @param stackInputs - An array of stack inputs, each containing an image ID and an actor UID.
2158
+ */
2159
+ public async addImages(stackInputs: Array<IStackInput>): Promise<void> {
2160
+ const actors = this.getActors();
2161
+ stackInputs.forEach((stackInput) => {
2162
+ const image = cache.getImage(stackInput.imageId);
2163
+
2164
+ const { origin, dimensions, direction, spacing, numComps } =
2165
+ this.getImageDataMetadata(image);
2166
+
2167
+ const imagedata = this.createVTKImageData({
2168
+ origin,
2169
+ dimensions,
2170
+ direction,
2171
+ spacing,
2172
+ numComps,
2173
+ pixelArray: image.getPixelData(),
2174
+ });
2175
+
2176
+ const imageActor = this.createActorMapper(imagedata);
2177
+ if (imageActor) {
2178
+ actors.push({ uid: stackInput.actorUID, actor: imageActor });
2179
+ if (stackInput.callback) {
2180
+ stackInput.callback({ imageActor, imageId: stackInput.imageId });
2181
+ }
2182
+ }
2183
+ });
2184
+ this.setActors(actors);
2185
+ }
2186
+
2162
2187
  /**
2163
2188
  * It updates the volume actor with the retrieved cornerstone image.
2164
2189
  * It first checks if the new image has the same dimensions, spacings, and
@@ -2245,7 +2270,7 @@ class StackViewport extends Viewport implements IStackViewport, IImagesLoader {
2245
2270
  spacing,
2246
2271
  numComps,
2247
2272
  imagePixelModule,
2248
- } = this._getImageDataMetadata(image);
2273
+ } = this.getImageDataMetadata(image);
2249
2274
 
2250
2275
  // 3b. If we cannot reuse the vtkImageData object (either the first render
2251
2276
  // or the size has changed), create a new one
@@ -0,0 +1,54 @@
1
+ import { StackViewport } from '..';
2
+ import type {
3
+ IStackViewport,
4
+ IStackInput,
5
+ IRenderingEngine,
6
+ } from '../../types';
7
+
8
+ /**
9
+ * For each provided viewport it adds a volume to the viewport using the
10
+ * provided renderingEngine
11
+ *
12
+ *
13
+ * @param renderingEngine - The rendering engine to use to get viewports from
14
+ * @param volumeInputs - Array of volume inputs including volumeId. Other properties
15
+ * such as visibility, callback, blendMode, slabThickness are optional
16
+ * @param viewportIds - Array of viewport IDs to add the volume to
17
+ * @param immediateRender - If true, the volumes will be rendered immediately
18
+ * @returns A promise that resolves when all volumes have been added
19
+ */
20
+ async function addImageSlicesToViewports(
21
+ renderingEngine: IRenderingEngine,
22
+ stackInputs: Array<IStackInput>,
23
+ viewportIds: Array<string>,
24
+ immediateRender = false,
25
+ suppressEvents = false
26
+ ): Promise<void> {
27
+ // Check if all viewports are volumeViewports
28
+ for (const viewportId of viewportIds) {
29
+ const viewport = renderingEngine.getViewport(viewportId);
30
+
31
+ if (!viewport) {
32
+ throw new Error(`Viewport with Id ${viewportId} does not exist`);
33
+ }
34
+
35
+ // if not instance of BaseVolumeViewport, throw
36
+ if (!(viewport instanceof StackViewport)) {
37
+ console.warn(
38
+ `Viewport with Id ${viewportId} is not a StackViewport. Cannot add image segmentation to this viewport.`
39
+ );
40
+
41
+ return;
42
+ }
43
+ }
44
+
45
+ const addStackPromises = viewportIds.map(async (viewportId) => {
46
+ const viewport = renderingEngine.getViewport(viewportId) as IStackViewport;
47
+
48
+ return viewport.addImages(stackInputs, immediateRender, suppressEvents);
49
+ });
50
+
51
+ await Promise.all(addStackPromises);
52
+ }
53
+
54
+ export default addImageSlicesToViewports;
@@ -4,6 +4,7 @@ import getOrCreateCanvas from './getOrCreateCanvas';
4
4
  import setVolumesForViewports from './setVolumesForViewports';
5
5
  import addVolumesToViewports from './addVolumesToViewports';
6
6
  import volumeNewImageEventDispatcher from './volumeNewImageEventDispatcher';
7
+ import addImageSlicesToViewports from './addImageSlicesToViewports';
7
8
 
8
9
  export {
9
10
  createVolumeActor,
@@ -11,5 +12,6 @@ export {
11
12
  getOrCreateCanvas,
12
13
  setVolumesForViewports,
13
14
  addVolumesToViewports,
15
+ addImageSlicesToViewports,
14
16
  volumeNewImageEventDispatcher,
15
17
  };
@@ -655,6 +655,28 @@ class Cache implements ICache {
655
655
  return cachedGeometry.geometry;
656
656
  };
657
657
 
658
+ /**
659
+ * Returns the image associated with the imageId
660
+ *
661
+ * @param imageId - image ID
662
+ * @returns Image
663
+ */
664
+ public getImage = (imageId: string): IImage => {
665
+ if (imageId === undefined) {
666
+ throw new Error('getImage: imageId must not be undefined');
667
+ }
668
+ const cachedImage = this._imageCache.get(imageId);
669
+
670
+ if (cachedImage === undefined) {
671
+ return;
672
+ }
673
+
674
+ // Bump time stamp for cached volume (not used for anything for now)
675
+ cachedImage.timeStamp = Date.now();
676
+
677
+ return cachedImage.image;
678
+ };
679
+
658
680
  /**
659
681
  * Returns the volume associated with the volumeId
660
682
  *
package/src/index.ts CHANGED
@@ -67,6 +67,7 @@ import triggerEvent from './utilities/triggerEvent';
67
67
  import {
68
68
  setVolumesForViewports,
69
69
  addVolumesToViewports,
70
+ addImageSlicesToViewports,
70
71
  } from './RenderingEngine/helpers';
71
72
 
72
73
  // Add new types here so that they can be imported singly as required.
@@ -127,6 +128,7 @@ export {
127
128
  utilities,
128
129
  setVolumesForViewports,
129
130
  addVolumesToViewports,
131
+ addImageSlicesToViewports,
130
132
  //
131
133
  imageLoadPoolManager as requestPoolManager,
132
134
  imageRetrievalPoolManager,
@@ -1,15 +1,51 @@
1
1
  import cache from '../cache/cache';
2
2
  import Events from '../enums/Events';
3
3
  import eventTarget from '../eventTarget';
4
- import { triggerEvent } from '../utilities';
5
- import { IImage, ImageLoaderFn, IImageLoadObject, EventTypes } from '../types';
4
+ import {
5
+ genericMetadataProvider,
6
+ getBufferConfiguration,
7
+ triggerEvent,
8
+ uuidv4,
9
+ } from '../utilities';
10
+ import {
11
+ IImage,
12
+ ImageLoaderFn,
13
+ IImageLoadObject,
14
+ EventTypes,
15
+ Point2,
16
+ Point3,
17
+ Mat3,
18
+ PixelDataTypedArrayString,
19
+ PixelDataTypedArray,
20
+ } from '../types';
6
21
  import imageLoadPoolManager from '../requestPool/imageLoadPoolManager';
22
+ import { metaData } from '../';
7
23
 
8
24
  export interface ImageLoaderOptions {
9
25
  priority: number;
10
26
  requestType: string;
11
27
  additionalDetails?: Record<string, unknown>;
12
28
  }
29
+
30
+ interface DerivedImageOptions {
31
+ imageId?: string;
32
+ targetBufferType?: PixelDataTypedArrayString;
33
+ }
34
+
35
+ interface DerivedImages {
36
+ imageIds: Array<string>;
37
+ promises: Array<Promise<IImage>>;
38
+ }
39
+
40
+ interface LocalImageOptions {
41
+ scalarData?: PixelDataTypedArray;
42
+ targetBufferType?: PixelDataTypedArrayString;
43
+ dimensions?: Point2;
44
+ spacing?: Point3;
45
+ origin?: Point3;
46
+ direction?: Mat3;
47
+ }
48
+
13
49
  /**
14
50
  * This module deals with ImageLoaders, loading images and caching images
15
51
  */
@@ -183,6 +219,170 @@ export function loadAndCacheImages(
183
219
  return allPromises;
184
220
  }
185
221
 
222
+ /**
223
+ * Loads an image given an imageId and optional priority and returns a promise
224
+ * which will resolve to the loaded image object or fail if an error occurred.
225
+ * The image is stored in the cache.
226
+ *
227
+ * @param referencedImageId - A Cornerstone Image Object's imageId
228
+ * @param options - Options to be passed to the Image Loader
229
+ *
230
+ * @returns Image Loader Object
231
+ */
232
+ export function createAndCacheDerivedImage(
233
+ referencedImageId: string,
234
+ options: DerivedImageOptions = {},
235
+ preventCache = false
236
+ ): Promise<IImage> {
237
+ if (referencedImageId === undefined) {
238
+ throw new Error(
239
+ 'createAndCacheDerivedImage: parameter imageId must not be undefined'
240
+ );
241
+ }
242
+
243
+ if (options.imageId === undefined) {
244
+ options.imageId = `derived:${uuidv4()}`;
245
+ }
246
+
247
+ const imagePlaneModule = metaData.get('imagePlaneModule', referencedImageId);
248
+
249
+ const length = imagePlaneModule.rows * imagePlaneModule.columns;
250
+
251
+ const { TypedArrayConstructor } = getBufferConfiguration(
252
+ options.targetBufferType,
253
+ length
254
+ );
255
+
256
+ const imageScalarData = new TypedArrayConstructor(length);
257
+ const derivedImageId = options.imageId;
258
+
259
+ ['imagePixelModule', 'imagePlaneModule', 'generalSeriesModule'].forEach(
260
+ (type) => {
261
+ genericMetadataProvider.add(derivedImageId, {
262
+ type,
263
+ metadata: metaData.get(type, referencedImageId),
264
+ });
265
+ }
266
+ );
267
+
268
+ const localImage = createAndCacheLocalImage(
269
+ { scalarData: imageScalarData },
270
+ options.imageId,
271
+ true
272
+ );
273
+
274
+ const imageLoadObject = {
275
+ promise: Promise.resolve(localImage),
276
+ };
277
+
278
+ if (!preventCache) {
279
+ cache.putImageLoadObject(derivedImageId, imageLoadObject);
280
+ }
281
+ return imageLoadObject.promise;
282
+ }
283
+
284
+ /**
285
+ * Load and cache a list of imageIds
286
+ *
287
+ * @param referencedImageIds - list of imageIds
288
+ * @param getDerivedImageId - optional function to generate derived imageId name however you want
289
+ */
290
+ export function createAndCacheDerivedImages(
291
+ referencedImageIds: Array<string>,
292
+ getDerivedImageId?: (referencedImageId: string) => string
293
+ ): DerivedImages {
294
+ if (referencedImageIds?.length === 0) {
295
+ throw new Error(
296
+ 'createAndCacheDerivedImages: parameter imageIds must be list of image Ids'
297
+ );
298
+ }
299
+
300
+ const derivedImageIds = [];
301
+ const allPromises = referencedImageIds.map((referencedImageId, index) => {
302
+ const options: DerivedImageOptions = {
303
+ imageId: getDerivedImageId
304
+ ? getDerivedImageId(referencedImageId)
305
+ : `derived:${uuidv4()}`,
306
+ };
307
+ derivedImageIds.push(options.imageId);
308
+ return createAndCacheDerivedImage(referencedImageId, options);
309
+ });
310
+
311
+ return { imageIds: derivedImageIds, promises: allPromises };
312
+ }
313
+
314
+ export function createAndCacheLocalImage(
315
+ options: LocalImageOptions,
316
+ imageId: string,
317
+ preventCache = false
318
+ ): IImage {
319
+ const imagePlaneModule = metaData.get('imagePlaneModule', imageId);
320
+
321
+ const length = imagePlaneModule.rows * imagePlaneModule.columns;
322
+
323
+ const image = {
324
+ imageId: imageId,
325
+ intercept: 0,
326
+ windowCenter: 0,
327
+ windowWidth: 0,
328
+ color: false,
329
+ numComps: 1,
330
+ slope: 1,
331
+ minPixelValue: 0,
332
+ maxPixelValue: 255,
333
+ voiLUTFunction: undefined,
334
+ rows: imagePlaneModule.rows,
335
+ columns: imagePlaneModule.columns,
336
+ getCanvas: undefined, // todo: which canvas?
337
+ height: imagePlaneModule.rows,
338
+ width: imagePlaneModule.columns,
339
+ rgba: undefined, // todo: how
340
+ columnPixelSpacing: imagePlaneModule.columnPixelSpacing,
341
+ rowPixelSpacing: imagePlaneModule.rowPixelSpacing,
342
+ invert: false,
343
+ } as IImage;
344
+
345
+ if (options.scalarData) {
346
+ const imageScalarData = options.scalarData;
347
+
348
+ if (
349
+ !(
350
+ imageScalarData instanceof Uint8Array ||
351
+ imageScalarData instanceof Float32Array ||
352
+ imageScalarData instanceof Uint16Array ||
353
+ imageScalarData instanceof Int16Array
354
+ )
355
+ ) {
356
+ throw new Error(
357
+ 'To use createLocalVolume you should pass scalarData of type Uint8Array, Uint16Array, Int16Array or Float32Array'
358
+ );
359
+ }
360
+
361
+ image.sizeInBytes = imageScalarData.byteLength;
362
+ image.getPixelData = () => imageScalarData;
363
+ } else {
364
+ const { numBytes, TypedArrayConstructor } = getBufferConfiguration(
365
+ options.targetBufferType,
366
+ length
367
+ );
368
+
369
+ const imageScalarData = new TypedArrayConstructor(length);
370
+
371
+ image.sizeInBytes = numBytes;
372
+ image.getPixelData = () => imageScalarData;
373
+ }
374
+
375
+ const imageLoadObject = {
376
+ promise: Promise.resolve(image),
377
+ };
378
+
379
+ if (!preventCache) {
380
+ cache.putImageLoadObject(image.imageId, imageLoadObject);
381
+ }
382
+
383
+ return image;
384
+ }
385
+
186
386
  /**
187
387
  * Removes the imageId from the request pool manager and executes the `cancel`
188
388
  * function if it exists.
@@ -11,8 +11,14 @@ import cache from '../cache/cache';
11
11
  import Events from '../enums/Events';
12
12
  import eventTarget from '../eventTarget';
13
13
  import triggerEvent from '../utilities/triggerEvent';
14
- import { uuidv4 } from '../utilities';
15
- import { Point3, Metadata, EventTypes, Mat3 } from '../types';
14
+ import { getBufferConfiguration, uuidv4 } from '../utilities';
15
+ import {
16
+ Point3,
17
+ Metadata,
18
+ EventTypes,
19
+ Mat3,
20
+ PixelDataTypedArray,
21
+ } from '../types';
16
22
  import { getConfiguration } from '../init';
17
23
 
18
24
  interface VolumeLoaderOptions {
@@ -27,7 +33,7 @@ interface DerivedVolumeOptions {
27
33
  };
28
34
  }
29
35
  interface LocalVolumeOptions {
30
- scalarData: Float32Array | Uint8Array | Uint16Array | Int16Array;
36
+ scalarData: PixelDataTypedArray;
31
37
  metadata: Metadata;
32
38
  dimensions: Point3;
33
39
  spacing: Point3;
@@ -272,32 +278,17 @@ export async function createAndCacheDerivedVolume(
272
278
  const scalarData = referencedVolume.getScalarData();
273
279
  const scalarLength = scalarData.length;
274
280
 
275
- let numBytes, TypedArray;
276
-
277
281
  const { useNorm16Texture } = getConfiguration().rendering;
278
282
 
279
283
  // If target buffer is provided
280
- if (targetBuffer) {
281
- if (targetBuffer.type === 'Float32Array') {
282
- numBytes = scalarLength * 4;
283
- TypedArray = Float32Array;
284
- } else if (targetBuffer.type === 'Uint8Array') {
285
- numBytes = scalarLength;
286
- TypedArray = Uint8Array;
287
- } else if (useNorm16Texture && targetBuffer.type === 'Uint16Array') {
288
- numBytes = scalarLength * 2;
289
- TypedArray = Uint16Array;
290
- } else if (useNorm16Texture && targetBuffer.type === 'Int16Array') {
291
- numBytes = scalarLength * 2;
292
- TypedArray = Uint16Array;
293
- } else {
294
- throw new Error('TargetBuffer should be Float32Array or Uint8Array');
284
+ const { TypedArrayConstructor, numBytes } = getBufferConfiguration(
285
+ targetBuffer?.type,
286
+ scalarLength,
287
+ {
288
+ use16BitTexture: useNorm16Texture,
289
+ isVolumeBuffer: true,
295
290
  }
296
- } else {
297
- // Use float32 if no targetBuffer is provided
298
- numBytes = scalarLength * 4;
299
- TypedArray = Float32Array;
300
- }
291
+ );
301
292
 
302
293
  // check if there is enough space in unallocated + image Cache
303
294
  const isCacheable = cache.isCacheable(numBytes);
@@ -308,9 +299,9 @@ export async function createAndCacheDerivedVolume(
308
299
  let volumeScalarData;
309
300
  if (targetBuffer?.sharedArrayBuffer) {
310
301
  const buffer = new SharedArrayBuffer(numBytes);
311
- volumeScalarData = new TypedArray(buffer);
302
+ volumeScalarData = new TypedArrayConstructor(buffer);
312
303
  } else {
313
- volumeScalarData = new TypedArray(scalarLength);
304
+ volumeScalarData = new TypedArrayConstructor(scalarLength);
314
305
  }
315
306
 
316
307
  // Todo: handle more than one component for segmentation (RGB)
@@ -10,6 +10,8 @@ import { ImageQualityStatus } from '../enums';
10
10
  interface IImage {
11
11
  /** Image Id */
12
12
  imageId: string;
13
+ /** referenced imageId if this image is derived from */
14
+ referencedImageId?: string;
13
15
  sharedCacheKey?: string;
14
16
  /** Whether the image is Pre-scaled during loading */
15
17
  isPreScaled?: boolean;
@@ -0,0 +1,30 @@
1
+ import { ImageActor } from './IActor';
2
+
3
+ /**
4
+ * Stack input callback type, used to perform operations on the image data
5
+ * after it has been loaded.
6
+ */
7
+ type StackInputCallback = (params: {
8
+ /** vtk image actor */
9
+ imageActor: ImageActor;
10
+ /** unique image Id in the cache */
11
+ imageId: string;
12
+ }) => unknown;
13
+
14
+ /**
15
+ * StackInput that can be used to add an image actor to a viewport. It includes
16
+ * mandatory `imageId` but other options such as `visibility` and `callback`
17
+ * can also be provided
18
+ */
19
+ interface IStackInput {
20
+ /** imageId of the image in the cache */
21
+ imageId: string;
22
+ // actorUID of the imageActor being added
23
+ actorUID?: string;
24
+ /** Visibility of the image actor - by default it is true */
25
+ visibility?: boolean;
26
+ /** Callback to be called when the image is added to the viewport */
27
+ callback?: StackInputCallback;
28
+ }
29
+
30
+ export type { IStackInput, StackInputCallback };