fix(multiframe): handling proxies properly (#4693)

Co-authored-by: Bill Wallace <wayfarer3130@gmail.com>
Co-authored-by: Chao Sui <chao.sui@curvebeamai.com>
This commit is contained in:
Alireza 2025-01-15 22:29:06 -05:00 committed by GitHub
parent 9f8df95f3e
commit ec4b5a6876
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 44 additions and 43 deletions

View File

@ -142,7 +142,9 @@ function createDicomLocalApi(dicomLocalConfig) {
study.series.forEach(aSeries => { study.series.forEach(aSeries => {
const { SeriesInstanceUID } = aSeries; const { SeriesInstanceUID } = aSeries;
aSeries.instances.forEach(instance => { const isMultiframe = aSeries.instances[0].NumberOfFrames > 1;
aSeries.instances.forEach((instance, index) => {
const { const {
url: imageId, url: imageId,
StudyInstanceUID, StudyInstanceUID,
@ -151,22 +153,14 @@ function createDicomLocalApi(dicomLocalConfig) {
} = instance; } = instance;
instance.imageId = imageId; instance.imageId = imageId;
const numberOfFrames = instance.NumberOfFrames || 1;
// Process all frames consistently, whether single or multiframe // Add imageId specific mapping to this data as the URL isn't necessarily WADO-URI.
for (let i = 0; i < numberOfFrames; i++) { metadataProvider.addImageIdToUIDs(imageId, {
const frameNumber = i + 1; StudyInstanceUID,
const frameImageId = implementation.getImageIdsForInstance({ SeriesInstanceUID,
instance, SOPInstanceUID,
frame: frameNumber, frameIndex: isMultiframe ? index : 1,
}); });
// Add imageId specific mapping to this data as the URL isn't necessarily WADO-URI.
metadataProvider.addImageIdToUIDs(frameImageId, {
StudyInstanceUID,
SeriesInstanceUID,
SOPInstanceUID,
frameNumber: numberOfFrames > 1 ? frameNumber : undefined,
});
}
}); });
DicomMetadataStore._broadcastEvent(EVENTS.INSTANCES_ADDED, { DicomMetadataStore._broadcastEvent(EVENTS.INSTANCES_ADDED, {

View File

@ -478,7 +478,6 @@ function createDicomWebApi(dicomWebConfig: DicomWebConfig, servicesManager) {
instance.wadoUri = dicomWebConfig.wadoUri; instance.wadoUri = dicomWebConfig.wadoUri;
const { StudyInstanceUID, SeriesInstanceUID, SOPInstanceUID } = instance; const { StudyInstanceUID, SeriesInstanceUID, SOPInstanceUID } = instance;
const numberOfFrames = instance.NumberOfFrames || 1; const numberOfFrames = instance.NumberOfFrames || 1;
// Process all frames consistently, whether single or multiframe // Process all frames consistently, whether single or multiframe
for (let i = 0; i < numberOfFrames; i++) { for (let i = 0; i < numberOfFrames; i++) {

View File

@ -8,7 +8,7 @@ window.config = {
showLoadingIndicator: true, showLoadingIndicator: true,
showWarningMessageForCrossOrigin: true, showWarningMessageForCrossOrigin: true,
showCPUFallbackMessage: true, showCPUFallbackMessage: true,
strictZSpacingForVolumeViewport: false, strictZSpacingForVolumeViewport: true,
// filterQueryParam: false, // filterQueryParam: false,
defaultDataSourceName: 'orthanc', defaultDataSourceName: 'orthanc',
dataSources: [ dataSources: [

View File

@ -9,7 +9,6 @@ import combineFrameInstance from '../utils/combineFrameInstance';
class MetadataProvider { class MetadataProvider {
private readonly imageURIToUIDs: Map<string, any> = new Map(); private readonly imageURIToUIDs: Map<string, any> = new Map();
private readonly imageUIDsByImageId: Map<string, any> = new Map();
// Can be used to store custom metadata for a specific type. // Can be used to store custom metadata for a specific type.
// For instance, the scaling metadata for PET can be stored here // For instance, the scaling metadata for PET can be stored here
// as type "scalingModule" // as type "scalingModule"
@ -25,7 +24,6 @@ class MetadataProvider {
// An example would be dicom hosted at some random site. // An example would be dicom hosted at some random site.
const imageURI = imageIdToURI(imageId); const imageURI = imageIdToURI(imageId);
this.imageURIToUIDs.set(imageURI, uids); this.imageURIToUIDs.set(imageURI, uids);
this.imageUIDsByImageId.set(imageId, uids);
} }
addCustomMetadata(imageId, type, metadata) { addCustomMetadata(imageId, type, metadata) {
@ -462,11 +460,6 @@ class MetadataProvider {
} }
getUIDsFromImageID(imageId) { getUIDsFromImageID(imageId) {
const cachedUIDs = this.imageUIDsByImageId.get(imageId);
if (cachedUIDs) {
return cachedUIDs;
}
if (imageId.startsWith('wadors:')) { if (imageId.startsWith('wadors:')) {
const strippedImageId = imageId.split('/studies/')[1]; const strippedImageId = imageId.split('/studies/')[1];
const splitImageId = strippedImageId.split('/'); const splitImageId = strippedImageId.split('/');

View File

@ -67,18 +67,27 @@ const combineFrameInstance = (frame, instance) => {
ImagePositionPatientToUse = [position[0], position[1], position[2]]; ImagePositionPatientToUse = [position[0], position[1], position[2]];
} }
} }
const sharedInstance = createCombinedValue(instance, SharedFunctionalGroupsSequence?.[0]);
// Cache the _parentInstance at the top level as a full copy to prevent
// setting values hard.
if (!instance._parentInstance) {
Object.defineProperty(instance, '_parentInstance', {
value: { ...instance },
});
}
const sharedInstance = createCombinedValue(
instance._parentInstance,
SharedFunctionalGroupsSequence?.[0],
'_shared'
);
const newInstance = createCombinedValue( const newInstance = createCombinedValue(
sharedInstance, sharedInstance,
PerFrameFunctionalGroupsSequence?.[frameNumber] PerFrameFunctionalGroupsSequence?.[frameNumber - 1],
frameNumber
); );
Object.defineProperty(newInstance, 'ImagePositionPatient', { newInstance.ImagePositionPatient = ImagePositionPatientToUse ??
value: ImagePositionPatientToUse ?? newInstance.ImagePositionPatient ?? [0, 0, frameNumber], newInstance.ImagePositionPatient ?? [0, 0, frameNumber];
writable: true,
enumerable: true,
configurable: true,
});
Object.defineProperty(newInstance, 'frameNumber', { Object.defineProperty(newInstance, 'frameNumber', {
value: frameNumber, value: frameNumber,
@ -92,14 +101,25 @@ const combineFrameInstance = (frame, instance) => {
} }
}; };
function createCombinedValue(parent, functionalGroups) { /**
* Creates a combined instance stored in the parent object which
* inherits from the parent instance the attributes in the functional groups.
* The storage key in the parent is in key
*/
function createCombinedValue(parent, functionalGroups, key) {
if (parent[key]) {
return parent[key];
}
// Exclude any proxying values
const newInstance = Object.create(parent); const newInstance = Object.create(parent);
Object.defineProperty(parent, key, {
value: newInstance,
writable: false,
enumerable: false,
});
if (!functionalGroups) { if (!functionalGroups) {
return newInstance; return newInstance;
} }
if (functionalGroups._sharedValue) {
return functionalGroups._sharedValue;
}
const shared = functionalGroups const shared = functionalGroups
? Object.values(functionalGroups) ? Object.values(functionalGroups)
.filter(Boolean) .filter(Boolean)
@ -117,11 +137,6 @@ function createCombinedValue(parent, functionalGroups) {
newInstance[key] = value; newInstance[key] = value;
}); });
}); });
Object.defineProperty(functionalGroups, '_sharedValue', {
value: newInstance,
writable: false,
enumerable: false,
});
return newInstance; return newInstance;
} }