Skip to content

Commit e7e1a8a

Browse files
ladeirarodolfoswederik
authored andcommitted
fix: 🐛 Add DicomLoaderService & FileLoaderService to fix SR, PDF, and SEG support in local file and WADO-RS-only use cases (#862)
* fix: 🐛 Local file: failing when retrieving segmentation data Fix segmentation data retrieval issues for local file. Changed from fecthing to use cornerstone loadAndCache method BREAKING CHANGE: DICOM Seg Closes: part of #838 * Switch SEG retrieval to WADO-RS * Forgot a debugger * refactor: 💡 Code refactor. Minor changes into methods * fix: 🐛 Load local files: PDF Items: 1. FileLoaderService: used for serveral operations on local files(load it, get list of studies, group them, accepting dicom and pdf) 2. DicomLoaderService: used for loading dicom based on dataset and studies. Depending on type of dicom loader might change. WIP 3. Refactor PDF and handleSegmentationStorage to use DicomLoaderService * fix: 🐛 Code review * fix: 🐛 Code review. Changed:Folder organization and dicom file Move fileLoaderService and others to a specific folder. When loading dicom file change to only retrieve the file(not use cornerstone to cache or anything else). * fix: 🐛 Code review. Move dicomLoaderService to core Moved dicomLoaderService to ohif/core and localFileLoaders to a specific folder. * fix: 🐛 Code review Simplified method to get study for dicom file. Added error handling on file loading. DicomLoaderService to be exposed on ohif/core/utils instead. * fix: 🐛 Reduce local load to one method only Reduced local file load to one method only * fix: 🐛 HTML to use dicomLoaderService. Prefer wadors than (uri) * fix: 🐛 Code implementation for multiframe files * fix: 🐛 Code review. Default local loader to dicom Closes: 838 * fix: 🐛 Code review. Use relative path to require DICOMWeb Closes: 838 * fix: 🐛 Code review. Fix unit test. Added DicomLoaderService mod Closes: 838 * fix: 🐛 Code review. Add 'Seg' on left thumb When getting/creating dataset get modality for file/image read Closes: 838
1 parent e66c27a commit e7e1a8a

16 files changed

Lines changed: 631 additions & 274 deletions

File tree

extensions/cornerstone/src/handleSegmentationStorage.js

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import OHIF from '@ohif/core';
44
import cornerstone from 'cornerstone-core';
55
import cornerstoneTools from 'cornerstone-tools';
66

7-
const { StackManager } = OHIF.utils;
7+
const { StackManager, DicomLoaderService } = OHIF.utils;
88

99
function getDisplaySet(studies, studyInstanceUid, displaySetInstanceUid) {
1010
const study = studies.find(
@@ -52,14 +52,6 @@ function addSegMetadataToCornerstoneToolState(
5252
}
5353
}
5454

55-
function retrieveDicomData(wadoUri) {
56-
// TODO: Authorization header depends on the server. If we ever have multiple servers
57-
// we will need to figure out how / when to pass this information in.
58-
return fetch(wadoUri, {
59-
headers: OHIF.DICOMWeb.getAuthorizationHeader(),
60-
}).then(response => response.arrayBuffer());
61-
}
62-
6355
async function handleSegmentationStorage(
6456
studies,
6557
studyInstanceUid,
@@ -73,8 +65,11 @@ async function handleSegmentationStorage(
7365
studyInstanceUid,
7466
displaySetInstanceUid
7567
);
76-
const segWadoUri = displaySet.images[0].getData().wadouri;
77-
const arrayBuffer = await retrieveDicomData(segWadoUri);
68+
69+
const arrayBuffer = await DicomLoaderService.findDicomDataPromise(
70+
displaySet,
71+
studies
72+
);
7873
const dicomData = dcmjs.data.DicomMessage.readFile(arrayBuffer);
7974
const dataset = dcmjs.data.DicomMetaDictionary.naturalizeDataset(
8075
dicomData.dict

extensions/dicom-html/src/OHIFDicomHtmlViewport.js

Lines changed: 10 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,41 @@
11
import React, { Component } from 'react';
22
import PropTypes from 'prop-types';
33
import DicomHtmlViewport from './DicomHtmlViewport';
4+
import OHIF from '@ohif/core';
5+
const { DicomLoaderService } = OHIF.utils;
46

57
class OHIFDicomHtmlViewport extends Component {
68
static propTypes = {
79
studies: PropTypes.object,
810
displaySet: PropTypes.object,
9-
viewportIndex: PropTypes.number
11+
viewportIndex: PropTypes.number,
1012
};
1113

1214
state = {
1315
byteArray: null,
14-
error: null
16+
error: null,
1517
};
1618

1719
componentDidMount() {
18-
const { displaySet } = this.props.viewportData;
19-
const {
20-
studyInstanceUid,
21-
seriesInstanceUid,
22-
sopInstanceUid,
23-
wadoRoot,
24-
wadoUri,
25-
authorizationHeaders
26-
} = displaySet;
20+
const { displaySet, studies } = this.props.viewportData;
2721

28-
this.retrieveDicomData(
29-
studyInstanceUid,
30-
seriesInstanceUid,
31-
sopInstanceUid,
32-
wadoRoot,
33-
wadoUri,
34-
authorizationHeaders
35-
).then(
36-
byteArray => {
22+
DicomLoaderService.findDicomDataPromise(displaySet, studies).then(
23+
data => {
24+
const byteArray = new Uint8Array(data);
3725
this.setState({
38-
byteArray
26+
byteArray: byteArray,
3927
});
4028
},
4129
error => {
4230
this.setState({
43-
error
31+
error,
4432
});
4533

4634
throw new Error(error);
4735
}
4836
);
4937
}
5038

51-
retrieveDicomData(
52-
studyInstanceUid,
53-
seriesInstanceUid,
54-
sopInstanceUid,
55-
wadoRoot,
56-
wadoUri,
57-
authorizationHeaders
58-
) {
59-
// TODO: Passing in a lot of data we aren't using
60-
61-
// TODO: Authorization header depends on the server. If we ever have multiple servers
62-
// we will need to figure out how / when to pass this information in.
63-
return fetch(wadoUri, {
64-
headers: authorizationHeaders
65-
})
66-
.then(response => response.arrayBuffer())
67-
.then(arraybuffer => {
68-
return new Uint8Array(arraybuffer);
69-
});
70-
}
71-
7239
render() {
7340
return (
7441
<>

extensions/dicom-pdf/src/DicomPDFViewport.js

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,46 @@ import TypedArrayProp from './TypedArrayProp';
44

55
// TODO: Should probably use dcmjs for this
66
const SOP_CLASS_UIDS = {
7-
ENCAPSULATED_PDF: '1.2.840.10008.5.1.4.1.1.104.1'
7+
ENCAPSULATED_PDF: '1.2.840.10008.5.1.4.1.1.104.1',
88
};
99

1010
class DicomPDFViewport extends Component {
1111
state = {
1212
fileURL: null,
13-
error: null
13+
error: null,
1414
};
1515

1616
static propTypes = {
17-
byteArray: TypedArrayProp.uint8
17+
byteArray: TypedArrayProp.uint8,
1818
};
1919

20-
renderPDF = dataSet => {
21-
const sopClassUid = dataSet.string('x00080016');
20+
renderPDF = (dataSet, byteArray) => {
21+
let pdfByteArray = byteArray;
2222

23-
if (sopClassUid !== SOP_CLASS_UIDS.ENCAPSULATED_PDF) {
24-
throw new Error('This is not a DICOM-encapsulated PDF');
23+
if (dataSet) {
24+
const sopClassUid = dataSet.string('x00080016');
25+
26+
if (sopClassUid !== SOP_CLASS_UIDS.ENCAPSULATED_PDF) {
27+
throw new Error('This is not a DICOM-encapsulated PDF');
28+
}
29+
30+
const fileTag = dataSet.elements.x00420011;
31+
const offset = fileTag.dataOffset;
32+
const remainder = offset + fileTag.length;
33+
pdfByteArray = dataSet.byteArray.slice(offset, remainder);
2534
}
2635

27-
const fileTag = dataSet.elements.x00420011;
28-
const offset = fileTag.dataOffset;
29-
const remainder = offset + fileTag.length;
30-
const pdfByteArray = dataSet.byteArray.slice(offset, remainder);
3136
const PDF = new Blob([pdfByteArray], { type: 'application/pdf' });
3237
const fileURL = URL.createObjectURL(PDF);
3338

3439
this.setState({
35-
fileURL
40+
fileURL,
3641
});
3742
};
3843

3944
parseByteArray = byteArray => {
4045
const options = {
41-
untilTag: ''
46+
untilTag: '',
4247
};
4348

4449
let dataSet;
@@ -47,7 +52,7 @@ class DicomPDFViewport extends Component {
4752
dataSet = dicomParser.parseDicom(byteArray, options);
4853
} catch (error) {
4954
this.setState({
50-
error
55+
error,
5156
});
5257
}
5358

@@ -57,7 +62,7 @@ class DicomPDFViewport extends Component {
5762
componentDidMount() {
5863
const dataSet = this.parseByteArray(this.props.byteArray);
5964

60-
this.renderPDF(dataSet);
65+
this.renderPDF(dataSet, this.props.byteArray);
6166
}
6267

6368
render() {

extensions/dicom-pdf/src/OHIFDicomPDFViewport.js

Lines changed: 18 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,61 @@
1-
import React, { Component } from "react";
2-
import PropTypes from "prop-types";
3-
import OHIF from "@ohif/core";
4-
import OHIFComponentPlugin from "./OHIFComponentPlugin.js";
5-
import DicomPDFViewport from "./DicomPDFViewport";
1+
import React, { Component } from 'react';
2+
import PropTypes from 'prop-types';
3+
import OHIF from '@ohif/core';
4+
import OHIFComponentPlugin from './OHIFComponentPlugin.js';
5+
import DicomPDFViewport from './DicomPDFViewport';
66

7-
const { DICOMWeb } = OHIF;
7+
const { DicomLoaderService } = OHIF.utils;
88

99
class OHIFDicomPDFViewport extends Component {
1010
static propTypes = {
1111
studies: PropTypes.object,
1212
displaySet: PropTypes.object,
13-
viewportIndex: PropTypes.number
13+
viewportIndex: PropTypes.number,
1414
};
1515

1616
state = {
1717
byteArray: null,
18-
error: null
18+
error: null,
1919
};
2020

21-
static id = "DicomPDFViewportPDF";
21+
static id = 'DicomPDFViewportPDF';
2222

2323
static init() {
24-
console.log("DicomPDFViewport init()");
24+
console.log('DicomPDFViewport init()');
2525
}
2626

2727
static destroy() {
28-
console.log("DicomPDFViewport destroy()");
28+
console.log('DicomPDFViewport destroy()');
2929
}
3030

3131
componentDidMount() {
32-
const { displaySet } = this.props.viewportData;
32+
const { displaySet, studies } = this.props.viewportData;
3333
const {
3434
studyInstanceUid,
3535
seriesInstanceUid,
3636
sopInstanceUid,
3737
wadoRoot,
3838
wadoUri,
39-
authorizationHeaders
39+
authorizationHeaders,
4040
} = displaySet;
4141

42-
this.retrieveDicomData(
43-
studyInstanceUid,
44-
seriesInstanceUid,
45-
sopInstanceUid,
46-
wadoRoot,
47-
wadoUri,
48-
authorizationHeaders
49-
).then(
50-
byteArray => {
42+
DicomLoaderService.findDicomDataPromise(displaySet, studies).then(
43+
data => {
44+
const byteArray = new Uint8Array(data);
5145
this.setState({
52-
byteArray
46+
byteArray: byteArray,
5347
});
5448
},
5549
error => {
5650
this.setState({
57-
error
51+
error,
5852
});
5953

6054
throw new Error(error);
6155
}
6256
);
6357
}
6458

65-
retrieveDicomData(
66-
studyInstanceUid,
67-
seriesInstanceUid,
68-
sopInstanceUid,
69-
wadoRoot,
70-
wadoUri,
71-
authorizationHeaders
72-
) {
73-
// TODO: Passing in a lot of data we aren't using
74-
75-
// TODO: Authorization header depends on the server. If we ever have multiple servers
76-
// we will need to figure out how / when to pass this information in.
77-
return fetch(wadoUri, {
78-
headers: authorizationHeaders
79-
})
80-
.then(response => response.arrayBuffer())
81-
.then(arraybuffer => {
82-
return new Uint8Array(arraybuffer);
83-
});
84-
}
85-
8659
render() {
8760
const { id, init, destroy } = OHIFDicomPDFViewport;
8861
const pluginProps = { id, init, destroy };

platform/core/src/classes/metadata/StudyMetadata.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ export class StudyMetadata extends Metadata {
129129
);
130130

131131
if (displaySet) {
132+
displaySet.sopClassModule = true;
132133
displaySets.push(displaySet);
133134

134135
return;
@@ -214,7 +215,7 @@ export class StudyMetadata extends Metadata {
214215
* @returns {boolean} True on success, false on failure.
215216
*/
216217
addDisplaySet(displaySet) {
217-
if (displaySet instanceof ImageSet) {
218+
if (displaySet instanceof ImageSet || displaySet.sopClassModule) {
218219
this._displaySets.push(displaySet);
219220
return true;
220221
}

platform/core/src/studies/services/wado/retrieveMetadata.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@ async function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
402402
baseWadoRsUri: baseWadoRsUri,
403403
wadouri: WADOProxy.convertURL(wadouri, server),
404404
wadorsuri: WADOProxy.convertURL(wadorsuri, server),
405+
wadoRoot: server.wadoRoot,
405406
imageRendering: server.imageRendering,
406407
thumbnailRendering: server.thumbnailRendering,
407408
};

0 commit comments

Comments
 (0)