* 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>
226 lines
6.7 KiB
JavaScript
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 };
|