Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | 18x 18x 18x 8x 8x 8x 8x 10x 10x 10x 10x 8x | import type { IViewport } from '../types/IViewport';
import type IStackViewport from '../types/IStackViewport';
import type IVolumeViewport from '../types/IVolumeViewport';
import type { ScalingDescriptor } from '../types/ScalingDescriptor';
import { isGenericViewport } from './viewportCapabilities';
import { getVolumeId } from './getVolumeId';
import { resolveGenericViewportVolumeId } from './resolveGenericViewportVolumeId';
type VolumeLike =
| { metadata?: { Modality?: string }; scaling?: object }
| undefined;
/**
* Builds a {@link ScalingDescriptor} for a viewport target, recovering the
* modality + pre-scaled state uniformly across the three viewport families.
*
* The native ("next" / PLANAR_NEXT) viewport exposes neither the StackViewport
* `.modality` / `.preScale` surface nor the VolumeViewport `.setVolumes` API, so
* each family is read from its own source of truth:
* - generic: the cache volume bound to the resolved actor (modality from its
* metadata, falling back to the image-data metadata; pre-scaled from its
* SUV `scaling`);
* - volume: the cache volume's metadata + `scaling`;
* - stack: the public `.modality` field + the rendered image's `preScale`.
*
* Families are discriminated by method presence (`setStack` / `setVolumes` /
* the generic surface) rather than `instanceof`, to avoid importing the viewport
* classes into core utilities (circular dependency).
*
* Returns `undefined` for viewport families with no modality-scaling concept
* (video / WSI / 3D), so callers that require one (e.g. `getViewportModality`)
* can throw while tolerant callers (e.g. `isViewportPreScaled`) treat it as
* not pre-scaled.
*
* `getVolume` is injected (rather than imported) to keep this utility free of
* the cache import cycle; use the `getScalingDescriptor` export from the
* utilities index, which supplies it.
*/
function _getScalingDescriptor(
viewport: IViewport,
targetId?: string,
getVolume?: (volumeId: string) => VolumeLike
): ScalingDescriptor | undefined {
Iif (!getVolume) {
throw new Error('getVolume is required, use the utilities export instead');
}
Iif (isGenericViewport(viewport)) {
const resolvedVolumeId = resolveGenericViewportVolumeId(viewport, targetId);
const volume = resolvedVolumeId ? getVolume(resolvedVolumeId) : undefined;
const imageData = (
viewport as { getImageData?: () => { metadata?: { Modality?: string } } }
).getImageData?.();
return {
modality: volume?.metadata?.Modality ?? imageData?.metadata?.Modality,
isPreScaled: isScalingPresent(volume?.scaling),
};
}
if (typeof (viewport as IVolumeViewport).setVolumes === 'function') {
const volumeViewport = viewport as IVolumeViewport;
const volumeId = targetId
? getVolumeId(targetId)
: volumeViewport.getVolumeId();
const volume = volumeId ? getVolume(volumeId) : undefined;
return {
modality: volume?.metadata?.Modality,
isPreScaled: isScalingPresent(volume?.scaling),
};
}
Eif (typeof (viewport as IStackViewport).setStack === 'function') {
const stackViewport = viewport as IStackViewport;
const { preScale } = stackViewport.getImageData() || {};
return {
modality: stackViewport.modality,
isPreScaled: !!preScale?.scaled,
};
}
return undefined;
}
function isScalingPresent(scaling: object | undefined): boolean {
return !!scaling && Object.keys(scaling).length > 0;
}
export { _getScalingDescriptor };
|