feat: Support for local DICOM drag and drop (#2445)
* Added drag and drop from local and local data source * fix: dicom SR drag and drop from local
This commit is contained in:
1 parent
99b8dc4759
commit
fdb6ca41d6
23 files changed
+656
-89
No files matched your search
@@ -43,7 +43,7 @@ function createDicomJSONApi(dicomJsonConfig) {
|
||||
const { name } = dicomJsonConfig;
|
||||
|
||||
const implementation = {
|
||||
parseRouteParams: async ({ params, query, url }) => {
|
||||
initialize: async ({ params, query, url }) => {
|
||||
if (!url) url = query.get('url');
|
||||
let metaData = getMetaDataByURL(url);
|
||||
|
||||
@@ -93,11 +93,12 @@ function createDicomJSONApi(dicomJsonConfig) {
|
||||
},
|
||||
query: {
|
||||
studies: {
|
||||
mapParams: () => {},
|
||||
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 => {
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
import { DicomMetadataStore, IWebApiDataSource } from '@ohif/core'
|
||||
import OHIF from '@ohif/core'
|
||||
import dcmjs from 'dcmjs';
|
||||
|
||||
const metadataProvider = OHIF.classes.MetadataProvider
|
||||
const { EVENTS } = DicomMetadataStore
|
||||
|
||||
// Sorting SR modalities to be at the end of series list
|
||||
function customSort(seriesA, seriesB) {
|
||||
const modalityA = seriesA.instances[0].Modality
|
||||
const modalityB = seriesB.instances[0].Modality
|
||||
|
||||
if (modalityA === "SR") {
|
||||
return +1;
|
||||
}
|
||||
if (modalityB === "SR") {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
function createDicomLocalApi(dicomLocalConfig) {
|
||||
const { name } = dicomLocalConfig
|
||||
|
||||
const implementation = {
|
||||
initialize: ({ params, query }) => {
|
||||
const { StudyInstanceUIDs: paramsStudyInstanceUIDs } = params
|
||||
const queryStudyInstanceUIDs = query.get('StudyInstanceUIDs')
|
||||
|
||||
const StudyInstanceUIDs =
|
||||
queryStudyInstanceUIDs || paramsStudyInstanceUIDs
|
||||
const StudyInstanceUIDsAsArray =
|
||||
StudyInstanceUIDs && Array.isArray(StudyInstanceUIDs)
|
||||
? StudyInstanceUIDs
|
||||
: [StudyInstanceUIDs]
|
||||
|
||||
|
||||
// Put SRs at the end of series list to make sure images are loaded first
|
||||
StudyInstanceUIDsAsArray.forEach(StudyInstanceUID => {
|
||||
const study = DicomMetadataStore.getStudy(StudyInstanceUID)
|
||||
study.series = study.series.sort(customSort)
|
||||
})
|
||||
|
||||
return StudyInstanceUIDsAsArray
|
||||
},
|
||||
query: {
|
||||
studies: {
|
||||
mapParams: () => { },
|
||||
search: (params) => {
|
||||
const studyUIDs = DicomMetadataStore.getStudyInstanceUIDs()
|
||||
|
||||
return studyUIDs.map(StudyInstanceUID => {
|
||||
let numInstances = 0
|
||||
const modalities = new Set()
|
||||
|
||||
// Calculating the number of instances in the study and modalities
|
||||
// present in the study
|
||||
const study = DicomMetadataStore.getStudy(StudyInstanceUID)
|
||||
study.series.forEach(aSeries => {
|
||||
numInstances += aSeries.instances.length
|
||||
modalities.add(aSeries.Modality);
|
||||
})
|
||||
|
||||
// first instance in the first series
|
||||
const firstInstance = study?.series[0]?.instances[0]
|
||||
|
||||
if (firstInstance) {
|
||||
return {
|
||||
accession: firstInstance.AccessionNumber,
|
||||
date: firstInstance.StudyDate,
|
||||
description: firstInstance.StudyDescription,
|
||||
mrn: firstInstance.PatientID,
|
||||
patientName: { Alphabetic: firstInstance.PatientName },
|
||||
studyInstanceUid: firstInstance.StudyInstanceUID,
|
||||
time: firstInstance.StudyTime,
|
||||
//
|
||||
instances: numInstances,
|
||||
modalities: Array.from(modalities).join('/'),
|
||||
NumInstances: numInstances,
|
||||
};
|
||||
}
|
||||
})
|
||||
},
|
||||
processResults: () => {
|
||||
console.debug(' DICOMLocal QUERY processResults')
|
||||
},
|
||||
},
|
||||
series: {
|
||||
// mapParams: mapParams.bind(),
|
||||
search: () => {
|
||||
console.debug(' DICOMLocal QUERY SERIES SEARCH')
|
||||
},
|
||||
},
|
||||
instances: {
|
||||
search: () => {
|
||||
console.debug(' DICOMLocal QUERY instances SEARCH')
|
||||
},
|
||||
},
|
||||
},
|
||||
retrieve: {
|
||||
series: {
|
||||
metaData: () => {
|
||||
console.debug(' DICOMLocal retrieve series metadata')
|
||||
},
|
||||
},
|
||||
},
|
||||
store: {
|
||||
dicom: (naturalizedReport) => {
|
||||
const reportBlob = dcmjs.data.datasetToBlob(naturalizedReport);
|
||||
|
||||
//Create a URL for the binary.
|
||||
var objectUrl = URL.createObjectURL(reportBlob);
|
||||
window.location.assign(objectUrl);
|
||||
},
|
||||
},
|
||||
retrieveSeriesMetadata: async ({
|
||||
StudyInstanceUID,
|
||||
madeInClient = false,
|
||||
} = {}) => {
|
||||
if (!StudyInstanceUID) {
|
||||
throw new Error(
|
||||
'Unable to query for SeriesMetadata without StudyInstanceUID'
|
||||
)
|
||||
}
|
||||
|
||||
// Instances metadata already added via local upload
|
||||
const study = DicomMetadataStore.getStudy(StudyInstanceUID, madeInClient)
|
||||
|
||||
// Series metadata already added via local upload
|
||||
DicomMetadataStore._broadcastEvent(EVENTS.SERIES_ADDED, {
|
||||
StudyInstanceUID,
|
||||
madeInClient,
|
||||
})
|
||||
|
||||
study.series.forEach((aSeries) => {
|
||||
const { SeriesInstanceUID } = aSeries
|
||||
|
||||
aSeries.instances.forEach((instance) => {
|
||||
const {
|
||||
url: imageId,
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
SOPInstanceUID,
|
||||
} = instance
|
||||
|
||||
// Add imageId specific mapping to this data as the URL isn't necessarily WADO-URI.
|
||||
metadataProvider.addImageIdToUIDs(imageId, {
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
SOPInstanceUID,
|
||||
})
|
||||
})
|
||||
|
||||
DicomMetadataStore._broadcastEvent(EVENTS.INSTANCES_ADDED, {
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
madeInClient,
|
||||
})
|
||||
})
|
||||
|
||||
},
|
||||
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 = this.getImageIdsForInstance({
|
||||
instance,
|
||||
frame: i,
|
||||
})
|
||||
imageIds.push(imageId)
|
||||
}
|
||||
} else {
|
||||
const imageId = this.getImageIdsForInstance({ instance })
|
||||
imageIds.push(imageId)
|
||||
}
|
||||
})
|
||||
|
||||
return imageIds
|
||||
},
|
||||
getImageIdsForInstance({ instance, frame }) {
|
||||
const { StudyInstanceUID, SeriesInstanceUID, SOPInstanceUID } = instance
|
||||
const storedInstance = DicomMetadataStore.getInstance(StudyInstanceUID, SeriesInstanceUID, SOPInstanceUID)
|
||||
if (storedInstance.url) {
|
||||
return storedInstance.url
|
||||
}
|
||||
},
|
||||
deleteStudyMetadataPromise() {
|
||||
console.log("deleteStudyMetadataPromise not implemented")
|
||||
}
|
||||
}
|
||||
return IWebApiDataSource.create(implementation)
|
||||
}
|
||||
|
||||
export { createDicomLocalApi }
|
||||
@@ -63,7 +63,7 @@ function createDicomWebApi(dicomWebConfig) {
|
||||
const wadoDicomWebClient = new api.DICOMwebClient(wadoConfig);
|
||||
|
||||
const implementation = {
|
||||
parseRouteParams: ({ params, query }) => {
|
||||
initialize: ({ params, query }) => {
|
||||
const { StudyInstanceUIDs: paramsStudyInstanceUIDs } = params;
|
||||
const queryStudyInstanceUIDs = query.get('StudyInstanceUIDs');
|
||||
|
||||
@@ -78,7 +78,7 @@ function createDicomWebApi(dicomWebConfig) {
|
||||
query: {
|
||||
studies: {
|
||||
mapParams: mapParams.bind(),
|
||||
search: async function(origParams) {
|
||||
search: async function (origParams) {
|
||||
const { studyInstanceUid, seriesInstanceUid, ...mappedParams } =
|
||||
mapParams(origParams, {
|
||||
supportsFuzzyMatching,
|
||||
@@ -98,7 +98,7 @@ function createDicomWebApi(dicomWebConfig) {
|
||||
},
|
||||
series: {
|
||||
// mapParams: mapParams.bind(),
|
||||
search: async function(studyInstanceUid) {
|
||||
search: async function (studyInstanceUid) {
|
||||
const results = await seriesInStudy(
|
||||
qidoDicomWebClient,
|
||||
studyInstanceUid
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
import { createDicomWebApi } from './DicomWebDataSource/index.js';
|
||||
import { createDicomJSONApi } from './DicomJSONDataSource/index.js';
|
||||
import { createDicomLocalApi } from './DicomLocalDataSource/index.js';
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -20,6 +21,11 @@ function getDataSourcesModule() {
|
||||
type: 'jsonApi',
|
||||
createDataSource: createDicomJSONApi,
|
||||
},
|
||||
{
|
||||
name: 'dicomlocal',
|
||||
type: 'localApi',
|
||||
createDataSource: createDicomLocalApi,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user