Moved the Cornerstone viewport code to an extension. Tons of changes to rollup and package.json files to make everything play nicely

This commit is contained in:
Erik Ziegler committed 2019-02-06 14:46:06 +01:00
1 parent 9a0f417eec
commit 22202141b8
45 files changed
+6193 -208

No files matched your search

@@ -0,0 +1,52 @@
import { connect } from 'react-redux';
import CornerstoneViewport from 'react-cornerstone-viewport';
import OHIF from 'ohif-core'
import cornerstone from "cornerstone-core";
import cornerstoneTools from "cornerstone-tools";
const { setViewportActive, setViewportSpecificData, clearViewportSpecificData } = OHIF.redux.actions;
const mapStateToProps = (state, ownProps) => {
const activeButton = state.tools.buttons.find(tool => tool.active === true);
// If this is the active viewport, enable prefetching.
const { viewportIndex } = ownProps;//.viewportData;
const isActive = viewportIndex === state.viewports.activeViewportIndex;
const viewportSpecificData = state.viewports.viewportSpecificData[viewportIndex] || {};
return {
layout: state.viewports.layout,
isActive,
activeTool: activeButton && activeButton.command,
enableStackPrefetch: isActive,
//stack: viewportSpecificData.stack,
cineToolData: viewportSpecificData.cine,
cornerstone,
cornerstoneTools
};
};
const mapDispatchToProps = (dispatch, ownProps) => {
const { viewportIndex } = ownProps;
return {
setViewportActive: () => {
dispatch(setViewportActive(viewportIndex))
},
setViewportSpecificData: (data) => {
dispatch(setViewportSpecificData(viewportIndex, data))
},
clearViewportSpecificData: () => {
dispatch(clearViewportSpecificData(viewportIndex));
}
};
};
const ConnectedCornerstoneViewport = connect(
mapStateToProps,
mapDispatchToProps
)(CornerstoneViewport);
export default ConnectedCornerstoneViewport;
@@ -0,0 +1,26 @@
import OHIFCornerstoneViewport from './OHIFCornerstoneViewport.js';
export default class OHIFCornerstoneExtension {
/**
* Extension ID is a unique id, might be used for namespacing extension specific redux actions/reducers (?)
*/
getExtensionId() {
return 'cornerstone';
}
getViewportModule() {
return OHIFCornerstoneViewport;
}
getSopClassHandler() {
return null;
}
getPanelModule() {
return null;
}
getToolbarModule() {
return null;
}
}
@@ -0,0 +1,168 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import OHIF from 'ohif-core';
import ConnectedCornerstoneViewport from './ConnectedCornerstoneViewport';
import cornerstoneTools from 'cornerstone-tools';
import cornerstone from 'cornerstone-core';
import './config';
import handleSegmentationStorage from './handleSegmentationStorage.js';
const { StackManager } = OHIF.utils;
// Create the synchronizer used to update reference lines
OHIF.viewer.updateImageSynchronizer = new cornerstoneTools.Synchronizer(
'cornerstonenewimage',
cornerstoneTools.updateImageSynchronizer
);
// Metadata configuration
const metadataProvider = new OHIF.cornerstone.MetadataProvider();
cornerstone.metaData.addProvider(
metadataProvider.provider.bind(metadataProvider)
);
StackManager.setMetadataProvider(metadataProvider);
const SOP_CLASSES = {
SEGMENTATION_STORAGE: '1.2.840.10008.5.1.4.1.1.66.4'
};
const specialCaseHandlers = {};
specialCaseHandlers[
SOP_CLASSES.SEGMENTATION_STORAGE
] = handleSegmentationStorage;
class OHIFCornerstoneViewport extends Component {
state = {
viewportData: null
};
static propTypes = {
studies: PropTypes.object,
displaySet: PropTypes.object,
viewportIndex: PropTypes.number
};
static id = 'OHIFCornerstoneViewport';
static init() {
console.log('OHIFCornerstoneViewport init()');
}
static destroy() {
console.log('OHIFCornerstoneViewport destroy()');
StackManager.clearStacks();
}
static getCornerstoneStack(studies, studyInstanceUid, displaySetInstanceUid) {
// Create shortcut to displaySet
const study = studies.find(
study => study.studyInstanceUid === studyInstanceUid
);
const displaySet = study.displaySets.find(set => {
return set.displaySetInstanceUid === displaySetInstanceUid;
});
// Get stack from Stack Manager
return StackManager.findOrCreateStack(study, displaySet);
}
static getViewportData = (
studies,
studyInstanceUid,
displaySetInstanceUid
) => {
const currentStack = OHIFCornerstoneViewport.getCornerstoneStack(
studies,
studyInstanceUid,
displaySetInstanceUid
);
// Clone the stack here so we don't mutate it later
const stack = Object.assign({}, currentStack);
stack.currentImageIdIndex = 0;
return stack;
};
getViewportData = async (
studies,
studyInstanceUid,
displaySetInstanceUid,
sopClassUid
) => {
let viewportData;
switch (sopClassUid) {
case SOP_CLASSES.SEGMENTATION_STORAGE:
const specialCaseHandler =
specialCaseHandlers[SOP_CLASSES.SEGMENTATION_STORAGE];
viewportData = await specialCaseHandler(
studies,
studyInstanceUid,
displaySetInstanceUid
);
break;
default:
const stack = OHIFCornerstoneViewport.getViewportData(
studies,
studyInstanceUid,
displaySetInstanceUid
);
viewportData = {
studyInstanceUid,
displaySetInstanceUid,
stack
};
break;
}
return viewportData;
};
componentDidMount() {
const { studies, displaySet } = this.props.viewportData;
const {
studyInstanceUid,
displaySetInstanceUid,
sopClassUids
} = displaySet;
if (sopClassUids.length > 1) {
console.warn(
'More than one SOPClassUid in the same series is not yet supported.'
);
}
const sopClassUid = sopClassUids[0];
this.getViewportData(
studies,
studyInstanceUid,
displaySetInstanceUid,
sopClassUid
).then(viewportData => {
this.setState({
viewportData
});
});
}
render() {
return (<>
{this.state.viewportData && (
<ConnectedCornerstoneViewport
viewportData={this.state.viewportData}
viewportIndex={this.props.viewportIndex}
/>
)}
</>
);
}
}
export default OHIFCornerstoneViewport;
@@ -0,0 +1,31 @@
import cornerstone from 'cornerstone-core';
import cornerstoneMath from 'cornerstone-math';
import cornerstoneTools from 'cornerstone-tools';
import Hammer from 'hammerjs';
import OHIF from 'ohif-core';
// For debugging
window.cornerstoneTools = cornerstoneTools;
cornerstoneTools.external.cornerstone = cornerstone;
cornerstoneTools.external.Hammer = Hammer;
cornerstoneTools.external.cornerstoneMath = cornerstoneMath;
cornerstoneTools.init();
OHIF.external.cornerstoneTools = cornerstoneTools;
// Set the tool font and font size
// context.font = "[style] [variant] [weight] [size]/[line height] [font family]";
const fontFamily =
'Roboto, OpenSans, HelveticaNeue-Light, Helvetica Neue Light, Helvetica Neue, Helvetica, Arial, Lucida Grande, sans-serif';
cornerstoneTools.textStyle.setFont(`16px ${fontFamily}`);
// Set the tool width
cornerstoneTools.toolStyle.setToolWidth(2);
// Set color for inactive tools
cornerstoneTools.toolColors.setToolColor('rgb(255, 255, 0)');
// Set color for active tools
cornerstoneTools.toolColors.setActiveColor('rgb(0, 255, 0)');
cornerstoneTools.store.state.touchProximity = 40;
@@ -0,0 +1,155 @@
import OHIF from 'ohif-core';
import cornerstone from 'cornerstone-core';
import cornerstoneTools from 'cornerstone-tools';
import * as dcmjs from 'dcmjs';
const { StackManager } = OHIF.utils;
function getDisplaySet(studies, studyInstanceUid, displaySetInstanceUid) {
const study = studies.find(
study => study.studyInstanceUid === studyInstanceUid
);
const displaySet = study.displaySets.find(set => {
return set.displaySetInstanceUid === displaySetInstanceUid;
});
return displaySet;
}
function getDisplaySetsBySeries(studies, studyInstanceUid, seriesInstanceUid) {
const study = studies.find(
study => study.studyInstanceUid === studyInstanceUid
);
return study.displaySets.filter(set => {
return set.seriesInstanceUid === seriesInstanceUid;
});
}
function getCornerstoneStack(studies, studyInstanceUid, displaySetInstanceUid) {
const study = studies.find(
study => study.studyInstanceUid === studyInstanceUid
);
// Create shortcut to displaySet
const displaySet = getDisplaySet(
studies,
studyInstanceUid,
displaySetInstanceUid
);
// Get stack from Stack Manager
const stack = StackManager.findOrCreateStack(study, displaySet);
// Clone the stack here so we don't mutate it later
const stackClone = Object.assign({}, stack);
stackClone.currentImageIdIndex = 0;
return stackClone;
}
function parseSeg(arrayBuffer, imageIds, firstImagePlane) {
return dcmjs.adapters.Cornerstone.Segmentation.readToolState(
imageIds,
arrayBuffer,
firstImagePlane
);
}
function addSegMetadataToCornerstoneToolState(
segMetadata,
toolState,
displaySetInstanceUid
) {
cornerstoneTools.globalImageIdSpecificToolStateManager.restoreToolState(
toolState
);
const brushModule = cornerstoneTools.store.modules.brush;
for (let i = 0; i < segMetadata.length; i++) {
brushModule.setters.metadata(displaySetInstanceUid, i, segMetadata[i]);
}
}
function retrieveDicomData(wadoUri) {
// TODO: Authorization header depends on the server. If we ever have multiple servers
// we will need to figure out how / when to pass this information in.
return fetch(wadoUri, {
headers: OHIF.DICOMWeb.getAuthorizationHeader()
}).then(response => response.arrayBuffer());
}
async function handleSegmentationStorage(
studies,
studyInstanceUid,
displaySetInstanceUid
) {
const study = studies.find(
study => study.studyInstanceUid === studyInstanceUid
);
const displaySet = getDisplaySet(
studies,
studyInstanceUid,
displaySetInstanceUid
);
const segWadoUri = displaySet.images[0].getData().wadouri;
const arrayBuffer = await retrieveDicomData(segWadoUri);
const dicomData = dcmjs.data.DicomMessage.readFile(arrayBuffer);
const dataset = dcmjs.data.DicomMetaDictionary.naturalizeDataset(
dicomData.dict
);
dataset._meta = dcmjs.data.DicomMetaDictionary.namifyDataset(dicomData.meta);
const seriesInstanceUid = dataset.ReferencedSeriesSequence.SeriesInstanceUID;
const displaySets = getDisplaySetsBySeries(
studies,
studyInstanceUid,
seriesInstanceUid
);
if (displaySets.length > 1) {
console.warn(
'More than one display set with the same seriesInstanceUid. This is not supported yet...'
);
}
const referenceDisplaySet = displaySets[0];
const imageIds = referenceDisplaySet.images.map(image => image.getImageId());
debugger;
const firstImagePlane = cornerstone.metadata.get('imagePlane', imageIds[0]);
const results = parseSeg(arrayBuffer, imageIds, firstImagePlane);
if (!results) {
throw new Error('Fractional segmentations are not supported');
}
const { segMetadata, toolState } = results;
segMetadata.seriesInstanceUid = seriesInstanceUid;
addSegMetadataToCornerstoneToolState(
segMetadata,
toolState,
displaySetInstanceUid
);
const cachedStack = StackManager.findOrCreateStack(
study,
referenceDisplaySet
);
const stack = Object.assign({}, cachedStack);
stack.currentImageIdIndex = 0;
return {
studyInstanceUid,
displaySetInstanceUid,
stack
};
}
export default handleSegmentationStorage;
@@ -0,0 +1,3 @@
import OHIFCornerstoneExtension from './OHIFCornerstoneExtension.js';
export default OHIFCornerstoneExtension;