Add DicomMicroscopy plugin

This commit is contained in:
Erik Ziegler 2019-01-30 11:24:34 +00:00
parent 84c949f2e6
commit 03c7274812
14 changed files with 2679 additions and 656 deletions

3
.gitmodules vendored
View File

@ -10,3 +10,6 @@
[submodule "Packages-react/plugins/VTKPlugin"]
path = Packages-react/plugins/VTKPlugin
url = git@github.com:OHIF/VTKPlugin.git
[submodule "Packages-react/plugins/OpenLayersPlugin"]
path = Packages-react/plugins/OpenLayersPlugin
url = git@github.com:OHIF/OpenLayersPlugin.git

View File

@ -97,16 +97,20 @@
"cornerstone-math": "^0.1.8",
"cornerstone-tools": "3.0.0-b.1512",
"cornerstone-wado-image-loader": "^2.2.3",
"dicom-microscopy-viewer": "^0.2.0",
"dicom-parser": "^1.8.3",
"dicomweb-client": "^0.4.1",
"hammerjs": "^2.0.8",
"lodash.isequal": "^4.5.0",
"ohif-core": "^0.1.7",
"oidc-client": "^1.6.1",
"prop-types": "^15.6.2",
"react": "^16.7.0",
"react-bootstrap-modal": "^4.2.0",
"react-cornerstone-viewport": "^0.1.8",
"react-dnd": "^7.0.2",
"react-dnd-html5-backend": "^7.0.2",
"react-dom": "^16.7.0",
"react-redux": "^6.0.0",
"react-router": "^4.3.1",
"react-router-dom": "^4.3.1",

View File

