import { DicomMetadataStore, IWebApiDataSource } from '@ohif/core'; import OHIF from '@ohif/core'; import getImageId from '../DicomWebDataSource/utils/getImageId'; import getDirectURL from '../utils/getDirectURL'; const metadataProvider = OHIF.classes.MetadataProvider; const mappings = { studyInstanceUid: 'StudyInstanceUID', patientId: 'PatientID', }; let _store = { urls: [], // { // url: url1 // studies: [Study1, Study2], // if multiple studies // } // { // url: url2 // studies: [Study1], // } // } }; const getMetaDataByURL = url => { return _store.urls.find(metaData => metaData.url === url); }; const findStudies = (key, value) => { let studies = []; _store.urls.map(metaData => { metaData.studies.map(aStudy => { if (aStudy[key] === value) { studies.push(aStudy); } }); }); return studies; }; function createDicomJSONApi(dicomJsonConfig) { const { name, wadoRoot } = dicomJsonConfig; const implementation = { initialize: async ({ params, query, url }) => { if (!url) url = query.get('url'); let metaData = getMetaDataByURL(url); // if we have already cached the data from this specific url // We are only handling one StudyInstanceUID to run; however, // all studies for patientID will be put in the correct tab if (metaData) { return metaData.studies.map(aStudy => { return aStudy.StudyInstanceUID; }); } const response = await fetch(url); let data = await response.json(); const studyInstanceUIDs = data.studies.map( study => study.StudyInstanceUID ); let StudyInstanceUID; let SeriesInstanceUID; data.studies.forEach(study => { StudyInstanceUID = study.StudyInstanceUID; study.series.forEach(series => { SeriesInstanceUID = series.SeriesInstanceUID; series.instances.forEach(instance => { const { url: imageId, metadata: naturalizedDicom } = instance; // Add imageId specific mapping to this data as the URL isn't necessarliy WADO-URI. metadataProvider.addImageIdToUIDs(imageId, { StudyInstanceUID, SeriesInstanceUID, SOPInstanceUID: naturalizedDicom.SOPInstanceUID, }); }); }); }); _store.urls.push({ url, studies: [...data.studies], }); return studyInstanceUIDs; }, query: { studies: { mapParams: () => { }, search: async param => { const [key, value] = Object.entries(param)[0]; const mappedParam = mappings[key]; // todo: should fetch from dicomMetadataStore const studies = findStudies(mappedParam, value); return studies.map(aStudy => { return { accession: aStudy.AccessionNumber, date: aStudy.StudyDate, description: aStudy.StudyDescription, instances: aStudy.NumInstances, modalities: aStudy.Modalities, mrn: aStudy.PatientID, patientName: aStudy.PatientName, studyInstanceUid: aStudy.StudyInstanceUID, NumInstances: aStudy.NumInstances, time: aStudy.StudyTime, }; }); }, processResults: () => { console.debug(' DICOMJson QUERY processResults'); }, }, series: { // mapParams: mapParams.bind(), search: () => { console.debug(' DICOMJson QUERY SERIES SEARCH'); }, }, instances: { search: () => { console.debug(' DICOMJson QUERY instances SEARCH'); }, }, }, retrieve: { /** * Generates a URL that can be used for direct retrieve of the bulkdata * * @param {object} params * @param {string} params.tag is the tag name of the URL to retrieve * @param {string} params.defaultPath path for the pixel data url * @param {object} params.instance is the instance object that the tag is in * @param {string} params.defaultType is the mime type of the response * @param {string} params.singlepart is the type of the part to retrieve * @param {string} params.fetchPart unknown? * @returns an absolute URL to the resource, if the absolute URL can be retrieved as singlepart, * or is already retrieved, or a promise to a URL for such use if a BulkDataURI */ directURL: params => { return getDirectURL(wadoRoot, params); }, series: { metadata: ({ StudyInstanceUID, madeInClient = false, customSort, } = {}) => { if (!StudyInstanceUID) { throw new Error( 'Unable to query for SeriesMetadata without StudyInstanceUID' ); } const study = findStudies('StudyInstanceUID', StudyInstanceUID)[0]; let series; if (customSort) { series = customSort(study.series); } else { series = study.series; } const seriesSummaryMetadata = series.map(series => { const seriesSummary = { StudyInstanceUID: study.StudyInstanceUID, ...series, }; delete seriesSummary.instances; return seriesSummary; }); // Async load series, store as retrieved function storeInstances(naturalizedInstances) { DicomMetadataStore.addInstances(naturalizedInstances, madeInClient); } DicomMetadataStore.addSeriesMetadata( seriesSummaryMetadata, madeInClient ); function setSuccessFlag() { const study = DicomMetadataStore.getStudy( StudyInstanceUID, madeInClient ); study.isLoaded = true; } const numberOfSeries = series.length; series.forEach((series, index) => { const instances = series.instances.map(instance => { const obj = { ...instance.metadata, url: instance.url, imageId: instance.url, ...series, ...study, }; delete obj.instances; delete obj.series; return obj; }); storeInstances(instances); if (index === numberOfSeries - 1) setSuccessFlag(); }); }, }, }, store: { dicom: () => { console.debug(' DICOMJson store dicom'); }, }, getImageIdsForDisplaySet(displaySet) { const images = displaySet.images; const imageIds = []; if (!images) { return imageIds; } displaySet.images.forEach(instance => { const NumberOfFrames = instance.NumberOfFrames; 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 }); imageIds.push(imageId); } }); return imageIds; }, getImageIdsForInstance({ instance, frame }) { const imageIds = getImageId({ instance, frame, }); return imageIds; }, }; return IWebApiDataSource.create(implementation); } export { createDicomJSONApi };