@cornerstonejs/core 2.0.0-beta.22 → 2.0.0-beta.23
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/cache/classes/BaseStreamingImageVolume.d.ts +85 -0
- package/dist/esm/cache/classes/BaseStreamingImageVolume.js +339 -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/types/ImageLoadRequests.d.ts +24 -0
- package/dist/esm/types/ImageLoadRequests.js +1 -0
- package/dist/esm/types/index.d.ts +2 -1
- package/dist/esm/utilities/autoLoad.d.ts +2 -0
- package/dist/esm/utilities/autoLoad.js +28 -0
- 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
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { StreamingDynamicImageVolume } from '../cache';
|
|
2
|
+
import { generateVolumePropsFromImageIds, sortImageIdsAndGetSpacing, splitImageIdsBy4DTags, VoxelManager, } from '../utilities';
|
|
3
|
+
function cornerstoneStreamingDynamicImageVolumeLoader(volumeId, options) {
|
|
4
|
+
if (!options || !options.imageIds || !options.imageIds.length) {
|
|
5
|
+
throw new Error('ImageIds must be provided to create a 4D streaming image volume');
|
|
6
|
+
}
|
|
7
|
+
const { imageIds } = options;
|
|
8
|
+
const { splittingTag, imageIdGroups } = splitImageIdsBy4DTags(imageIds);
|
|
9
|
+
const volumeProps = generateVolumePropsFromImageIds(imageIdGroups[0], volumeId);
|
|
10
|
+
const { metadata: volumeMetadata, dimensions, spacing, direction, sizeInBytes, origin, numberOfComponents, dataType, } = volumeProps;
|
|
11
|
+
const scanAxisNormal = direction.slice(6, 9);
|
|
12
|
+
const sortedImageIdGroups = imageIdGroups.map((imageIds) => {
|
|
13
|
+
const sortedImageIds = sortImageIdsAndGetSpacing(imageIds, scanAxisNormal).sortedImageIds;
|
|
14
|
+
return sortedImageIds;
|
|
15
|
+
});
|
|
16
|
+
const sortedFlatImageIds = sortedImageIdGroups.flat();
|
|
17
|
+
const voxelManager = VoxelManager.createScalarDynamicVolumeVoxelManager({
|
|
18
|
+
dimensions,
|
|
19
|
+
imageIdGroups: sortedImageIdGroups,
|
|
20
|
+
timePoint: 0,
|
|
21
|
+
numberOfComponents,
|
|
22
|
+
});
|
|
23
|
+
let streamingImageVolume = new StreamingDynamicImageVolume({
|
|
24
|
+
volumeId,
|
|
25
|
+
metadata: volumeMetadata,
|
|
26
|
+
dimensions,
|
|
27
|
+
spacing,
|
|
28
|
+
origin,
|
|
29
|
+
direction,
|
|
30
|
+
sizeInBytes,
|
|
31
|
+
imageIds: sortedFlatImageIds,
|
|
32
|
+
imageIdGroups: sortedImageIdGroups,
|
|
33
|
+
splittingTag,
|
|
34
|
+
voxelManager,
|
|
35
|
+
numberOfComponents,
|
|
36
|
+
dataType,
|
|
37
|
+
}, {
|
|
38
|
+
imageIds: sortedFlatImageIds,
|
|
39
|
+
loadStatus: {
|
|
40
|
+
loaded: false,
|
|
41
|
+
loading: false,
|
|
42
|
+
cancelled: false,
|
|
43
|
+
cachedFrames: [],
|
|
44
|
+
callbacks: [],
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
48
|
+
promise: Promise.resolve(streamingImageVolume),
|
|
49
|
+
decache: () => {
|
|
50
|
+
streamingImageVolume.destroy();
|
|
51
|
+
streamingImageVolume = null;
|
|
52
|
+
},
|
|
53
|
+
cancel: () => {
|
|
54
|
+
streamingImageVolume.cancelLoading();
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export { cornerstoneStreamingDynamicImageVolumeLoader };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import StreamingImageVolume from '../cache/classes/StreamingImageVolume';
|
|
2
|
+
import type { IRetrieveConfiguration } from '../types';
|
|
3
|
+
interface IVolumeLoader {
|
|
4
|
+
promise: Promise<StreamingImageVolume>;
|
|
5
|
+
cancel: () => void;
|
|
6
|
+
decache: () => void;
|
|
7
|
+
}
|
|
8
|
+
declare function cornerstoneStreamingImageVolumeLoader(volumeId: string, options: {
|
|
9
|
+
imageIds: string[];
|
|
10
|
+
progressiveRendering?: boolean | IRetrieveConfiguration;
|
|
11
|
+
}): IVolumeLoader;
|
|
12
|
+
export { cornerstoneStreamingImageVolumeLoader };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import StreamingImageVolume from '../cache/classes/StreamingImageVolume';
|
|
2
|
+
import { RequestType } from '../enums';
|
|
3
|
+
import imageLoadPoolManager from '../requestPool/imageLoadPoolManager';
|
|
4
|
+
import { generateVolumePropsFromImageIds } from '../utilities';
|
|
5
|
+
import { loadImage } from './imageLoader';
|
|
6
|
+
function cornerstoneStreamingImageVolumeLoader(volumeId, options) {
|
|
7
|
+
if (!options || !options.imageIds || !options.imageIds.length) {
|
|
8
|
+
throw new Error('ImageIds must be provided to create a streaming image volume');
|
|
9
|
+
}
|
|
10
|
+
async function getStreamingImageVolume() {
|
|
11
|
+
if (options.imageIds[0].split(':')[0] === 'wadouri') {
|
|
12
|
+
const [middleImageIndex, lastImageIndex] = [
|
|
13
|
+
Math.floor(options.imageIds.length / 2),
|
|
14
|
+
options.imageIds.length - 1,
|
|
15
|
+
];
|
|
16
|
+
const indexesToPrefetch = [0, middleImageIndex, lastImageIndex];
|
|
17
|
+
await Promise.all(indexesToPrefetch.map((index) => {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
const imageId = options.imageIds[index];
|
|
20
|
+
imageLoadPoolManager.addRequest(async () => {
|
|
21
|
+
loadImage(imageId)
|
|
22
|
+
.then(() => {
|
|
23
|
+
console.log(`Prefetched imageId: ${imageId}`);
|
|
24
|
+
resolve(true);
|
|
25
|
+
})
|
|
26
|
+
.catch((err) => {
|
|
27
|
+
reject(err);
|
|
28
|
+
});
|
|
29
|
+
}, RequestType.Prefetch, { volumeId }, 1);
|
|
30
|
+
});
|
|
31
|
+
})).catch(console.error);
|
|
32
|
+
}
|
|
33
|
+
const volumeProps = generateVolumePropsFromImageIds(options.imageIds, volumeId);
|
|
34
|
+
const { dimensions, spacing, origin, direction, metadata, imageIds, dataType, numberOfComponents, } = volumeProps;
|
|
35
|
+
const streamingImageVolume = new StreamingImageVolume({
|
|
36
|
+
volumeId,
|
|
37
|
+
metadata,
|
|
38
|
+
dimensions,
|
|
39
|
+
spacing,
|
|
40
|
+
origin,
|
|
41
|
+
direction,
|
|
42
|
+
imageIds,
|
|
43
|
+
dataType,
|
|
44
|
+
numberOfComponents,
|
|
45
|
+
}, {
|
|
46
|
+
imageIds,
|
|
47
|
+
loadStatus: {
|
|
48
|
+
loaded: false,
|
|
49
|
+
loading: false,
|
|
50
|
+
cancelled: false,
|
|
51
|
+
cachedFrames: [],
|
|
52
|
+
callbacks: [],
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
return streamingImageVolume;
|
|
56
|
+
}
|
|
57
|
+
const streamingImageVolumePromise = getStreamingImageVolume();
|
|
58
|
+
return {
|
|
59
|
+
promise: streamingImageVolumePromise,
|
|
60
|
+
decache: () => {
|
|
61
|
+
streamingImageVolumePromise.then((streamingImageVolume) => {
|
|
62
|
+
streamingImageVolume.destroy();
|
|
63
|
+
streamingImageVolume = null;
|
|
64
|
+
});
|
|
65
|
+
},
|
|
66
|
+
cancel: () => {
|
|
67
|
+
streamingImageVolumePromise.then((streamingImageVolume) => {
|
|
68
|
+
streamingImageVolume.cancelLoading();
|
|
69
|
+
});
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export { cornerstoneStreamingImageVolumeLoader };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { RequestType } from '../enums';
|
|
2
|
+
import type { ScalingParameters } from './ScalingParameters';
|
|
3
|
+
export default interface ImageLoadRequests {
|
|
4
|
+
callLoadImage: (imageId: string, imageIdIndex: number, options: unknown) => Promise<void>;
|
|
5
|
+
imageId: string;
|
|
6
|
+
imageIdIndex: number;
|
|
7
|
+
options: {
|
|
8
|
+
targetBuffer: {
|
|
9
|
+
type: string;
|
|
10
|
+
rows: number;
|
|
11
|
+
columns: number;
|
|
12
|
+
};
|
|
13
|
+
preScale: {
|
|
14
|
+
enabled: boolean;
|
|
15
|
+
scalingParameters: ScalingParameters;
|
|
16
|
+
};
|
|
17
|
+
transferPixelData: boolean;
|
|
18
|
+
};
|
|
19
|
+
priority: number;
|
|
20
|
+
requestType: RequestType;
|
|
21
|
+
additionalDetails: {
|
|
22
|
+
volumeId: string;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -92,4 +92,5 @@ import type IImageFrame from './IImageFrame';
|
|
|
92
92
|
import type { DicomDateObject, DicomTimeObject, GeneralSeriesModuleMetadata, ImagePlaneModuleMetadata, SopCommonModuleMetadata, ImagePixelModuleMetadata, PatientStudyModuleMetadata, TransferSyntaxMetadata } from './MetadataModuleTypes';
|
|
93
93
|
import type { IVoxelManager } from './IVoxelManager';
|
|
94
94
|
import type { IRLEVoxelMap, RLERun } from './IRLEVoxelMap';
|
|
95
|
-
|
|
95
|
+
import type ImageLoadRequests from './ImageLoadRequests';
|
|
96
|
+
export type { Cornerstone3DConfig, ICamera, IStackViewport, IVideoViewport, IWSIViewport, IVolumeViewport, IEnabledElement, ICache, IVolume, IViewportId, IImageVolume, ImageVolumeProps, IDynamicImageVolume, IRenderingEngine, ScalingParameters, PTScaling, IPointsManager, PolyDataPointConfiguration, Scaling, IStreamingImageVolume, IImage, IImageData, IImageCalibration, CPUIImageData, CPUImageData, EventTypes, ImageLoaderFn, VolumeLoaderFn, IRegisterImageLoader, IStreamingVolumeProperties, IViewport, ViewReference, DataSetOptions as ImageSetOptions, ViewPresentation, ViewPresentationSelector, ReferenceCompatibleOptions, ViewReferenceSpecifier, StackViewportProperties, VolumeViewportProperties, ViewportProperties, PublicViewportInput, VolumeActor, Actor, ActorEntry, ImageActor, ICanvasActor, IImageLoadObject, IVolumeLoadObject, IVolumeInput, VolumeInputCallback, IStackInput, StackInputCallback, ViewportPreset, Metadata, OrientationVectors, AABB2, AABB3, Point2, Point3, PointsXYZ, Point4, Mat3, Plane, ViewportInputOptions, VideoViewportProperties, WSIViewportProperties, VOIRange, VOI, DisplayArea, FlipDirection, ICachedImage, ICachedVolume, CPUFallbackEnabledElement, CPUFallbackViewport, CPUFallbackTransform, CPUFallbackColormapData, CPUFallbackViewportDisplayedArea, CPUFallbackColormapsData, CPUFallbackColormap, TransformMatrix2D, CPUFallbackLookupTable, CPUFallbackLUT, CPUFallbackRenderingTools, CustomEventType, ActorSliceRange, ImageSliceData, IGeometry, IGeometryLoadObject, ICachedGeometry, PublicContourSetData, ContourSetData, ContourData, IContourSet, IContour, PublicSurfaceData, SurfaceData, ISurface, RGB, ColormapPublic, ColormapRegistration, PixelDataTypedArray, PixelDataTypedArrayString, ImagePixelModule, ImagePlaneModule, AffineMatrix, ImageLoadListener, InternalVideoCamera, VideoViewportInput, WSIViewportInput, BoundsIJK, BoundsLPS, Color, ColorLUT, VolumeProps, IImageFrame, DicomDateObject, DicomTimeObject, GeneralSeriesModuleMetadata, ImagePlaneModuleMetadata, SopCommonModuleMetadata, ImagePixelModuleMetadata, PatientStudyModuleMetadata, TransferSyntaxMetadata, LocalVolumeOptions, IVoxelManager, IRLEVoxelMap, RLERun, ViewportInput, ImageLoadRequests, };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { getRenderingEngines } from '../RenderingEngine/getRenderingEngine';
|
|
2
|
+
import getViewportsWithVolumeId from './getViewportsWithVolumeId';
|
|
3
|
+
const autoLoad = (volumeId) => {
|
|
4
|
+
const renderingEngineAndViewportIds = getRenderingEngineAndViewportsContainingVolume(volumeId);
|
|
5
|
+
if (!renderingEngineAndViewportIds?.length) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
renderingEngineAndViewportIds.forEach(({ renderingEngine, viewportIds }) => {
|
|
9
|
+
if (!renderingEngine.hasBeenDestroyed) {
|
|
10
|
+
renderingEngine.renderViewports(viewportIds);
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
function getRenderingEngineAndViewportsContainingVolume(volumeId) {
|
|
15
|
+
const renderingEnginesArray = getRenderingEngines();
|
|
16
|
+
const renderingEngineAndViewportIds = [];
|
|
17
|
+
renderingEnginesArray.forEach((renderingEngine) => {
|
|
18
|
+
const viewports = getViewportsWithVolumeId(volumeId, renderingEngine.id);
|
|
19
|
+
if (viewports.length) {
|
|
20
|
+
renderingEngineAndViewportIds.push({
|
|
21
|
+
renderingEngine,
|
|
22
|
+
viewportIds: viewports.map((viewport) => viewport.id),
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return renderingEngineAndViewportIds;
|
|
27
|
+
}
|
|
28
|
+
export default autoLoad;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import splitImageIdsBy4DTags from './splitImageIdsBy4DTags';
|
|
2
|
+
function getDynamicVolumeInfo(imageIds) {
|
|
3
|
+
const { imageIdGroups: timePoints, splittingTag } = splitImageIdsBy4DTags(imageIds);
|
|
4
|
+
const isDynamicVolume = timePoints.length > 1;
|
|
5
|
+
return { isDynamicVolume, timePoints, splittingTag };
|
|
6
|
+
}
|
|
7
|
+
export default getDynamicVolumeInfo;
|
|
@@ -73,5 +73,9 @@ import * as colormap from './colormap';
|
|
|
73
73
|
import * as transferFunctionUtils from './transferFunctionUtils';
|
|
74
74
|
import * as color from './color';
|
|
75
75
|
import type { IViewport } from '../types/IViewport';
|
|
76
|
+
import getDynamicVolumeInfo from './getDynamicVolumeInfo';
|
|
77
|
+
import autoLoad from './autoLoad';
|
|
78
|
+
import scaleArray from './scaleArray';
|
|
79
|
+
import splitImageIdsBy4DTags from './splitImageIdsBy4DTags';
|
|
76
80
|
declare const getViewportModality: (viewport: IViewport, volumeId?: string) => string;
|
|
77
|
-
export { eventListener, csUtils as invertRgbTransferFunction, createSigmoidRGBTransferFunction, getVoiFromSigmoidRGBTransferFunction, createLinearRGBTransferFunction, scaleRgbTransferFunction, triggerEvent, imageIdToURI, calibratedPixelSpacingMetadataProvider, clamp, uuidv4, planar, getMinMax, getRuntimeId, isEqual, isEqualAbs, isEqualNegative, isOpposite, getViewportModality, windowLevel, convertToGrayscale, getClosestImageId, getSpacingInNormalDirection, getTargetVolumeAndSpacingInNormalDir, getVolumeActorCorners, indexWithinDimensions, getVolumeViewportsContainingSameVolumes, getViewportsWithVolumeId, transformWorldToIndex, transformIndexToWorld, loadImageToCanvas, renderToCanvasCPU, renderToCanvasGPU, worldToImageCoords, imageToWorldCoords, getVolumeSliceRangeInfo, getVolumeViewportScrollInfo, getSliceRange, snapFocalPointToSlice, getImageSliceDataForVolumeViewport, isImageActor, isPTPrescaledWithSUV, actorIsA, getViewportsWithImageURI, getClosestStackImageIndexForPoint, getCurrentVolumeViewportSlice, calculateViewportsSpatialRegistration, spatialRegistrationMetadataProvider, getViewportImageCornersInWorld, hasNaNValues, applyPreset, deepMerge, PointsManager, getScalingParameters, colormap, getImageLegacy, ProgressiveIterator, decimate, imageRetrieveMetadataProvider, transferFunctionUtils, updateVTKImageDataWithCornerstoneImage, sortImageIdsAndGetSpacing, makeVolumeMetadata, isValidVolume, genericMetadataProvider, isVideoTransferSyntax, generateVolumePropsFromImageIds, getBufferConfiguration, VoxelManager, RLEVoxelMap, convertStackToVolumeViewport, convertVolumeToStackViewport, roundNumber, roundToPrecision, getViewportImageIds, getRandomSampleFromArray, getVolumeId, color, hasFloatScalingParameters, };
|
|
81
|
+
export { eventListener, csUtils as invertRgbTransferFunction, createSigmoidRGBTransferFunction, getVoiFromSigmoidRGBTransferFunction, createLinearRGBTransferFunction, scaleRgbTransferFunction, triggerEvent, imageIdToURI, calibratedPixelSpacingMetadataProvider, clamp, uuidv4, planar, getMinMax, getRuntimeId, isEqual, isEqualAbs, isEqualNegative, isOpposite, getViewportModality, windowLevel, convertToGrayscale, getClosestImageId, getSpacingInNormalDirection, getTargetVolumeAndSpacingInNormalDir, getVolumeActorCorners, indexWithinDimensions, getVolumeViewportsContainingSameVolumes, getViewportsWithVolumeId, transformWorldToIndex, transformIndexToWorld, loadImageToCanvas, renderToCanvasCPU, renderToCanvasGPU, worldToImageCoords, imageToWorldCoords, getVolumeSliceRangeInfo, getVolumeViewportScrollInfo, getSliceRange, snapFocalPointToSlice, getImageSliceDataForVolumeViewport, isImageActor, isPTPrescaledWithSUV, actorIsA, getViewportsWithImageURI, getClosestStackImageIndexForPoint, getCurrentVolumeViewportSlice, calculateViewportsSpatialRegistration, spatialRegistrationMetadataProvider, getViewportImageCornersInWorld, hasNaNValues, applyPreset, deepMerge, PointsManager, getScalingParameters, colormap, getImageLegacy, ProgressiveIterator, decimate, imageRetrieveMetadataProvider, transferFunctionUtils, updateVTKImageDataWithCornerstoneImage, sortImageIdsAndGetSpacing, makeVolumeMetadata, isValidVolume, genericMetadataProvider, isVideoTransferSyntax, generateVolumePropsFromImageIds, getBufferConfiguration, VoxelManager, RLEVoxelMap, convertStackToVolumeViewport, convertVolumeToStackViewport, roundNumber, roundToPrecision, getViewportImageIds, getRandomSampleFromArray, getVolumeId, color, hasFloatScalingParameters, getDynamicVolumeInfo, autoLoad, scaleArray, splitImageIdsBy4DTags, };
|
|
@@ -74,5 +74,9 @@ import * as transferFunctionUtils from './transferFunctionUtils';
|
|
|
74
74
|
import * as color from './color';
|
|
75
75
|
import { _getViewportModality } from './getViewportModality';
|
|
76
76
|
import cache from '../cache/cache';
|
|
77
|
+
import getDynamicVolumeInfo from './getDynamicVolumeInfo';
|
|
78
|
+
import autoLoad from './autoLoad';
|
|
79
|
+
import scaleArray from './scaleArray';
|
|
80
|
+
import splitImageIdsBy4DTags from './splitImageIdsBy4DTags';
|
|
77
81
|
const getViewportModality = (viewport, volumeId) => _getViewportModality(viewport, volumeId, cache.getVolume);
|
|
78
|
-
export { eventListener, csUtils as invertRgbTransferFunction, createSigmoidRGBTransferFunction, getVoiFromSigmoidRGBTransferFunction, createLinearRGBTransferFunction, scaleRgbTransferFunction, triggerEvent, imageIdToURI, calibratedPixelSpacingMetadataProvider, clamp, uuidv4, planar, getMinMax, getRuntimeId, isEqual, isEqualAbs, isEqualNegative, isOpposite, getViewportModality, windowLevel, convertToGrayscale, getClosestImageId, getSpacingInNormalDirection, getTargetVolumeAndSpacingInNormalDir, getVolumeActorCorners, indexWithinDimensions, getVolumeViewportsContainingSameVolumes, getViewportsWithVolumeId, transformWorldToIndex, transformIndexToWorld, loadImageToCanvas, renderToCanvasCPU, renderToCanvasGPU, worldToImageCoords, imageToWorldCoords, getVolumeSliceRangeInfo, getVolumeViewportScrollInfo, getSliceRange, snapFocalPointToSlice, getImageSliceDataForVolumeViewport, isImageActor, isPTPrescaledWithSUV, actorIsA, getViewportsWithImageURI, getClosestStackImageIndexForPoint, getCurrentVolumeViewportSlice, calculateViewportsSpatialRegistration, spatialRegistrationMetadataProvider, getViewportImageCornersInWorld, hasNaNValues, applyPreset, deepMerge, PointsManager, getScalingParameters, colormap, getImageLegacy, ProgressiveIterator, decimate, imageRetrieveMetadataProvider, transferFunctionUtils, updateVTKImageDataWithCornerstoneImage, sortImageIdsAndGetSpacing, makeVolumeMetadata, isValidVolume, genericMetadataProvider, isVideoTransferSyntax, generateVolumePropsFromImageIds, getBufferConfiguration, VoxelManager, RLEVoxelMap, convertStackToVolumeViewport, convertVolumeToStackViewport, roundNumber, roundToPrecision, getViewportImageIds, getRandomSampleFromArray, getVolumeId, color, hasFloatScalingParameters, };
|
|
82
|
+
export { eventListener, csUtils as invertRgbTransferFunction, createSigmoidRGBTransferFunction, getVoiFromSigmoidRGBTransferFunction, createLinearRGBTransferFunction, scaleRgbTransferFunction, triggerEvent, imageIdToURI, calibratedPixelSpacingMetadataProvider, clamp, uuidv4, planar, getMinMax, getRuntimeId, isEqual, isEqualAbs, isEqualNegative, isOpposite, getViewportModality, windowLevel, convertToGrayscale, getClosestImageId, getSpacingInNormalDirection, getTargetVolumeAndSpacingInNormalDir, getVolumeActorCorners, indexWithinDimensions, getVolumeViewportsContainingSameVolumes, getViewportsWithVolumeId, transformWorldToIndex, transformIndexToWorld, loadImageToCanvas, renderToCanvasCPU, renderToCanvasGPU, worldToImageCoords, imageToWorldCoords, getVolumeSliceRangeInfo, getVolumeViewportScrollInfo, getSliceRange, snapFocalPointToSlice, getImageSliceDataForVolumeViewport, isImageActor, isPTPrescaledWithSUV, actorIsA, getViewportsWithImageURI, getClosestStackImageIndexForPoint, getCurrentVolumeViewportSlice, calculateViewportsSpatialRegistration, spatialRegistrationMetadataProvider, getViewportImageCornersInWorld, hasNaNValues, applyPreset, deepMerge, PointsManager, getScalingParameters, colormap, getImageLegacy, ProgressiveIterator, decimate, imageRetrieveMetadataProvider, transferFunctionUtils, updateVTKImageDataWithCornerstoneImage, sortImageIdsAndGetSpacing, makeVolumeMetadata, isValidVolume, genericMetadataProvider, isVideoTransferSyntax, generateVolumePropsFromImageIds, getBufferConfiguration, VoxelManager, RLEVoxelMap, convertStackToVolumeViewport, convertVolumeToStackViewport, roundNumber, roundToPrecision, getViewportImageIds, getRandomSampleFromArray, getVolumeId, color, hasFloatScalingParameters, getDynamicVolumeInfo, autoLoad, scaleArray, splitImageIdsBy4DTags, };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export default function scaleArray(array, scalingParameters) {
|
|
2
|
+
const arrayLength = array.length;
|
|
3
|
+
const { rescaleSlope, rescaleIntercept, suvbw } = scalingParameters;
|
|
4
|
+
if (scalingParameters.modality === 'PT' && typeof suvbw === 'number') {
|
|
5
|
+
for (let i = 0; i < arrayLength; i++) {
|
|
6
|
+
array[i] = suvbw * (array[i] * rescaleSlope + rescaleIntercept);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
for (let i = 0; i < arrayLength; i++) {
|
|
11
|
+
array[i] = array[i] * rescaleSlope + rescaleIntercept;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return array;
|
|
15
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import * as metaData from '../metaData';
|
|
2
|
+
const groupBy = (array, key) => {
|
|
3
|
+
return array.reduce((rv, x) => {
|
|
4
|
+
(rv[x[key]] = rv[x[key]] || []).push(x);
|
|
5
|
+
return rv;
|
|
6
|
+
}, {});
|
|
7
|
+
};
|
|
8
|
+
function getIPPGroups(imageIds) {
|
|
9
|
+
const ippMetadata = imageIds.map((imageId) => {
|
|
10
|
+
const { imagePositionPatient } = metaData.get('imagePlaneModule', imageId) || {};
|
|
11
|
+
return { imageId, imagePositionPatient };
|
|
12
|
+
});
|
|
13
|
+
if (!ippMetadata.every((item) => item.imagePositionPatient)) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const positionGroups = groupBy(ippMetadata, 'imagePositionPatient');
|
|
17
|
+
const positions = Object.keys(positionGroups);
|
|
18
|
+
const frame_count = positionGroups[positions[0]].length;
|
|
19
|
+
if (frame_count === 1) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
const frame_count_equal = positions.every((k) => positionGroups[k].length === frame_count);
|
|
23
|
+
if (!frame_count_equal) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return positionGroups;
|
|
27
|
+
}
|
|
28
|
+
function test4DTag(IPPGroups, value_getter) {
|
|
29
|
+
const frame_groups = {};
|
|
30
|
+
let first_frame_value_set = [];
|
|
31
|
+
const positions = Object.keys(IPPGroups);
|
|
32
|
+
for (let i = 0; i < positions.length; i++) {
|
|
33
|
+
const frame_value_set = new Set();
|
|
34
|
+
const frames = IPPGroups[positions[i]];
|
|
35
|
+
for (let j = 0; j < frames.length; j++) {
|
|
36
|
+
const frame_value = value_getter(frames[j].imageId) || 0;
|
|
37
|
+
frame_groups[frame_value] = frame_groups[frame_value] || [];
|
|
38
|
+
frame_groups[frame_value].push({ imageId: frames[j].imageId });
|
|
39
|
+
frame_value_set.add(frame_value);
|
|
40
|
+
if (frame_value_set.size - 1 < j) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (i == 0) {
|
|
45
|
+
first_frame_value_set = Array.from(frame_value_set);
|
|
46
|
+
}
|
|
47
|
+
else if (!setEquals(first_frame_value_set, frame_value_set)) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return frame_groups;
|
|
52
|
+
}
|
|
53
|
+
function getTagValue(imageId, tag) {
|
|
54
|
+
const value = metaData.get(tag, imageId);
|
|
55
|
+
try {
|
|
56
|
+
return parseFloat(value);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function getPhilipsPrivateBValue(imageId) {
|
|
63
|
+
const value = metaData.get('20011003', imageId);
|
|
64
|
+
try {
|
|
65
|
+
const { InlineBinary } = value;
|
|
66
|
+
if (InlineBinary) {
|
|
67
|
+
const value_bytes = atob(InlineBinary);
|
|
68
|
+
const ary_buf = new ArrayBuffer(value_bytes.length);
|
|
69
|
+
const dv = new DataView(ary_buf);
|
|
70
|
+
for (let i = 0; i < value_bytes.length; i++) {
|
|
71
|
+
dv.setUint8(i, value_bytes.charCodeAt(i));
|
|
72
|
+
}
|
|
73
|
+
return new Float32Array(ary_buf)[0];
|
|
74
|
+
}
|
|
75
|
+
return parseFloat(value);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function getSiemensPrivateBValue(imageId) {
|
|
82
|
+
let value = metaData.get('0019100c', imageId) || metaData.get('0019100C', imageId);
|
|
83
|
+
try {
|
|
84
|
+
const { InlineBinary } = value;
|
|
85
|
+
if (InlineBinary) {
|
|
86
|
+
value = atob(InlineBinary);
|
|
87
|
+
}
|
|
88
|
+
return parseFloat(value);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function getGEPrivateBValue(imageId) {
|
|
95
|
+
let value = metaData.get('00431039', imageId);
|
|
96
|
+
try {
|
|
97
|
+
const { InlineBinary } = value;
|
|
98
|
+
if (InlineBinary) {
|
|
99
|
+
value = atob(InlineBinary).split('//');
|
|
100
|
+
}
|
|
101
|
+
return parseFloat(value[0]) % 100000;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function setEquals(set_a, set_b) {
|
|
108
|
+
if (set_a.length != set_b.size) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
for (let i = 0; i < set_a.length; i++) {
|
|
112
|
+
if (!set_b.has(set_a[i])) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
function getPetFrameReferenceTime(imageId) {
|
|
119
|
+
const moduleInfo = metaData.get('petImageModule', imageId);
|
|
120
|
+
return moduleInfo ? moduleInfo['frameReferenceTime'] : 0;
|
|
121
|
+
}
|
|
122
|
+
function splitImageIdsBy4DTags(imageIds) {
|
|
123
|
+
const positionGroups = getIPPGroups(imageIds);
|
|
124
|
+
if (!positionGroups) {
|
|
125
|
+
return { imageIdGroups: [imageIds], splittingTag: null };
|
|
126
|
+
}
|
|
127
|
+
const tags = [
|
|
128
|
+
'TemporalPositionIdentifier',
|
|
129
|
+
'DiffusionBValue',
|
|
130
|
+
'TriggerTime',
|
|
131
|
+
'EchoTime',
|
|
132
|
+
'EchoNumber',
|
|
133
|
+
'PhilipsPrivateBValue',
|
|
134
|
+
'SiemensPrivateBValue',
|
|
135
|
+
'GEPrivateBValue',
|
|
136
|
+
'PetFrameReferenceTime',
|
|
137
|
+
];
|
|
138
|
+
const fncList2 = [
|
|
139
|
+
(imageId) => getTagValue(imageId, tags[0]),
|
|
140
|
+
(imageId) => getTagValue(imageId, tags[1]),
|
|
141
|
+
(imageId) => getTagValue(imageId, tags[2]),
|
|
142
|
+
(imageId) => getTagValue(imageId, tags[3]),
|
|
143
|
+
(imageId) => getTagValue(imageId, tags[4]),
|
|
144
|
+
getPhilipsPrivateBValue,
|
|
145
|
+
getSiemensPrivateBValue,
|
|
146
|
+
getGEPrivateBValue,
|
|
147
|
+
getPetFrameReferenceTime,
|
|
148
|
+
];
|
|
149
|
+
for (let i = 0; i < fncList2.length; i++) {
|
|
150
|
+
const frame_groups = test4DTag(positionGroups, fncList2[i]);
|
|
151
|
+
if (frame_groups) {
|
|
152
|
+
const sortedKeys = Object.keys(frame_groups)
|
|
153
|
+
.map(Number.parseFloat)
|
|
154
|
+
.sort((a, b) => a - b);
|
|
155
|
+
const imageIdGroups = sortedKeys.map((key) => frame_groups[key].map((item) => item.imageId));
|
|
156
|
+
return { imageIdGroups, splittingTag: tags[i] };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return { imageIdGroups: [imageIds], splittingTag: null };
|
|
160
|
+
}
|
|
161
|
+
export default splitImageIdsBy4DTags;
|