@cornerstonejs/core 4.15.0 → 4.15.2

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.
@@ -35,6 +35,7 @@ export declare class ImageVolume {
35
35
  referencedImageIds?: string[];
36
36
  hasPixelSpacing: boolean;
37
37
  additionalDetails?: Record<string, unknown>;
38
+ numDimensionGroups: number;
38
39
  voxelManager?: IVoxelManager<number> | IVoxelManager<RGB>;
39
40
  dataType?: PixelDataTypedArrayString;
40
41
  get numTimePoints(): number;
@@ -82,7 +82,7 @@ import { buildMetadata } from './buildMetadata';
82
82
  import getDynamicVolumeInfo from './getDynamicVolumeInfo';
83
83
  import autoLoad from './autoLoad';
84
84
  import scaleArray from './scaleArray';
85
- import splitImageIdsBy4DTags from './splitImageIdsBy4DTags';
85
+ import splitImageIdsBy4DTags, { handleMultiframe4D, generateFrameImageId } from './splitImageIdsBy4DTags';
86
86
  import { deepClone } from './deepClone';
87
87
  import { jumpToSlice } from './jumpToSlice';
88
88
  import scroll from './scroll';
@@ -97,4 +97,4 @@ import { asArray } from './asArray';
97
97
  export { updatePlaneRestriction } from './updatePlaneRestriction';
98
98
  declare const getViewportModality: (viewport: IViewport, volumeId?: string) => string;
99
99
  export * from './isEqual';
100
- export { FrameRange, eventListener, csUtils as invertRgbTransferFunction, createSigmoidRGBTransferFunction, getVoiFromSigmoidRGBTransferFunction, createLinearRGBTransferFunction, scaleRgbTransferFunction, triggerEvent, imageIdToURI, fnv1aHash, calibratedPixelSpacingMetadataProvider, clamp, uuidv4, getMinMax, getRuntimeId, 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, HistoryMemo, generateVolumePropsFromImageIds, getBufferConfiguration, VoxelManager, RLEVoxelMap, convertStackToVolumeViewport, convertVolumeToStackViewport, roundNumber, roundToPrecision, getViewportImageIds, getRandomSampleFromArray, getVolumeId, color, hasFloatScalingParameters, getDynamicVolumeInfo, autoLoad, scaleArray, deepClone, splitImageIdsBy4DTags, pointInShapeCallback, deepEqual, jumpToSlice, scroll, clip, transformWorldToIndexContinuous, createSubVolume, getVolumeDirectionVectors, calculateSpacingBetweenImageIds, getImageDataMetadata, buildMetadata, calculateNeighborhoodStats, asArray, };
100
+ export { FrameRange, eventListener, csUtils as invertRgbTransferFunction, createSigmoidRGBTransferFunction, getVoiFromSigmoidRGBTransferFunction, createLinearRGBTransferFunction, scaleRgbTransferFunction, triggerEvent, imageIdToURI, fnv1aHash, calibratedPixelSpacingMetadataProvider, clamp, uuidv4, getMinMax, getRuntimeId, 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, HistoryMemo, generateVolumePropsFromImageIds, getBufferConfiguration, VoxelManager, RLEVoxelMap, convertStackToVolumeViewport, convertVolumeToStackViewport, roundNumber, roundToPrecision, getViewportImageIds, getRandomSampleFromArray, getVolumeId, color, hasFloatScalingParameters, getDynamicVolumeInfo, autoLoad, scaleArray, deepClone, splitImageIdsBy4DTags, handleMultiframe4D, generateFrameImageId, pointInShapeCallback, deepEqual, jumpToSlice, scroll, clip, transformWorldToIndexContinuous, createSubVolume, getVolumeDirectionVectors, calculateSpacingBetweenImageIds, getImageDataMetadata, buildMetadata, calculateNeighborhoodStats, asArray, };
@@ -83,7 +83,7 @@ import cache from '../cache/cache';
83
83
  import getDynamicVolumeInfo from './getDynamicVolumeInfo';
84
84
  import autoLoad from './autoLoad';
85
85
  import scaleArray from './scaleArray';
86
- import splitImageIdsBy4DTags from './splitImageIdsBy4DTags';
86
+ import splitImageIdsBy4DTags, { handleMultiframe4D, generateFrameImageId, } from './splitImageIdsBy4DTags';
87
87
  import { deepClone } from './deepClone';
88
88
  import { jumpToSlice } from './jumpToSlice';
89
89
  import scroll from './scroll';
@@ -98,4 +98,4 @@ import { asArray } from './asArray';
98
98
  export { updatePlaneRestriction } from './updatePlaneRestriction';
99
99
  const getViewportModality = (viewport, volumeId) => _getViewportModality(viewport, volumeId, cache.getVolume);
100
100
  export * from './isEqual';
101
- export { FrameRange, eventListener, csUtils as invertRgbTransferFunction, createSigmoidRGBTransferFunction, getVoiFromSigmoidRGBTransferFunction, createLinearRGBTransferFunction, scaleRgbTransferFunction, triggerEvent, imageIdToURI, fnv1aHash, calibratedPixelSpacingMetadataProvider, clamp, uuidv4, getMinMax, getRuntimeId, 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, HistoryMemo, generateVolumePropsFromImageIds, getBufferConfiguration, VoxelManager, RLEVoxelMap, convertStackToVolumeViewport, convertVolumeToStackViewport, roundNumber, roundToPrecision, getViewportImageIds, getRandomSampleFromArray, getVolumeId, color, hasFloatScalingParameters, getDynamicVolumeInfo, autoLoad, scaleArray, deepClone, splitImageIdsBy4DTags, pointInShapeCallback, deepEqual, jumpToSlice, scroll, clip, transformWorldToIndexContinuous, createSubVolume, getVolumeDirectionVectors, calculateSpacingBetweenImageIds, getImageDataMetadata, buildMetadata, calculateNeighborhoodStats, asArray, };
101
+ export { FrameRange, eventListener, csUtils as invertRgbTransferFunction, createSigmoidRGBTransferFunction, getVoiFromSigmoidRGBTransferFunction, createLinearRGBTransferFunction, scaleRgbTransferFunction, triggerEvent, imageIdToURI, fnv1aHash, calibratedPixelSpacingMetadataProvider, clamp, uuidv4, getMinMax, getRuntimeId, 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, HistoryMemo, generateVolumePropsFromImageIds, getBufferConfiguration, VoxelManager, RLEVoxelMap, convertStackToVolumeViewport, convertVolumeToStackViewport, roundNumber, roundToPrecision, getViewportImageIds, getRandomSampleFromArray, getVolumeId, color, hasFloatScalingParameters, getDynamicVolumeInfo, autoLoad, scaleArray, deepClone, splitImageIdsBy4DTags, handleMultiframe4D, generateFrameImageId, pointInShapeCallback, deepEqual, jumpToSlice, scroll, clip, transformWorldToIndexContinuous, createSubVolume, getVolumeDirectionVectors, calculateSpacingBetweenImageIds, getImageDataMetadata, buildMetadata, calculateNeighborhoodStats, asArray, };
@@ -1,5 +1,12 @@
1
+ interface MultiframeSplitResult {
2
+ imageIdGroups: string[][];
3
+ splittingTag: string;
4
+ }
5
+ declare function generateFrameImageId(baseImageId: string, frameNumber: number): string;
6
+ declare function handleMultiframe4D(imageIds: string[]): MultiframeSplitResult | null;
1
7
  declare function splitImageIdsBy4DTags(imageIds: string[]): {
2
8
  imageIdGroups: string[][];
3
9
  splittingTag: string | null;
4
10
  };
5
11
  export default splitImageIdsBy4DTags;
12
+ export { handleMultiframe4D, generateFrameImageId };
@@ -1,4 +1,72 @@
1
1
  import * as metaData from '../metaData';
2
+ function generateFrameImageId(baseImageId, frameNumber) {
3
+ const framePattern = /\/frames\/\d+/;
4
+ if (!framePattern.test(baseImageId)) {
5
+ throw new Error(`generateFrameImageId: baseImageId must contain a "/frames/" pattern followed by a digit. ` +
6
+ `Expected format: e.g., "wadouri:http://example.com/image/frames/1" or "wadors:/path/to/image.dcm/frames/1". ` +
7
+ `Received: ${baseImageId}`);
8
+ }
9
+ return baseImageId.replace(framePattern, `/frames/${frameNumber}`);
10
+ }
11
+ function handleMultiframe4D(imageIds) {
12
+ if (!imageIds || imageIds.length === 0) {
13
+ return null;
14
+ }
15
+ const baseImageId = imageIds[0];
16
+ const instance = metaData.get('instance', baseImageId);
17
+ if (!instance) {
18
+ return null;
19
+ }
20
+ const numberOfFrames = instance.NumberOfFrames;
21
+ if (!numberOfFrames || numberOfFrames <= 1) {
22
+ return null;
23
+ }
24
+ const timeSlotVector = instance.TimeSlotVector;
25
+ if (!timeSlotVector || !Array.isArray(timeSlotVector)) {
26
+ return null;
27
+ }
28
+ const sliceVector = instance.SliceVector;
29
+ const numberOfSlices = instance.NumberOfSlices;
30
+ if (timeSlotVector.length !== numberOfFrames) {
31
+ console.warn('TimeSlotVector length does not match NumberOfFrames:', timeSlotVector.length, 'vs', numberOfFrames);
32
+ return null;
33
+ }
34
+ if (sliceVector) {
35
+ if (!Array.isArray(sliceVector)) {
36
+ console.warn('SliceVector exists but is not an array. Expected length:', numberOfFrames);
37
+ return null;
38
+ }
39
+ if (sliceVector.length !== numberOfFrames ||
40
+ sliceVector.some((val) => val === undefined)) {
41
+ console.warn('SliceVector exists but has invalid length or undefined entries. Expected length:', numberOfFrames, 'Actual length:', sliceVector.length);
42
+ return null;
43
+ }
44
+ }
45
+ const timeSlotGroups = new Map();
46
+ for (let frameIndex = 0; frameIndex < numberOfFrames; frameIndex++) {
47
+ const timeSlot = timeSlotVector[frameIndex];
48
+ const sliceIndex = sliceVector?.[frameIndex] ?? frameIndex;
49
+ if (!timeSlotGroups.has(timeSlot)) {
50
+ timeSlotGroups.set(timeSlot, []);
51
+ }
52
+ timeSlotGroups.get(timeSlot).push({ frameIndex, sliceIndex });
53
+ }
54
+ const sortedTimeSlots = Array.from(timeSlotGroups.keys()).sort((a, b) => a - b);
55
+ const imageIdGroups = sortedTimeSlots.map((timeSlot) => {
56
+ const frames = timeSlotGroups.get(timeSlot);
57
+ frames.sort((a, b) => a.sliceIndex - b.sliceIndex);
58
+ return frames.map((frame) => generateFrameImageId(baseImageId, frame.frameIndex + 1));
59
+ });
60
+ const expectedSlicesPerTimeSlot = numberOfSlices || imageIdGroups[0]?.length;
61
+ const allGroupsHaveSameLength = imageIdGroups.every((group) => group.length === expectedSlicesPerTimeSlot);
62
+ if (!allGroupsHaveSameLength) {
63
+ console.warn('Multiframe 4D split resulted in uneven time slot groups. Expected', expectedSlicesPerTimeSlot, 'slices per time slot.');
64
+ }
65
+ return {
66
+ imageIdGroups,
67
+ splittingTag: 'TimeSlotVector',
68
+ };
69
+ }
2
70
  const groupBy = (array, key) => {
3
71
  return array.reduce((rv, x) => {
4
72
  (rv[x[key]] = rv[x[key]] || []).push(x);
@@ -120,6 +188,10 @@ function getPetFrameReferenceTime(imageId) {
120
188
  return moduleInfo ? moduleInfo['frameReferenceTime'] : 0;
121
189
  }
122
190
  function splitImageIdsBy4DTags(imageIds) {
191
+ const multiframeResult = handleMultiframe4D(imageIds);
192
+ if (multiframeResult) {
193
+ return multiframeResult;
194
+ }
123
195
  const positionGroups = getIPPGroups(imageIds);
124
196
  if (!positionGroups) {
125
197
  return { imageIdGroups: [imageIds], splittingTag: null };
@@ -159,3 +231,4 @@ function splitImageIdsBy4DTags(imageIds) {
159
231
  return { imageIdGroups: [imageIds], splittingTag: null };
160
232
  }
161
233
  export default splitImageIdsBy4DTags;
234
+ export { handleMultiframe4D, generateFrameImageId };
@@ -1 +1 @@
1
- export declare const version = "4.15.0";
1
+ export declare const version = "4.15.2";
@@ -1 +1 @@
1
- export const version = '4.15.0';
1
+ export const version = '4.15.2';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/core",
3
- "version": "4.15.0",
3
+ "version": "4.15.2",
4
4
  "description": "Cornerstone3D Core",
5
5
  "module": "./dist/esm/index.js",
6
6
  "types": "./dist/esm/index.d.ts",
@@ -97,5 +97,5 @@
97
97
  "type": "individual",
98
98
  "url": "https://ohif.org/donate"
99
99
  },
100
- "gitHead": "e115fd3cf5e0fe7c0f1f216f3d1bda0d05e9ea14"
100
+ "gitHead": "c18cad49aa3f5276bd5251b81843437bee76e552"
101
101
  }