From 8eaa1877fd8f3a3b33a91f9c805bd973c74d722f Mon Sep 17 00:00:00 2001 From: Joe Boccanfuso <109477394+jbocce@users.noreply.github.com> Date: Wed, 10 May 2023 12:42:48 -0400 Subject: [PATCH] fix(DICOM PDF and Video): fixes for local DICOM load and remote data sources (#3374) * fix(DICOM PDF and Video) - added retrieve.directURL for local DICOM load data source; it returns a data URL - fixed various checks for video using transfer syntaxes and SOP class UID with number of frames - added call to 'rendered' endpoint for those data sources that support it; others get BulkDataURI * Added DOC (PDF) and OT (for video in particular) to list of non-image thumbnail modalities. * Fixed broken e2e tests. --- .../default/src/DicomLocalDataSource/index.js | 12 ++++++++++++ .../default/src/DicomWebDataSource/index.js | 10 ++++++++-- extensions/default/src/utils/getDirectURL.js | 18 ++++++++++-------- .../viewports/OHIFCornerstonePdfViewport.tsx | 5 ++--- .../src/getSopClassHandlerModule.js | 13 ++++++++++++- .../viewports/OHIFCornerstoneVideoViewport.tsx | 3 +-- .../PanelStudyBrowserTracking.tsx | 2 ++ .../ThumbnailNoImage/ThumbnailNoImage.tsx | 3 ++- .../cypress/integration/OHIFPdfDisplay.spec.js | 2 +- .../integration/OHIFVideoDisplay.spec.js | 6 ++++-- .../viewer/public/config/local_dcm4chee.js | 1 + .../viewer/src/routes/Local/dicomFileLoader.js | 4 ++++ 12 files changed, 59 insertions(+), 20 deletions(-) diff --git a/extensions/default/src/DicomLocalDataSource/index.js b/extensions/default/src/DicomLocalDataSource/index.js index f10d427ba..d7b3d7106 100644 --- a/extensions/default/src/DicomLocalDataSource/index.js +++ b/extensions/default/src/DicomLocalDataSource/index.js @@ -115,6 +115,18 @@ function createDicomLocalApi(dicomLocalConfig) { }, }, 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) { diff --git a/extensions/default/src/DicomWebDataSource/index.js b/extensions/default/src/DicomWebDataSource/index.js index c5782375c..01943417e 100644 --- a/extensions/default/src/DicomWebDataSource/index.js +++ b/extensions/default/src/DicomWebDataSource/index.js @@ -178,7 +178,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { * or is already retrieved, or a promise to a URL for such use if a BulkDataURI */ directURL: params => { - return getDirectURL(wadoRoot, params); + return getDirectURL({ wadoRoot, singlepart }, params); }, bulkDataURI: async ({ StudyInstanceUID, BulkDataURI }) => { const options = { @@ -394,7 +394,13 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) { }; // Todo: this needs to be from wado dicom web client return qidoDicomWebClient.retrieveBulkData(options).then(val => { - const ret = (val && val[0]) || undefined; + // There are DICOM PDF cases where the first ArrayBuffer in the array is + // the bulk data and DICOM video cases where the second ArrayBuffer is + // the bulk data. Here we play it safe and do a find. + const ret = + (val instanceof Array && + val.find(arrayBuffer => arrayBuffer?.byteLength)) || + undefined; value.Value = ret; return ret; }); diff --git a/extensions/default/src/utils/getDirectURL.js b/extensions/default/src/utils/getDirectURL.js index e90ff17af..4580b8d30 100644 --- a/extensions/default/src/utils/getDirectURL.js +++ b/extensions/default/src/utils/getDirectURL.js @@ -19,13 +19,13 @@ import { * @returns an absolute URL to the resource, if the absolute URL can be retrieved as singlepart, * or is already retrieved, or a promise to a URL for such use if a BulkDataURI */ -const getDirectURL = (wadoRoot, params) => { +const getDirectURL = (config, params) => { + const { wadoRoot, singlepart } = config; const { instance, tag = 'PixelData', defaultPath = '/pixeldata', defaultType = 'video/mp4', - singlepart = null, singlepart: fetchPart = 'video', } = params; const value = instance[tag]; @@ -53,11 +53,7 @@ const getDirectURL = (wadoRoot, params) => { return undefined; } - const { - StudyInstanceUID, - SeriesInstanceUID, - SOPInstanceUID, - } = instance; + const { StudyInstanceUID, SeriesInstanceUID, SOPInstanceUID } = instance; const BulkDataURI = (value && value.BulkDataURI) || `series/${SeriesInstanceUID}/instances/${SOPInstanceUID}${defaultPath}`; @@ -66,7 +62,13 @@ const getDirectURL = (wadoRoot, params) => { const acceptUri = BulkDataURI + (hasAccept ? '' : (hasQuery ? '&' : '?') + `accept=${defaultType}`); - if (BulkDataURI.indexOf('http') === 0) return acceptUri; + if (BulkDataURI.indexOf('http') === 0) { + if (tag === 'PixelData' || tag === 'EncapsulatedDocument') { + return `${wadoRoot}/studies/${StudyInstanceUID}/series/${SeriesInstanceUID}/instances/${SOPInstanceUID}/rendered`; + } else { + return acceptUri; + } + } if (BulkDataURI.indexOf('/') === 0) { return wadoRoot + acceptUri; } diff --git a/extensions/dicom-pdf/src/viewports/OHIFCornerstonePdfViewport.tsx b/extensions/dicom-pdf/src/viewports/OHIFCornerstonePdfViewport.tsx index 99488a21f..9da1904c1 100644 --- a/extensions/dicom-pdf/src/viewports/OHIFCornerstonePdfViewport.tsx +++ b/extensions/dicom-pdf/src/viewports/OHIFCornerstonePdfViewport.tsx @@ -14,15 +14,14 @@ function OHIFCornerstonePdfViewport({ displaySets }) { useEffect(() => { const load = async () => { - await pdfUrl; - setUrl(pdfUrl); + setUrl(await pdfUrl); }; load(); }, [pdfUrl]); return ( -