init
This commit is contained in:
260
extensions/default/src/DicomLocalDataSource/index.js
Normal file
260
extensions/default/src/DicomLocalDataSource/index.js
Normal file
@@ -0,0 +1,260 @@
|
||||
import { DicomMetadataStore, IWebApiDataSource, utils } from '@ohif/core';
|
||||
import OHIF from '@ohif/core';
|
||||
import dcmjs from 'dcmjs';
|
||||
|
||||
const metadataProvider = OHIF.classes.MetadataProvider;
|
||||
const { EVENTS } = DicomMetadataStore;
|
||||
|
||||
const END_MODALITIES = {
|
||||
SR: true,
|
||||
SEG: true,
|
||||
DOC: true,
|
||||
};
|
||||
|
||||
const compareValue = (v1, v2, def = 0) => {
|
||||
if (v1 === v2) {
|
||||
return def;
|
||||
}
|
||||
if (v1 < v2) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
};
|
||||
|
||||
// Sorting SR modalities to be at the end of series list
|
||||
const customSort = (seriesA, seriesB) => {
|
||||
const instanceA = seriesA.instances[0];
|
||||
const instanceB = seriesB.instances[0];
|
||||
const modalityA = instanceA.Modality;
|
||||
const modalityB = instanceB.Modality;
|
||||
|
||||
const isEndA = END_MODALITIES[modalityA];
|
||||
const isEndB = END_MODALITIES[modalityB];
|
||||
|
||||
if (isEndA && isEndB) {
|
||||
// Compare by series date
|
||||
return compareValue(instanceA.SeriesNumber, instanceB.SeriesNumber);
|
||||
}
|
||||
if (!isEndA && !isEndB) {
|
||||
return compareValue(instanceB.SeriesNumber, instanceA.SeriesNumber);
|
||||
}
|
||||
return isEndA ? -1 : 1;
|
||||
};
|
||||
|
||||
function createDicomLocalApi(dicomLocalConfig) {
|
||||
const { name } = dicomLocalConfig;
|
||||
|
||||
const implementation = {
|
||||
initialize: ({ params, query }) => {},
|
||||
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.instances[0].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: utils.formatPN(firstInstance.PatientName),
|
||||
studyInstanceUid: firstInstance.StudyInstanceUID,
|
||||
time: firstInstance.StudyTime,
|
||||
//
|
||||
instances: numInstances,
|
||||
modalities: Array.from(modalities).join('/'),
|
||||
NumInstances: numInstances,
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
processResults: () => {
|
||||
console.warn(' DICOMLocal QUERY processResults not implemented');
|
||||
},
|
||||
},
|
||||
series: {
|
||||
search: studyInstanceUID => {
|
||||
const study = DicomMetadataStore.getStudy(studyInstanceUID);
|
||||
return study.series.map(aSeries => {
|
||||
const firstInstance = aSeries?.instances[0];
|
||||
return {
|
||||
studyInstanceUid: studyInstanceUID,
|
||||
seriesInstanceUid: firstInstance.SeriesInstanceUID,
|
||||
modality: firstInstance.Modality,
|
||||
seriesNumber: firstInstance.SeriesNumber,
|
||||
seriesDate: firstInstance.SeriesDate,
|
||||
numSeriesInstances: aSeries.instances.length,
|
||||
description: firstInstance.SeriesDescription,
|
||||
};
|
||||
});
|
||||
},
|
||||
},
|
||||
instances: {
|
||||
search: () => {
|
||||
console.warn(' DICOMLocal QUERY instances SEARCH not implemented');
|
||||
},
|
||||
},
|
||||
},
|
||||
retrieve: {
|
||||
directURL: params => {
|
||||
const { instance, tag, defaultType } = params;
|
||||
|
||||
const value = instance[tag];
|
||||
if (value instanceof Array && value[0] instanceof ArrayBuffer) {
|
||||
return URL.createObjectURL(
|
||||
new Blob([value[0]], {
|
||||
type: defaultType,
|
||||
})
|
||||
);
|
||||
}
|
||||
},
|
||||
series: {
|
||||
metadata: 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;
|
||||
|
||||
const isMultiframe = aSeries.instances[0].NumberOfFrames > 1;
|
||||
|
||||
aSeries.instances.forEach((instance, index) => {
|
||||
const {
|
||||
url: imageId,
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
SOPInstanceUID,
|
||||
} = instance;
|
||||
|
||||
instance.imageId = imageId;
|
||||
|
||||
// Add imageId specific mapping to this data as the URL isn't necessarily WADO-URI.
|
||||
metadataProvider.addImageIdToUIDs(imageId, {
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
SOPInstanceUID,
|
||||
frameIndex: isMultiframe ? index : 1,
|
||||
});
|
||||
});
|
||||
|
||||
DicomMetadataStore._broadcastEvent(EVENTS.INSTANCES_ADDED, {
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
madeInClient,
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
store: {
|
||||
dicom: naturalizedReport => {
|
||||
const reportBlob = dcmjs.data.datasetToBlob(naturalizedReport);
|
||||
|
||||
//Create a URL for the binary.
|
||||
var objectUrl = URL.createObjectURL(reportBlob);
|
||||
window.location.assign(objectUrl);
|
||||
},
|
||||
},
|
||||
getImageIdsForDisplaySet(displaySet) {
|
||||
const images = displaySet.images;
|
||||
const imageIds = [];
|
||||
|
||||
if (!images) {
|
||||
return imageIds;
|
||||
}
|
||||
|
||||
displaySet.images.forEach(instance => {
|
||||
const NumberOfFrames = instance.NumberOfFrames;
|
||||
if (NumberOfFrames > 1) {
|
||||
// in multiframe we start at frame 1
|
||||
for (let i = 1; 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 }) {
|
||||
if (instance.imageId) {
|
||||
return instance.imageId;
|
||||
}
|
||||
|
||||
const { StudyInstanceUID, SeriesInstanceUID, SOPInstanceUID } = instance;
|
||||
const storedInstance = DicomMetadataStore.getInstance(
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
SOPInstanceUID
|
||||
);
|
||||
|
||||
let imageId = storedInstance.url;
|
||||
|
||||
if (frame !== undefined) {
|
||||
imageId += `&frame=${frame}`;
|
||||
}
|
||||
|
||||
return imageId;
|
||||
},
|
||||
deleteStudyMetadataPromise() {
|
||||
console.log('deleteStudyMetadataPromise not implemented');
|
||||
},
|
||||
getStudyInstanceUIDs: ({ params, query }) => {
|
||||
const { StudyInstanceUIDs: paramsStudyInstanceUIDs } = params;
|
||||
const queryStudyInstanceUIDs = query.getAll('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
|
||||
let isStudyInCache = false;
|
||||
StudyInstanceUIDsAsArray.forEach(StudyInstanceUID => {
|
||||
const study = DicomMetadataStore.getStudy(StudyInstanceUID);
|
||||
if (study) {
|
||||
study.series = study.series.sort(customSort);
|
||||
isStudyInCache = true;
|
||||
}
|
||||
});
|
||||
|
||||
return isStudyInCache ? StudyInstanceUIDsAsArray : [];
|
||||
},
|
||||
};
|
||||
return IWebApiDataSource.create(implementation);
|
||||
}
|
||||
|
||||
export { createDicomLocalApi };
|
||||
Reference in New Issue
Block a user