Skip to content

Commit 4cff356

Browse files
authored
fix(dicomweb-client):Make the retrieveBulkData handle either single or multipart responses. (#48)
* feat(dcmjs):Support singlepart responses * Docs update
1 parent eb43b1b commit 4cff356

File tree

3 files changed

+42
-41
lines changed

3 files changed

+42
-41
lines changed

README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,15 @@ client.searchForStudies().then(studies => {
4949
});
5050
```
5151

52-
An optional, custom `XMLHttpRequest` can be passed to `storeInstances` as a property of the `options` parameter. When present, instead of creating a new `XMLHttpRequest` instance, the passed instance is used instead. One use of this would be to track the progress of a DICOM store and/or cancel it.
53-
54-
See the js snippet below for an example of where the upload's percentage progress is output to the console.
52+
## Configuration Options
53+
The API can be configured with a number of custom configuration options to control the requests. These are:
54+
* url to retrieve from for the base requests
55+
* singlepart, either true or a set of parts from `bulkdata,image,video` to request as single part responses
56+
* headers to add to the retrieve
57+
* `XMLHttpRequest` can be passed to `storeInstances` as a property of the `options` parameter. When present, instead of creating a new `XMLHttpRequest` instance, the passed instance is used instead. One use of this would be to track the progress of a DICOM store and/or cancel it.
58+
59+
An example use of `XMLHttpRequest` being passed into the store is shown in the js snippet below
60+
as an example of where the upload's percentage progress is output to the console.
5561

5662
```js
5763
const url = 'http://localhost:8080/dicomweb';

src/api.js

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ class DICOMwebClient {
6666
* @param {Object=} options.headers - HTTP headers
6767
* @param {Array.<RequestHook>=} options.requestHooks - Request hooks.
6868
* @param {Object=} options.verbose - print to console request warnings and errors, default true
69+
* @param {boolean|String} options.singlepart - retrieve singlepart for the named types.
70+
* The available types are: bulkdata, video, image. true means all.
6971
*/
7072
constructor(options) {
7173
this.baseURL = options.url;
@@ -104,6 +106,13 @@ class DICOMwebClient {
104106
this.stowURL = this.baseURL;
105107
}
106108

109+
if (options.singlepart) {
110+
console.log('use singlepart', options.singlepart);
111+
this.singlepart = options.singlepart === true ? 'bulkdata,video,image' : options.singlepart;
112+
} else {
113+
this.singlepart = '';
114+
}
115+
107116
if ('requestHooks' in options) {
108117
this.requestHooks = options.requestHooks;
109118
}
@@ -197,7 +206,16 @@ class DICOMwebClient {
197206
request.onreadystatechange = () => {
198207
if (request.readyState === 4) {
199208
if (request.status === 200) {
200-
resolve(request.response);
209+
const contentType = request.getResponseHeader('Content-Type');
210+
// Automatically distinguishes between multipart and singlepart in an array buffer, and
211+
// converts them into a consistent type.
212+
if (contentType && contentType.indexOf('multipart') !== -1) {
213+
resolve(multipartDecode(request.response));
214+
} else if (request.responseType === 'arraybuffer') {
215+
resolve([request.response]);
216+
} else {
217+
resolve(request.response);
218+
}
201219
} else if (request.status === 202) {
202220
if (this.verbose) {
203221
console.warn('some resources already existed: ', request);
@@ -564,13 +582,7 @@ class DICOMwebClient {
564582
supportedMediaTypes,
565583
);
566584

567-
return this._httpGet(
568-
url,
569-
headers,
570-
'arraybuffer',
571-
progressCallback,
572-
withCredentials,
573-
).then(multipartDecode);
585+
return this._httpGet(url, headers, 'arraybuffer', progressCallback, withCredentials);
574586
}
575587

576588
/**
@@ -626,13 +638,7 @@ class DICOMwebClient {
626638
supportedMediaTypes,
627639
);
628640

629-
return this._httpGet(
630-
url,
631-
headers,
632-
'arraybuffer',
633-
progressCallback,
634-
withCredentials,
635-
).then(multipartDecode);
641+
return this._httpGet(url, headers, 'arraybuffer', progressCallback, withCredentials);
636642
}
637643

638644
/**
@@ -688,13 +694,7 @@ class DICOMwebClient {
688694
supportedMediaTypes,
689695
);
690696

691-
return this._httpGet(
692-
url,
693-
headers,
694-
'arraybuffer',
695-
progressCallback,
696-
withCredentials,
697-
).then(multipartDecode);
697+
return this._httpGet(url, headers, 'arraybuffer', progressCallback, withCredentials);
698698
}
699699

700700
/**
@@ -738,13 +738,7 @@ class DICOMwebClient {
738738
supportedMediaTypes,
739739
);
740740

741-
return this._httpGet(
742-
url,
743-
headers,
744-
'arraybuffer',
745-
progressCallback,
746-
withCredentials,
747-
).then(multipartDecode);
741+
return this._httpGet(url, headers, 'arraybuffer', progressCallback, withCredentials);
748742
}
749743

750744
/**
@@ -1301,13 +1295,7 @@ class DICOMwebClient {
13011295
supportedMediaTypes,
13021296
),
13031297
};
1304-
return this._httpGet(
1305-
url,
1306-
headers,
1307-
'arraybuffer',
1308-
progressCallback,
1309-
withCredentials,
1310-
).then(multipartDecode);
1298+
return this._httpGet(url, headers, 'arraybuffer', progressCallback, withCredentials);
13111299
}
13121300

13131301
const commonMediaType = DICOMwebClient._getCommonMediaType(mediaTypes);
@@ -1868,7 +1856,9 @@ class DICOMwebClient {
18681856
* See http://dicom.nema.org/medical/dicom/current/output/chtml/part18/sect_6.5.5.html
18691857
*
18701858
* @param {Object} options
1871-
* @param {String} BulkDataURI - URI for retrieval of bulkdata
1859+
* @param {string} options.BulkDataURI to retrieve
1860+
* @param {Array} options.mediaTypes to use to fetch the URI
1861+
* @param {string} options.byteRange to request a sub-range (only valid on single part)
18721862
* @returns {Promise<Array>} Bulkdata parts
18731863
*/
18741864
retrieveBulkData(options) {
@@ -1881,6 +1871,10 @@ class DICOMwebClient {
18811871
const { withCredentials = false } = options;
18821872
const { progressCallback = false } = options;
18831873

1874+
if (this.singlepart.indexOf('bulkdata') !== -1) {
1875+
return this._httpGet(url, options.headers, 'arraybuffer', null, withCredentials);
1876+
}
1877+
18841878
if (!mediaTypes) {
18851879
return this._httpGetMultipartApplicationOctetStream(
18861880
url,

src/message.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,8 @@ function multipartEncode(
184184
* @returns {Array} The content
185185
*/
186186
function multipartDecode(response) {
187-
const message = new Uint8Array(response);
187+
// Use the raw data if it is provided in an appropriate format
188+
const message = ArrayBuffer.isView(response) ? response : new Uint8Array(response);
188189

189190
/* Set a maximum length to search for the header boundaries, otherwise
190191
findToken can run for a long time

0 commit comments

Comments
 (0)