@ -1,5 +1,4 @@
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import { createStore, combineReducers } from 'redux';
@ -12,6 +11,8 @@ import OHIFCornerstoneViewportPlugin from './connectedComponents/OHIFCornerstone
import WhiteLabellingContext from './WhiteLabellingContext';
import OHIFDicomPDFViewportPlugin from './connectedComponents/OHIFDicomPDFViewportPlugin/OHIFDicomPDFViewportPlugin.js';
import OHIFDicomPDFSopClassHandlerPlugin from './connectedComponents/OHIFDicomPDFViewportPlugin/OHIFDicomPDFSopClassHandlerPlugin.js';
import DicomMicroscopySopClassHandlerPlugin from './connectedComponents/DicomMicroscopyPlugin/DicomMicroscopySopClassHandlerPlugin.js';
import DicomMicroscopyViewport from './connectedComponents/DicomMicroscopyPlugin/DicomMicroscopyViewport.js';
import {
loadUser,
@ -103,7 +104,6 @@ const buttonsAction = OHIF.redux.actions.setAvailableButtons(defaultButtons);
store.dispatch(buttonsAction);
const { plugins } = OHIF;
const { PLUGIN_TYPES } = plugins;
@ -125,9 +125,25 @@ const pdfPluginActionSopClass = OHIF.redux.actions.addPlugin({
component: OHIFDicomPDFSopClassHandlerPlugin
});
const microscopyPluginAction = OHIF.redux.actions.addPlugin({
id: 'microscopy',
type: PLUGIN_TYPES.VIEWPORT,
component: DicomMicroscopyViewport
});
const microscopyPluginActionPluginActionSopClass = OHIF.redux.actions.addPlugin(
{
id: 'microscopy_sopClassHandler',
type: PLUGIN_TYPES.SOP_CLASS_HANDLER,
component: DicomMicroscopySopClassHandlerPlugin
}
);
store.dispatch(cornerstonePluginAction);
store.dispatch(pdfPluginAction);
store.dispatch(pdfPluginActionSopClass);
store.dispatch(microscopyPluginAction);
store.dispatch(microscopyPluginActionPluginActionSopClass);
// TODO[react] Use a provider when the whole tree is React
window.store = store;
@ -193,6 +209,10 @@ class App extends Component {
routerBasename: PropTypes.string
};
static defaultProps = {
whiteLabelling: {}
};
constructor(props) {
super(props);

View File

@ -7,7 +7,7 @@ import list from './HeaderMenuList.json';
import OHIFLogo from '../OHIFLogo/OHIFLogo.js';
//import Icons from "../../images/icons.svg";
const Icons = '/icons.svg';
//const Icons = '/icons.svg';
function Header({ home, location, children }) {
const { state } = location;
@ -19,21 +19,25 @@ function Header({ home, location, children }) {
return (
<div className={`entry-header ${home ? 'header-big' : ''}`}>
<div className="header-left-box">
{
state && state.studyLink &&
{state && state.studyLink && (
<Link to={state.studyLink} className="header-btn header-viewerLink">
Back to Viewer
</Link>
}
)}
{children}
{!home &&
<Link className='header-btn header-studyListLinkSection' to={{
pathname: "/",
state: { studyLink: location.pathname }
}}>Study list</Link>
}
{!home && (
<Link
className="header-btn header-studyListLinkSection"
to={{
pathname: '/',
state: { studyLink: location.pathname }
}}
>
Study list
</Link>
)}
</div>
<div className="header-menu">

View File

@ -8,9 +8,9 @@ import version from './version.js';
import { homepage } from '../package.json';
window.info = {
sha,
version,
homepage
sha,
version,
homepage
};
// For debugging
@ -25,7 +25,7 @@ OHIF.external.cornerstoneMath = cornerstoneMath;
OHIF.external.cornerstoneWADOImageLoader = cornerstoneWADOImageLoader;
// TODO: Is there a better way to guess ROOT_URL?
let ROOT_URL = homepage;
//let ROOT_URL = homepage;
// If the page we are on is not a subset of the expected homepage
// provided in the package.json file, we might be doing local development.
@ -53,21 +53,21 @@ cornerstoneWADOImageLoader.webWorkerManager.initialize(config);
*/
OHIF.user.getAccessToken = () => {
// TODO: Get the Redux store from somewhere else
const state = window.store.getState();
if (!state.oidc || !state.oidc.user) {
return;
}
// TODO: Get the Redux store from somewhere else
const state = window.store.getState();
if (!state.oidc || !state.oidc.user) {
return;
}
return state.oidc.user.access_token;
}
return state.oidc.user.access_token;
};
cornerstoneWADOImageLoader.configure({
beforeSend: function(xhr) {
const headers = OHIF.DICOMWeb.getAuthorizationHeader();
beforeSend: function(xhr) {
const headers = OHIF.DICOMWeb.getAuthorizationHeader();
if (headers.Authorization) {
xhr.setRequestHeader("Authorization", headers.Authorization);
}
if (headers.Authorization) {
xhr.setRequestHeader('Authorization', headers.Authorization);
}
}
});

View File

@ -0,0 +1,43 @@
import OHIF from 'ohif-core';
import { api } from 'dicomweb-client';
const { plugins, utils } = OHIF;
const { PLUGIN_TYPES } = plugins;
const SOP_CLASS_UIDS = {
VL_WHOLE_SLIDE_MICROSCOPY_IMAGE_STORAGE: '1.2.840.10008.5.1.4.1.1.77.1.6'
};
const dwc = api.DICOMwebClient;
const DicomMicrscopySopClassHandlerPlugin = {
id: 'DicomMicroscopySopClassHandlerPlugin',
type: PLUGIN_TYPES.SOP_CLASS_HANDLER,
sopClassUids: [SOP_CLASS_UIDS.VL_WHOLE_SLIDE_MICROSCOPY_IMAGE_STORAGE],
getDisplaySetFromSeries(series, study) {
const instance = series.getFirstInstance();
const headers = OHIF.DICOMWeb.getAuthorizationHeader();
console.warn(headers);
debugger;
const dicomWebClient = new dwc({
url: study.getData().wadoRoot,
headers
});
// Note: We are passing the dicomweb client into each viewport!
return {
plugin: 'microscopy',
displaySetInstanceUid: utils.guid(),
dicomWebClient,
sopInstanceUid: instance.getSOPInstanceUID(),
seriesInstanceUid: series.getSeriesInstanceUID(),
studyInstanceUid: study.getStudyInstanceUID()
};
}
};
export default DicomMicrscopySopClassHandlerPlugin;

View File

@ -0,0 +1,86 @@
import React, { Component } from 'react';
import { api } from 'dicom-microscopy-viewer';
const microscopyViewer = api.VLWholeSlideMicroscopyImageViewer;
class DicomMicroscopyViewport extends Component {
state = {
error: null
};
constructor(props) {
super(props);
this.container = React.createRef();
}
// install the microscopy renderer into the web page.
// you should only do this once.
installOpenLayersRenderer(container, displaySet) {
const dicomWebClient = displaySet.dicomWebClient;
const searchInstanceOptions = {
studyInstanceUID: displaySet.studyInstanceUid,
seriesInstanceUID: displaySet.seriesInstanceUid
};
dicomWebClient
.searchForInstances(searchInstanceOptions)
.then(instances => {
const promises = [];
for (let i = 0; i < instances.length; i++) {
const sopInstanceUID = instances[i]['00080018']['Value'][0];
const retrieveInstanceOptions = {
studyInstanceUID: displaySet.studyInstanceUid,
seriesInstanceUID: displaySet.seriesInstanceUid,
sopInstanceUID
};
const promise = dicomWebClient
.retrieveInstanceMetadata(retrieveInstanceOptions)
.then(metadata => {
const imageType = metadata[0]['00080008']['Value'];
if (imageType[2] === 'VOLUME') {
return metadata[0];
}
});
promises.push(promise);
}
return Promise.all(promises);
})
.then(metadata => {
console.warn(metadata);
metadata = metadata.filter(m => m);
const viewer = new microscopyViewer({
client: dicomWebClient,
metadata
});
debugger;
viewer.render({ container });
});
}
componentDidMount() {
const { studies, displaySet } = this.props.viewportData;
this.installOpenLayersRenderer(this.container.current, displaySet);
}
render() {
const style = { width: '100%', height: '100%' };
return (
<div className={'DicomMicroscopyViewer'} style={style}>
{this.state.error ? (
<h2>{JSON.stringify(this.state.error)}</h2>
) : (
<div ref={this.container} />
)}
</div>
);
}
}
export default DicomMicroscopyViewport;

View File

@ -1,8 +1,6 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import cornerstone from 'cornerstone-core';
import cornerstoneTools from 'cornerstone-tools';
import OHIF from 'ohif-core';
//import OHIF from 'ohif-core';
//import { CineDialog } from 'react-viewerbase';
import WhiteLabellingContext from '../WhiteLabellingContext.js';

View File

@ -2,7 +2,6 @@
* Entry point index.js for development
*/
import App from './App.js';
import React from 'react';
import ReactDOM from 'react-dom';
@ -21,7 +20,7 @@ Example config with OIDC
// Try going to:
// http://localhost:5000/viewer/1.3.6.1.4.1.25403.345050719074.3824.20170126082328.1
// http://ohif-viewer-react.s3-website-us-east-1.amazonaws.com/viewer/1.3.6.1.4.1.25403.345050719074.3824.20170126082328.1
props.servers = {
/*props.servers = {
"dicomWeb": [{
"name": "DCM4CHEE",
"wadoUriRoot": "https://cancer.crowds-cure.org/dcm4chee-arc/aets/DCM4CHEE/wado",
@ -49,7 +48,37 @@ props.oidc = [{
"kc_idp_hint": "crowds-cure-cancer-auth0-oidc",
"client_id": "crowds-cure-cancer"
}
}];
}];*/
props.servers = {
dicomWeb: [
{
name: 'DCM4CHEE',
wadoUriRoot:
'https://k8s-testing.ohif.org/dcm4chee-arc/aets/DCM4CHEE/wado',
qidoRoot: 'https://k8s-testing.ohif.org/dcm4chee-arc/aets/DCM4CHEE/rs',
wadoRoot: 'https://k8s-testing.ohif.org/dcm4chee-arc/aets/DCM4CHEE/rs',
qidoSupportsIncludeField: true,
imageRendering: 'wadors',
thumbnailRendering: 'wadors',
requestOptions: {
requestFromBrowser: true
}
}
]
};
props.oidc = [
{
authServerUrl: 'https://k8s-testing.ohif.org/auth/realms/dcm4che',
authRedirectUri: routerBasename + '/callback',
postLogoutRedirectUri: routerBasename + '/logout-redirect.html',
clientId: 'ohif-viewer',
responseType: 'id_token token',
scope: 'email profile openid',
revokeAccessTokenOnSignout: true
}
];
/* Example config without OIDC */
// Try going to:
@ -115,12 +144,10 @@ function RadicalImagingLogo() {
);
}
props.whiteLabelling = {
/*props.whiteLabelling = {
logoComponent: RadicalImagingLogo()
};
};*/
// TODO: Why do we need to do this? Something is wrong with our rollup settings
//var Viewer = window.OHIFStandaloneViewer.App;
var app = React.createElement(App, props, null);
ReactDOM.render(app, document.getElementById('root'));

View File

@ -1 +1 @@
export default '1242155351531';
export default '84c949f2e68036ef488e09e05aed890a47e1a161';

View File

@ -1 +1 @@
export default '0.0.0';
export default '0.0.6';

File diff suppressed because it is too large Load Diff

@ -0,0 +1 @@
Subproject commit 2405290b1e5e80d13bae5358625463605eb83930

@ -1 +1 @@
Subproject commit 3af04fe6f45b5582d1d672696736d1668c9ea985
Subproject commit 1a66caa34d5a841ef414437a53093f7d22be840c