Add DicomMicroscopy plugin
This commit is contained in:
parent
84c949f2e6
commit
03c7274812
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -10,3 +10,6 @@
|
|||||||
[submodule "Packages-react/plugins/VTKPlugin"]
|
[submodule "Packages-react/plugins/VTKPlugin"]
|
||||||
path = Packages-react/plugins/VTKPlugin
|
path = Packages-react/plugins/VTKPlugin
|
||||||
url = git@github.com:OHIF/VTKPlugin.git
|
url = git@github.com:OHIF/VTKPlugin.git
|
||||||
|
[submodule "Packages-react/plugins/OpenLayersPlugin"]
|
||||||
|
path = Packages-react/plugins/OpenLayersPlugin
|
||||||
|
url = git@github.com:OHIF/OpenLayersPlugin.git
|
||||||
|
|||||||
@ -97,16 +97,20 @@
|
|||||||
"cornerstone-math": "^0.1.8",
|
"cornerstone-math": "^0.1.8",
|
||||||
"cornerstone-tools": "3.0.0-b.1512",
|
"cornerstone-tools": "3.0.0-b.1512",
|
||||||
"cornerstone-wado-image-loader": "^2.2.3",
|
"cornerstone-wado-image-loader": "^2.2.3",
|
||||||
|
"dicom-microscopy-viewer": "^0.2.0",
|
||||||
"dicom-parser": "^1.8.3",
|
"dicom-parser": "^1.8.3",
|
||||||
|
"dicomweb-client": "^0.4.1",
|
||||||
"hammerjs": "^2.0.8",
|
"hammerjs": "^2.0.8",
|
||||||
"lodash.isequal": "^4.5.0",
|
"lodash.isequal": "^4.5.0",
|
||||||
"ohif-core": "^0.1.7",
|
"ohif-core": "^0.1.7",
|
||||||
"oidc-client": "^1.6.1",
|
"oidc-client": "^1.6.1",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
|
"react": "^16.7.0",
|
||||||
"react-bootstrap-modal": "^4.2.0",
|
"react-bootstrap-modal": "^4.2.0",
|
||||||
"react-cornerstone-viewport": "^0.1.8",
|
"react-cornerstone-viewport": "^0.1.8",
|
||||||
"react-dnd": "^7.0.2",
|
"react-dnd": "^7.0.2",
|
||||||
"react-dnd-html5-backend": "^7.0.2",
|
"react-dnd-html5-backend": "^7.0.2",
|
||||||
|
"react-dom": "^16.7.0",
|
||||||
"react-redux": "^6.0.0",
|
"react-redux": "^6.0.0",
|
||||||
"react-router": "^4.3.1",
|
"react-router": "^4.3.1",
|
||||||
"react-router-dom": "^4.3.1",
|
"react-router-dom": "^4.3.1",
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
import { BrowserRouter } from 'react-router-dom';
|
import { BrowserRouter } from 'react-router-dom';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { createStore, combineReducers } from 'redux';
|
import { createStore, combineReducers } from 'redux';
|
||||||
@ -12,6 +11,8 @@ import OHIFCornerstoneViewportPlugin from './connectedComponents/OHIFCornerstone
|
|||||||
import WhiteLabellingContext from './WhiteLabellingContext';
|
import WhiteLabellingContext from './WhiteLabellingContext';
|
||||||
import OHIFDicomPDFViewportPlugin from './connectedComponents/OHIFDicomPDFViewportPlugin/OHIFDicomPDFViewportPlugin.js';
|
import OHIFDicomPDFViewportPlugin from './connectedComponents/OHIFDicomPDFViewportPlugin/OHIFDicomPDFViewportPlugin.js';
|
||||||
import OHIFDicomPDFSopClassHandlerPlugin from './connectedComponents/OHIFDicomPDFViewportPlugin/OHIFDicomPDFSopClassHandlerPlugin.js';
|
import OHIFDicomPDFSopClassHandlerPlugin from './connectedComponents/OHIFDicomPDFViewportPlugin/OHIFDicomPDFSopClassHandlerPlugin.js';
|
||||||
|
import DicomMicroscopySopClassHandlerPlugin from './connectedComponents/DicomMicroscopyPlugin/DicomMicroscopySopClassHandlerPlugin.js';
|
||||||
|
import DicomMicroscopyViewport from './connectedComponents/DicomMicroscopyPlugin/DicomMicroscopyViewport.js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
loadUser,
|
loadUser,
|
||||||
@ -103,7 +104,6 @@ const buttonsAction = OHIF.redux.actions.setAvailableButtons(defaultButtons);
|
|||||||
|
|
||||||
store.dispatch(buttonsAction);
|
store.dispatch(buttonsAction);
|
||||||
|
|
||||||
|
|
||||||
const { plugins } = OHIF;
|
const { plugins } = OHIF;
|
||||||
const { PLUGIN_TYPES } = plugins;
|
const { PLUGIN_TYPES } = plugins;
|
||||||
|
|
||||||
@ -125,9 +125,25 @@ const pdfPluginActionSopClass = OHIF.redux.actions.addPlugin({
|
|||||||
component: OHIFDicomPDFSopClassHandlerPlugin
|
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(cornerstonePluginAction);
|
||||||
store.dispatch(pdfPluginAction);
|
store.dispatch(pdfPluginAction);
|
||||||
store.dispatch(pdfPluginActionSopClass);
|
store.dispatch(pdfPluginActionSopClass);
|
||||||
|
store.dispatch(microscopyPluginAction);
|
||||||
|
store.dispatch(microscopyPluginActionPluginActionSopClass);
|
||||||
|
|
||||||
// TODO[react] Use a provider when the whole tree is React
|
// TODO[react] Use a provider when the whole tree is React
|
||||||
window.store = store;
|
window.store = store;
|
||||||
@ -193,6 +209,10 @@ class App extends Component {
|
|||||||
routerBasename: PropTypes.string
|
routerBasename: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
whiteLabelling: {}
|
||||||
|
};
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import list from './HeaderMenuList.json';
|
|||||||
import OHIFLogo from '../OHIFLogo/OHIFLogo.js';
|
import OHIFLogo from '../OHIFLogo/OHIFLogo.js';
|
||||||
//import Icons from "../../images/icons.svg";
|
//import Icons from "../../images/icons.svg";
|
||||||
|
|
||||||
const Icons = '/icons.svg';
|
//const Icons = '/icons.svg';
|
||||||
|
|
||||||
function Header({ home, location, children }) {
|
function Header({ home, location, children }) {
|
||||||
const { state } = location;
|
const { state } = location;
|
||||||
@ -19,21 +19,25 @@ function Header({ home, location, children }) {
|
|||||||
return (
|
return (
|
||||||
<div className={`entry-header ${home ? 'header-big' : ''}`}>
|
<div className={`entry-header ${home ? 'header-big' : ''}`}>
|
||||||
<div className="header-left-box">
|
<div className="header-left-box">
|
||||||
{
|
{state && state.studyLink && (
|
||||||
state && state.studyLink &&
|
|
||||||
<Link to={state.studyLink} className="header-btn header-viewerLink">
|
<Link to={state.studyLink} className="header-btn header-viewerLink">
|
||||||
Back to Viewer
|
Back to Viewer
|
||||||
</Link>
|
</Link>
|
||||||
}
|
)}
|
||||||
|
|
||||||
{children}
|
{children}
|
||||||
|
|
||||||
{!home &&
|
{!home && (
|
||||||
<Link className='header-btn header-studyListLinkSection' to={{
|
<Link
|
||||||
pathname: "/",
|
className="header-btn header-studyListLinkSection"
|
||||||
state: { studyLink: location.pathname }
|
to={{
|
||||||
}}>Study list</Link>
|
pathname: '/',
|
||||||
}
|
state: { studyLink: location.pathname }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Study list
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="header-menu">
|
<div className="header-menu">
|
||||||
|
|||||||
@ -8,9 +8,9 @@ import version from './version.js';
|
|||||||
import { homepage } from '../package.json';
|
import { homepage } from '../package.json';
|
||||||
|
|
||||||
window.info = {
|
window.info = {
|
||||||
sha,
|
sha,
|
||||||
version,
|
version,
|
||||||
homepage
|
homepage
|
||||||
};
|
};
|
||||||
|
|
||||||
// For debugging
|
// For debugging
|
||||||
@ -25,7 +25,7 @@ OHIF.external.cornerstoneMath = cornerstoneMath;
|
|||||||
OHIF.external.cornerstoneWADOImageLoader = cornerstoneWADOImageLoader;
|
OHIF.external.cornerstoneWADOImageLoader = cornerstoneWADOImageLoader;
|
||||||
|
|
||||||
// TODO: Is there a better way to guess ROOT_URL?
|
// 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
|
// 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.
|
// provided in the package.json file, we might be doing local development.
|
||||||
@ -53,21 +53,21 @@ cornerstoneWADOImageLoader.webWorkerManager.initialize(config);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
OHIF.user.getAccessToken = () => {
|
OHIF.user.getAccessToken = () => {
|
||||||
// TODO: Get the Redux store from somewhere else
|
// TODO: Get the Redux store from somewhere else
|
||||||
const state = window.store.getState();
|
const state = window.store.getState();
|
||||||
if (!state.oidc || !state.oidc.user) {
|
if (!state.oidc || !state.oidc.user) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.oidc.user.access_token;
|
return state.oidc.user.access_token;
|
||||||
}
|
};
|
||||||
|
|
||||||
cornerstoneWADOImageLoader.configure({
|
cornerstoneWADOImageLoader.configure({
|
||||||
beforeSend: function(xhr) {
|
beforeSend: function(xhr) {
|
||||||
const headers = OHIF.DICOMWeb.getAuthorizationHeader();
|
const headers = OHIF.DICOMWeb.getAuthorizationHeader();
|
||||||
|
|
||||||
if (headers.Authorization) {
|
if (headers.Authorization) {
|
||||||
xhr.setRequestHeader("Authorization", headers.Authorization);
|
xhr.setRequestHeader('Authorization', headers.Authorization);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -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;
|
||||||
@ -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;
|
||||||
@ -1,8 +1,6 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import cornerstone from 'cornerstone-core';
|
//import OHIF from 'ohif-core';
|
||||||
import cornerstoneTools from 'cornerstone-tools';
|
|
||||||
import OHIF from 'ohif-core';
|
|
||||||
//import { CineDialog } from 'react-viewerbase';
|
//import { CineDialog } from 'react-viewerbase';
|
||||||
|
|
||||||
import WhiteLabellingContext from '../WhiteLabellingContext.js';
|
import WhiteLabellingContext from '../WhiteLabellingContext.js';
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
* Entry point index.js for development
|
* Entry point index.js for development
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import App from './App.js';
|
import App from './App.js';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
@ -21,7 +20,7 @@ Example config with OIDC
|
|||||||
// Try going to:
|
// Try going to:
|
||||||
// http://localhost:5000/viewer/1.3.6.1.4.1.25403.345050719074.3824.20170126082328.1
|
// 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
|
// 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": [{
|
"dicomWeb": [{
|
||||||
"name": "DCM4CHEE",
|
"name": "DCM4CHEE",
|
||||||
"wadoUriRoot": "https://cancer.crowds-cure.org/dcm4chee-arc/aets/DCM4CHEE/wado",
|
"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",
|
"kc_idp_hint": "crowds-cure-cancer-auth0-oidc",
|
||||||
"client_id": "crowds-cure-cancer"
|
"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 */
|
/* Example config without OIDC */
|
||||||
// Try going to:
|
// Try going to:
|
||||||
@ -115,12 +144,10 @@ function RadicalImagingLogo() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
props.whiteLabelling = {
|
/*props.whiteLabelling = {
|
||||||
logoComponent: RadicalImagingLogo()
|
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);
|
var app = React.createElement(App, props, null);
|
||||||
|
|
||||||
ReactDOM.render(app, document.getElementById('root'));
|
ReactDOM.render(app, document.getElementById('root'));
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export default '1242155351531';
|
export default '84c949f2e68036ef488e09e05aed890a47e1a161';
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export default '0.0.0';
|
export default '0.0.6';
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
1
Packages-react/plugins/OpenLayersPlugin
Submodule
1
Packages-react/plugins/OpenLayersPlugin
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 2405290b1e5e80d13bae5358625463605eb83930
|
||||||
@ -1 +1 @@
|
|||||||
Subproject commit 3af04fe6f45b5582d1d672696736d1668c9ea985
|
Subproject commit 1a66caa34d5a841ef414437a53093f7d22be840c
|
||||||
Loading…
Reference in New Issue
Block a user