fix: Overlays were broken. (#2614)
* fix(OHIFv3):Overlays were broken. Adds a retrieveBulkData to elements containing BulkDataURI so that anyone display the data can retrieve the required information. * fix(OHIFv3):Added a call in the wrong spot, removed it. * docs(OHIFv3):Added some documentation as requested
This commit is contained in:
parent
fac04ccb5e
commit
277c3bf419
@ -162,9 +162,9 @@ function createDicomWebApi(dicomWebConfig, UserAuthenticationService) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const storeInstances = instances => {
|
const storeInstances = instances => {
|
||||||
const naturalizedInstances = instances.map(naturalizeDataset);
|
const naturalizedInstances = instances.map(naturalizeDataset);
|
||||||
|
|
||||||
DicomMetadataStore.addInstances(naturalizedInstances);
|
DicomMetadataStore.addInstances(naturalizedInstances);
|
||||||
callback(naturalizedInstances);
|
callback(naturalizedInstances);
|
||||||
};
|
};
|
||||||
@ -252,9 +252,47 @@ function createDicomWebApi(dicomWebConfig, UserAuthenticationService) {
|
|||||||
sortFunction
|
sortFunction
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* naturalizes the dataset, and adds a retrieve bulkdata method
|
||||||
|
* to any values containing BulkDataURI.
|
||||||
|
* @param {*} instance
|
||||||
|
* @returns naturalized dataset, with retrieveBulkData methods
|
||||||
|
*/
|
||||||
|
const addRetrieveBulkData = instance => {
|
||||||
|
const naturalized = naturalizeDataset(instance);
|
||||||
|
Object.keys(naturalized).forEach(key => {
|
||||||
|
const value = naturalized[key];
|
||||||
|
// The value.Value will be set with the bulkdata read value
|
||||||
|
// in which case it isn't necessary to re-read this.
|
||||||
|
if (value && value.BulkDataURI && !value.Value) {
|
||||||
|
// Provide a method to fetch bulkdata
|
||||||
|
value.retrieveBulkData = () => {
|
||||||
|
const options = {
|
||||||
|
// The bulkdata fetches work with either multipart or
|
||||||
|
// singlepart, so set multipart to false to let the server
|
||||||
|
// decide which type to respond with.
|
||||||
|
multipart: false,
|
||||||
|
BulkDataURI: value.BulkDataURI,
|
||||||
|
// The study instance UID is required if the bulkdata uri
|
||||||
|
// is relative - that isn't disallowed by DICOMweb, but
|
||||||
|
// isn't well specified in the standard, but is needed in
|
||||||
|
// any implementation that stores static copies of the metadata
|
||||||
|
StudyInstanceUID: naturalized.StudyInstanceUID,
|
||||||
|
};
|
||||||
|
return qidoDicomWebClient.retrieveBulkData(options).then(val => {
|
||||||
|
const ret = val && val[0] || undefined;
|
||||||
|
value.Value = ret;
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return naturalized
|
||||||
|
};
|
||||||
|
|
||||||
// Async load series, store as retrieved
|
// Async load series, store as retrieved
|
||||||
function storeInstances(instances) {
|
function storeInstances(instances) {
|
||||||
const naturalizedInstances = instances.map(naturalizeDataset);
|
const naturalizedInstances = instances.map(addRetrieveBulkData);
|
||||||
|
|
||||||
DicomMetadataStore.addInstances(naturalizedInstances, madeInClient);
|
DicomMetadataStore.addInstances(naturalizedInstances, madeInClient);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
import queryString from 'query-string';
|
import queryString from 'query-string';
|
||||||
import dicomParser from 'dicom-parser';
|
import dicomParser from 'dicom-parser';
|
||||||
import getPixelSpacingInformation from '../utils/metadataProvider/getPixelSpacingInformation';
|
import getPixelSpacingInformation from '../utils/metadataProvider/getPixelSpacingInformation';
|
||||||
import fetchPaletteColorLookupTableData from '../utils/metadataProvider/fetchPaletteColorLookupTableData';
|
|
||||||
import fetchOverlayData from '../utils/metadataProvider/fetchOverlayData';
|
|
||||||
import DicomMetadataStore from '../services/DicomMetadataStore';
|
import DicomMetadataStore from '../services/DicomMetadataStore';
|
||||||
|
|
||||||
class MetadataProvider {
|
class MetadataProvider {
|
||||||
@ -105,14 +103,6 @@ class MetadataProvider {
|
|||||||
// return instance;
|
// return instance;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// async _checkBulkDataAndInlineBinaries(instance, server) {
|
|
||||||
// await fetchOverlayData(instance, server);
|
|
||||||
|
|
||||||
// if (instance.PhotometricInterpretation === 'PALETTE COLOR') {
|
|
||||||
// await fetchPaletteColorLookupTableData(instance, server);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
_getInstance(imageId) {
|
_getInstance(imageId) {
|
||||||
const uids = this._getUIDsFromImageID(imageId);
|
const uids = this._getUIDsFromImageID(imageId);
|
||||||
|
|
||||||
@ -508,4 +498,3 @@ const WADO_IMAGE_LOADER_TAGS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const INSTANCE = 'instance';
|
const INSTANCE = 'instance';
|
||||||
const DICOMWEB = 'dicomweb';
|
|
||||||
|
|||||||
@ -1,82 +0,0 @@
|
|||||||
import { api } from 'dicomweb-client';
|
|
||||||
import DICOMWeb from '../../DICOMWeb';
|
|
||||||
import str2ab from '../str2ab';
|
|
||||||
import unpackOverlay from './unpackOverlay';
|
|
||||||
|
|
||||||
import errorHandler from '../../errorHandler';
|
|
||||||
|
|
||||||
export default async function fetchOverlayData(instance, server) {
|
|
||||||
const OverlayDataPromises = [];
|
|
||||||
const OverlayDataTags = [];
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
for (let overlayGroup = 0x00; overlayGroup <= 0x1e; overlayGroup += 0x02) {
|
|
||||||
let groupStr = `60${overlayGroup.toString(16)}`;
|
|
||||||
|
|
||||||
if (groupStr.length === 3) {
|
|
||||||
groupStr = `600${overlayGroup.toString(16)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const OverlayDataTag = `${groupStr}3000`;
|
|
||||||
|
|
||||||
if (instance[OverlayDataTag] && instance[OverlayDataTag].InlineBinary) {
|
|
||||||
const inlineBinaryData = atob(instance[OverlayDataTag].InlineBinary);
|
|
||||||
const arraybuffer = str2ab(inlineBinaryData);
|
|
||||||
|
|
||||||
instance[OverlayDataTag] = unpackOverlay(arraybuffer);
|
|
||||||
} else if (
|
|
||||||
instance[OverlayDataTag] &&
|
|
||||||
instance[OverlayDataTag].BulkDataURI
|
|
||||||
) {
|
|
||||||
OverlayDataPromises.push(
|
|
||||||
_getOverlayData(instance[OverlayDataTag], server)
|
|
||||||
);
|
|
||||||
OverlayDataTags.push(OverlayDataTag);
|
|
||||||
} else if (
|
|
||||||
instance[OverlayDataTag] &&
|
|
||||||
instance[OverlayDataTag] instanceof ArrayBuffer
|
|
||||||
) {
|
|
||||||
instance[OverlayDataTag] = unpackOverlay(instance[OverlayDataTag]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OverlayDataPromises.length) {
|
|
||||||
Promise.all(OverlayDataPromises).then(results => {
|
|
||||||
for (let i = 0; i < results.length; i++) {
|
|
||||||
instance[OverlayDataTags[i]] = results[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function _getOverlayData(tag, server) {
|
|
||||||
const { BulkDataURI } = tag;
|
|
||||||
|
|
||||||
let uri = BulkDataURI;
|
|
||||||
|
|
||||||
// TODO: Workaround for dcm4chee behind SSL-terminating proxy returning
|
|
||||||
// incorrect bulk data URIs
|
|
||||||
if (server.wadoRoot.indexOf('https') === 0 && !uri.includes('https')) {
|
|
||||||
uri = uri.replace('http', 'https');
|
|
||||||
}
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
url: server.wadoRoot, //BulkDataURI is absolute, so this isn't used
|
|
||||||
headers: DICOMWeb.getAuthorizationHeader(server),
|
|
||||||
errorInterceptor: errorHandler.getHTTPErrorHandler(),
|
|
||||||
};
|
|
||||||
const dicomWeb = new api.DICOMwebClient(config);
|
|
||||||
const options = {
|
|
||||||
BulkDataURI: uri,
|
|
||||||
};
|
|
||||||
|
|
||||||
return dicomWeb
|
|
||||||
.retrieveBulkData(options)
|
|
||||||
.then(result => result[0])
|
|
||||||
.then(unpackOverlay);
|
|
||||||
}
|
|
||||||
@ -4,13 +4,4 @@
|
|||||||
* @param {String} str Input String
|
* @param {String} str Input String
|
||||||
* @return {ArrayBuffer} Output converted ArrayBuffer
|
* @return {ArrayBuffer} Output converted ArrayBuffer
|
||||||
*/
|
*/
|
||||||
export default function str2ab(str) {
|
export default str => Uint8Array.from(atob(str), c => c.charCodeAt(0));
|
||||||
const strLen = str.length;
|
|
||||||
const bytes = new Uint8Array(strLen);
|
|
||||||
|
|
||||||
for (let i = 0; i < strLen; i++) {
|
|
||||||
bytes[i] = str.charCodeAt(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes.buffer;
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user