@cornerstonejs/core 1.32.3 → 1.34.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.
- package/dist/cjs/RenderingEngine/StackViewport.d.ts +24 -3
- package/dist/cjs/RenderingEngine/StackViewport.js +47 -31
- package/dist/cjs/RenderingEngine/StackViewport.js.map +1 -1
- package/dist/cjs/RenderingEngine/helpers/addImageSlicesToViewports.d.ts +3 -0
- package/dist/cjs/RenderingEngine/helpers/addImageSlicesToViewports.js +33 -0
- package/dist/cjs/RenderingEngine/helpers/addImageSlicesToViewports.js.map +1 -0
- package/dist/cjs/RenderingEngine/helpers/index.d.ts +2 -1
- package/dist/cjs/RenderingEngine/helpers/index.js +3 -1
- package/dist/cjs/RenderingEngine/helpers/index.js.map +1 -1
- package/dist/cjs/cache/cache.d.ts +2 -1
- package/dist/cjs/cache/cache.js +11 -0
- package/dist/cjs/cache/cache.js.map +1 -1
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.js +2 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/loaders/imageLoader.d.ts +21 -1
- package/dist/cjs/loaders/imageLoader.js +97 -1
- package/dist/cjs/loaders/imageLoader.js.map +1 -1
- package/dist/cjs/loaders/volumeLoader.d.ts +2 -2
- package/dist/cjs/loaders/volumeLoader.js +6 -28
- package/dist/cjs/loaders/volumeLoader.js.map +1 -1
- package/dist/cjs/types/IImage.d.ts +1 -0
- package/dist/cjs/types/IStackInput.d.ts +12 -0
- package/dist/cjs/types/IStackInput.js +3 -0
- package/dist/cjs/types/IStackInput.js.map +1 -0
- package/dist/cjs/types/IStackViewport.d.ts +3 -0
- package/dist/cjs/types/PixelDataTypedArray.d.ts +1 -0
- package/dist/cjs/types/index.d.ts +3 -2
- package/dist/cjs/utilities/calculateViewportsSpatialRegistration.d.ts +2 -2
- package/dist/cjs/utilities/calculateViewportsSpatialRegistration.js.map +1 -1
- package/dist/cjs/utilities/genericMetadataProvider.d.ts +6 -0
- package/dist/cjs/utilities/genericMetadataProvider.js +23 -0
- package/dist/cjs/utilities/genericMetadataProvider.js.map +1 -0
- package/dist/cjs/utilities/getBufferConfiguration.d.ts +9 -0
- package/dist/cjs/utilities/getBufferConfiguration.js +47 -0
- package/dist/cjs/utilities/getBufferConfiguration.js.map +1 -0
- package/dist/cjs/utilities/index.d.ts +7 -1
- package/dist/cjs/utilities/index.js +13 -1
- package/dist/cjs/utilities/index.js.map +1 -1
- package/dist/cjs/utilities/isValidVolume.d.ts +2 -0
- package/dist/cjs/utilities/isValidVolume.js +35 -0
- package/dist/cjs/utilities/isValidVolume.js.map +1 -0
- package/dist/cjs/utilities/makeVolumeMetadata.d.ts +2 -0
- package/dist/cjs/utilities/makeVolumeMetadata.js +55 -0
- package/dist/cjs/utilities/makeVolumeMetadata.js.map +1 -0
- package/dist/cjs/utilities/sortImageIdsAndGetSpacing.d.ts +9 -0
- package/dist/cjs/utilities/sortImageIdsAndGetSpacing.js +82 -0
- package/dist/cjs/utilities/sortImageIdsAndGetSpacing.js.map +1 -0
- package/dist/cjs/utilities/updateVTKImageDataWithCornerstoneImage.d.ts +4 -0
- package/dist/cjs/utilities/updateVTKImageDataWithCornerstoneImage.js +27 -0
- package/dist/cjs/utilities/updateVTKImageDataWithCornerstoneImage.js.map +1 -0
- package/dist/esm/RenderingEngine/StackViewport.js +46 -32
- package/dist/esm/RenderingEngine/StackViewport.js.map +1 -1
- package/dist/esm/RenderingEngine/helpers/addImageSlicesToViewports.js +20 -0
- package/dist/esm/RenderingEngine/helpers/addImageSlicesToViewports.js.map +1 -0
- package/dist/esm/RenderingEngine/helpers/index.js +2 -1
- package/dist/esm/RenderingEngine/helpers/index.js.map +1 -1
- package/dist/esm/cache/cache.js +11 -0
- package/dist/esm/cache/cache.js.map +1 -1
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/loaders/imageLoader.js +94 -1
- package/dist/esm/loaders/imageLoader.js.map +1 -1
- package/dist/esm/loaders/volumeLoader.js +7 -29
- package/dist/esm/loaders/volumeLoader.js.map +1 -1
- package/dist/esm/types/IStackInput.js +2 -0
- package/dist/esm/types/IStackInput.js.map +1 -0
- package/dist/esm/utilities/calculateViewportsSpatialRegistration.js.map +1 -1
- package/dist/esm/utilities/genericMetadataProvider.js +20 -0
- package/dist/esm/utilities/genericMetadataProvider.js.map +1 -0
- package/dist/esm/utilities/getBufferConfiguration.js +44 -0
- package/dist/esm/utilities/getBufferConfiguration.js.map +1 -0
- package/dist/esm/utilities/index.js +7 -1
- package/dist/esm/utilities/index.js.map +1 -1
- package/dist/esm/utilities/isValidVolume.js +29 -0
- package/dist/esm/utilities/isValidVolume.js.map +1 -0
- package/dist/esm/utilities/makeVolumeMetadata.js +52 -0
- package/dist/esm/utilities/makeVolumeMetadata.js.map +1 -0
- package/dist/esm/utilities/sortImageIdsAndGetSpacing.js +79 -0
- package/dist/esm/utilities/sortImageIdsAndGetSpacing.js.map +1 -0
- package/dist/esm/utilities/updateVTKImageDataWithCornerstoneImage.js +24 -0
- package/dist/esm/utilities/updateVTKImageDataWithCornerstoneImage.js.map +1 -0
- package/dist/types/RenderingEngine/StackViewport.d.ts +24 -3
- package/dist/types/RenderingEngine/StackViewport.d.ts.map +1 -1
- package/dist/types/RenderingEngine/helpers/addImageSlicesToViewports.d.ts +4 -0
- package/dist/types/RenderingEngine/helpers/addImageSlicesToViewports.d.ts.map +1 -0
- package/dist/types/RenderingEngine/helpers/index.d.ts +2 -1
- package/dist/types/RenderingEngine/helpers/index.d.ts.map +1 -1
- package/dist/types/cache/cache.d.ts +2 -1
- package/dist/types/cache/cache.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/loaders/imageLoader.d.ts +21 -1
- package/dist/types/loaders/imageLoader.d.ts.map +1 -1
- package/dist/types/loaders/volumeLoader.d.ts +2 -2
- package/dist/types/loaders/volumeLoader.d.ts.map +1 -1
- package/dist/types/types/IImage.d.ts +1 -0
- package/dist/types/types/IImage.d.ts.map +1 -1
- package/dist/types/types/IStackInput.d.ts +13 -0
- package/dist/types/types/IStackInput.d.ts.map +1 -0
- package/dist/types/types/IStackViewport.d.ts +3 -0
- package/dist/types/types/IStackViewport.d.ts.map +1 -1
- package/dist/types/types/PixelDataTypedArray.d.ts +1 -0
- package/dist/types/types/PixelDataTypedArray.d.ts.map +1 -1
- package/dist/types/types/index.d.ts +3 -2
- package/dist/types/types/index.d.ts.map +1 -1
- package/dist/types/utilities/calculateViewportsSpatialRegistration.d.ts +2 -2
- package/dist/types/utilities/calculateViewportsSpatialRegistration.d.ts.map +1 -1
- package/dist/types/utilities/genericMetadataProvider.d.ts +7 -0
- package/dist/types/utilities/genericMetadataProvider.d.ts.map +1 -0
- package/dist/types/utilities/getBufferConfiguration.d.ts +10 -0
- package/dist/types/utilities/getBufferConfiguration.d.ts.map +1 -0
- package/dist/types/utilities/index.d.ts +7 -1
- package/dist/types/utilities/index.d.ts.map +1 -1
- package/dist/types/utilities/isValidVolume.d.ts +3 -0
- package/dist/types/utilities/isValidVolume.d.ts.map +1 -0
- package/dist/types/utilities/makeVolumeMetadata.d.ts +3 -0
- package/dist/types/utilities/makeVolumeMetadata.d.ts.map +1 -0
- package/dist/types/utilities/sortImageIdsAndGetSpacing.d.ts +10 -0
- package/dist/types/utilities/sortImageIdsAndGetSpacing.d.ts.map +1 -0
- package/dist/types/utilities/updateVTKImageDataWithCornerstoneImage.d.ts +5 -0
- package/dist/types/utilities/updateVTKImageDataWithCornerstoneImage.d.ts.map +1 -0
- package/dist/umd/index.js +1 -1
- package/dist/umd/index.js.map +1 -1
- package/package.json +2 -2
- package/src/RenderingEngine/StackViewport.ts +77 -52
- package/src/RenderingEngine/helpers/addImageSlicesToViewports.ts +54 -0
- package/src/RenderingEngine/helpers/index.ts +2 -0
- package/src/cache/cache.ts +22 -0
- package/src/index.ts +2 -0
- package/src/loaders/imageLoader.ts +202 -2
- package/src/loaders/volumeLoader.ts +18 -27
- package/src/types/IImage.ts +2 -0
- package/src/types/IStackInput.ts +30 -0
- package/src/types/IStackViewport.ts +10 -3
- package/src/types/PixelDataTypedArray.ts +8 -0
- package/src/types/index.ts +8 -1
- package/src/utilities/calculateViewportsSpatialRegistration.ts +3 -3
- package/src/utilities/genericMetadataProvider.ts +43 -0
- package/src/utilities/getBufferConfiguration.ts +69 -0
- package/src/utilities/index.ts +12 -0
- package/src/utilities/isValidVolume.ts +59 -0
- package/src/utilities/makeVolumeMetadata.ts +87 -0
- package/src/utilities/sortImageIdsAndGetSpacing.ts +174 -0
- 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.
|
|
3
|
+
"version": "1.34.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": "
|
|
50
|
+
"gitHead": "a1bdeb0d4083453272dbca7e8c5f445d30d1fd4c"
|
|
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
|
-
|
|
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
|
-
})
|
|
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
|
-
|
|
1604
|
+
const imageData = vtkImageData.newInstance();
|
|
1610
1605
|
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
};
|
package/src/cache/cache.ts
CHANGED
|
@@ -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 {
|
|
5
|
-
|
|
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 {
|
|
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:
|
|
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
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
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
|
-
|
|
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
|
|
302
|
+
volumeScalarData = new TypedArrayConstructor(buffer);
|
|
312
303
|
} else {
|
|
313
|
-
volumeScalarData = new
|
|
304
|
+
volumeScalarData = new TypedArrayConstructor(scalarLength);
|
|
314
305
|
}
|
|
315
306
|
|
|
316
307
|
// Todo: handle more than one component for segmentation (RGB)
|
package/src/types/IImage.ts
CHANGED
|
@@ -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 };
|