diff --git a/extensions/cornerstone/package.json b/extensions/cornerstone/package.json
index 8ba04384de6..9d0dcb80deb 100644
--- a/extensions/cornerstone/package.json
+++ b/extensions/cornerstone/package.json
@@ -36,7 +36,7 @@
"cornerstone-math": "^0.1.8",
"cornerstone-tools": "4.12.5",
"cornerstone-wado-image-loader": "^3.1.0",
- "dcmjs": "^0.12.2",
+ "dcmjs": "^0.12.3",
"dicom-parser": "^1.8.3",
"hammerjs": "^2.0.8",
"prop-types": "^15.6.2",
diff --git a/extensions/dicom-html/package.json b/extensions/dicom-html/package.json
index 5628aed9b17..8dca4f8a139 100644
--- a/extensions/dicom-html/package.json
+++ b/extensions/dicom-html/package.json
@@ -29,7 +29,7 @@
},
"peerDependencies": {
"@ohif/core": "^0.50.0",
- "dcmjs": "^0.12.2",
+ "dcmjs": "^0.12.3",
"prop-types": "^15.6.2",
"react": "^16.8.6",
"react-dom": "^16.8.6"
diff --git a/extensions/dicom-rt/package.json b/extensions/dicom-rt/package.json
index 85be0531a89..5a2ed51f087 100644
--- a/extensions/dicom-rt/package.json
+++ b/extensions/dicom-rt/package.json
@@ -31,7 +31,7 @@
"@ohif/core": "^0.50.0",
"cornerstone-core": "^2.2.8",
"cornerstone-tools": "^4.0.9",
- "dcmjs": "^0.12.2",
+ "dcmjs": "^0.12.3",
"prop-types": "^15.6.2",
"react": "^16.8.6",
"react-dom": "^16.8.6"
diff --git a/extensions/dicom-segmentation/src/OHIFDicomSegSopClassHandler.js b/extensions/dicom-segmentation/src/OHIFDicomSegSopClassHandler.js
deleted file mode 100644
index c6ada274698..00000000000
--- a/extensions/dicom-segmentation/src/OHIFDicomSegSopClassHandler.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import { MODULE_TYPES, utils } from '@ohif/core';
-import loadSegmentation from './loadSegmentation';
-
-// TODO: Should probably use dcmjs for this
-const SOP_CLASS_UIDS = {
- DICOM_SEG: '1.2.840.10008.5.1.4.1.1.66.4',
-};
-
-const sopClassUIDs = Object.values(SOP_CLASS_UIDS);
-
-// TODO: Handle the case where there is more than one SOP Class Handler for the
-// same SOP Class.
-const OHIFDicomSegSopClassHandler = {
- id: 'OHIFDicomSegSopClassHandler',
- type: MODULE_TYPES.SOP_CLASS_HANDLER,
- sopClassUIDs,
- getDisplaySetFromSeries: function (
- series,
- study,
- dicomWebClient,
- authorizationHeaders
- ) {
- const instance = series.getFirstInstance();
- const metadata = instance.getData().metadata;
-
- const {
- SeriesDate,
- SeriesTime,
- SeriesDescription,
- FrameOfReferenceUID,
- SOPInstanceUID,
- SeriesInstanceUID,
- StudyInstanceUID,
- } = metadata;
-
- const segDisplaySet = {
- Modality: 'SEG',
- displaySetInstanceUID: utils.guid(),
- wadoRoot: study.getData().wadoRoot,
- wadoUri: instance.getData().wadouri,
- SOPInstanceUID,
- SeriesInstanceUID,
- StudyInstanceUID,
- FrameOfReferenceUID,
- authorizationHeaders,
- metadata,
- isDerived: true,
- referencedDisplaySetUID: null, // Assigned when loaded.
- labelmapIndex: null, // Assigned when loaded.
- isLoaded: false,
- SeriesDate,
- SeriesTime,
- SeriesDescription,
- };
-
- segDisplaySet.load = function (referencedDisplaySet, studies) {
- return loadSegmentation(
- segDisplaySet,
- referencedDisplaySet,
- studies
- ).catch(error => {
- segDisplaySet.isLoaded = false;
- throw new Error(error);
- });
- };
-
- return segDisplaySet;
- },
-};
-
-export default OHIFDicomSegSopClassHandler;
diff --git a/extensions/dicom-segmentation/src/components/SegmentationPanel/SegmentationPanel.js b/extensions/dicom-segmentation/src/components/SegmentationPanel/SegmentationPanel.js
index e532d9d8119..a0c0d8bb45d 100644
--- a/extensions/dicom-segmentation/src/components/SegmentationPanel/SegmentationPanel.js
+++ b/extensions/dicom-segmentation/src/components/SegmentationPanel/SegmentationPanel.js
@@ -41,6 +41,7 @@ const SegmentationPanel = ({
activeIndex,
isOpen,
onSegItemClick,
+ UINotificationService,
}) => {
/*
* TODO: wrap get/set interactions with the cornerstoneTools
@@ -115,7 +116,11 @@ const SegmentationPanel = ({
firstImageId,
activeViewport
);
- const segmentList = getSegmentList(labelmap3D, firstImageId, brushStackState);
+ const segmentList = getSegmentList(
+ labelmap3D,
+ firstImageId,
+ brushStackState
+ );
setState(state => ({
...state,
brushStackState,
@@ -130,7 +135,14 @@ const SegmentationPanel = ({
segmentList: [],
}));
}
- }, [studies, viewports, activeIndex, getLabelmapList, getSegmentList, state.selectedSegmentation]);
+ }, [
+ studies,
+ viewports,
+ activeIndex,
+ getLabelmapList,
+ getSegmentList,
+ state.selectedSegmentation,
+ ]);
/* Handle open/closed panel behaviour */
useEffect(() => {
@@ -170,7 +182,8 @@ const SegmentationPanel = ({
studies,
displaySet,
firstImageId,
- brushStackState.activeLabelmapIndex
+ brushStackState.activeLabelmapIndex,
+ UINotificationService
);
updateState('selectedSegmentation', activatedLabelmapIndex);
},
@@ -424,7 +437,9 @@ const SegmentationPanel = ({
Segmentations
i.value === state.selectedSegmentation)}
+ value={state.labelmapList.find(
+ i => i.value === state.selectedSegmentation
+ )}
formatOptionLabel={SegmentationItem}
options={state.labelmapList}
/>
@@ -509,7 +524,8 @@ const _setActiveLabelmap = async (
studies,
displaySet,
firstImageId,
- activeLabelmapIndex
+ activeLabelmapIndex,
+ UINotificationService
) => {
if (displaySet.labelmapIndex === activeLabelmapIndex) {
log.warn(`${activeLabelmapIndex} is already the active labelmap`);
@@ -519,7 +535,22 @@ const _setActiveLabelmap = async (
if (!displaySet.isLoaded) {
// What props does this expect `viewportSpecificData` to have?
// TODO: Should this return the `labelmapIndex`?
- await displaySet.load(viewportSpecificData, studies);
+
+ const loadPromise = displaySet.load(viewportSpecificData, studies);
+
+ loadPromise.catch(error => {
+ UINotificationService.show({
+ title: 'DICOM Segmentation Loader',
+ message: error.message,
+ type: 'error',
+ autoClose: false,
+ });
+
+ // Return old index.
+ return activeLabelmapIndex;
+ });
+
+ await loadPromise;
}
const { state } = cornerstoneTools.getModule('segmentation');
diff --git a/extensions/dicom-segmentation/src/getOHIFDicomSegSopClassHandler.js b/extensions/dicom-segmentation/src/getOHIFDicomSegSopClassHandler.js
new file mode 100644
index 00000000000..f589f6e5411
--- /dev/null
+++ b/extensions/dicom-segmentation/src/getOHIFDicomSegSopClassHandler.js
@@ -0,0 +1,64 @@
+import { MODULE_TYPES, utils } from '@ohif/core';
+import loadSegmentation from './loadSegmentation';
+
+// TODO: Should probably use dcmjs for this
+const SOP_CLASS_UIDS = {
+ DICOM_SEG: '1.2.840.10008.5.1.4.1.1.66.4',
+};
+
+const sopClassUIDs = Object.values(SOP_CLASS_UIDS);
+
+export default function getSopClassHandlerModule({ servicesManager }) {
+ // TODO: Handle the case where there is more than one SOP Class Handler for the
+ // same SOP Class.
+ return {
+ id: 'OHIFDicomSegSopClassHandler',
+ type: MODULE_TYPES.SOP_CLASS_HANDLER,
+ sopClassUIDs,
+ getDisplaySetFromSeries: function(
+ series,
+ study,
+ dicomWebClient,
+ authorizationHeaders
+ ) {
+ const instance = series.getFirstInstance();
+ const metadata = instance.getData().metadata;
+
+ const {
+ SeriesDate,
+ SeriesTime,
+ SeriesDescription,
+ FrameOfReferenceUID,
+ SOPInstanceUID,
+ SeriesInstanceUID,
+ StudyInstanceUID,
+ } = metadata;
+
+ const segDisplaySet = {
+ Modality: 'SEG',
+ displaySetInstanceUID: utils.guid(),
+ wadoRoot: study.getData().wadoRoot,
+ wadoUri: instance.getData().wadouri,
+ SOPInstanceUID,
+ SeriesInstanceUID,
+ StudyInstanceUID,
+ FrameOfReferenceUID,
+ authorizationHeaders,
+ metadata,
+ isDerived: true,
+ referencedDisplaySetUID: null, // Assigned when loaded.
+ labelmapIndex: null, // Assigned when loaded.
+ isLoaded: false,
+ SeriesDate,
+ SeriesTime,
+ SeriesDescription,
+ };
+
+ segDisplaySet.load = function(referencedDisplaySet, studies) {
+ return loadSegmentation(segDisplaySet, referencedDisplaySet, studies);
+ };
+
+ return segDisplaySet;
+ },
+ };
+}
diff --git a/extensions/dicom-segmentation/src/index.js b/extensions/dicom-segmentation/src/index.js
index 22a146326f9..188dd1fb562 100644
--- a/extensions/dicom-segmentation/src/index.js
+++ b/extensions/dicom-segmentation/src/index.js
@@ -2,7 +2,7 @@ import React from 'react';
import init from './init.js';
import toolbarModule from './toolbarModule.js';
-import sopClassHandlerModule from './OHIFDicomSegSopClassHandler.js';
+import getSopClassHandlerModule from './getOHIFDicomSegSopClassHandler.js';
import SegmentationPanel from './components/SegmentationPanel/SegmentationPanel.js';
export default {
@@ -23,14 +23,20 @@ export default {
getToolbarModule({ servicesManager }) {
return toolbarModule;
},
- getPanelModule({ commandsManager }) {
+ getPanelModule({ commandsManager, servicesManager }) {
const ExtendedSegmentationPanel = props => {
const segItemClickHandler = segData => {
commandsManager.runCommand('jumpToImage', segData);
};
+ const { UINotificationService } = servicesManager.services;
+
return (
-
+
);
};
@@ -72,7 +78,5 @@ export default {
defaultContext: ['VIEWER'],
};
},
- getSopClassHandlerModule({ servicesManager }) {
- return sopClassHandlerModule;
- },
+ getSopClassHandlerModule,
};
diff --git a/extensions/dicom-segmentation/src/loadSegmentation.js b/extensions/dicom-segmentation/src/loadSegmentation.js
index 1244b52c902..b0f9dde9b5e 100644
--- a/extensions/dicom-segmentation/src/loadSegmentation.js
+++ b/extensions/dicom-segmentation/src/loadSegmentation.js
@@ -34,28 +34,35 @@ export default async function loadSegmentation(
referencedDisplaySet.SeriesInstanceUID
);
- const results = _parseSeg(segArrayBuffer, imageIds);
+ return new Promise((resolve, reject) => {
+ let results;
+
+ try {
+ results = _parseSeg(segArrayBuffer, imageIds);
+ } catch (error) {
+ segDisplaySet.isLoaded = false;
+ reject(error);
+ }
- if (!results) {
- throw new Error('Fractional segmentations are not yet supported');
- }
+ const { labelmapBuffer, segMetadata, segmentsOnFrame } = results;
+ const { setters } = cornerstoneTools.getModule('segmentation');
- const { labelmapBuffer, segMetadata, segmentsOnFrame } = results;
- const { setters } = cornerstoneTools.getModule('segmentation');
+ // TODO: Could define a color LUT based on colors in the SEG.
+ const labelmapIndex = _getNextLabelmapIndex(imageIds[0]);
- // TODO: Could define a color LUT based on colors in the SEG.
- const labelmapIndex = _getNextLabelmapIndex(imageIds[0]);
+ setters.labelmap3DByFirstImageId(
+ imageIds[0],
+ labelmapBuffer,
+ labelmapIndex,
+ segMetadata,
+ imageIds.length,
+ segmentsOnFrame
+ );
- setters.labelmap3DByFirstImageId(
- imageIds[0],
- labelmapBuffer,
- labelmapIndex,
- segMetadata,
- imageIds.length,
- segmentsOnFrame
- );
+ segDisplaySet.labelmapIndex = labelmapIndex;
- segDisplaySet.labelmapIndex = labelmapIndex;
+ resolve(labelmapIndex);
+ });
}
function _getNextLabelmapIndex(firstImageId) {
diff --git a/platform/core/src/utils/loadAndCacheDerivedDisplaySets.js b/platform/core/src/utils/loadAndCacheDerivedDisplaySets.js
index b7ab4fdbe9b..b32eb581b2c 100644
--- a/platform/core/src/utils/loadAndCacheDerivedDisplaySets.js
+++ b/platform/core/src/utils/loadAndCacheDerivedDisplaySets.js
@@ -50,10 +50,12 @@ import studyMetadataManager from './studyMetadataManager';
const loadAndCacheDerivedDisplaySets = (referencedDisplaySet, studies) => {
const { StudyInstanceUID, SeriesInstanceUID } = referencedDisplaySet;
+ const promises = [];
+
const studyMetadata = studyMetadataManager.get(StudyInstanceUID);
if (!studyMetadata) {
- return;
+ return promises;
}
const derivedDisplaySets = studyMetadata.getDerivedDatasets({
@@ -61,7 +63,7 @@ const loadAndCacheDerivedDisplaySets = (referencedDisplaySet, studies) => {
});
if (!derivedDisplaySets.length) {
- return;
+ return promises;
}
// Filter by type
@@ -100,8 +102,10 @@ const loadAndCacheDerivedDisplaySets = (referencedDisplaySet, studies) => {
}
});
- recentDisplaySet.load(referencedDisplaySet, studies);
+ promises.push(recentDisplaySet.load(referencedDisplaySet, studies));
});
+
+ return promises;
};
export default loadAndCacheDerivedDisplaySets;
diff --git a/platform/ui/src/components/snackbar/Snackbar.css b/platform/ui/src/components/snackbar/Snackbar.css
index 8b0ee787e4e..bb99cefe6b6 100644
--- a/platform/ui/src/components/snackbar/Snackbar.css
+++ b/platform/ui/src/components/snackbar/Snackbar.css
@@ -127,7 +127,7 @@
.sb-message {
font-size: 14px;
- word-break: break-all;
+ word-break: normal;
}
.sb-item {
diff --git a/platform/viewer/src/components/ViewportGrid/ViewportGrid.js b/platform/viewer/src/components/ViewportGrid/ViewportGrid.js
index 7dbd126e609..082ec6eb112 100644
--- a/platform/viewer/src/components/ViewportGrid/ViewportGrid.js
+++ b/platform/viewer/src/components/ViewportGrid/ViewportGrid.js
@@ -4,6 +4,7 @@ import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { utils } from '@ohif/core';
+import { useSnackbarContext } from '@ohif/ui';
//
import ViewportPane from './ViewportPane.js';
import DefaultViewport from './DefaultViewport.js';
@@ -11,7 +12,7 @@ import EmptyViewport from './EmptyViewport.js';
const { loadAndCacheDerivedDisplaySets } = utils;
-const ViewportGrid = function (props) {
+const ViewportGrid = function(props) {
const {
activeViewportIndex,
availablePlugins,
@@ -33,9 +34,22 @@ const ViewportGrid = function (props) {
return null;
}
+ const snackbar = useSnackbarContext();
+
useEffect(() => {
viewportData.forEach(displaySet => {
- loadAndCacheDerivedDisplaySets(displaySet, studies);
+ const promises = loadAndCacheDerivedDisplaySets(displaySet, studies);
+
+ promises.forEach(promise => {
+ promise.catch(error => {
+ snackbar.show({
+ title: 'Error loading derived display set:',
+ message: error.message,
+ type: 'error',
+ autoClose: false,
+ });
+ });
+ });
});
}, [studies, viewportData]);