ohif-viewer/extensions/default/src/DicomWebDataSource/index.js
James Petts eb8f3a63f2
OHIF-197 (#1833)
* Viewport letter only in multi-viewport layout.

* If SliceThickness not available print N/A

* Create displaySet in local session on SR generation.

* remove empty line

* remove console log

* Give storeMeasurements an onSuccess handler instead of always creating dataSets.

Co-authored-by: Danny Brown <danny.ri.brown@gmail.com>
2020-06-30 15:10:27 +01:00

226 lines
6.7 KiB
JavaScript

import { api } from 'dicomweb-client';
import {
mapParams,
search as qidoSearch,
seriesInStudy,
processResults,
processSeriesResults,
} from './qido.js';
import { DicomMetadataStore, IWebApiDataSource, utils } from '@ohif/core';
import getImageId from './utils/getImageId';
import * as dcmjs from 'dcmjs';
import {
retrieveStudyMetadata,
deleteStudyMetadataPromise,
} from './retrieveStudyMetadata.js';
const { DicomMetaDictionary, DicomDict } = dcmjs.data;
const { naturalizeDataset, denaturalizeDataset } = DicomMetaDictionary;
const { urlUtil } = utils;
const ImplementationClassUID =
'2.25.270695996825855179949881587723571202391.2.0.0';
const ImplementationVersionName = 'OHIF-VIEWER-2.0.0';
const EXPLICIT_VR_LITTLE_ENDIAN = '1.2.840.10008.1.2.1';
/**
*
* @param {string} name - Data source name
* @param {string} wadoUriRoot - Legacy? (potentially unused/replaced)
* @param {string} qidoRoot - Base URL to use for QIDO requests
* @param {string} wadoRoot - Base URL to use for WADO requests
* @param {boolean} qidoSupportsIncludeField - Whether QIDO supports the "Include" option to request additional fields in response
* @param {string} imageRengering - wadors | ? (unsure of where/how this is used)
* @param {string} thumbnailRendering - wadors | ? (unsure of where/how this is used)
* @param {bool} lazyLoadStudy - "enableStudyLazyLoad"; Request series meta async instead of blocking
*/
function createDicomWebApi(dicomWebConfig) {
const { qidoRoot, wadoRoot, enableStudyLazyLoad } = dicomWebConfig;
const qidoConfig = {
url: qidoRoot,
// headers: DICOMWeb.getAuthorizationHeader(server),
};
const wadoConfig = {
url: wadoRoot,
};
// TODO -> Two clients sucks, but its better than 1000.
// TODO -> We'll need to merge auth later.
const qidoDicomWebClient = new api.DICOMwebClient(qidoConfig);
const wadoDicomWebClient = new api.DICOMwebClient(wadoConfig);
return IWebApiDataSource.create({
query: {
studies: {
mapParams: mapParams.bind(),
search: async function(origParams) {
const { studyInstanceUid, seriesInstanceUid, ...mappedParams } =
mapParams(origParams) || {};
const results = await qidoSearch(
qidoDicomWebClient,
undefined,
undefined,
mappedParams
);
return processResults(results);
},
processResults: processResults.bind(),
},
series: {
// mapParams: mapParams.bind(),
search: async function(studyInstanceUid) {
const results = await seriesInStudy(
qidoDicomWebClient,
studyInstanceUid
);
return processSeriesResults(results);
},
// processResults: processResults.bind(),
},
instances: {
search: (studyInstanceUid, queryParameters) =>
qidoSearch.call(
undefined,
qidoDicomWebClient,
studyInstanceUid,
null,
queryParameters
),
},
},
retrieve: {
series: {
// TODO: change queryParams to `StudyInstanceUID` for now?
// Conduct query, return a promise like others
// Await this call and add to DicomMetadataStore after receiving result
metadata: (queryParams, callback) => {
let { StudyInstanceUIDs } = urlUtil.parse(queryParams, true);
StudyInstanceUIDs = urlUtil.paramString.parseParam(StudyInstanceUIDs);
if (!StudyInstanceUIDs) {
throw new Error(
'Incomplete queryParams, missing StudyInstanceUIDs'
);
}
const storeInstances = instances => {
const naturalizedInstances = instances.map(naturalizeDataset);
DicomMetadataStore.addInstances(naturalizedInstances);
callback(naturalizedInstances);
};
const studyPromises = StudyInstanceUIDs.map(StudyInstanceUID =>
retrieveStudyMetadata(
wadoDicomWebClient,
StudyInstanceUID,
enableStudyLazyLoad
)
);
studyPromises.forEach(studyPromise => {
studyPromise.then(seriesPromises => {
seriesPromises.forEach(seriesPromise => {
seriesPromise.then(instances => {
storeInstances(instances);
});
});
});
});
},
},
},
store: {
dicom: async dataset => {
const meta = {
FileMetaInformationVersion:
dataset._meta.FileMetaInformationVersion.Value,
MediaStorageSOPClassUID: dataset.SOPClassUID,
MediaStorageSOPInstanceUID: dataset.SOPInstanceUID,
TransferSyntaxUID: EXPLICIT_VR_LITTLE_ENDIAN,
ImplementationClassUID,
ImplementationVersionName,
};
const denaturalized = denaturalizeDataset(meta);
const dicomDict = new DicomDict(denaturalized);
dicomDict.dict = denaturalizeDataset(dataset);
const part10Buffer = dicomDict.write();
const options = {
datasets: [part10Buffer],
};
await wadoDicomWebClient.storeInstances(options);
},
},
retrieveSeriesMetadata: async ({ StudyInstanceUID } = {}) => {
if (!StudyInstanceUID) {
throw new Error(
'Unable to query for SeriesMetadata without StudyInstanceUID'
);
}
// Get Series
const seriesPromises = await retrieveStudyMetadata(
wadoDicomWebClient,
StudyInstanceUID,
enableStudyLazyLoad
);
// Async load series, store as retrieved
function storeInstances(instances) {
const naturalizedInstances = instances.map(naturalizeDataset);
DicomMetadataStore.addInstances(naturalizedInstances);
}
seriesPromises.forEach(async seriesPromise => {
const instances = await seriesPromise;
storeInstances(instances);
});
},
deleteStudyMetadataPromise,
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: dicomWebConfig,
});
imageIds.push(imageId);
}
} else {
const imageId = getImageId({ instance, config: dicomWebConfig });
imageIds.push(imageId);
}
});
return imageIds;
},
});
}
export { createDicomWebApi };