@cornerstonejs/core 2.0.0-beta.22 → 2.0.0-beta.24
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/esm/RenderingEngine/BaseVolumeViewport.d.ts +2 -2
- package/dist/esm/RenderingEngine/BaseVolumeViewport.js +1 -0
- package/dist/esm/RenderingEngine/StackViewport.js +4 -3
- package/dist/esm/cache/cache.d.ts +1 -1
- package/dist/esm/cache/cache.js +1 -1
- package/dist/esm/cache/classes/BaseStreamingImageVolume.d.ts +85 -0
- package/dist/esm/cache/classes/BaseStreamingImageVolume.js +338 -0
- package/dist/esm/cache/classes/StreamingDynamicImageVolume.d.ts +52 -0
- package/dist/esm/cache/classes/StreamingDynamicImageVolume.js +81 -0
- package/dist/esm/cache/classes/StreamingImageVolume.d.ts +8 -0
- package/dist/esm/cache/classes/StreamingImageVolume.js +21 -0
- package/dist/esm/cache/index.d.ts +3 -1
- package/dist/esm/cache/index.js +3 -1
- package/dist/esm/enums/Events.d.ts +2 -1
- package/dist/esm/enums/Events.js +1 -0
- package/dist/esm/index.d.ts +3 -1
- package/dist/esm/index.js +3 -1
- package/dist/esm/loaders/cornerstoneStreamingDynamicImageVolumeLoader.d.ts +10 -0
- package/dist/esm/loaders/cornerstoneStreamingDynamicImageVolumeLoader.js +58 -0
- package/dist/esm/loaders/cornerstoneStreamingImageVolumeLoader.d.ts +12 -0
- package/dist/esm/loaders/cornerstoneStreamingImageVolumeLoader.js +73 -0
- package/dist/esm/loaders/volumeLoader.js +0 -8
- package/dist/esm/types/IBaseVolumeViewport.d.ts +2 -0
- package/dist/esm/types/IBaseVolumeViewport.js +1 -0
- package/dist/esm/types/IStackViewport.d.ts +2 -69
- package/dist/esm/types/IVideoViewport.d.ts +2 -40
- package/dist/esm/types/IViewport.d.ts +2 -88
- package/dist/esm/types/IVolumeViewport.d.ts +3 -45
- package/dist/esm/types/IVoxelManager.d.ts +2 -54
- package/dist/esm/types/IWSIViewport.d.ts +3 -16
- package/dist/esm/types/ImageLoadRequests.d.ts +24 -0
- package/dist/esm/types/ImageLoadRequests.js +1 -0
- package/dist/esm/types/MetadataModuleTypes.d.ts +1 -0
- package/dist/esm/types/index.d.ts +3 -1
- package/dist/esm/utilities/VoxelManager.d.ts +6 -5
- package/dist/esm/utilities/VoxelManager.js +12 -3
- package/dist/esm/utilities/autoLoad.d.ts +2 -0
- package/dist/esm/utilities/autoLoad.js +28 -0
- package/dist/esm/utilities/generateVolumePropsFromImageIds.js +2 -2
- package/dist/esm/utilities/getDynamicVolumeInfo.d.ts +6 -0
- package/dist/esm/utilities/getDynamicVolumeInfo.js +7 -0
- package/dist/esm/utilities/index.d.ts +5 -1
- package/dist/esm/utilities/index.js +5 -1
- package/dist/esm/utilities/scaleArray.d.ts +2 -0
- package/dist/esm/utilities/scaleArray.js +15 -0
- package/dist/esm/utilities/splitImageIdsBy4DTags.d.ts +5 -0
- package/dist/esm/utilities/splitImageIdsBy4DTags.js +161 -0
- package/dist/umd/index.js +1 -1
- package/dist/umd/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { mat4 } from 'gl-matrix';
|
|
2
2
|
import type { BlendModes, InterpolationType, OrientationAxis } from '../enums';
|
|
3
|
-
import type { FlipDirection, IImageData, IVolumeInput, OrientationVectors, Point2, Point3, VolumeViewportProperties, ViewReferenceSpecifier, ReferenceCompatibleOptions, ViewReference,
|
|
3
|
+
import type { FlipDirection, IImageData, IVolumeInput, OrientationVectors, Point2, Point3, VolumeViewportProperties, ViewReferenceSpecifier, ReferenceCompatibleOptions, ViewReference, IBaseVolumeViewport } from '../types';
|
|
4
4
|
import type { VoiModifiedEventDetail } from '../types/EventTypes';
|
|
5
5
|
import type { ViewportInput } from '../types/IViewport';
|
|
6
6
|
import type { TransferFunctionNodes } from '../types/ITransferFunctionNode';
|
|
7
7
|
import Viewport from './Viewport';
|
|
8
|
-
declare abstract class BaseVolumeViewport extends Viewport implements
|
|
8
|
+
declare abstract class BaseVolumeViewport extends Viewport implements IBaseVolumeViewport {
|
|
9
9
|
useCPURendering: boolean;
|
|
10
10
|
private _FrameOfReferenceUID;
|
|
11
11
|
protected initialTransferFunctionNodes: TransferFunctionNodes;
|
|
@@ -419,6 +419,7 @@ class BaseVolumeViewport extends Viewport {
|
|
|
419
419
|
const volumeIdToUse = applicableVolumeActorInfo.volumeId;
|
|
420
420
|
let voiRangeToUse = voiRange;
|
|
421
421
|
if (typeof voiRangeToUse === 'undefined') {
|
|
422
|
+
throw new Error('voiRangeToUse is undefined, need to implement this in the new volume model');
|
|
422
423
|
const imageData = volumeActor.getMapper().getInputData();
|
|
423
424
|
const range = imageData.getPointData().getScalars().getRange();
|
|
424
425
|
const maxVoiRange = { lower: range[0], upper: range[1] };
|
|
@@ -1663,9 +1663,10 @@ class StackViewport extends Viewport {
|
|
|
1663
1663
|
return options.asVolume;
|
|
1664
1664
|
}
|
|
1665
1665
|
let testIndex = this.getCurrentImageIdIndex();
|
|
1666
|
-
|
|
1666
|
+
let currentImageId = this.imageIds[testIndex];
|
|
1667
1667
|
if (options.withNavigation && typeof sliceIndex === 'number') {
|
|
1668
1668
|
testIndex = sliceIndex;
|
|
1669
|
+
currentImageId = this.imageIds[testIndex];
|
|
1669
1670
|
}
|
|
1670
1671
|
if (!currentImageId) {
|
|
1671
1672
|
return false;
|
|
@@ -1822,17 +1823,17 @@ class StackViewport extends Viewport {
|
|
|
1822
1823
|
}
|
|
1823
1824
|
_getImagePlaneModule(imageId) {
|
|
1824
1825
|
const imagePlaneModule = metaData.get(MetadataModules.IMAGE_PLANE, imageId);
|
|
1826
|
+
this.hasPixelSpacing =
|
|
1827
|
+
!imagePlaneModule.usingDefaultValues || this.calibration?.scale > 0;
|
|
1825
1828
|
this.calibration ||= imagePlaneModule.calibration;
|
|
1826
1829
|
const newImagePlaneModule = {
|
|
1827
1830
|
...imagePlaneModule,
|
|
1828
1831
|
};
|
|
1829
1832
|
if (!newImagePlaneModule.columnPixelSpacing) {
|
|
1830
1833
|
newImagePlaneModule.columnPixelSpacing = 1;
|
|
1831
|
-
this.hasPixelSpacing = this.calibration?.scale > 0;
|
|
1832
1834
|
}
|
|
1833
1835
|
if (!newImagePlaneModule.rowPixelSpacing) {
|
|
1834
1836
|
newImagePlaneModule.rowPixelSpacing = 1;
|
|
1835
|
-
this.hasPixelSpacing = this.calibration?.scale > 0;
|
|
1836
1837
|
}
|
|
1837
1838
|
if (!newImagePlaneModule.columnCosines) {
|
|
1838
1839
|
newImagePlaneModule.columnCosines = [0, 1, 0];
|
package/dist/esm/cache/cache.js
CHANGED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { ImageQualityStatus, RequestType } from '../../enums';
|
|
2
|
+
import type { IImagesLoader, ImageLoadRequests, ImageVolumeProps, IStreamingVolumeProperties, PixelDataTypedArrayString, ScalingParameters } from '../../types';
|
|
3
|
+
import ImageVolume from './ImageVolume';
|
|
4
|
+
export default class BaseStreamingImageVolume extends ImageVolume implements IImagesLoader {
|
|
5
|
+
private framesLoaded;
|
|
6
|
+
private framesProcessed;
|
|
7
|
+
private framesUpdated;
|
|
8
|
+
protected autoRenderOnLoad: boolean;
|
|
9
|
+
protected cachedFrames: any[];
|
|
10
|
+
protected reRenderTarget: number;
|
|
11
|
+
protected reRenderFraction: number;
|
|
12
|
+
dataType: PixelDataTypedArrayString;
|
|
13
|
+
loadStatus: {
|
|
14
|
+
loaded: boolean;
|
|
15
|
+
loading: boolean;
|
|
16
|
+
cancelled: boolean;
|
|
17
|
+
callbacks: Array<(...args: unknown[]) => void>;
|
|
18
|
+
};
|
|
19
|
+
imagesLoader: IImagesLoader;
|
|
20
|
+
constructor(imageVolumeProperties: ImageVolumeProps, streamingProperties: IStreamingVolumeProperties);
|
|
21
|
+
protected invalidateVolume(immediate: boolean): void;
|
|
22
|
+
cancelLoading: () => void;
|
|
23
|
+
clearLoadCallbacks(): void;
|
|
24
|
+
protected callLoadStatusCallback(evt: any): void;
|
|
25
|
+
protected updateTextureAndTriggerEvents(imageIdIndex: any, imageId: any, imageQualityStatus?: ImageQualityStatus): void;
|
|
26
|
+
successCallback(imageId: string, image: any): void;
|
|
27
|
+
errorCallback(imageId: any, permanent: any, error: any): void;
|
|
28
|
+
load: (callback: (...args: unknown[]) => void) => void;
|
|
29
|
+
getLoaderImageOptions(imageId: string): {
|
|
30
|
+
targetBuffer: {
|
|
31
|
+
type: PixelDataTypedArrayString;
|
|
32
|
+
rows: any;
|
|
33
|
+
columns: any;
|
|
34
|
+
};
|
|
35
|
+
allowFloatRendering: boolean;
|
|
36
|
+
preScale: {
|
|
37
|
+
enabled: boolean;
|
|
38
|
+
scalingParameters: ScalingParameters;
|
|
39
|
+
};
|
|
40
|
+
transferPixelData: boolean;
|
|
41
|
+
requestType: RequestType;
|
|
42
|
+
transferSyntaxUID: any;
|
|
43
|
+
additionalDetails: {
|
|
44
|
+
imageId: string;
|
|
45
|
+
imageIdIndex: number;
|
|
46
|
+
volumeId: string;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
callLoadImage(imageId: any, imageIdIndex: any, options: any): any;
|
|
50
|
+
protected getImageIdsRequests(imageIds: string[], priorityDefault: number): {
|
|
51
|
+
callLoadImage: (imageId: any, imageIdIndex: any, options: any) => any;
|
|
52
|
+
imageId: string;
|
|
53
|
+
imageIdIndex: number;
|
|
54
|
+
options: {
|
|
55
|
+
targetBuffer: {
|
|
56
|
+
type: PixelDataTypedArrayString;
|
|
57
|
+
rows: any;
|
|
58
|
+
columns: any;
|
|
59
|
+
};
|
|
60
|
+
allowFloatRendering: boolean;
|
|
61
|
+
preScale: {
|
|
62
|
+
enabled: boolean;
|
|
63
|
+
scalingParameters: ScalingParameters;
|
|
64
|
+
};
|
|
65
|
+
transferPixelData: boolean;
|
|
66
|
+
requestType: RequestType;
|
|
67
|
+
transferSyntaxUID: any;
|
|
68
|
+
additionalDetails: {
|
|
69
|
+
imageId: string;
|
|
70
|
+
imageIdIndex: number;
|
|
71
|
+
volumeId: string;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
priority: number;
|
|
75
|
+
requestType: RequestType;
|
|
76
|
+
additionalDetails: {
|
|
77
|
+
volumeId: string;
|
|
78
|
+
};
|
|
79
|
+
}[];
|
|
80
|
+
getImageLoadRequests(priority: number): ImageLoadRequests[];
|
|
81
|
+
getImageIdsToLoad(): string[];
|
|
82
|
+
loadImages(): Promise<boolean>;
|
|
83
|
+
private _prefetchImageIds;
|
|
84
|
+
private _addScalingToVolume;
|
|
85
|
+
}
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import * as metaData from '../../metaData';
|
|
2
|
+
import { Events, ImageQualityStatus, RequestType } from '../../enums';
|
|
3
|
+
import eventTarget from '../../eventTarget';
|
|
4
|
+
import imageLoadPoolManager from '../../requestPool/imageLoadPoolManager';
|
|
5
|
+
import { ProgressiveIterator, imageRetrieveMetadataProvider, hasFloatScalingParameters, autoLoad, triggerEvent, } from '../../utilities';
|
|
6
|
+
import ImageVolume from './ImageVolume';
|
|
7
|
+
import ProgressiveRetrieveImages from '../../loaders/ProgressiveRetrieveImages';
|
|
8
|
+
import { canRenderFloatTextures } from '../../init';
|
|
9
|
+
import { loadAndCacheImage } from '../../loaders/imageLoader';
|
|
10
|
+
const requestTypeDefault = RequestType.Prefetch;
|
|
11
|
+
export default class BaseStreamingImageVolume extends ImageVolume {
|
|
12
|
+
constructor(imageVolumeProperties, streamingProperties) {
|
|
13
|
+
super(imageVolumeProperties);
|
|
14
|
+
this.framesLoaded = 0;
|
|
15
|
+
this.framesProcessed = 0;
|
|
16
|
+
this.framesUpdated = 0;
|
|
17
|
+
this.autoRenderOnLoad = true;
|
|
18
|
+
this.cachedFrames = [];
|
|
19
|
+
this.reRenderTarget = 0;
|
|
20
|
+
this.reRenderFraction = 2;
|
|
21
|
+
this.imagesLoader = this;
|
|
22
|
+
this.cancelLoading = () => {
|
|
23
|
+
const { loadStatus } = this;
|
|
24
|
+
if (!loadStatus || !loadStatus.loading) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
loadStatus.loading = false;
|
|
28
|
+
loadStatus.cancelled = true;
|
|
29
|
+
this.clearLoadCallbacks();
|
|
30
|
+
const filterFunction = ({ additionalDetails }) => {
|
|
31
|
+
return additionalDetails.volumeId !== this.volumeId;
|
|
32
|
+
};
|
|
33
|
+
imageLoadPoolManager.filterRequests(filterFunction);
|
|
34
|
+
};
|
|
35
|
+
this.load = (callback) => {
|
|
36
|
+
const { imageIds, loadStatus, numFrames } = this;
|
|
37
|
+
const { transferSyntaxUID } = metaData.get('transferSyntax', imageIds[0]) || {};
|
|
38
|
+
const imageRetrieveConfiguration = metaData.get(imageRetrieveMetadataProvider.IMAGE_RETRIEVE_CONFIGURATION, this.volumeId, transferSyntaxUID, 'volume');
|
|
39
|
+
this.imagesLoader = imageRetrieveConfiguration
|
|
40
|
+
? (imageRetrieveConfiguration.create ||
|
|
41
|
+
ProgressiveRetrieveImages.createProgressive)(imageRetrieveConfiguration)
|
|
42
|
+
: this;
|
|
43
|
+
if (loadStatus.loading === true) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const { loaded } = this.loadStatus;
|
|
47
|
+
const totalNumFrames = imageIds.length;
|
|
48
|
+
if (loaded) {
|
|
49
|
+
if (callback) {
|
|
50
|
+
callback({
|
|
51
|
+
success: true,
|
|
52
|
+
framesLoaded: totalNumFrames,
|
|
53
|
+
framesProcessed: totalNumFrames,
|
|
54
|
+
numFrames,
|
|
55
|
+
totalNumFrames,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (callback) {
|
|
61
|
+
this.loadStatus.callbacks.push(callback);
|
|
62
|
+
}
|
|
63
|
+
this._prefetchImageIds();
|
|
64
|
+
};
|
|
65
|
+
this.loadStatus = streamingProperties.loadStatus;
|
|
66
|
+
}
|
|
67
|
+
invalidateVolume(immediate) {
|
|
68
|
+
const { vtkOpenGLTexture } = this;
|
|
69
|
+
const { numFrames } = this;
|
|
70
|
+
for (let i = 0; i < numFrames; i++) {
|
|
71
|
+
vtkOpenGLTexture.setUpdatedFrame(i);
|
|
72
|
+
}
|
|
73
|
+
this.modified();
|
|
74
|
+
if (immediate) {
|
|
75
|
+
autoLoad(this.volumeId);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
clearLoadCallbacks() {
|
|
79
|
+
this.loadStatus.callbacks = [];
|
|
80
|
+
}
|
|
81
|
+
callLoadStatusCallback(evt) {
|
|
82
|
+
const { framesUpdated, framesProcessed, totalNumFrames } = evt;
|
|
83
|
+
const { volumeId, reRenderFraction, loadStatus, metadata } = this;
|
|
84
|
+
const { FrameOfReferenceUID } = metadata;
|
|
85
|
+
if (this.autoRenderOnLoad) {
|
|
86
|
+
if (framesUpdated > this.reRenderTarget ||
|
|
87
|
+
framesProcessed === totalNumFrames) {
|
|
88
|
+
this.reRenderTarget += reRenderFraction;
|
|
89
|
+
autoLoad(volumeId);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (framesProcessed === totalNumFrames) {
|
|
93
|
+
loadStatus.callbacks.forEach((callback) => callback(evt));
|
|
94
|
+
const eventDetail = {
|
|
95
|
+
FrameOfReferenceUID,
|
|
96
|
+
volumeId: volumeId,
|
|
97
|
+
};
|
|
98
|
+
triggerEvent(eventTarget, Events.IMAGE_VOLUME_LOADING_COMPLETED, eventDetail);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
updateTextureAndTriggerEvents(imageIdIndex, imageId, imageQualityStatus = ImageQualityStatus.FULL_RESOLUTION) {
|
|
102
|
+
const frameIndex = this.imageIdIndexToFrameIndex(imageIdIndex);
|
|
103
|
+
const { cachedFrames, numFrames, totalNumFrames } = this;
|
|
104
|
+
const { FrameOfReferenceUID } = this.metadata;
|
|
105
|
+
const currentStatus = cachedFrames[frameIndex];
|
|
106
|
+
if (currentStatus > imageQualityStatus) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (cachedFrames[frameIndex] === ImageQualityStatus.FULL_RESOLUTION) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const complete = imageQualityStatus === ImageQualityStatus.FULL_RESOLUTION;
|
|
113
|
+
cachedFrames[imageIdIndex] = imageQualityStatus;
|
|
114
|
+
this.framesUpdated++;
|
|
115
|
+
if (complete) {
|
|
116
|
+
this.framesLoaded++;
|
|
117
|
+
this.framesProcessed++;
|
|
118
|
+
}
|
|
119
|
+
const eventDetail = {
|
|
120
|
+
FrameOfReferenceUID,
|
|
121
|
+
volumeId: this.volumeId,
|
|
122
|
+
numberOfFrames: numFrames,
|
|
123
|
+
framesProcessed: this.framesProcessed,
|
|
124
|
+
};
|
|
125
|
+
triggerEvent(eventTarget, Events.IMAGE_VOLUME_MODIFIED, eventDetail);
|
|
126
|
+
if (complete && this.framesProcessed === this.totalNumFrames) {
|
|
127
|
+
this.loadStatus.loaded = true;
|
|
128
|
+
this.loadStatus.loading = false;
|
|
129
|
+
}
|
|
130
|
+
this.callLoadStatusCallback({
|
|
131
|
+
success: true,
|
|
132
|
+
imageIdIndex,
|
|
133
|
+
imageId,
|
|
134
|
+
framesLoaded: this.framesLoaded,
|
|
135
|
+
framesProcessed: this.framesProcessed,
|
|
136
|
+
framesUpdated: this.framesUpdated,
|
|
137
|
+
numFrames,
|
|
138
|
+
totalNumFrames,
|
|
139
|
+
complete,
|
|
140
|
+
imageQualityStatus,
|
|
141
|
+
});
|
|
142
|
+
this.vtkOpenGLTexture.setUpdatedFrame(frameIndex);
|
|
143
|
+
if (this.loadStatus.loaded) {
|
|
144
|
+
this.loadStatus.callbacks = [];
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
successCallback(imageId, image) {
|
|
148
|
+
const imageIdIndex = this.getImageIdIndex(imageId);
|
|
149
|
+
const { imageQualityStatus } = image;
|
|
150
|
+
if (this.loadStatus.cancelled) {
|
|
151
|
+
console.warn('volume load cancelled, returning for imageIdIndex: ', imageIdIndex);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
return this.updateTextureAndTriggerEvents(imageIdIndex, imageId, imageQualityStatus);
|
|
155
|
+
}
|
|
156
|
+
errorCallback(imageId, permanent, error) {
|
|
157
|
+
if (!permanent) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
const { totalNumFrames, numFrames } = this;
|
|
161
|
+
const imageIdIndex = this.getImageIdIndex(imageId);
|
|
162
|
+
this.framesProcessed++;
|
|
163
|
+
if (this.framesProcessed === totalNumFrames) {
|
|
164
|
+
this.loadStatus.loaded = true;
|
|
165
|
+
this.loadStatus.loading = false;
|
|
166
|
+
}
|
|
167
|
+
this.callLoadStatusCallback({
|
|
168
|
+
success: false,
|
|
169
|
+
imageId,
|
|
170
|
+
imageIdIndex,
|
|
171
|
+
error,
|
|
172
|
+
framesLoaded: this.framesLoaded,
|
|
173
|
+
framesProcessed: this.framesProcessed,
|
|
174
|
+
framesUpdated: this.framesUpdated,
|
|
175
|
+
numFrames,
|
|
176
|
+
totalNumFrames,
|
|
177
|
+
});
|
|
178
|
+
if (this.loadStatus.loaded) {
|
|
179
|
+
this.loadStatus.callbacks = [];
|
|
180
|
+
}
|
|
181
|
+
const eventDetail = {
|
|
182
|
+
error,
|
|
183
|
+
imageIdIndex,
|
|
184
|
+
imageId,
|
|
185
|
+
};
|
|
186
|
+
triggerEvent(eventTarget, Events.IMAGE_LOAD_ERROR, eventDetail);
|
|
187
|
+
}
|
|
188
|
+
getLoaderImageOptions(imageId) {
|
|
189
|
+
const { transferSyntaxUID: transferSyntaxUID } = metaData.get('transferSyntax', imageId) || {};
|
|
190
|
+
const imagePlaneModule = metaData.get('imagePlaneModule', imageId) || {};
|
|
191
|
+
const { rows, columns } = imagePlaneModule;
|
|
192
|
+
const imageIdIndex = this.getImageIdIndex(imageId);
|
|
193
|
+
const modalityLutModule = metaData.get('modalityLutModule', imageId) || {};
|
|
194
|
+
const generalSeriesModule = metaData.get('generalSeriesModule', imageId) || {};
|
|
195
|
+
const scalingParameters = {
|
|
196
|
+
rescaleSlope: modalityLutModule.rescaleSlope,
|
|
197
|
+
rescaleIntercept: modalityLutModule.rescaleIntercept,
|
|
198
|
+
modality: generalSeriesModule.modality,
|
|
199
|
+
};
|
|
200
|
+
if (scalingParameters.modality === 'PT') {
|
|
201
|
+
const suvFactor = metaData.get('scalingModule', imageId);
|
|
202
|
+
if (suvFactor) {
|
|
203
|
+
this._addScalingToVolume(suvFactor);
|
|
204
|
+
scalingParameters.suvbw = suvFactor.suvbw;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
const floatAfterScale = hasFloatScalingParameters(scalingParameters);
|
|
208
|
+
const allowFloatRendering = canRenderFloatTextures();
|
|
209
|
+
this.isPreScaled = true;
|
|
210
|
+
if (scalingParameters &&
|
|
211
|
+
scalingParameters.rescaleSlope !== undefined &&
|
|
212
|
+
scalingParameters.rescaleIntercept !== undefined) {
|
|
213
|
+
const { rescaleSlope, rescaleIntercept } = scalingParameters;
|
|
214
|
+
this.isPreScaled =
|
|
215
|
+
typeof rescaleSlope === 'number' &&
|
|
216
|
+
typeof rescaleIntercept === 'number';
|
|
217
|
+
}
|
|
218
|
+
if (!allowFloatRendering && floatAfterScale) {
|
|
219
|
+
this.isPreScaled = false;
|
|
220
|
+
}
|
|
221
|
+
const targetBuffer = {
|
|
222
|
+
type: this.dataType,
|
|
223
|
+
rows,
|
|
224
|
+
columns,
|
|
225
|
+
};
|
|
226
|
+
return {
|
|
227
|
+
targetBuffer,
|
|
228
|
+
allowFloatRendering,
|
|
229
|
+
preScale: {
|
|
230
|
+
enabled: this.isPreScaled,
|
|
231
|
+
scalingParameters,
|
|
232
|
+
},
|
|
233
|
+
transferPixelData: true,
|
|
234
|
+
requestType: requestTypeDefault,
|
|
235
|
+
transferSyntaxUID,
|
|
236
|
+
additionalDetails: {
|
|
237
|
+
imageId,
|
|
238
|
+
imageIdIndex,
|
|
239
|
+
volumeId: this.volumeId,
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
callLoadImage(imageId, imageIdIndex, options) {
|
|
244
|
+
const { cachedFrames } = this;
|
|
245
|
+
if (cachedFrames[imageIdIndex] === ImageQualityStatus.FULL_RESOLUTION) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
const handleImageCacheAdded = (event) => {
|
|
249
|
+
const { image } = event.detail;
|
|
250
|
+
if (image.imageId === imageId) {
|
|
251
|
+
this.vtkOpenGLTexture.setUpdatedFrame(imageIdIndex);
|
|
252
|
+
eventTarget.removeEventListener(Events.IMAGE_CACHE_IMAGE_ADDED, handleImageCacheAdded);
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
eventTarget.addEventListener(Events.IMAGE_CACHE_IMAGE_ADDED, handleImageCacheAdded);
|
|
256
|
+
const uncompressedIterator = ProgressiveIterator.as(loadAndCacheImage(imageId, options));
|
|
257
|
+
return uncompressedIterator.forEach((image) => {
|
|
258
|
+
this.successCallback(imageId, image);
|
|
259
|
+
}, this.errorCallback.bind(this, imageIdIndex, imageId));
|
|
260
|
+
}
|
|
261
|
+
getImageIdsRequests(imageIds, priorityDefault) {
|
|
262
|
+
this.totalNumFrames = this.imageIds.length;
|
|
263
|
+
const autoRenderPercentage = 2;
|
|
264
|
+
if (this.autoRenderOnLoad) {
|
|
265
|
+
this.reRenderFraction =
|
|
266
|
+
this.totalNumFrames * (autoRenderPercentage / 100);
|
|
267
|
+
this.reRenderTarget = this.reRenderFraction;
|
|
268
|
+
}
|
|
269
|
+
const requests = imageIds.map((imageId) => {
|
|
270
|
+
const imageIdIndex = this.getImageIdIndex(imageId);
|
|
271
|
+
const requestType = requestTypeDefault;
|
|
272
|
+
const priority = priorityDefault;
|
|
273
|
+
const options = this.getLoaderImageOptions(imageId);
|
|
274
|
+
return {
|
|
275
|
+
callLoadImage: this.callLoadImage.bind(this),
|
|
276
|
+
imageId,
|
|
277
|
+
imageIdIndex,
|
|
278
|
+
options,
|
|
279
|
+
priority,
|
|
280
|
+
requestType,
|
|
281
|
+
additionalDetails: {
|
|
282
|
+
volumeId: this.volumeId,
|
|
283
|
+
},
|
|
284
|
+
};
|
|
285
|
+
});
|
|
286
|
+
return requests;
|
|
287
|
+
}
|
|
288
|
+
getImageLoadRequests(priority) {
|
|
289
|
+
throw new Error('Abstract method');
|
|
290
|
+
}
|
|
291
|
+
getImageIdsToLoad() {
|
|
292
|
+
throw new Error('Abstract method');
|
|
293
|
+
}
|
|
294
|
+
loadImages() {
|
|
295
|
+
this.loadStatus.loading = true;
|
|
296
|
+
const requests = this.getImageLoadRequests(5);
|
|
297
|
+
requests.reverse().forEach((request) => {
|
|
298
|
+
if (!request) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const { callLoadImage, imageId, imageIdIndex, options, priority, requestType, additionalDetails, } = request;
|
|
302
|
+
imageLoadPoolManager.addRequest(callLoadImage.bind(this, imageId, imageIdIndex, options), requestType, additionalDetails, priority);
|
|
303
|
+
});
|
|
304
|
+
return Promise.resolve(true);
|
|
305
|
+
}
|
|
306
|
+
_prefetchImageIds() {
|
|
307
|
+
this.loadStatus.loading = true;
|
|
308
|
+
const imageIds = [...this.getImageIdsToLoad()];
|
|
309
|
+
imageIds.reverse();
|
|
310
|
+
this.totalNumFrames = this.imageIds.length;
|
|
311
|
+
const autoRenderPercentage = 2;
|
|
312
|
+
if (this.autoRenderOnLoad) {
|
|
313
|
+
this.reRenderFraction =
|
|
314
|
+
this.totalNumFrames * (autoRenderPercentage / 100);
|
|
315
|
+
this.reRenderTarget = this.reRenderFraction;
|
|
316
|
+
}
|
|
317
|
+
return this.imagesLoader.loadImages(imageIds, this).catch((e) => {
|
|
318
|
+
console.debug('progressive loading failed to complete', e);
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
_addScalingToVolume(suvFactor) {
|
|
322
|
+
if (this.scaling) {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
const { suvbw, suvlbm, suvbsa } = suvFactor;
|
|
326
|
+
const petScaling = {};
|
|
327
|
+
if (suvlbm) {
|
|
328
|
+
petScaling.suvbwToSuvlbm = suvlbm / suvbw;
|
|
329
|
+
}
|
|
330
|
+
if (suvbsa) {
|
|
331
|
+
petScaling.suvbwToSuvbsa = suvbsa / suvbw;
|
|
332
|
+
}
|
|
333
|
+
if (suvbw) {
|
|
334
|
+
petScaling.suvbw = suvbw;
|
|
335
|
+
}
|
|
336
|
+
this.scaling = { PT: petScaling };
|
|
337
|
+
}
|
|
338
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { IDynamicImageVolume, ImageVolumeProps, IStreamingVolumeProperties } from '../../types';
|
|
2
|
+
import BaseStreamingImageVolume from './BaseStreamingImageVolume';
|
|
3
|
+
export default class StreamingDynamicImageVolume extends BaseStreamingImageVolume implements IDynamicImageVolume {
|
|
4
|
+
private _timePointIndex;
|
|
5
|
+
private _splittingTag;
|
|
6
|
+
private _imageIdGroups;
|
|
7
|
+
numTimePoints: number;
|
|
8
|
+
constructor(imageVolumeProperties: ImageVolumeProps & {
|
|
9
|
+
splittingTag: string;
|
|
10
|
+
imageIdGroups: string[][];
|
|
11
|
+
}, streamingProperties: IStreamingVolumeProperties);
|
|
12
|
+
private _getImageIdsToLoad;
|
|
13
|
+
private _getImageIdRequests;
|
|
14
|
+
getImageIdsToLoad(): string[];
|
|
15
|
+
get timePointIndex(): number;
|
|
16
|
+
set timePointIndex(index: number);
|
|
17
|
+
scroll(delta: number): void;
|
|
18
|
+
getCurrentTimePointImageIds(): string[];
|
|
19
|
+
flatImageIdIndexToTimePointIndex(flatImageIdIndex: number): number;
|
|
20
|
+
flatImageIdIndexToImageIdIndex(flatImageIdIndex: number): number;
|
|
21
|
+
get splittingTag(): string;
|
|
22
|
+
getImageLoadRequests: (priority: number) => {
|
|
23
|
+
callLoadImage: (imageId: any, imageIdIndex: any, options: any) => any;
|
|
24
|
+
imageId: string;
|
|
25
|
+
imageIdIndex: number;
|
|
26
|
+
options: {
|
|
27
|
+
targetBuffer: {
|
|
28
|
+
type: import("../../types").PixelDataTypedArrayString;
|
|
29
|
+
rows: any;
|
|
30
|
+
columns: any;
|
|
31
|
+
};
|
|
32
|
+
allowFloatRendering: boolean;
|
|
33
|
+
preScale: {
|
|
34
|
+
enabled: boolean;
|
|
35
|
+
scalingParameters: import("../../types").ScalingParameters;
|
|
36
|
+
};
|
|
37
|
+
transferPixelData: boolean;
|
|
38
|
+
requestType: import("../../enums").RequestType;
|
|
39
|
+
transferSyntaxUID: any;
|
|
40
|
+
additionalDetails: {
|
|
41
|
+
imageId: string;
|
|
42
|
+
imageIdIndex: number;
|
|
43
|
+
volumeId: string;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
priority: number;
|
|
47
|
+
requestType: import("../../enums").RequestType;
|
|
48
|
+
additionalDetails: {
|
|
49
|
+
volumeId: string;
|
|
50
|
+
};
|
|
51
|
+
}[];
|
|
52
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Events } from '../../enums';
|
|
2
|
+
import eventTarget from '../../eventTarget';
|
|
3
|
+
import { triggerEvent } from '../../utilities';
|
|
4
|
+
import BaseStreamingImageVolume from './BaseStreamingImageVolume';
|
|
5
|
+
export default class StreamingDynamicImageVolume extends BaseStreamingImageVolume {
|
|
6
|
+
constructor(imageVolumeProperties, streamingProperties) {
|
|
7
|
+
super(imageVolumeProperties, streamingProperties);
|
|
8
|
+
this._timePointIndex = 0;
|
|
9
|
+
this._getImageIdRequests = (imageIds, priority) => {
|
|
10
|
+
return this.getImageIdsRequests(imageIds, priority);
|
|
11
|
+
};
|
|
12
|
+
this.getImageLoadRequests = (priority) => {
|
|
13
|
+
const imageIds = this.getImageIdsToLoad();
|
|
14
|
+
return this._getImageIdRequests(imageIds, priority);
|
|
15
|
+
};
|
|
16
|
+
const { imageIdGroups, splittingTag } = imageVolumeProperties;
|
|
17
|
+
this._splittingTag = splittingTag;
|
|
18
|
+
this._imageIdGroups = imageIdGroups;
|
|
19
|
+
this.numTimePoints = this._imageIdGroups.length;
|
|
20
|
+
}
|
|
21
|
+
_getImageIdsToLoad() {
|
|
22
|
+
const imageIdGroups = this._imageIdGroups;
|
|
23
|
+
const initialImageIdGroupIndex = this._timePointIndex;
|
|
24
|
+
const imageIds = [...imageIdGroups[initialImageIdGroupIndex]];
|
|
25
|
+
let leftIndex = initialImageIdGroupIndex - 1;
|
|
26
|
+
let rightIndex = initialImageIdGroupIndex + 1;
|
|
27
|
+
while (leftIndex >= 0 || rightIndex < imageIdGroups.length) {
|
|
28
|
+
if (leftIndex >= 0) {
|
|
29
|
+
imageIds.push(...imageIdGroups[leftIndex--]);
|
|
30
|
+
}
|
|
31
|
+
if (rightIndex < imageIdGroups.length) {
|
|
32
|
+
imageIds.push(...imageIdGroups[rightIndex++]);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return imageIds;
|
|
36
|
+
}
|
|
37
|
+
getImageIdsToLoad() {
|
|
38
|
+
return this._getImageIdsToLoad();
|
|
39
|
+
}
|
|
40
|
+
get timePointIndex() {
|
|
41
|
+
return this._timePointIndex;
|
|
42
|
+
}
|
|
43
|
+
set timePointIndex(index) {
|
|
44
|
+
if (this._timePointIndex === index) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
this._timePointIndex = index;
|
|
48
|
+
this.voxelManager.setTimePoint(index);
|
|
49
|
+
this.invalidateVolume(true);
|
|
50
|
+
triggerEvent(eventTarget, Events.DYNAMIC_VOLUME_TIME_POINT_INDEX_CHANGED, {
|
|
51
|
+
volumeId: this.volumeId,
|
|
52
|
+
imageIdGroupIndex: index,
|
|
53
|
+
numImageIdGroups: this.numTimePoints,
|
|
54
|
+
splittingTag: this.splittingTag,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
scroll(delta) {
|
|
58
|
+
const newIndex = this._timePointIndex + delta;
|
|
59
|
+
if (newIndex < 0) {
|
|
60
|
+
this.timePointIndex = this.numTimePoints - 1;
|
|
61
|
+
}
|
|
62
|
+
else if (newIndex >= this.numTimePoints) {
|
|
63
|
+
this.timePointIndex = 0;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
this.timePointIndex = newIndex;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
getCurrentTimePointImageIds() {
|
|
70
|
+
return this._imageIdGroups[this._timePointIndex];
|
|
71
|
+
}
|
|
72
|
+
flatImageIdIndexToTimePointIndex(flatImageIdIndex) {
|
|
73
|
+
return Math.floor(flatImageIdIndex / this._imageIdGroups[0].length);
|
|
74
|
+
}
|
|
75
|
+
flatImageIdIndexToImageIdIndex(flatImageIdIndex) {
|
|
76
|
+
return flatImageIdIndex % this._imageIdGroups[0].length;
|
|
77
|
+
}
|
|
78
|
+
get splittingTag() {
|
|
79
|
+
return this._splittingTag;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ImageLoadRequests, ImageVolumeProps, IStreamingVolumeProperties, PixelDataTypedArray } from '../../types';
|
|
2
|
+
import BaseStreamingImageVolume from './BaseStreamingImageVolume';
|
|
3
|
+
export default class StreamingImageVolume extends BaseStreamingImageVolume {
|
|
4
|
+
constructor(imageVolumeProperties: ImageVolumeProps, streamingProperties: IStreamingVolumeProperties);
|
|
5
|
+
getScalarData(): PixelDataTypedArray;
|
|
6
|
+
getImageLoadRequests(priority: number): ImageLoadRequests[];
|
|
7
|
+
getImageIdsToLoad: () => string[];
|
|
8
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import BaseStreamingImageVolume from './BaseStreamingImageVolume';
|
|
2
|
+
export default class StreamingImageVolume extends BaseStreamingImageVolume {
|
|
3
|
+
constructor(imageVolumeProperties, streamingProperties) {
|
|
4
|
+
if (!imageVolumeProperties.imageIds) {
|
|
5
|
+
imageVolumeProperties.imageIds = streamingProperties.imageIds;
|
|
6
|
+
}
|
|
7
|
+
super(imageVolumeProperties, streamingProperties);
|
|
8
|
+
this.getImageIdsToLoad = () => {
|
|
9
|
+
const { imageIds } = this;
|
|
10
|
+
this.numFrames = imageIds.length;
|
|
11
|
+
return imageIds;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
getScalarData() {
|
|
15
|
+
return this.voxelManager.getScalarData();
|
|
16
|
+
}
|
|
17
|
+
getImageLoadRequests(priority) {
|
|
18
|
+
const { imageIds } = this;
|
|
19
|
+
return this.getImageIdsRequests(imageIds, priority);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Cache } from './cache';
|
|
2
2
|
import ImageVolume from './classes/ImageVolume';
|
|
3
3
|
import { Surface } from './classes/Surface';
|
|
4
|
-
|
|
4
|
+
import StreamingImageVolume from './classes/StreamingImageVolume';
|
|
5
|
+
import StreamingDynamicImageVolume from './classes/StreamingDynamicImageVolume';
|
|
6
|
+
export { ImageVolume, Cache, Surface, StreamingImageVolume, StreamingDynamicImageVolume, };
|
package/dist/esm/cache/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Cache } from './cache';
|
|
2
2
|
import ImageVolume from './classes/ImageVolume';
|
|
3
3
|
import { Surface } from './classes/Surface';
|
|
4
|
-
|
|
4
|
+
import StreamingImageVolume from './classes/StreamingImageVolume';
|
|
5
|
+
import StreamingDynamicImageVolume from './classes/StreamingDynamicImageVolume';
|
|
6
|
+
export { ImageVolume, Cache, Surface, StreamingImageVolume, StreamingDynamicImageVolume, };
|