@cornerstonejs/core 1.75.2 → 1.76.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/helpers/addImageSlicesToViewports.d.ts +1 -1
- package/dist/cjs/RenderingEngine/helpers/addImageSlicesToViewports.js +2 -2
- package/dist/cjs/RenderingEngine/helpers/addImageSlicesToViewports.js.map +1 -1
- package/dist/cjs/loaders/imageLoader.js +6 -1
- package/dist/cjs/loaders/imageLoader.js.map +1 -1
- package/dist/cjs/types/IStackViewport.d.ts +2 -49
- package/dist/cjs/types/IStackViewport.js +1 -0
- package/dist/cjs/types/IStackViewport.js.map +1 -1
- package/dist/cjs/utilities/getScalingParameters.js +3 -2
- package/dist/cjs/utilities/getScalingParameters.js.map +1 -1
- package/dist/cjs/utilities/loadImageToCanvas.d.ts +21 -5
- package/dist/cjs/utilities/loadImageToCanvas.js +32 -17
- package/dist/cjs/utilities/loadImageToCanvas.js.map +1 -1
- package/dist/cjs/utilities/renderToCanvasCPU.d.ts +3 -2
- package/dist/cjs/utilities/renderToCanvasCPU.js +7 -2
- package/dist/cjs/utilities/renderToCanvasCPU.js.map +1 -1
- package/dist/cjs/utilities/renderToCanvasGPU.d.ts +5 -2
- package/dist/cjs/utilities/renderToCanvasGPU.js +45 -12
- package/dist/cjs/utilities/renderToCanvasGPU.js.map +1 -1
- package/dist/esm/RenderingEngine/helpers/addImageSlicesToViewports.js +2 -2
- package/dist/esm/RenderingEngine/helpers/addImageSlicesToViewports.js.map +1 -1
- package/dist/esm/loaders/imageLoader.js +13 -1
- package/dist/esm/loaders/imageLoader.js.map +1 -1
- package/dist/esm/types/IStackViewport.js +1 -1
- package/dist/esm/types/IStackViewport.js.map +1 -1
- package/dist/esm/utilities/getScalingParameters.js +2 -2
- package/dist/esm/utilities/getScalingParameters.js.map +1 -1
- package/dist/esm/utilities/loadImageToCanvas.js +33 -17
- package/dist/esm/utilities/loadImageToCanvas.js.map +1 -1
- package/dist/esm/utilities/renderToCanvasCPU.js +7 -2
- package/dist/esm/utilities/renderToCanvasCPU.js.map +1 -1
- package/dist/esm/utilities/renderToCanvasGPU.js +45 -12
- package/dist/esm/utilities/renderToCanvasGPU.js.map +1 -1
- package/dist/types/RenderingEngine/helpers/addImageSlicesToViewports.d.ts +1 -1
- package/dist/types/RenderingEngine/helpers/addImageSlicesToViewports.d.ts.map +1 -1
- package/dist/types/loaders/imageLoader.d.ts.map +1 -1
- package/dist/types/types/IStackViewport.d.ts +2 -49
- package/dist/types/types/IStackViewport.d.ts.map +1 -1
- package/dist/types/utilities/loadImageToCanvas.d.ts +21 -5
- package/dist/types/utilities/loadImageToCanvas.d.ts.map +1 -1
- package/dist/types/utilities/renderToCanvasCPU.d.ts +3 -2
- package/dist/types/utilities/renderToCanvasCPU.d.ts.map +1 -1
- package/dist/types/utilities/renderToCanvasGPU.d.ts +5 -2
- package/dist/types/utilities/renderToCanvasGPU.d.ts.map +1 -1
- package/dist/umd/index.js +1 -1
- package/dist/umd/index.js.map +1 -1
- package/package.json +2 -2
- package/src/RenderingEngine/helpers/addImageSlicesToViewports.ts +2 -5
- package/src/loaders/imageLoader.ts +20 -8
- package/src/types/IStackViewport.ts +2 -178
- package/src/utilities/getScalingParameters.ts +2 -2
- package/src/utilities/loadImageToCanvas.ts +93 -32
- package/src/utilities/renderToCanvasCPU.ts +10 -3
- package/src/utilities/renderToCanvasGPU.ts +61 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.76.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": "97c7f819997bdff7dda77b94e99c5ae2f7502fc5"
|
|
51
51
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { StackViewport } from '..';
|
|
2
1
|
import type {
|
|
3
2
|
IStackViewport,
|
|
4
3
|
IStackInput,
|
|
@@ -20,9 +19,7 @@ import type {
|
|
|
20
19
|
async function addImageSlicesToViewports(
|
|
21
20
|
renderingEngine: IRenderingEngine,
|
|
22
21
|
stackInputs: Array<IStackInput>,
|
|
23
|
-
viewportIds: Array<string
|
|
24
|
-
immediateRender = false,
|
|
25
|
-
suppressEvents = false
|
|
22
|
+
viewportIds: Array<string>
|
|
26
23
|
): Promise<void> {
|
|
27
24
|
// Check if all viewports are volumeViewports
|
|
28
25
|
for (const viewportId of viewportIds) {
|
|
@@ -45,7 +42,7 @@ async function addImageSlicesToViewports(
|
|
|
45
42
|
const addStackPromises = viewportIds.map(async (viewportId) => {
|
|
46
43
|
const viewport = renderingEngine.getViewport(viewportId) as IStackViewport;
|
|
47
44
|
|
|
48
|
-
return viewport.addImages(stackInputs
|
|
45
|
+
return viewport.addImages(stackInputs);
|
|
49
46
|
});
|
|
50
47
|
|
|
51
48
|
await Promise.all(addStackPromises);
|
|
@@ -283,14 +283,26 @@ export function createAndCacheDerivedImage(
|
|
|
283
283
|
);
|
|
284
284
|
const derivedImageId = imageId;
|
|
285
285
|
|
|
286
|
-
['
|
|
287
|
-
(
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
);
|
|
286
|
+
['imagePlaneModule', 'generalSeriesModule'].forEach((type) => {
|
|
287
|
+
genericMetadataProvider.add(derivedImageId, {
|
|
288
|
+
type,
|
|
289
|
+
metadata: metaData.get(type, referencedImageId),
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
const imagePixelModule = metaData.get('imagePixelModule', referencedImageId);
|
|
294
|
+
// TODO - add a general way to specify this
|
|
295
|
+
genericMetadataProvider.add(derivedImageId, {
|
|
296
|
+
type: 'imagePixelModule',
|
|
297
|
+
metadata: {
|
|
298
|
+
...imagePixelModule,
|
|
299
|
+
bitsAllocated: 8,
|
|
300
|
+
bitsStored: 8,
|
|
301
|
+
highBit: 7,
|
|
302
|
+
samplesPerPixel: 1,
|
|
303
|
+
pixelRepresentation: 0,
|
|
304
|
+
},
|
|
305
|
+
});
|
|
294
306
|
|
|
295
307
|
const localImage = createAndCacheLocalImage(
|
|
296
308
|
{ scalarData: imageScalarData, onCacheAdd, skipCreateBuffer },
|
|
@@ -1,179 +1,3 @@
|
|
|
1
|
-
import
|
|
2
|
-
import ICamera from './ICamera';
|
|
3
|
-
import IImageData from './IImageData';
|
|
4
|
-
import { IViewport } from './IViewport';
|
|
5
|
-
import Point2 from './Point2';
|
|
6
|
-
import Point3 from './Point3';
|
|
7
|
-
import { Scaling } from './ScalingParameters';
|
|
8
|
-
import StackViewportProperties from './StackViewportProperties';
|
|
9
|
-
import type IImage from './IImage';
|
|
10
|
-
import { IStackInput } from './IStackInput';
|
|
11
|
-
/**
|
|
12
|
-
* Interface for Stack Viewport
|
|
13
|
-
*/
|
|
14
|
-
export default interface IStackViewport extends IViewport {
|
|
15
|
-
modality: string;
|
|
16
|
-
/** Scaling parameters */
|
|
17
|
-
scaling: Scaling;
|
|
1
|
+
import type IStackViewport from '../RenderingEngine/StackViewport';
|
|
18
2
|
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Resizes the viewport - only used in CPU fallback for StackViewport. The
|
|
22
|
-
* GPU resizing happens inside the RenderingEngine.
|
|
23
|
-
*/
|
|
24
|
-
resize: () => void;
|
|
25
|
-
/**
|
|
26
|
-
* Returns the frame of reference UID, if the image doesn't have imagePlaneModule
|
|
27
|
-
* metadata, it returns undefined, otherwise, frameOfReferenceUID is returned.
|
|
28
|
-
*/
|
|
29
|
-
getFrameOfReferenceUID: () => string;
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Update the default properties of the viewport and add properties by imageId if specified
|
|
33
|
-
* setting the VOI, inverting the colors and setting the interpolation type, rotation
|
|
34
|
-
*/
|
|
35
|
-
setDefaultProperties(
|
|
36
|
-
ViewportProperties: StackViewportProperties,
|
|
37
|
-
imageId?: string
|
|
38
|
-
): void;
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Remove the global default properties of the viewport or remove default properties for an imageId if specified
|
|
42
|
-
*/
|
|
43
|
-
clearDefaultProperties(imageId?: string): void;
|
|
44
|
-
/**
|
|
45
|
-
* Sets the properties for the viewport on the default actor. Properties include
|
|
46
|
-
* setting the VOI, inverting the colors and setting the interpolation type, rotation
|
|
47
|
-
*/
|
|
48
|
-
setProperties(
|
|
49
|
-
{
|
|
50
|
-
voiRange,
|
|
51
|
-
invert,
|
|
52
|
-
interpolationType,
|
|
53
|
-
rotation,
|
|
54
|
-
colormap,
|
|
55
|
-
}: StackViewportProperties,
|
|
56
|
-
suppressEvents?: boolean
|
|
57
|
-
): void;
|
|
58
|
-
/**
|
|
59
|
-
* Retrieve the viewport default properties
|
|
60
|
-
*/
|
|
61
|
-
getDefaultProperties: (imageId?: string) => StackViewportProperties;
|
|
62
|
-
/**
|
|
63
|
-
* Retrieve the viewport properties
|
|
64
|
-
*/
|
|
65
|
-
getProperties: () => StackViewportProperties;
|
|
66
|
-
/**
|
|
67
|
-
* canvasToWorld Returns the world coordinates of the given `canvasPos`
|
|
68
|
-
* projected onto the plane defined by the `Viewport`'s camera.
|
|
69
|
-
*/
|
|
70
|
-
canvasToWorld: (canvasPos: Point2) => Point3;
|
|
71
|
-
/**
|
|
72
|
-
* Returns the canvas coordinates of the given `worldPos`
|
|
73
|
-
* projected onto the `Viewport`'s `canvas`.
|
|
74
|
-
*/
|
|
75
|
-
worldToCanvas: (worldPos: Point3) => Point2;
|
|
76
|
-
/**
|
|
77
|
-
* Returns the index of the imageId being renderer
|
|
78
|
-
*/
|
|
79
|
-
getCurrentImageIdIndex: () => number;
|
|
80
|
-
/**
|
|
81
|
-
* Returns the list of image Ids for the current viewport
|
|
82
|
-
*/
|
|
83
|
-
getImageIds: () => string[];
|
|
84
|
-
/**
|
|
85
|
-
* Returns true if the viewport contains the imageId
|
|
86
|
-
*/
|
|
87
|
-
hasImageId: (imageId: string) => boolean;
|
|
88
|
-
/**
|
|
89
|
-
* Returns true if the viewport contains the imageURI
|
|
90
|
-
*/
|
|
91
|
-
hasImageURI: (imageURI: string) => boolean;
|
|
92
|
-
/**
|
|
93
|
-
* Returns the currently rendered imageId
|
|
94
|
-
*/
|
|
95
|
-
getCurrentImageId: () => string;
|
|
96
|
-
/**
|
|
97
|
-
* Add Image Slices actors to the viewport
|
|
98
|
-
*/
|
|
99
|
-
addImages(
|
|
100
|
-
stackInputs: Array<IStackInput>,
|
|
101
|
-
immediateRender: boolean,
|
|
102
|
-
suppressEvents: boolean
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
getImageDataMetadata(image: IImage): any;
|
|
106
|
-
/**
|
|
107
|
-
* Custom rendering pipeline for the rendering for the CPU fallback
|
|
108
|
-
*/
|
|
109
|
-
customRenderViewportToCanvas: () => {
|
|
110
|
-
canvas: HTMLCanvasElement;
|
|
111
|
-
element: HTMLDivElement;
|
|
112
|
-
viewportId: string;
|
|
113
|
-
renderingEngineId: string;
|
|
114
|
-
};
|
|
115
|
-
/**
|
|
116
|
-
* Returns the image and its properties that is being shown inside the
|
|
117
|
-
* stack viewport. It returns, the image dimensions, image direction,
|
|
118
|
-
* image scalar data, vtkImageData object, metadata, and scaling (e.g., PET suvbw)
|
|
119
|
-
*/
|
|
120
|
-
getImageData(): IImageData | CPUIImageData;
|
|
121
|
-
/**
|
|
122
|
-
* Returns the raw/loaded image being shown inside the stack viewport.
|
|
123
|
-
*/
|
|
124
|
-
getCornerstoneImage: () => IImage;
|
|
125
|
-
/**
|
|
126
|
-
* Reset the viewport properties to the his default values if possible
|
|
127
|
-
*/
|
|
128
|
-
resetToDefaultProperties(): void;
|
|
129
|
-
/**
|
|
130
|
-
* Reset the viewport properties to the default metadata values
|
|
131
|
-
*/
|
|
132
|
-
resetProperties(): void;
|
|
133
|
-
/**
|
|
134
|
-
* If the user has selected CPU rendering, return the CPU camera, otherwise
|
|
135
|
-
* return the default camera
|
|
136
|
-
*/
|
|
137
|
-
getCamera(): ICamera;
|
|
138
|
-
/**
|
|
139
|
-
* Set the camera based on the provided camera object.
|
|
140
|
-
*/
|
|
141
|
-
setCamera(cameraInterface: ICamera): void;
|
|
142
|
-
/**
|
|
143
|
-
* Sets the imageIds to be visualized inside the stack viewport. It accepts
|
|
144
|
-
* list of imageIds, the index of the first imageId to be viewed. It is a
|
|
145
|
-
* asynchronous function that returns a promise resolving to imageId being
|
|
146
|
-
* displayed in the stack viewport.
|
|
147
|
-
*
|
|
148
|
-
* @param retrieveConfiguration - Set this to a progressive retriever of your
|
|
149
|
-
* choice for progressive retrieval, or leave empty for non-progressive.
|
|
150
|
-
*/
|
|
151
|
-
setStack(
|
|
152
|
-
imageIds: Array<string>,
|
|
153
|
-
currentImageIdIndex?: number
|
|
154
|
-
): Promise<string>;
|
|
155
|
-
/**
|
|
156
|
-
* Centers Pan and resets the zoom for stack viewport.
|
|
157
|
-
*/
|
|
158
|
-
resetCamera(resetPan?: boolean, resetZoom?: boolean): boolean;
|
|
159
|
-
/**
|
|
160
|
-
* Loads the image based on the provided imageIdIndex. It is an Async function which
|
|
161
|
-
* returns a promise that resolves to the imageId.
|
|
162
|
-
*/
|
|
163
|
-
setImageIdIndex(imageIdIndex: number): Promise<string>;
|
|
164
|
-
/**
|
|
165
|
-
* Calibrates the image with new metadata that has been added for imageId. To calibrate
|
|
166
|
-
* a viewport, you should add your calibration data manually to
|
|
167
|
-
* calibratedPixelSpacingMetadataProvider and call viewport.calibrateSpacing
|
|
168
|
-
* for it get applied.
|
|
169
|
-
*/
|
|
170
|
-
calibrateSpacing(imageId: string): void;
|
|
171
|
-
/**
|
|
172
|
-
* If the renderer is CPU based, throw an error. Otherwise, returns the `vtkRenderer` responsible for rendering the `Viewport`.
|
|
173
|
-
*/
|
|
174
|
-
getRenderer(): any;
|
|
175
|
-
/**
|
|
176
|
-
* It sets the colormap to the default colormap.
|
|
177
|
-
*/
|
|
178
|
-
unsetColormap(): void;
|
|
179
|
-
}
|
|
3
|
+
export default IStackViewport;
|
|
@@ -17,8 +17,8 @@ export default function getScalingParameters(
|
|
|
17
17
|
const { modality } = generalSeriesModule;
|
|
18
18
|
|
|
19
19
|
const scalingParameters = {
|
|
20
|
-
rescaleSlope: modalityLutModule.rescaleSlope,
|
|
21
|
-
rescaleIntercept: modalityLutModule.rescaleIntercept,
|
|
20
|
+
rescaleSlope: modalityLutModule.rescaleSlope || 1,
|
|
21
|
+
rescaleIntercept: modalityLutModule.rescaleIntercept ?? 0,
|
|
22
22
|
modality,
|
|
23
23
|
};
|
|
24
24
|
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
IImage,
|
|
3
|
+
ViewPresentation,
|
|
4
|
+
ViewReference,
|
|
5
|
+
ViewportInputOptions,
|
|
6
|
+
Point3,
|
|
7
|
+
IVolume,
|
|
8
|
+
} from '../types';
|
|
2
9
|
|
|
3
10
|
import { loadAndCacheImage } from '../loaders/imageLoader';
|
|
4
11
|
import * as metaData from '../metaData';
|
|
@@ -7,10 +14,52 @@ import imageLoadPoolManager from '../requestPool/imageLoadPoolManager';
|
|
|
7
14
|
import renderToCanvasGPU from './renderToCanvasGPU';
|
|
8
15
|
import renderToCanvasCPU from './renderToCanvasCPU';
|
|
9
16
|
import { getConfiguration } from '../init';
|
|
17
|
+
import cache from '../cache';
|
|
10
18
|
|
|
11
|
-
|
|
12
|
-
|
|
19
|
+
/**
|
|
20
|
+
* The original load image options specified just an image id, which is optimal
|
|
21
|
+
* for things like thumbnails rendering a single image.
|
|
22
|
+
*/
|
|
23
|
+
export type StackLoadImageOptions = {
|
|
13
24
|
imageId: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The full image load options allows specifying more parameters for both the
|
|
29
|
+
* presentation and the view so that a specific view can be referenced/displayed.
|
|
30
|
+
*/
|
|
31
|
+
export type FullImageLoadOptions = {
|
|
32
|
+
viewReference: ViewReference;
|
|
33
|
+
viewPresentation: ViewPresentation;
|
|
34
|
+
imageId: undefined;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The canvas load position allows for determining the rendered position of
|
|
39
|
+
* image data within the canvas, and can be used to map loaded canvas points
|
|
40
|
+
* to and from other viewport positions for things like external computations
|
|
41
|
+
* on the load image to canvas view and the viewport view (which may contain
|
|
42
|
+
* extraneous data such as segmentation and thus not be usable for external
|
|
43
|
+
* computations.)
|
|
44
|
+
*/
|
|
45
|
+
export type CanvasLoadPosition = {
|
|
46
|
+
origin: Point3;
|
|
47
|
+
topRight: Point3;
|
|
48
|
+
bottomLeft: Point3;
|
|
49
|
+
thicknessMm: number;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The image canvas can be loaded/set with various view conditions to specify the initial
|
|
54
|
+
* view as well as how and where ot render the image.
|
|
55
|
+
*/
|
|
56
|
+
export type LoadImageOptions = {
|
|
57
|
+
canvas: HTMLCanvasElement;
|
|
58
|
+
// Define the view specification as optional here, and then incorporate specific
|
|
59
|
+
// requirements in mix in types.
|
|
60
|
+
imageId?: string;
|
|
61
|
+
viewReference?: ViewReference;
|
|
62
|
+
viewPresentation?: ViewPresentation;
|
|
14
63
|
requestType?: RequestType;
|
|
15
64
|
priority?: number;
|
|
16
65
|
renderingEngineId?: string;
|
|
@@ -24,7 +73,7 @@ export interface LoadImageOptions {
|
|
|
24
73
|
physicalPixels?: boolean;
|
|
25
74
|
// Sets the viewport input options Defaults to scale to fit 110%
|
|
26
75
|
viewportOptions?: ViewportInputOptions;
|
|
27
|
-
}
|
|
76
|
+
} & (StackLoadImageOptions | FullImageLoadOptions);
|
|
28
77
|
|
|
29
78
|
/**
|
|
30
79
|
* Loads and renders an imageId to a Canvas. It will use the GPU rendering pipeline
|
|
@@ -46,55 +95,61 @@ export interface LoadImageOptions {
|
|
|
46
95
|
* @param useCPURendering - Force the use of the CPU rendering pipeline (default to false)
|
|
47
96
|
* @param thumbnail - Render a thumbnail image
|
|
48
97
|
* @param imageAspect - assign the width based on the aspect ratio of the image
|
|
49
|
-
* @param physicalPixels - set the width/height to the physical pixel size
|
|
50
98
|
* @returns - A promise that resolves when the image has been rendered with the imageId
|
|
51
99
|
*/
|
|
52
100
|
export default function loadImageToCanvas(
|
|
53
101
|
options: LoadImageOptions
|
|
54
|
-
): Promise<
|
|
102
|
+
): Promise<CanvasLoadPosition> {
|
|
55
103
|
const {
|
|
56
104
|
canvas,
|
|
57
105
|
imageId,
|
|
106
|
+
viewReference,
|
|
58
107
|
requestType = RequestType.Thumbnail,
|
|
59
108
|
priority = -5,
|
|
60
109
|
renderingEngineId = '_thumbnails',
|
|
61
110
|
useCPURendering = false,
|
|
62
111
|
thumbnail = false,
|
|
63
112
|
imageAspect = false,
|
|
64
|
-
|
|
65
|
-
viewportOptions,
|
|
113
|
+
viewportOptions: baseViewportOptions,
|
|
66
114
|
} = options;
|
|
115
|
+
const volumeId = viewReference?.volumeId;
|
|
116
|
+
const isVolume = volumeId && !imageId;
|
|
117
|
+
const viewportOptions =
|
|
118
|
+
viewReference && baseViewportOptions
|
|
119
|
+
? { ...baseViewportOptions, viewReference }
|
|
120
|
+
: baseViewportOptions;
|
|
67
121
|
|
|
68
|
-
const devicePixelRatio = window.devicePixelRatio || 1;
|
|
69
122
|
const renderFn = useCPURendering ? renderToCanvasCPU : renderToCanvasGPU;
|
|
70
123
|
|
|
71
124
|
return new Promise((resolve, reject) => {
|
|
72
|
-
function successCallback(
|
|
125
|
+
function successCallback(imageOrVolume: IImage | IVolume, imageId: string) {
|
|
73
126
|
const { modality } = metaData.get('generalSeriesModule', imageId) || {};
|
|
74
127
|
|
|
75
|
-
image
|
|
128
|
+
const image = !isVolume && (imageOrVolume as IImage);
|
|
129
|
+
const volume = isVolume && (imageOrVolume as IVolume);
|
|
130
|
+
if (image) {
|
|
131
|
+
image.isPreScaled = image.isPreScaled || image.preScale?.scaled;
|
|
132
|
+
}
|
|
76
133
|
|
|
77
134
|
if (thumbnail) {
|
|
78
135
|
canvas.height = 256;
|
|
79
136
|
canvas.width = 256;
|
|
80
137
|
}
|
|
81
|
-
if (
|
|
82
|
-
canvas.width = canvas.
|
|
83
|
-
canvas.height = canvas.offsetHeight * devicePixelRatio;
|
|
138
|
+
if (imageAspect && image) {
|
|
139
|
+
canvas.width = image && (canvas.height * image.width) / image.height;
|
|
84
140
|
}
|
|
85
|
-
|
|
86
|
-
|
|
141
|
+
canvas.style.width = `${canvas.width / devicePixelRatio}px`;
|
|
142
|
+
canvas.style.height = `${canvas.height / devicePixelRatio}px`;
|
|
143
|
+
if (volume && useCPURendering) {
|
|
144
|
+
reject(new Error('CPU rendering of volume not supported'));
|
|
87
145
|
}
|
|
88
|
-
|
|
89
146
|
renderFn(
|
|
90
147
|
canvas,
|
|
91
|
-
|
|
148
|
+
imageOrVolume,
|
|
92
149
|
modality,
|
|
93
150
|
renderingEngineId,
|
|
94
151
|
viewportOptions
|
|
95
|
-
).then(
|
|
96
|
-
resolve(imageId);
|
|
97
|
-
});
|
|
152
|
+
).then(resolve);
|
|
98
153
|
}
|
|
99
154
|
|
|
100
155
|
function errorCallback(error: Error, imageId: string) {
|
|
@@ -113,29 +168,35 @@ export default function loadImageToCanvas(
|
|
|
113
168
|
);
|
|
114
169
|
}
|
|
115
170
|
|
|
116
|
-
const { useNorm16Texture
|
|
117
|
-
getConfiguration().rendering;
|
|
118
|
-
const useNativeDataType = useNorm16Texture || preferSizeOverAccuracy;
|
|
171
|
+
const { useNorm16Texture } = getConfiguration().rendering;
|
|
119
172
|
|
|
120
173
|
// IMPORTANT: Request type should be passed if not the 'interaction'
|
|
121
174
|
// highest priority will be used for the request type in the imageRetrievalPool
|
|
122
175
|
const options = {
|
|
123
176
|
targetBuffer: {
|
|
124
|
-
type:
|
|
177
|
+
type: useNorm16Texture ? undefined : 'Float32Array',
|
|
125
178
|
},
|
|
126
179
|
preScale: {
|
|
127
180
|
enabled: true,
|
|
128
181
|
},
|
|
129
|
-
useNativeDataType,
|
|
130
182
|
useRGBA: !!useCPURendering,
|
|
131
183
|
requestType,
|
|
132
184
|
};
|
|
133
185
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
186
|
+
if (volumeId) {
|
|
187
|
+
const volume = cache.getVolume(volumeId) as unknown as IVolume;
|
|
188
|
+
if (!volume) {
|
|
189
|
+
reject(new Error(`Volume id ${volumeId} not found in cache`));
|
|
190
|
+
}
|
|
191
|
+
const useImageId = volume.imageIds[0];
|
|
192
|
+
successCallback(volume, useImageId);
|
|
193
|
+
} else {
|
|
194
|
+
imageLoadPoolManager.addRequest(
|
|
195
|
+
sendRequest.bind(null, imageId, null, options),
|
|
196
|
+
requestType,
|
|
197
|
+
{ imageId },
|
|
198
|
+
priority
|
|
199
|
+
);
|
|
200
|
+
}
|
|
140
201
|
});
|
|
141
202
|
}
|
|
@@ -2,11 +2,13 @@ import {
|
|
|
2
2
|
IImage,
|
|
3
3
|
CPUFallbackEnabledElement,
|
|
4
4
|
ViewportInputOptions,
|
|
5
|
+
IVolume,
|
|
5
6
|
} from '../types';
|
|
6
7
|
|
|
7
8
|
import getDefaultViewport from '../RenderingEngine/helpers/cpuFallback/rendering/getDefaultViewport';
|
|
8
9
|
import calculateTransform from '../RenderingEngine/helpers/cpuFallback/rendering/calculateTransform';
|
|
9
10
|
import drawImageSync from '../RenderingEngine/helpers/cpuFallback/drawImageSync';
|
|
11
|
+
import type { CanvasLoadPosition } from './loadImageToCanvas';
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
14
|
* Renders a cornerstone image object to a canvas.
|
|
@@ -17,11 +19,16 @@ import drawImageSync from '../RenderingEngine/helpers/cpuFallback/drawImageSync'
|
|
|
17
19
|
*/
|
|
18
20
|
export default function renderToCanvasCPU(
|
|
19
21
|
canvas: HTMLCanvasElement,
|
|
20
|
-
|
|
22
|
+
imageOrVolume: IImage | IVolume,
|
|
21
23
|
modality?: string,
|
|
22
24
|
_renderingEngineId?: string,
|
|
23
25
|
_viewportOptions?: ViewportInputOptions
|
|
24
|
-
): Promise<
|
|
26
|
+
): Promise<CanvasLoadPosition> {
|
|
27
|
+
const volume = imageOrVolume as IVolume;
|
|
28
|
+
if (volume.volumeId) {
|
|
29
|
+
throw new Error('Unsupported volume rendering for CPU');
|
|
30
|
+
}
|
|
31
|
+
const image = imageOrVolume as IImage;
|
|
25
32
|
const viewport = getDefaultViewport(canvas, image, modality);
|
|
26
33
|
|
|
27
34
|
const enabledElement: CPUFallbackEnabledElement = {
|
|
@@ -36,6 +43,6 @@ export default function renderToCanvasCPU(
|
|
|
36
43
|
const invalidated = true;
|
|
37
44
|
return new Promise((resolve, reject) => {
|
|
38
45
|
drawImageSync(enabledElement, invalidated);
|
|
39
|
-
resolve(
|
|
46
|
+
resolve(null);
|
|
40
47
|
});
|
|
41
48
|
}
|
|
@@ -2,11 +2,18 @@ import getOrCreateCanvas, {
|
|
|
2
2
|
EPSILON,
|
|
3
3
|
} from '../RenderingEngine/helpers/getOrCreateCanvas';
|
|
4
4
|
import { ViewportType, Events } from '../enums';
|
|
5
|
-
import
|
|
6
|
-
|
|
5
|
+
import {
|
|
6
|
+
IImage,
|
|
7
|
+
IStackViewport,
|
|
8
|
+
IVolume,
|
|
9
|
+
ViewportInputOptions,
|
|
10
|
+
IVolumeViewport,
|
|
11
|
+
ViewReference,
|
|
12
|
+
} from '../types';
|
|
7
13
|
import { getRenderingEngine } from '../RenderingEngine/getRenderingEngine';
|
|
8
14
|
import RenderingEngine from '../RenderingEngine';
|
|
9
15
|
import isPTPrescaledWithSUV from './isPTPrescaledWithSUV';
|
|
16
|
+
import { CanvasLoadPosition } from './loadImageToCanvas';
|
|
10
17
|
|
|
11
18
|
/**
|
|
12
19
|
* Renders an cornerstone image to a Canvas. This method will handle creation
|
|
@@ -23,26 +30,33 @@ import isPTPrescaledWithSUV from './isPTPrescaledWithSUV';
|
|
|
23
30
|
* renderToCanvasGPU(canvas, image)
|
|
24
31
|
* ```
|
|
25
32
|
* @param canvas - Canvas element to render to
|
|
26
|
-
* @param
|
|
33
|
+
* @param imageOrVolume - The image to render
|
|
27
34
|
* @param modality - [Default = undefined] The modality of the image
|
|
28
35
|
* @returns - A promise that resolves when the image has been rendered with the imageId
|
|
29
36
|
*/
|
|
30
37
|
export default function renderToCanvasGPU(
|
|
31
38
|
canvas: HTMLCanvasElement,
|
|
32
|
-
|
|
39
|
+
imageOrVolume: IImage | IVolume,
|
|
33
40
|
modality = undefined,
|
|
34
41
|
renderingEngineId = '_thumbnails',
|
|
35
|
-
viewportOptions: ViewportInputOptions
|
|
36
|
-
|
|
42
|
+
viewportOptions: ViewportInputOptions & { viewReference?: ViewReference } = {
|
|
43
|
+
displayArea: { imageArea: [1, 1] },
|
|
44
|
+
}
|
|
45
|
+
): Promise<CanvasLoadPosition> {
|
|
37
46
|
if (!canvas || !(canvas instanceof HTMLCanvasElement)) {
|
|
38
47
|
throw new Error('canvas element is required');
|
|
39
48
|
}
|
|
40
49
|
|
|
41
|
-
const
|
|
50
|
+
const isVolume = !(imageOrVolume as IImage).imageId;
|
|
51
|
+
const image = !isVolume && (imageOrVolume as IImage);
|
|
52
|
+
const volume = isVolume && (imageOrVolume as IVolume);
|
|
53
|
+
const imageIdToPrint = image?.imageId || volume?.volumeId;
|
|
42
54
|
const viewportId = `renderGPUViewport-${imageIdToPrint}`;
|
|
43
|
-
const imageId = image.imageId;
|
|
44
55
|
const element = document.createElement('div');
|
|
45
56
|
const devicePixelRatio = window.devicePixelRatio || 1;
|
|
57
|
+
if (!viewportOptions.displayArea) {
|
|
58
|
+
viewportOptions.displayArea = { imageArea: [1, 1] };
|
|
59
|
+
}
|
|
46
60
|
const originalWidth = canvas.width;
|
|
47
61
|
const originalHeight = canvas.height;
|
|
48
62
|
// The canvas width/height are set by flooring the CSS size converted
|
|
@@ -50,17 +64,12 @@ export default function renderToCanvasGPU(
|
|
|
50
64
|
// isn't exact, and using the exact value sometimes leads to an off by 1
|
|
51
65
|
// in the actual size, so adding EPSILON to the size resolves
|
|
52
66
|
// the problem.
|
|
53
|
-
|
|
54
|
-
element.style.
|
|
67
|
+
// Don't touch the canvas size here as what we get out is a canvas at the right size
|
|
68
|
+
element.style.width = `${originalWidth / devicePixelRatio + EPSILON}px`;
|
|
69
|
+
element.style.height = `${originalHeight / devicePixelRatio + EPSILON}px`;
|
|
55
70
|
element.style.visibility = 'hidden';
|
|
56
71
|
element.style.position = 'absolute';
|
|
57
72
|
|
|
58
|
-
// Up-sampling the provided canvas to match the device pixel ratio
|
|
59
|
-
// since we use device pixel ratio to determine the size of the canvas
|
|
60
|
-
// inside the rendering engine.
|
|
61
|
-
canvas.width = originalWidth * devicePixelRatio;
|
|
62
|
-
canvas.height = originalHeight * devicePixelRatio;
|
|
63
|
-
|
|
64
73
|
document.body.appendChild(element);
|
|
65
74
|
|
|
66
75
|
// add id to the element so we can find it later, and fix the : which is not allowed in css
|
|
@@ -73,20 +82,20 @@ export default function renderToCanvasGPU(
|
|
|
73
82
|
(getRenderingEngine(renderingEngineId) as RenderingEngine) ||
|
|
74
83
|
new RenderingEngine(renderingEngineId);
|
|
75
84
|
|
|
76
|
-
let viewport = renderingEngine.getViewport(viewportId)
|
|
85
|
+
let viewport = renderingEngine.getViewport(viewportId);
|
|
77
86
|
|
|
78
87
|
if (!viewport) {
|
|
79
|
-
const
|
|
88
|
+
const viewportInput = {
|
|
80
89
|
viewportId,
|
|
81
|
-
type: ViewportType.STACK,
|
|
90
|
+
type: isVolume ? ViewportType.ORTHOGRAPHIC : ViewportType.STACK,
|
|
82
91
|
element,
|
|
83
92
|
defaultOptions: {
|
|
84
93
|
...viewportOptions,
|
|
85
94
|
suppressEvents: true,
|
|
86
95
|
},
|
|
87
96
|
};
|
|
88
|
-
renderingEngine.enableElement(
|
|
89
|
-
viewport = renderingEngine.getViewport(viewportId)
|
|
97
|
+
renderingEngine.enableElement(viewportInput);
|
|
98
|
+
viewport = renderingEngine.getViewport(viewportId);
|
|
90
99
|
}
|
|
91
100
|
|
|
92
101
|
return new Promise((resolve) => {
|
|
@@ -94,11 +103,20 @@ export default function renderToCanvasGPU(
|
|
|
94
103
|
// enable it and later disable it without losing the canvas context
|
|
95
104
|
let elementRendered = false;
|
|
96
105
|
|
|
106
|
+
let { viewReference } = viewportOptions;
|
|
107
|
+
|
|
97
108
|
// Create a named function to handle the event
|
|
98
109
|
const onImageRendered = (eventDetail) => {
|
|
99
110
|
if (elementRendered) {
|
|
100
111
|
return;
|
|
101
112
|
}
|
|
113
|
+
if (viewReference) {
|
|
114
|
+
const useViewRef = viewReference;
|
|
115
|
+
viewReference = null;
|
|
116
|
+
viewport.setViewReference(useViewRef);
|
|
117
|
+
viewport.render();
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
102
120
|
|
|
103
121
|
// Copy the temporary canvas to the given canvas
|
|
104
122
|
const context = canvas.getContext('2d');
|
|
@@ -114,6 +132,16 @@ export default function renderToCanvasGPU(
|
|
|
114
132
|
canvas.height // destination dimensions
|
|
115
133
|
);
|
|
116
134
|
|
|
135
|
+
const origin = viewport.canvasToWorld([0, 0]);
|
|
136
|
+
const topRight = viewport.canvasToWorld([
|
|
137
|
+
temporaryCanvas.width / devicePixelRatio,
|
|
138
|
+
0,
|
|
139
|
+
]);
|
|
140
|
+
const bottomLeft = viewport.canvasToWorld([
|
|
141
|
+
0,
|
|
142
|
+
temporaryCanvas.height / devicePixelRatio,
|
|
143
|
+
]);
|
|
144
|
+
const thicknessMm = 1;
|
|
117
145
|
elementRendered = true;
|
|
118
146
|
|
|
119
147
|
// remove based on id
|
|
@@ -135,17 +163,26 @@ export default function renderToCanvasGPU(
|
|
|
135
163
|
element.remove();
|
|
136
164
|
});
|
|
137
165
|
}, 0);
|
|
138
|
-
resolve(
|
|
166
|
+
resolve({
|
|
167
|
+
origin,
|
|
168
|
+
bottomLeft,
|
|
169
|
+
topRight,
|
|
170
|
+
thicknessMm,
|
|
171
|
+
});
|
|
139
172
|
};
|
|
140
173
|
|
|
141
174
|
element.addEventListener(Events.IMAGE_RENDERED, onImageRendered);
|
|
142
|
-
|
|
175
|
+
if (isVolume) {
|
|
176
|
+
(viewport as IVolumeViewport).setVolumes([volume], false, true);
|
|
177
|
+
} else {
|
|
178
|
+
(viewport as IStackViewport).renderImageObject(imageOrVolume);
|
|
179
|
+
}
|
|
143
180
|
|
|
144
181
|
// force a reset camera to center the image and undo the small scaling
|
|
145
182
|
viewport.resetCamera();
|
|
146
183
|
|
|
147
184
|
if (modality === 'PT' && !isPTPrescaledWithSUV(image)) {
|
|
148
|
-
viewport.setProperties({
|
|
185
|
+
(viewport as IStackViewport).setProperties({
|
|
149
186
|
voiRange: {
|
|
150
187
|
lower: image.minPixelValue,
|
|
151
188
|
upper: image.maxPixelValue,
|