@cornerstonejs/core 1.30.1 → 1.32.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.js +1 -0
- package/dist/cjs/RenderingEngine/StackViewport.js.map +1 -1
- package/dist/cjs/RenderingEngine/VideoViewport.d.ts +15 -2
- package/dist/cjs/RenderingEngine/VideoViewport.js +97 -33
- package/dist/cjs/RenderingEngine/VideoViewport.js.map +1 -1
- package/dist/cjs/RenderingEngine/Viewport.js +1 -1
- package/dist/cjs/RenderingEngine/Viewport.js.map +1 -1
- package/dist/cjs/enums/RequestType.d.ts +2 -1
- package/dist/cjs/enums/RequestType.js +1 -0
- package/dist/cjs/enums/RequestType.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/init.d.ts +2 -1
- package/dist/cjs/init.js +16 -1
- package/dist/cjs/init.js.map +1 -1
- package/dist/cjs/requestPool/requestPoolManager.d.ts +1 -2
- package/dist/cjs/requestPool/requestPoolManager.js +8 -10
- package/dist/cjs/requestPool/requestPoolManager.js.map +1 -1
- package/dist/cjs/types/IVideoViewport.d.ts +6 -1
- package/dist/cjs/utilities/getViewportsWithImageURI.js +6 -5
- package/dist/cjs/utilities/getViewportsWithImageURI.js.map +1 -1
- package/dist/cjs/webWorkerManager/webWorkerManager.d.ts +21 -0
- package/dist/cjs/webWorkerManager/webWorkerManager.js +167 -0
- package/dist/cjs/webWorkerManager/webWorkerManager.js.map +1 -0
- package/dist/esm/RenderingEngine/StackViewport.js +1 -0
- package/dist/esm/RenderingEngine/StackViewport.js.map +1 -1
- package/dist/esm/RenderingEngine/VideoViewport.js +97 -33
- package/dist/esm/RenderingEngine/VideoViewport.js.map +1 -1
- package/dist/esm/RenderingEngine/Viewport.js +1 -1
- package/dist/esm/RenderingEngine/Viewport.js.map +1 -1
- package/dist/esm/enums/RequestType.js +1 -0
- package/dist/esm/enums/RequestType.js.map +1 -1
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/init.js +12 -1
- package/dist/esm/init.js.map +1 -1
- package/dist/esm/requestPool/requestPoolManager.js +8 -10
- package/dist/esm/requestPool/requestPoolManager.js.map +1 -1
- package/dist/esm/utilities/getViewportsWithImageURI.js +6 -5
- package/dist/esm/utilities/getViewportsWithImageURI.js.map +1 -1
- package/dist/esm/webWorkerManager/webWorkerManager.js +132 -0
- package/dist/esm/webWorkerManager/webWorkerManager.js.map +1 -0
- package/dist/types/RenderingEngine/StackViewport.d.ts.map +1 -1
- package/dist/types/RenderingEngine/VideoViewport.d.ts +15 -2
- package/dist/types/RenderingEngine/VideoViewport.d.ts.map +1 -1
- package/dist/types/enums/RequestType.d.ts +2 -1
- package/dist/types/enums/RequestType.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/init.d.ts +2 -1
- package/dist/types/init.d.ts.map +1 -1
- package/dist/types/requestPool/requestPoolManager.d.ts +1 -2
- package/dist/types/requestPool/requestPoolManager.d.ts.map +1 -1
- package/dist/types/types/IVideoViewport.d.ts +6 -1
- package/dist/types/types/IVideoViewport.d.ts.map +1 -1
- package/dist/types/utilities/getViewportsWithImageURI.d.ts.map +1 -1
- package/dist/types/webWorkerManager/webWorkerManager.d.ts +22 -0
- package/dist/types/webWorkerManager/webWorkerManager.d.ts.map +1 -0
- package/dist/umd/index.js +1 -2
- package/dist/umd/index.js.map +1 -1
- package/package.json +3 -2
- package/src/RenderingEngine/StackViewport.ts +1 -0
- package/src/RenderingEngine/VideoViewport.ts +146 -28
- package/src/RenderingEngine/Viewport.ts +1 -1
- package/src/enums/RequestType.ts +3 -1
- package/src/index.ts +2 -0
- package/src/init.ts +18 -0
- package/src/requestPool/requestPoolManager.ts +9 -13
- package/src/types/IVideoViewport.ts +44 -4
- package/src/utilities/getViewportsWithImageURI.ts +6 -13
- package/src/webWorkerManager/webWorkerManager.js +218 -0
- package/dist/umd/index.js.LICENSE.txt +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.32.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "dist/types/index.d.ts",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@kitware/vtk.js": "27.3.1",
|
|
34
|
+
"comlink": "^4.4.1",
|
|
34
35
|
"detect-gpu": "^5.0.22",
|
|
35
36
|
"gl-matrix": "^3.4.3",
|
|
36
37
|
"lodash.clonedeep": "4.5.0"
|
|
@@ -46,5 +47,5 @@
|
|
|
46
47
|
"type": "individual",
|
|
47
48
|
"url": "https://ohif.org/donate"
|
|
48
49
|
},
|
|
49
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "c5094313cbe028576a1d332ed5366f888cdc8d2c"
|
|
50
51
|
}
|
|
@@ -25,6 +25,8 @@ import { getOrCreateCanvas } from './helpers';
|
|
|
25
25
|
* looking into an internal scene, and an associated target output `canvas`.
|
|
26
26
|
*/
|
|
27
27
|
class VideoViewport extends Viewport implements IVideoViewport {
|
|
28
|
+
public static frameRangeExtractor = /(\/frames\/|[&?]frameNumber=)([^/&?]*)/i;
|
|
29
|
+
|
|
28
30
|
public modality;
|
|
29
31
|
// Viewport Data
|
|
30
32
|
protected imageId: string;
|
|
@@ -35,11 +37,15 @@ class VideoViewport extends Viewport implements IVideoViewport {
|
|
|
35
37
|
private videoWidth = 0;
|
|
36
38
|
private videoHeight = 0;
|
|
37
39
|
|
|
38
|
-
private loop =
|
|
40
|
+
private loop = true;
|
|
39
41
|
private mute = true;
|
|
40
42
|
private isPlaying = false;
|
|
41
43
|
private scrollSpeed = 1;
|
|
42
44
|
private playbackRate = 1;
|
|
45
|
+
/**
|
|
46
|
+
* The range is the set of frames to play
|
|
47
|
+
*/
|
|
48
|
+
private frameRange: [number, number] = [0, 0];
|
|
43
49
|
|
|
44
50
|
protected metadata;
|
|
45
51
|
|
|
@@ -50,6 +56,9 @@ class VideoViewport extends Viewport implements IVideoViewport {
|
|
|
50
56
|
*/
|
|
51
57
|
private fps = 30;
|
|
52
58
|
|
|
59
|
+
/** The number of frames in the video */
|
|
60
|
+
private numberOfFrames = 0;
|
|
61
|
+
|
|
53
62
|
private videoCamera: InternalVideoCamera = {
|
|
54
63
|
panWorld: [0, 0],
|
|
55
64
|
parallelScale: 1,
|
|
@@ -156,14 +165,15 @@ class VideoViewport extends Viewport implements IVideoViewport {
|
|
|
156
165
|
origin = [0, 0, 0];
|
|
157
166
|
}
|
|
158
167
|
|
|
159
|
-
const xSpacing = imagePlaneModule.columnPixelSpacing;
|
|
160
|
-
const ySpacing = imagePlaneModule.rowPixelSpacing;
|
|
168
|
+
const xSpacing = imagePlaneModule.columnPixelSpacing || 1;
|
|
169
|
+
const ySpacing = imagePlaneModule.rowPixelSpacing || 1;
|
|
161
170
|
const xVoxels = imagePlaneModule.columns;
|
|
162
171
|
const yVoxels = imagePlaneModule.rows;
|
|
163
172
|
|
|
164
173
|
const zSpacing = 1;
|
|
165
174
|
const zVoxels = 1;
|
|
166
175
|
|
|
176
|
+
this.hasPixelSpacing = !!imagePlaneModule.columnPixelSpacing;
|
|
167
177
|
return {
|
|
168
178
|
bitsAllocated: 8,
|
|
169
179
|
numComps: 3,
|
|
@@ -171,6 +181,7 @@ class VideoViewport extends Viewport implements IVideoViewport {
|
|
|
171
181
|
direction: [...rowCosineVec, ...colCosineVec, ...scanAxisNormal],
|
|
172
182
|
dimensions: [xVoxels, yVoxels, zVoxels],
|
|
173
183
|
spacing: [xSpacing, ySpacing, zSpacing],
|
|
184
|
+
hasPixelSpacing: this.hasPixelSpacing,
|
|
174
185
|
numVoxels: xVoxels * yVoxels * zVoxels,
|
|
175
186
|
imagePlaneModule,
|
|
176
187
|
};
|
|
@@ -181,23 +192,33 @@ class VideoViewport extends Viewport implements IVideoViewport {
|
|
|
181
192
|
* Requirements are to have the imageUrlModule in the metadata
|
|
182
193
|
* with the rendered endpoint being the raw video in video/mp4 format.
|
|
183
194
|
*/
|
|
184
|
-
public setVideo(
|
|
185
|
-
|
|
186
|
-
frameNumber?: number
|
|
187
|
-
): Promise<unknown> {
|
|
188
|
-
this.imageId = Array.isArray(imageIds) ? imageIds[0] : imageIds;
|
|
189
|
-
const { imageId } = this;
|
|
195
|
+
public setVideo(imageId: string, frameNumber?: number): Promise<unknown> {
|
|
196
|
+
this.imageId = Array.isArray(imageId) ? imageId[0] : imageId;
|
|
190
197
|
const { rendered } = metaData.get(MetadataModules.IMAGE_URL, imageId);
|
|
191
198
|
const generalSeries = metaData.get(MetadataModules.GENERAL_SERIES, imageId);
|
|
192
199
|
this.modality = generalSeries?.Modality;
|
|
193
200
|
this.metadata = this._getImageDataMetadata();
|
|
194
201
|
|
|
195
202
|
return this.setVideoURL(rendered).then(() => {
|
|
196
|
-
|
|
203
|
+
let { cineRate, numberOfFrames } = metaData.get(
|
|
204
|
+
MetadataModules.CINE,
|
|
205
|
+
imageId
|
|
206
|
+
);
|
|
207
|
+
if (!numberOfFrames) {
|
|
208
|
+
numberOfFrames = Math.round(
|
|
209
|
+
this.videoElement.duration * (cineRate || 30)
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
if (!cineRate) {
|
|
213
|
+
cineRate = Math.round(numberOfFrames / this.videoElement.duration);
|
|
214
|
+
}
|
|
197
215
|
this.fps = cineRate;
|
|
216
|
+
this.numberOfFrames = numberOfFrames;
|
|
217
|
+
// 1 based range setting
|
|
218
|
+
this.setFrameRange([1, numberOfFrames]);
|
|
198
219
|
if (frameNumber !== undefined) {
|
|
199
220
|
this.pause();
|
|
200
|
-
this.
|
|
221
|
+
this.setFrameNumber(frameNumber);
|
|
201
222
|
}
|
|
202
223
|
});
|
|
203
224
|
}
|
|
@@ -326,10 +347,31 @@ class VideoViewport extends Viewport implements IVideoViewport {
|
|
|
326
347
|
}
|
|
327
348
|
|
|
328
349
|
// Sets the frame number - note according to DICOM, this is 1 based
|
|
329
|
-
public async
|
|
350
|
+
public async setFrameNumber(frame: number) {
|
|
330
351
|
this.setTime((frame - 1) / this.fps);
|
|
331
352
|
}
|
|
332
353
|
|
|
354
|
+
/**
|
|
355
|
+
* Sets the playback frame range. The video will play over the given set
|
|
356
|
+
* of frames (assuming it is playing).
|
|
357
|
+
* @param frameRange - the minimum to maximum (inclusive) frames to play over
|
|
358
|
+
* @returns
|
|
359
|
+
*/
|
|
360
|
+
public setFrameRange(frameRange: number[]) {
|
|
361
|
+
if (!frameRange) {
|
|
362
|
+
this.frameRange = [1, this.numberOfFrames];
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
if (frameRange.length !== 2 || frameRange[0] === frameRange[1]) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
this.frameRange = [frameRange[0], frameRange[1]];
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
public getFrameRange(): [number, number] {
|
|
372
|
+
return this.frameRange;
|
|
373
|
+
}
|
|
374
|
+
|
|
333
375
|
public setProperties(props: VideoViewportProperties) {
|
|
334
376
|
if (props.loop !== undefined) {
|
|
335
377
|
this.videoElement.loop = props.loop;
|
|
@@ -421,6 +463,7 @@ class VideoViewport extends Viewport implements IVideoViewport {
|
|
|
421
463
|
origin: metadata.origin,
|
|
422
464
|
direction: metadata.direction,
|
|
423
465
|
metadata: { Modality: this.modality },
|
|
466
|
+
getScalarData: () => this.getScalarData(),
|
|
424
467
|
imageData: {
|
|
425
468
|
getDirection: () => metadata.direction,
|
|
426
469
|
getDimensions: () => metadata.dimensions,
|
|
@@ -445,6 +488,32 @@ class VideoViewport extends Viewport implements IVideoViewport {
|
|
|
445
488
|
};
|
|
446
489
|
}
|
|
447
490
|
|
|
491
|
+
/**
|
|
492
|
+
* Checks to see if the imageURI is currently being displayed. The imageURI
|
|
493
|
+
* may contain frame numbers according to the DICOM standard format, which
|
|
494
|
+
* will be stripped to compare the base image URI, and then the values used
|
|
495
|
+
* to check if that frame is currently being displayed.
|
|
496
|
+
*
|
|
497
|
+
* The DICOM standard allows for comma separated values as well, however,
|
|
498
|
+
* this is not supported here, with only a single range or single value
|
|
499
|
+
* being tested.
|
|
500
|
+
*
|
|
501
|
+
* For a single value, the time range +/- 5 frames is permitted to allow
|
|
502
|
+
* the detection to actually succeed when nearby without requiring an exact
|
|
503
|
+
* time frame to be matched.
|
|
504
|
+
*
|
|
505
|
+
* @param imageURI - containing frame number or range.
|
|
506
|
+
* @returns
|
|
507
|
+
*/
|
|
508
|
+
public hasImageURI(imageURI: string) {
|
|
509
|
+
// TODO - move annotationFrameRange into core so it can be used here.
|
|
510
|
+
const framesMatch = imageURI.match(VideoViewport.frameRangeExtractor);
|
|
511
|
+
const testURI = framesMatch
|
|
512
|
+
? imageURI.substring(0, framesMatch.index)
|
|
513
|
+
: imageURI;
|
|
514
|
+
return this.imageId.indexOf(testURI) !== -1;
|
|
515
|
+
}
|
|
516
|
+
|
|
448
517
|
public setVOI(voiRange: VOIRange): void {
|
|
449
518
|
this.voiRange = voiRange;
|
|
450
519
|
this.setColorTransform();
|
|
@@ -470,8 +539,6 @@ class VideoViewport extends Viewport implements IVideoViewport {
|
|
|
470
539
|
const white = this.averageWhite || [255, 255, 255];
|
|
471
540
|
const maxWhite = Math.max(...white);
|
|
472
541
|
const scaleWhite = white.map((c) => maxWhite / c);
|
|
473
|
-
// From the DICOM standard: ((x - (c - 0.5)) / (w-1) + 0.5) * (ymax- ymin) + ymin
|
|
474
|
-
// which is x/(w-1) - (c - 0.5) / (w-1) + 0.5 for this case
|
|
475
542
|
const { lower = 0, upper = 255 } = this.voiRange || {};
|
|
476
543
|
const wlScale = (upper - lower + 1) / 255;
|
|
477
544
|
const wlDelta = lower / 255;
|
|
@@ -496,7 +563,8 @@ class VideoViewport extends Viewport implements IVideoViewport {
|
|
|
496
563
|
// NOTE: the parallel scale should be done first
|
|
497
564
|
// because it affects the focal point later
|
|
498
565
|
if (camera.parallelScale !== undefined) {
|
|
499
|
-
this.videoCamera.parallelScale =
|
|
566
|
+
this.videoCamera.parallelScale =
|
|
567
|
+
this.element.clientHeight / 2 / parallelScale;
|
|
500
568
|
}
|
|
501
569
|
|
|
502
570
|
if (focalPoint !== undefined) {
|
|
@@ -526,6 +594,33 @@ class VideoViewport extends Viewport implements IVideoViewport {
|
|
|
526
594
|
}
|
|
527
595
|
}
|
|
528
596
|
|
|
597
|
+
/**
|
|
598
|
+
* This function returns the imageID associated with either the current
|
|
599
|
+
* frame being displayed, or the range of frames being played. This may not
|
|
600
|
+
* correspond to any particular imageId that has imageId metadata, as the
|
|
601
|
+
* format is one of:
|
|
602
|
+
* `<DICOMweb URI>/frames/<Start Frame>(-<End Frame>)?`
|
|
603
|
+
* or
|
|
604
|
+
* `<Other URI>[?&]frameNumber=<Start Frame>(-<EndFrame>)?`
|
|
605
|
+
* for a URL parameter.
|
|
606
|
+
*
|
|
607
|
+
* @returns an imageID for video
|
|
608
|
+
*/
|
|
609
|
+
public getCurrentImageId() {
|
|
610
|
+
const current = this.imageId.replace(
|
|
611
|
+
'/frames/1',
|
|
612
|
+
this.isPlaying
|
|
613
|
+
? `/frames/1-${this.numberOfFrames}`
|
|
614
|
+
: `/frames/${this.getFrameNumber()}`
|
|
615
|
+
);
|
|
616
|
+
return current;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
public getFrameNumber() {
|
|
620
|
+
// Need to round this as the fps/time isn't exact
|
|
621
|
+
return 1 + Math.round(this.videoElement.currentTime * this.fps);
|
|
622
|
+
}
|
|
623
|
+
|
|
529
624
|
public getCamera(): ICamera {
|
|
530
625
|
const { parallelScale } = this.videoCamera;
|
|
531
626
|
|
|
@@ -543,7 +638,8 @@ class VideoViewport extends Viewport implements IVideoViewport {
|
|
|
543
638
|
parallelProjection: true,
|
|
544
639
|
focalPoint: canvasCenterWorld,
|
|
545
640
|
position: [0, 0, 0],
|
|
546
|
-
|
|
641
|
+
viewUp: [0, -1, 0],
|
|
642
|
+
parallelScale: this.element.clientHeight / 2 / parallelScale, // Reverse zoom direction back
|
|
547
643
|
viewPlaneNormal: [0, 0, 1],
|
|
548
644
|
};
|
|
549
645
|
}
|
|
@@ -561,7 +657,9 @@ class VideoViewport extends Viewport implements IVideoViewport {
|
|
|
561
657
|
};
|
|
562
658
|
|
|
563
659
|
public getNumberOfSlices = (): number => {
|
|
564
|
-
return (
|
|
660
|
+
return Math.round(
|
|
661
|
+
(this.videoElement.duration * this.fps) / this.scrollSpeed
|
|
662
|
+
);
|
|
565
663
|
};
|
|
566
664
|
|
|
567
665
|
public getFrameOfReferenceUID = (): string => {
|
|
@@ -636,18 +734,23 @@ class VideoViewport extends Viewport implements IVideoViewport {
|
|
|
636
734
|
return canvasPos;
|
|
637
735
|
};
|
|
638
736
|
|
|
737
|
+
public getPan(): Point2 {
|
|
738
|
+
const worldPan = this.videoCamera.panWorld;
|
|
739
|
+
return [worldPan[0], worldPan[1]];
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
public getRotation = () => 0;
|
|
743
|
+
|
|
639
744
|
protected canvasToIndex = (canvasPos: Point2): Point2 => {
|
|
640
|
-
const
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
return
|
|
745
|
+
const transform = this.getTransform();
|
|
746
|
+
transform.invert();
|
|
747
|
+
|
|
748
|
+
return transform.transformPoint(canvasPos);
|
|
644
749
|
};
|
|
645
750
|
|
|
646
751
|
protected indexToCanvas = (indexPos: Point2): Point2 => {
|
|
647
|
-
const
|
|
648
|
-
|
|
649
|
-
const pan = this.getPan();
|
|
650
|
-
return [x * ratio - pan[0], y * ratio - pan[1]];
|
|
752
|
+
const transform = this.getTransform();
|
|
753
|
+
return transform.transformPoint(indexPos);
|
|
651
754
|
};
|
|
652
755
|
|
|
653
756
|
private refreshRenderValues() {
|
|
@@ -692,17 +795,15 @@ class VideoViewport extends Viewport implements IVideoViewport {
|
|
|
692
795
|
this.renderFrame();
|
|
693
796
|
};
|
|
694
797
|
|
|
695
|
-
|
|
798
|
+
protected getTransform() {
|
|
696
799
|
const panWorld: Point2 = this.videoCamera.panWorld;
|
|
697
800
|
const worldToCanvasRatio: number = this.getWorldToCanvasRatio();
|
|
698
801
|
const canvasToWorldRatio: number = this.getCanvasToWorldRatio();
|
|
699
|
-
|
|
700
802
|
const halfCanvas = [this.canvas.width / 2, this.canvas.height / 2];
|
|
701
803
|
const halfCanvasWorldCoordinates = [
|
|
702
804
|
halfCanvas[0] * canvasToWorldRatio,
|
|
703
805
|
halfCanvas[1] * canvasToWorldRatio,
|
|
704
806
|
];
|
|
705
|
-
|
|
706
807
|
const transform = new Transform();
|
|
707
808
|
|
|
708
809
|
// Translate to the center of the canvas (move origin of the transform
|
|
@@ -720,6 +821,10 @@ class VideoViewport extends Viewport implements IVideoViewport {
|
|
|
720
821
|
-halfCanvasWorldCoordinates[0],
|
|
721
822
|
-halfCanvasWorldCoordinates[1]
|
|
722
823
|
);
|
|
824
|
+
return transform;
|
|
825
|
+
}
|
|
826
|
+
private renderFrame = () => {
|
|
827
|
+
const transform = this.getTransform();
|
|
723
828
|
const transformationMatrix: number[] = transform.getMatrix();
|
|
724
829
|
|
|
725
830
|
this.canvasContext.transform(
|
|
@@ -749,6 +854,19 @@ class VideoViewport extends Viewport implements IVideoViewport {
|
|
|
749
854
|
time: this.videoElement.currentTime,
|
|
750
855
|
duration: this.videoElement.duration,
|
|
751
856
|
});
|
|
857
|
+
|
|
858
|
+
const frame = this.getFrameNumber();
|
|
859
|
+
if (this.isPlaying) {
|
|
860
|
+
if (frame < this.frameRange[0]) {
|
|
861
|
+
this.setFrameNumber(this.frameRange[0]);
|
|
862
|
+
} else if (frame > this.frameRange[1]) {
|
|
863
|
+
if (this.loop) {
|
|
864
|
+
this.setFrameNumber(this.frameRange[0]);
|
|
865
|
+
} else {
|
|
866
|
+
this.pause();
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
}
|
|
752
870
|
};
|
|
753
871
|
|
|
754
872
|
private renderWhilstPlaying = () => {
|
|
@@ -1113,7 +1113,7 @@ class Viewport implements IViewport {
|
|
|
1113
1113
|
}
|
|
1114
1114
|
|
|
1115
1115
|
if (viewUp) {
|
|
1116
|
-
viewUpHasChanged = isEqual(currentViewUp, prevViewUp);
|
|
1116
|
+
viewUpHasChanged = !isEqual(currentViewUp, prevViewUp);
|
|
1117
1117
|
}
|
|
1118
1118
|
|
|
1119
1119
|
// only modify the clipping planes if the camera is modified out of plane
|
package/src/enums/RequestType.ts
CHANGED
|
@@ -6,8 +6,10 @@ enum RequestType {
|
|
|
6
6
|
Interaction = 'interaction',
|
|
7
7
|
/** Second highest priority for loading*/
|
|
8
8
|
Thumbnail = 'thumbnail',
|
|
9
|
-
/**
|
|
9
|
+
/** Third highest priority for loading, usually used for image loading in the background*/
|
|
10
10
|
Prefetch = 'prefetch',
|
|
11
|
+
/** Lower priority, often used for background computations in the worker */
|
|
12
|
+
Compute = 'compute',
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
export default RequestType;
|
package/src/index.ts
CHANGED
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
resetUseSharedArrayBuffer,
|
|
41
41
|
getConfiguration,
|
|
42
42
|
setConfiguration,
|
|
43
|
+
getWebWorkerManager,
|
|
43
44
|
} from './init';
|
|
44
45
|
|
|
45
46
|
// Classes
|
|
@@ -85,6 +86,7 @@ export {
|
|
|
85
86
|
// configs
|
|
86
87
|
getConfiguration,
|
|
87
88
|
setConfiguration,
|
|
89
|
+
getWebWorkerManager,
|
|
88
90
|
// enums
|
|
89
91
|
Enums,
|
|
90
92
|
CONSTANTS,
|
package/src/init.ts
CHANGED
|
@@ -6,6 +6,8 @@ let useSharedArrayBuffer = true;
|
|
|
6
6
|
let sharedArrayBufferMode = SharedArrayBufferModes.TRUE;
|
|
7
7
|
import { deepMerge } from './utilities';
|
|
8
8
|
import { Cornerstone3DConfig } from './types';
|
|
9
|
+
import CentralizedWebWorkerManager from './webWorkerManager/webWorkerManager';
|
|
10
|
+
|
|
9
11
|
// TODO: move sharedArrayBuffer into config.
|
|
10
12
|
// TODO: change config into a class with methods to better control get/set
|
|
11
13
|
const defaultConfig: Cornerstone3DConfig = {
|
|
@@ -36,6 +38,8 @@ let config: Cornerstone3DConfig = {
|
|
|
36
38
|
// ...
|
|
37
39
|
};
|
|
38
40
|
|
|
41
|
+
let webWorkerManager = null;
|
|
42
|
+
|
|
39
43
|
function _getGLContext(): RenderingContext {
|
|
40
44
|
// Create canvas element. The canvas is not added to the
|
|
41
45
|
// document itself, so it is never displayed in the
|
|
@@ -133,6 +137,11 @@ async function init(configuration = config): Promise<boolean> {
|
|
|
133
137
|
setUseSharedArrayBuffer(sharedArrayBufferMode);
|
|
134
138
|
|
|
135
139
|
csRenderInitialized = true;
|
|
140
|
+
|
|
141
|
+
if (!webWorkerManager) {
|
|
142
|
+
webWorkerManager = new CentralizedWebWorkerManager();
|
|
143
|
+
}
|
|
144
|
+
|
|
136
145
|
return csRenderInitialized;
|
|
137
146
|
}
|
|
138
147
|
|
|
@@ -256,6 +265,14 @@ function _updateRenderingPipelinesForAllViewports(): void {
|
|
|
256
265
|
);
|
|
257
266
|
}
|
|
258
267
|
|
|
268
|
+
function getWebWorkerManager() {
|
|
269
|
+
if (!webWorkerManager) {
|
|
270
|
+
webWorkerManager = new CentralizedWebWorkerManager();
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return webWorkerManager;
|
|
274
|
+
}
|
|
275
|
+
|
|
259
276
|
export {
|
|
260
277
|
init,
|
|
261
278
|
getShouldUseCPURendering,
|
|
@@ -268,4 +285,5 @@ export {
|
|
|
268
285
|
resetUseSharedArrayBuffer,
|
|
269
286
|
getConfiguration,
|
|
270
287
|
setConfiguration,
|
|
288
|
+
getWebWorkerManager,
|
|
271
289
|
};
|
|
@@ -78,12 +78,14 @@ class RequestPoolManager {
|
|
|
78
78
|
interaction: 0,
|
|
79
79
|
thumbnail: 0,
|
|
80
80
|
prefetch: 0,
|
|
81
|
+
compute: 0,
|
|
81
82
|
};
|
|
82
83
|
/* maximum number of requests of each type. */
|
|
83
84
|
public maxNumRequests: {
|
|
84
85
|
interaction: number;
|
|
85
86
|
thumbnail: number;
|
|
86
87
|
prefetch: number;
|
|
88
|
+
compute: number;
|
|
87
89
|
};
|
|
88
90
|
/* A public property that is used to set the delay between requests. */
|
|
89
91
|
public grabDelay: number;
|
|
@@ -101,6 +103,7 @@ class RequestPoolManager {
|
|
|
101
103
|
interaction: { 0: [] },
|
|
102
104
|
thumbnail: { 0: [] },
|
|
103
105
|
prefetch: { 0: [] },
|
|
106
|
+
compute: { 0: [] },
|
|
104
107
|
};
|
|
105
108
|
|
|
106
109
|
this.grabDelay = 5;
|
|
@@ -110,12 +113,14 @@ class RequestPoolManager {
|
|
|
110
113
|
interaction: 0,
|
|
111
114
|
thumbnail: 0,
|
|
112
115
|
prefetch: 0,
|
|
116
|
+
compute: 0,
|
|
113
117
|
};
|
|
114
118
|
|
|
115
119
|
this.maxNumRequests = {
|
|
116
120
|
interaction: 6,
|
|
117
121
|
thumbnail: 6,
|
|
118
122
|
prefetch: 5,
|
|
123
|
+
compute: 15,
|
|
119
124
|
};
|
|
120
125
|
}
|
|
121
126
|
|
|
@@ -185,15 +190,7 @@ class RequestPoolManager {
|
|
|
185
190
|
// Adding the request to the correct priority group of the request type
|
|
186
191
|
this.requestPool[type][priority].push(requestDetails);
|
|
187
192
|
|
|
188
|
-
|
|
189
|
-
if (!this.awake) {
|
|
190
|
-
this.awake = true;
|
|
191
|
-
this.startGrabbing();
|
|
192
|
-
} else if (type === RequestType.Interaction) {
|
|
193
|
-
// Todo: this is a hack for interaction right now, we should separate
|
|
194
|
-
// the grabbing from the adding requests
|
|
195
|
-
this.startGrabbing();
|
|
196
|
-
}
|
|
193
|
+
this.startGrabbing();
|
|
197
194
|
}
|
|
198
195
|
|
|
199
196
|
/**
|
|
@@ -273,11 +270,13 @@ class RequestPoolManager {
|
|
|
273
270
|
const hasRemainingPrefetchRequests = this.sendRequests(
|
|
274
271
|
RequestType.Prefetch
|
|
275
272
|
);
|
|
273
|
+
const hasRemainingComputeRequests = this.sendRequests(RequestType.Compute);
|
|
276
274
|
|
|
277
275
|
if (
|
|
278
276
|
!hasRemainingInteractionRequests &&
|
|
279
277
|
!hasRemainingThumbnailRequests &&
|
|
280
|
-
!hasRemainingPrefetchRequests
|
|
278
|
+
!hasRemainingPrefetchRequests &&
|
|
279
|
+
!hasRemainingComputeRequests
|
|
281
280
|
) {
|
|
282
281
|
this.awake = false;
|
|
283
282
|
}
|
|
@@ -323,7 +322,4 @@ class RequestPoolManager {
|
|
|
323
322
|
}
|
|
324
323
|
}
|
|
325
324
|
|
|
326
|
-
const requestPoolManager = new RequestPoolManager();
|
|
327
|
-
|
|
328
325
|
export { RequestPoolManager };
|
|
329
|
-
export default requestPoolManager;
|
|
@@ -19,11 +19,26 @@ export default interface IVideoViewport extends IViewport {
|
|
|
19
19
|
*/
|
|
20
20
|
getProperties: () => VideoViewportProperties;
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Sets the video to play.
|
|
24
|
+
* The video should have at least some metadata in the metadata provider,
|
|
25
|
+
* including:
|
|
26
|
+
* * study/series/sop common module for UIDs
|
|
27
|
+
* * `cineModule` for information on number of frames and playback rate
|
|
28
|
+
* * `imageUrlModule` - to get the URL for the image under the `rendered` attribute
|
|
29
|
+
*
|
|
30
|
+
* Without these, other tools requiring metadata wont work, although basic
|
|
31
|
+
* playback does work if the setVideoURL is used instead.
|
|
32
|
+
*/
|
|
33
|
+
setVideo: (imageIds: string, imageIdIndex?: number) => Promise<unknown>;
|
|
26
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Displays a raw video, without any metadata associated with it. Plays back,
|
|
37
|
+
* but does not permit tools to apply to the viewport, which requires providing
|
|
38
|
+
* additional metadata for the study.
|
|
39
|
+
*
|
|
40
|
+
* @param url - to display
|
|
41
|
+
*/
|
|
27
42
|
setVideoURL: (url: string) => void;
|
|
28
43
|
|
|
29
44
|
play: () => void;
|
|
@@ -35,6 +50,31 @@ export default interface IVideoViewport extends IViewport {
|
|
|
35
50
|
*/
|
|
36
51
|
resetProperties(): void;
|
|
37
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Gets the current image id, including frame selction or frameless.
|
|
55
|
+
*/
|
|
56
|
+
getCurrentImageId(): string;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Gets the current frame, 1 based
|
|
60
|
+
*/
|
|
61
|
+
getFrameNumber(): number;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Sets the current frame
|
|
65
|
+
*/
|
|
66
|
+
setFrameNumber(frameNo: number);
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Sets the range of frames for displaying. This is the range of frames
|
|
70
|
+
* that are shown/looped over when the video is playing.
|
|
71
|
+
* Note that ability to playback a frame range depends on the server
|
|
72
|
+
* implementing byte range requests, OR the video being easily cached in memory.
|
|
73
|
+
*/
|
|
74
|
+
setFrameRange(range?: [number, number]);
|
|
75
|
+
|
|
76
|
+
getFrameRange(): [number, number];
|
|
77
|
+
|
|
38
78
|
/**
|
|
39
79
|
* Centers Pan and resets the zoom for stack viewport.
|
|
40
80
|
*/
|
|
@@ -26,20 +26,13 @@ export default function getViewportsWithImageURI(
|
|
|
26
26
|
|
|
27
27
|
const viewports = [];
|
|
28
28
|
renderingEngines.forEach((renderingEngine) => {
|
|
29
|
-
const
|
|
29
|
+
const viewportsForRenderingEngine = renderingEngine.getViewports();
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
viewport.hasImageURI(imageURI)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const volumeViewports = renderingEngine.getVolumeViewports();
|
|
37
|
-
|
|
38
|
-
const filteredVolumeViewports = volumeViewports.filter((viewport) =>
|
|
39
|
-
viewport.hasImageURI(imageURI)
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
viewports.push(...filteredStackViewports, ...filteredVolumeViewports);
|
|
31
|
+
viewportsForRenderingEngine.forEach((viewport) => {
|
|
32
|
+
if (viewport.hasImageURI(imageURI)) {
|
|
33
|
+
viewports.push(viewport);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
43
36
|
});
|
|
44
37
|
|
|
45
38
|
return viewports;
|