Files
ohif-viewer/extensions/default/src/DicomLocalDataSource/index.js
T

263 lines
8.2 KiB
JavaScript
Raw Normal View History

import { DicomMetadataStore, IWebApiDataSource, utils } from '@ohif/core';
2022-02-08 13:17:37 +00:00
import OHIF from '@ohif/core';
import dcmjs from 'dcmjs';
2022-02-08 13:17:37 +00:00
const metadataProvider = OHIF.classes.MetadataProvider;
const { EVENTS } = DicomMetadataStore;
2023-02-06 17:05:13 -05:00
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;
}
2023-02-06 17:05:13 -05:00
return 1;
};
// Sorting SR modalities to be at the end of series list
2023-02-06 17:05:13 -05:00
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];
2023-02-06 17:05:13 -05:00
if (isEndA && isEndB) {
// Compare by series date
return compareValue(instanceA.SeriesNumber, instanceB.SeriesNumber);
}
2023-02-06 17:05:13 -05:00
if (!isEndA && !isEndB) {
return compareValue(instanceB.SeriesNumber, instanceA.SeriesNumber);
}
2023-02-06 17:05:13 -05:00
return isEndA ? -1 : 1;
};
function createDicomLocalApi(dicomLocalConfig) {
2022-02-08 13:17:37 +00:00
const { name } = dicomLocalConfig;
const implementation = {
initialize: ({ params, query }) => {},
query: {
studies: {
2022-02-08 13:17:37 +00:00
mapParams: () => {},
search: params => {
const studyUIDs = DicomMetadataStore.getStudyInstanceUIDs();
return studyUIDs.map(StudyInstanceUID => {
2022-02-08 13:17:37 +00:00
let numInstances = 0;
const modalities = new Set();
// Calculating the number of instances in the study and modalities
// present in the study
2022-02-08 13:17:37 +00:00
const study = DicomMetadataStore.getStudy(StudyInstanceUID);
study.series.forEach(aSeries => {
2022-02-08 13:17:37 +00:00
numInstances += aSeries.instances.length;
modalities.add(aSeries.instances[0].Modality);
2022-02-08 13:17:37 +00:00
});
// first instance in the first series
2022-02-08 13:17:37 +00:00
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,
};
}
2022-02-08 13:17:37 +00:00
});
},
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 } = {}) => {
2022-02-08 13:17:37 +00:00
if (!StudyInstanceUID) {
throw new Error('Unable to query for SeriesMetadata without StudyInstanceUID');
2022-02-08 13:17:37 +00:00
}
// Instances metadata already added via local upload
const study = DicomMetadataStore.getStudy(StudyInstanceUID, madeInClient);
2022-02-08 13:17:37 +00:00
// 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) => {
2022-02-08 13:17:37 +00:00
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,
});
2022-02-08 13:17:37 +00:00
});
DicomMetadataStore._broadcastEvent(EVENTS.INSTANCES_ADDED, {
StudyInstanceUID,
SeriesInstanceUID,
madeInClient,
});
});
},
},
},
store: {
2022-02-08 13:17:37 +00:00
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) {
2022-02-08 13:17:37 +00:00
const images = displaySet.images;
const imageIds = [];
if (!images) {
2022-02-08 13:17:37 +00:00
return imageIds;
}
2022-02-08 13:17:37 +00:00
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,
2022-02-08 13:17:37 +00:00
});
imageIds.push(imageId);
}
} else {
2022-02-08 13:17:37 +00:00
const imageId = this.getImageIdsForInstance({ instance });
imageIds.push(imageId);
}
2022-02-08 13:17:37 +00:00
});
2022-02-08 13:17:37 +00:00
return imageIds;
},
getImageIdsForInstance({ instance, frame }) {
// Important: Never use instance.imageId because it might be multiframe,
// which would make it an invalid imageId.
// if (instance.imageId) {
// return instance.imageId;
// }
2024-11-06 07:15:27 -05:00
const { StudyInstanceUID, SeriesInstanceUID } = instance;
const SOPInstanceUID = instance.SOPInstanceUID || instance.SopInstanceUID;
2022-02-08 13:17:37 +00:00
const storedInstance = DicomMetadataStore.getInstance(
StudyInstanceUID,
SeriesInstanceUID,
SOPInstanceUID
);
let imageId = storedInstance.url;
if (frame !== undefined) {
imageId += `&frame=${frame}`;
}
return imageId;
},
deleteStudyMetadataPromise() {
2022-02-08 13:17:37 +00:00
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 : [];
},
2022-02-08 13:17:37 +00:00
};
return IWebApiDataSource.create(implementation);
}
2022-02-08 13:17:37 +00:00
export { createDicomLocalApi };