From 3dd0666c0c090cbd66161f24bc9795f96abb3697 Mon Sep 17 00:00:00 2001 From: Igor Octaviano Date: Thu, 17 Oct 2024 10:38:40 -0300 Subject: [PATCH] fix(dicomjson): Update getUIDsFromImageID to work with json data source + update getDisplaySetImageUIDs to work with mixed sop class json (#4322) --- .../default/src/DicomJSONDataSource/index.js | 41 +++++++++++-------- platform/core/src/classes/MetadataProvider.ts | 39 +++++++----------- 2 files changed, 37 insertions(+), 43 deletions(-) diff --git a/extensions/default/src/DicomJSONDataSource/index.js b/extensions/default/src/DicomJSONDataSource/index.js index 969144d06..bb0a9b43d 100644 --- a/extensions/default/src/DicomJSONDataSource/index.js +++ b/extensions/default/src/DicomJSONDataSource/index.js @@ -1,5 +1,6 @@ import { DicomMetadataStore, IWebApiDataSource } from '@ohif/core'; import OHIF from '@ohif/core'; +import qs from 'query-string'; import getImageId from '../DicomWebDataSource/utils/getImageId'; import getDirectURL from '../utils/getDirectURL'; @@ -90,11 +91,14 @@ function createDicomJSONApi(dicomJsonConfig) { const { metadata: naturalizedDicom } = instance; const imageId = getImageId({ instance, config: dicomJsonConfig }); + const { query } = qs.parseUrl(instance.url); + // Add imageId specific mapping to this data as the URL isn't necessarliy WADO-URI. metadataProvider.addImageIdToUIDs(imageId, { StudyInstanceUID, SeriesInstanceUID, SOPInstanceUID: naturalizedDicom.SOPInstanceUID, + frameNumber: query.frame ? parseInt(query.frame) : undefined, }); }); }); @@ -258,26 +262,27 @@ function createDicomJSONApi(dicomJsonConfig) { const { StudyInstanceUID, SeriesInstanceUID } = displaySet; const study = findStudies('StudyInstanceUID', StudyInstanceUID)[0]; - const series = study.series.find(s => s.SeriesInstanceUID === SeriesInstanceUID); - let instances = displaySet.images; - if (series.instances.length > displaySet.images.length) { - instances = series.instances; - } + const series = study.series.find(s => s.SeriesInstanceUID === SeriesInstanceUID) || []; - instances.forEach(instance => { - const NumberOfFrames = instance.NumberOfFrames; + const instanceMap = new Map(); + series.instances.forEach(instance => { + if (instance?.metadata?.SOPInstanceUID) { + const { metadata, url } = instance; + const existingInstances = instanceMap.get(metadata.SOPInstanceUID) || []; + existingInstances.push({ ...metadata, url }); + instanceMap.set(metadata.SOPInstanceUID, existingInstances); + } + }); - if (NumberOfFrames > 1) { - for (let i = 0; i < NumberOfFrames; i++) { - const imageId = getImageId({ - instance, - frame: i, - config: dicomJsonConfig, - }); - imageIds.push(imageId); - } - } else { - const imageId = getImageId({ instance, config: dicomJsonConfig }); + displaySet.images.forEach(instance => { + const NumberOfFrames = instance.NumberOfFrames || 1; + const instances = instanceMap.get(instance.SOPInstanceUID) || [instance]; + for (let i = 0; i < NumberOfFrames; i++) { + const imageId = getImageId({ + instance: instances[Math.min(i, instances.length - 1)], + frame: NumberOfFrames > 1 ? i : undefined, + config: dicomJsonConfig, + }); imageIds.push(imageId); } }); diff --git a/platform/core/src/classes/MetadataProvider.ts b/platform/core/src/classes/MetadataProvider.ts index a2ea77e82..3130a75c4 100644 --- a/platform/core/src/classes/MetadataProvider.ts +++ b/platform/core/src/classes/MetadataProvider.ts @@ -8,31 +8,13 @@ import toNumber from '../utils/toNumber'; import combineFrameInstance from '../utils/combineFrameInstance'; class MetadataProvider { - constructor() { - // Define the main "metadataLookup" private property as an immutable property. - Object.defineProperty(this, 'studies', { - configurable: false, - enumerable: false, - writable: false, - value: new Map(), - }); - Object.defineProperty(this, 'imageURIToUIDs', { - configurable: false, - enumerable: false, - writable: false, - value: new Map(), - }); - // Can be used to store custom metadata for a specific type. - // For instance, the scaling metadata for PET can be stored here - // as type "scalingModule" - // - Object.defineProperty(this, 'customMetadata', { - configurable: false, - enumerable: false, - writable: false, - value: new Map(), - }); - } + private readonly studies: Map = new Map(); + private readonly imageURIToUIDs: Map = new Map(); + private readonly imageUIDsByImageId: Map = new Map(); + // Can be used to store custom metadata for a specific type. + // For instance, the scaling metadata for PET can be stored here + // as type "scalingModule" + private readonly customMetadata: Map = new Map(); addImageIdToUIDs(imageId, uids) { // This method is a fallback for when you don't have WADO-URI or WADO-RS. @@ -40,6 +22,7 @@ class MetadataProvider { // An example would be dicom hosted at some random site. const imageURI = imageIdToURI(imageId); this.imageURIToUIDs.set(imageURI, uids); + this.imageUIDsByImageId.set(imageId, uids); } addCustomMetadata(imageId, type, metadata) { @@ -482,6 +465,12 @@ class MetadataProvider { // SOPInstanceUID, // }) // somewhere else + + const cachedUIDs = this.imageUIDsByImageId.get(imageId); + if (cachedUIDs) { + return cachedUIDs; + } + if (imageId.startsWith('wadors:')) { const strippedImageId = imageId.split('/studies/')[1]; const splitImageId = strippedImageId.split('/');