chore(dicomweb-client): Switch to dicomweb-client.js to push logic out of OHIF
This commit is contained in:
parent
45c5867663
commit
89d97a7a3a
@ -92,7 +92,6 @@ ohif:core@0.0.1
|
|||||||
ohif:cornerstone@0.0.1
|
ohif:cornerstone@0.0.1
|
||||||
ohif:cornerstone-settings@0.0.1
|
ohif:cornerstone-settings@0.0.1
|
||||||
ohif:design@0.0.1
|
ohif:design@0.0.1
|
||||||
ohif:dicomweb-client@0.0.1
|
|
||||||
ohif:hanging-protocols@0.0.1
|
ohif:hanging-protocols@0.0.1
|
||||||
ohif:header@0.0.1
|
ohif:header@0.0.1
|
||||||
ohif:hotkeys@0.0.1
|
ohif:hotkeys@0.0.1
|
||||||
|
|||||||
@ -37,7 +37,6 @@ ohif:cornerstone
|
|||||||
ohif:cornerstone-settings
|
ohif:cornerstone-settings
|
||||||
ohif:viewerbase
|
ohif:viewerbase
|
||||||
ohif:study-list
|
ohif:study-list
|
||||||
ohif:dicomweb-client
|
|
||||||
ohif:hanging-protocols
|
ohif:hanging-protocols
|
||||||
ohif:metadata
|
ohif:metadata
|
||||||
ohif:user-oidc
|
ohif:user-oidc
|
||||||
|
|||||||
@ -82,7 +82,6 @@ ohif:core@0.0.1
|
|||||||
ohif:cornerstone@0.0.1
|
ohif:cornerstone@0.0.1
|
||||||
ohif:cornerstone-settings@0.0.1
|
ohif:cornerstone-settings@0.0.1
|
||||||
ohif:design@0.0.1
|
ohif:design@0.0.1
|
||||||
ohif:dicomweb-client@0.0.1
|
|
||||||
ohif:hanging-protocols@0.0.1
|
ohif:hanging-protocols@0.0.1
|
||||||
ohif:header@0.0.1
|
ohif:header@0.0.1
|
||||||
ohif:hotkeys@0.0.1
|
ohif:hotkeys@0.0.1
|
||||||
|
|||||||
@ -22,10 +22,10 @@ Meteor.startup(function() {
|
|||||||
|
|
||||||
cornerstoneWADOImageLoader.configure({
|
cornerstoneWADOImageLoader.configure({
|
||||||
beforeSend: function(xhr) {
|
beforeSend: function(xhr) {
|
||||||
const accessToken = OHIF.user.getAccessToken();
|
const headers = OHIF.DICOMWeb.getAuthorizationHeader();
|
||||||
|
|
||||||
if (accessToken) {
|
if (headers.Authorization) {
|
||||||
xhr.setRequestHeader("Authorization", `Bearer ${accessToken}`);
|
xhr.setRequestHeader("Authorization", headers.Authorization);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -5,7 +5,7 @@ Package.describe({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.4');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
// Meteor packages
|
// Meteor packages
|
||||||
api.use([
|
api.use([
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
* @param [defaultValue] - The value to return if the element is not present
|
* @param [defaultValue] - The value to return if the element is not present
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
const getAttribute = function(element, defaultValue) {
|
export default function getAttribute(element, defaultValue) {
|
||||||
if (!element) {
|
if (!element) {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
@ -42,5 +42,3 @@ function convertToInt(input) {
|
|||||||
|
|
||||||
return parseInt(output, 16);
|
return parseInt(output, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default getAttribute;
|
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
import { btoa } from 'isomorphic-base64';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Authorization header as part of an Object.
|
||||||
|
*
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
export default function getAuthorizationHeader() {
|
||||||
|
const headers = {};
|
||||||
|
|
||||||
|
// Check for OHIF.user since this can also be run on the server
|
||||||
|
const accessToken = OHIF.user && OHIF.user.getAccessToken && OHIF.user.getAccessToken();
|
||||||
|
const server = OHIF.servers.getCurrentServer();
|
||||||
|
|
||||||
|
if (server &&
|
||||||
|
server.requestOptions &&
|
||||||
|
server.requestOptions.auth) {
|
||||||
|
// HTTP Basic Auth (user:password)
|
||||||
|
headers.Authorization = `Basic ${btoa(server.requestOptions.auth)}`;
|
||||||
|
} else if (accessToken) {
|
||||||
|
headers.Authorization = `Bearer ${accessToken}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
const getModalities = function(modality, modalitiesInStudy) {
|
export default function getModalities(modality, modalitiesInStudy) {
|
||||||
var modalities = {};
|
var modalities = {};
|
||||||
if (modality) {
|
if (modality) {
|
||||||
modalities = modality;
|
modalities = modality;
|
||||||
@ -19,5 +19,3 @@ const getModalities = function(modality, modalitiesInStudy) {
|
|||||||
}
|
}
|
||||||
return modalities;
|
return modalities;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default getModalities;
|
|
||||||
@ -1,25 +1,19 @@
|
|||||||
import get from './get.js';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
import getAttribute from './getAttribute.js';
|
import getAttribute from './getAttribute.js';
|
||||||
import getBulkData from './getBulkData.js';
|
import getAuthorizationHeader from './getAuthorizationHeader.js';
|
||||||
import getJSON from './getJSON.js';
|
|
||||||
import getModalities from './getModalities.js';
|
import getModalities from './getModalities.js';
|
||||||
import getName from './getName.js';
|
import getName from './getName.js';
|
||||||
import getNumber from './getNumber.js';
|
import getNumber from './getNumber.js';
|
||||||
import getString from './getString.js';
|
import getString from './getString.js';
|
||||||
import getAccessToken from './getAccessToken.js';
|
|
||||||
import makeRequest from './makeRequest.js';
|
|
||||||
|
|
||||||
const DICOMWeb = {
|
const DICOMWeb = {
|
||||||
get,
|
|
||||||
getAttribute,
|
getAttribute,
|
||||||
getBulkData,
|
getAuthorizationHeader,
|
||||||
getJSON,
|
|
||||||
getModalities,
|
getModalities,
|
||||||
getName,
|
getName,
|
||||||
getNumber,
|
getNumber,
|
||||||
getString,
|
getString,
|
||||||
getAccessToken,
|
|
||||||
makeRequest
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export { DICOMWeb };
|
OHIF.DICOMWeb = DICOMWeb;
|
||||||
@ -1 +1,2 @@
|
|||||||
import './object.js';
|
import './object.js';
|
||||||
|
import './DICOMWeb/';
|
||||||
|
|||||||
@ -16,4 +16,4 @@ OHIF.utils.absoluteUrl = function(path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return absolutePath.replace(/\/\/+/g, '/');
|
return absolutePath.replace(/\/\/+/g, '/');
|
||||||
};
|
};
|
||||||
|
|||||||
@ -11,6 +11,7 @@ const OHIF = {
|
|||||||
viewer: {},
|
viewer: {},
|
||||||
cornerstone: {},
|
cornerstone: {},
|
||||||
user: {},
|
user: {},
|
||||||
|
DICOMWeb: {}, // Temporarily added
|
||||||
};
|
};
|
||||||
|
|
||||||
// Expose the OHIF object to the client if it is on development mode
|
// Expose the OHIF object to the client if it is on development mode
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
Npm.depends({
|
Npm.depends({
|
||||||
'twbs-pagination': '1.4.1'
|
'twbs-pagination': '1.4.1',
|
||||||
|
'isomorphic-base64': '1.0.2',
|
||||||
});
|
});
|
||||||
|
|
||||||
Package.describe({
|
Package.describe({
|
||||||
@ -9,7 +10,7 @@ Package.describe({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.4');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
api.use('ecmascript');
|
api.use('ecmascript');
|
||||||
api.use('standard-app-packages');
|
api.use('standard-app-packages');
|
||||||
@ -44,5 +45,4 @@ Package.onUse(function(api) {
|
|||||||
|
|
||||||
// Client and server imports
|
// Client and server imports
|
||||||
api.addFiles('both/index.js', ['client', 'server']);
|
api.addFiles('both/index.js', ['client', 'server']);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -5,7 +5,7 @@ Package.describe({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.5');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
api.use('ecmascript');
|
api.use('ecmascript');
|
||||||
api.use('ohif:cornerstone');
|
api.use('ohif:cornerstone');
|
||||||
|
|||||||
@ -15,7 +15,7 @@ Npm.depends({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.5');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
api.use('ecmascript');
|
api.use('ecmascript');
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@ Package.describe({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.4.2.3');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
api.use('ecmascript');
|
api.use('ecmascript');
|
||||||
api.use('standard-app-packages');
|
api.use('standard-app-packages');
|
||||||
|
|||||||
@ -1,22 +0,0 @@
|
|||||||
Package.describe({
|
|
||||||
name: 'ohif:dicomweb-client',
|
|
||||||
summary: 'DICOM Services: DICOMWeb',
|
|
||||||
version: '0.0.1'
|
|
||||||
});
|
|
||||||
|
|
||||||
Npm.depends({
|
|
||||||
'url-parse': '1.4.1',
|
|
||||||
'isomorphic-fetch': '2.2.1',
|
|
||||||
'isomorphic-base64': '1.0.2'
|
|
||||||
});
|
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
|
||||||
api.versionsFrom('1.6');
|
|
||||||
|
|
||||||
api.use('ecmascript');
|
|
||||||
|
|
||||||
// DICOMWeb functions
|
|
||||||
api.mainModule('src/index.js');
|
|
||||||
|
|
||||||
api.export('DICOMWeb');
|
|
||||||
});
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
import makeRequest from "./makeRequest";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make a request to the URL given a set of options.
|
|
||||||
* This function will add optional timing, request, and respone logging.
|
|
||||||
*
|
|
||||||
* @param {String} url
|
|
||||||
* @param {Object} options
|
|
||||||
* @return {Promise<*>}
|
|
||||||
*/
|
|
||||||
const get = async function get(url, options) {
|
|
||||||
if (options.logRequests) {
|
|
||||||
console.log(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.logTiming) {
|
|
||||||
console.time(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await makeRequest(url, options);
|
|
||||||
|
|
||||||
if (options.logTiming) {
|
|
||||||
console.timeEnd(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.logResponses) {
|
|
||||||
console.info(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default get;
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
import { OHIF } from 'meteor/ohif:core';
|
|
||||||
|
|
||||||
export default function getAccessToken() {
|
|
||||||
if (!global.window || !window.sessionStorage || !sessionStorage) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const userAccessToken = OHIF.user.getAccessToken();
|
|
||||||
if (userAccessToken) {
|
|
||||||
return userAccessToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sessionStorage.token;
|
|
||||||
}
|
|
||||||
@ -1,133 +0,0 @@
|
|||||||
import get from './get.js';
|
|
||||||
|
|
||||||
const ASCII = 'ascii';
|
|
||||||
|
|
||||||
function getMultipartContentInfo(headers) {
|
|
||||||
const multipartRegex = /^\s*multipart\/[^;]+/g;
|
|
||||||
const contentType = headers.get('content-type');
|
|
||||||
let dict = null;
|
|
||||||
|
|
||||||
if (typeof contentType === 'string' && multipartRegex.test(contentType)) {
|
|
||||||
let match;
|
|
||||||
let pairRegex = /;\s*([^=]+)=([^;\r\n]+)/g;
|
|
||||||
|
|
||||||
pairRegex.lastIndex = multipartRegex.lastIndex;
|
|
||||||
while ((match = pairRegex.exec(contentType)) !== null) {
|
|
||||||
let key = match[1]
|
|
||||||
let value = match[2];
|
|
||||||
|
|
||||||
if (dict === null) {
|
|
||||||
dict = {};
|
|
||||||
}
|
|
||||||
dict[key] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dict;
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseContentHeader(data, offset) {
|
|
||||||
const endOfHeader = data.indexOf('\r\n\r\n', offset);
|
|
||||||
|
|
||||||
if (endOfHeader < 0 || endOfHeader <= offset || endOfHeader > data.length) {
|
|
||||||
throw new Error('End of content header cannot be determined...');
|
|
||||||
}
|
|
||||||
|
|
||||||
const header = {
|
|
||||||
start: offset,
|
|
||||||
end: endOfHeader + 4,
|
|
||||||
fields: {}
|
|
||||||
};
|
|
||||||
const headerRegex = /([\w\-]+):\s*([^\r\n]+)(?:\r\n)?/g;
|
|
||||||
const headerContentRegex = /\t([^\r\n]+)(?:\r\n)?/g;
|
|
||||||
const headerString = data.slice(offset, endOfHeader);
|
|
||||||
|
|
||||||
let match;
|
|
||||||
|
|
||||||
while ((match = headerRegex.exec(headerString)) !== null) {
|
|
||||||
const key = match[1].toLowerCase(), value = match[2];
|
|
||||||
|
|
||||||
while (headerString.charAt(headerRegex.lastIndex) === '\t') {
|
|
||||||
headerContentRegex.lastIndex = headerRegex.lastIndex;
|
|
||||||
|
|
||||||
if ((match = headerContentRegex.exec(headerString)) !== null) {
|
|
||||||
headerRegex.lastIndex = headerContentRegex.lastIndex;
|
|
||||||
value += ' ' + match[1];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
header.fields[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return header;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function toBytes(input) {
|
|
||||||
const data = [];
|
|
||||||
for (let i = 0; i < input.length; i++){
|
|
||||||
data.push(input.charCodeAt(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function parseResponse(headers, data) {
|
|
||||||
const contentInfo = getMultipartContentInfo(headers);
|
|
||||||
|
|
||||||
if (!contentInfo || !contentInfo.boundary) {
|
|
||||||
throw new Error('Content boundary not specified...');
|
|
||||||
}
|
|
||||||
|
|
||||||
const boundary = contentInfo.boundary;
|
|
||||||
const delimiter = '--' + boundary + '\r\n';
|
|
||||||
let index = data.indexOf(delimiter, 0, ASCII);
|
|
||||||
|
|
||||||
if (index < 0) {
|
|
||||||
throw new Error('DICOMWeb: The specified boundary could not be found...');
|
|
||||||
}
|
|
||||||
|
|
||||||
let closingIndex
|
|
||||||
let closingDelimiter = '\r\n--' + boundary + '--';
|
|
||||||
|
|
||||||
index += delimiter.length;
|
|
||||||
if (data[index] !== 0x0D || data[index + 1] !== 0x0A) {
|
|
||||||
// multipart content headers are present, so let's parse them...
|
|
||||||
let contentHeader = parseContentHeader(data, index);
|
|
||||||
if (contentHeader && contentHeader.end > index) {
|
|
||||||
if (contentHeader.fields['content-length'] > 0) {
|
|
||||||
let endOfData = contentHeader.end + parseInt(contentHeader.fields['content-length'], 10);
|
|
||||||
if (endOfData === data.indexOf(closingDelimiter, endOfData)) {
|
|
||||||
// content-length is valid...
|
|
||||||
return data.slice(contentHeader.end, endOfData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
index = contentHeader.end;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// no headers, the content comes right after...
|
|
||||||
index += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
closingIndex = data.indexOf(closingDelimiter, index);
|
|
||||||
if (closingIndex < 0 || closingIndex < index) {
|
|
||||||
throw new Error('DICOMWeb: The end of the content could not be determined...')
|
|
||||||
}
|
|
||||||
|
|
||||||
return toBytes(data.slice(index, closingIndex));
|
|
||||||
}
|
|
||||||
|
|
||||||
const getBulkData = async function(url, options = {}) {
|
|
||||||
options.headers = options.headers || {};
|
|
||||||
options.headers.Accept = 'multipart/related; type=application/octet-stream';
|
|
||||||
|
|
||||||
const response = await get(url, options);
|
|
||||||
const data = await response.text();
|
|
||||||
|
|
||||||
return parseResponse(response.headers, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default getBulkData;
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
import get from './get.js';
|
|
||||||
import getAttribute from "./getAttribute";
|
|
||||||
|
|
||||||
const getJSON = async function (url, options) {
|
|
||||||
options.headers = options.headers || {};
|
|
||||||
options.headers.Accept = 'application/json';
|
|
||||||
return get(url, options).then(response => {
|
|
||||||
if (!(response instanceof Response)) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.json();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default getJSON;
|
|
||||||
@ -1,69 +0,0 @@
|
|||||||
import { Meteor } from "meteor/meteor";
|
|
||||||
import URL from 'url-parse';
|
|
||||||
import 'isomorphic-fetch';
|
|
||||||
import { btoa } from 'isomorphic-base64';
|
|
||||||
import getAccessToken from './getAccessToken.js';
|
|
||||||
|
|
||||||
async function makeRequest(url, options) {
|
|
||||||
const parsed = new URL(url);
|
|
||||||
|
|
||||||
let requestOpt = {
|
|
||||||
method: 'GET',
|
|
||||||
headers: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
const accessToken = getAccessToken();
|
|
||||||
if (accessToken) {
|
|
||||||
requestOpt.headers = {
|
|
||||||
Authorization: `Bearer ${accessToken}`
|
|
||||||
};
|
|
||||||
} else if (options.auth) {
|
|
||||||
requestOpt.headers = {
|
|
||||||
Authorization: `Basic ${btoa(options.auth)}`
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.headers) {
|
|
||||||
Object.keys(options.headers).forEach(key => {
|
|
||||||
requestOpt.headers[key] = options.headers[key];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if(options.method) {
|
|
||||||
requestOpt.method = options.method;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.method === 'POST' && options.body) {
|
|
||||||
requestOpt.body = options.body;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
// TODO: Kept getting weird build errors from RegExp
|
|
||||||
const isAbsolute = parsed.href.indexOf('http://') === 0 || parsed.href.indexOf('https://') === 0;
|
|
||||||
|
|
||||||
let url = parsed.href;
|
|
||||||
|
|
||||||
if (isAbsolute === false) {
|
|
||||||
url = Meteor.absoluteUrl(parsed.href);
|
|
||||||
}
|
|
||||||
|
|
||||||
fetch(url, requestOpt).then((response) => {
|
|
||||||
if (response.status >= 400) {
|
|
||||||
reject(new Error(response.status));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.status === 204) {
|
|
||||||
resolve([]);
|
|
||||||
} else {
|
|
||||||
// TODO: Handle 204 no content
|
|
||||||
resolve(response);
|
|
||||||
}
|
|
||||||
}, (error) => {
|
|
||||||
console.error('There was an error in the DICOMWeb Server');
|
|
||||||
|
|
||||||
reject(new Error(error));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export default makeRequest;
|
|
||||||
@ -9,7 +9,7 @@ Npm.depends({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.4');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
api.use('ecmascript');
|
api.use('ecmascript');
|
||||||
api.use('standard-app-packages');
|
api.use('standard-app-packages');
|
||||||
|
|||||||
@ -5,7 +5,7 @@ Package.describe({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.4.2.3');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
// Meteor packages
|
// Meteor packages
|
||||||
api.use('ecmascript');
|
api.use('ecmascript');
|
||||||
|
|||||||
@ -9,7 +9,7 @@ Npm.depends({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.4');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
// Meteor packages
|
// Meteor packages
|
||||||
api.use([
|
api.use([
|
||||||
|
|||||||
@ -5,7 +5,7 @@ Package.describe({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.4');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
api.use('ecmascript');
|
api.use('ecmascript');
|
||||||
api.use('standard-app-packages');
|
api.use('standard-app-packages');
|
||||||
|
|||||||
@ -9,7 +9,7 @@ Npm.depends({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.4');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
api.use('ecmascript');
|
api.use('ecmascript');
|
||||||
api.use('standard-app-packages');
|
api.use('standard-app-packages');
|
||||||
|
|||||||
@ -18,7 +18,7 @@ export const retrieveMeasurements = (patientId, timepointIds) => {
|
|||||||
|
|
||||||
export const storeMeasurements = (measurementData, timepointIds) => {
|
export const storeMeasurements = (measurementData, timepointIds) => {
|
||||||
OHIF.log.info('storeMeasurements');
|
OHIF.log.info('storeMeasurements');
|
||||||
|
|
||||||
const server = OHIF.servers.getCurrentServer();
|
const server = OHIF.servers.getCurrentServer();
|
||||||
if (!server || server.type !== 'dicomWeb') {
|
if (!server || server.type !== 'dicomWeb') {
|
||||||
return Promise.resolve({});
|
return Promise.resolve({});
|
||||||
@ -28,6 +28,8 @@ export const storeMeasurements = (measurementData, timepointIds) => {
|
|||||||
|
|
||||||
return stowSRFromMeasurements(measurementData).then( () => {
|
return stowSRFromMeasurements(measurementData).then( () => {
|
||||||
OHIF.studies.deleteStudyMetadataPromise(studyInstanceUid);
|
OHIF.studies.deleteStudyMetadataPromise(studyInstanceUid);
|
||||||
|
}, error => {
|
||||||
|
throw new Error(error);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,60 +1,51 @@
|
|||||||
import { dcmjs } from 'meteor/ohif:cornerstone';
|
import { dcmjs } from 'meteor/ohif:cornerstone';
|
||||||
import retrieveDataFromSR from './retrieveDataFromSR';
|
import retrieveDataFromSR from './retrieveDataFromSR';
|
||||||
import retrieveDataFromMeasurements from './retrieveDataFromMeasurements';
|
import retrieveDataFromMeasurements from './retrieveDataFromMeasurements';
|
||||||
import {
|
|
||||||
multipartEncode
|
import DICOMwebClient from 'dicomweb-client';
|
||||||
} from './srUtils';
|
|
||||||
|
|
||||||
const retrieveMeasurementFromSR = async (series) => {
|
const retrieveMeasurementFromSR = async (series) => {
|
||||||
const instance = series.getFirstInstance();
|
const server = OHIF.servers.getCurrentServer();
|
||||||
const options = {
|
const url = WADOProxy.convertURL(server.wadoRoot, server);
|
||||||
method: 'GET',
|
|
||||||
responseType: 'arraybuffer',
|
|
||||||
};
|
|
||||||
const url = instance.getDataProperty('wadouri');
|
|
||||||
|
|
||||||
try {
|
const config = {
|
||||||
const result = await DICOMWeb.makeRequest(url, options);
|
url,
|
||||||
const data = await result.arrayBuffer();
|
headers: OHIF.DICOMWeb.getAuthorizationHeader()
|
||||||
const measurementData = retrieveDataFromSR(data);
|
};
|
||||||
return Promise.resolve(measurementData);
|
|
||||||
} catch(error) {
|
const dicomWeb = new DICOMwebClient.api.DICOMwebClient(config);
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
const instance = series.getFirstInstance();
|
||||||
|
const options = {
|
||||||
|
studyInstanceUID: instance.getStudyInstanceUID(),
|
||||||
|
seriesInstanceUID: instance.getSeriesInstanceUID(),
|
||||||
|
sopInstanceUID: instance.getSOPInstanceUID(),
|
||||||
|
};
|
||||||
|
|
||||||
|
return dicomWeb.retrieveInstance(options).then(retrieveDataFromSR);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the DICOMWeb STOW-RS URL for the current server.
|
|
||||||
*
|
|
||||||
* See ftp://medical.nema.org/medical/dicom/current/output/html/part18.html#sect_6.6.1.1
|
|
||||||
*
|
|
||||||
* @return {string|null} The URL, rerouted to the proxy if the WADOProxy is enabled.
|
|
||||||
*/
|
|
||||||
function getStowRsUrl() {
|
|
||||||
const server = OHIF.servers.getCurrentServer();
|
|
||||||
const url = `${server.wadoRoot}/studies`;
|
|
||||||
|
|
||||||
return WADOProxy.convertURL(url, server);
|
|
||||||
}
|
|
||||||
|
|
||||||
const stowSRFromMeasurements = async (measurements) => {
|
const stowSRFromMeasurements = async (measurements) => {
|
||||||
const serverUrl = getStowRsUrl();
|
const server = OHIF.servers.getCurrentServer();
|
||||||
|
const url = WADOProxy.convertURL(server.wadoRoot, server);
|
||||||
const reportDataset = retrieveDataFromMeasurements(measurements);
|
const reportDataset = retrieveDataFromMeasurements(measurements);
|
||||||
const boundary = dcmjs.data.DicomMetaDictionary.uid();
|
const denaturalizedMetaheader = dcmjs.data.DicomMetaDictionary.denaturalizeDataset(dataset._meta);
|
||||||
const options = {
|
const dicomDict = new dcmjs.data.DicomDict(denaturalizedMetaheader);
|
||||||
method: 'POST',
|
|
||||||
body: multipartEncode(reportDataset, boundary),
|
dicomDict.dict = dcmjs.data.DicomMetaDictionary.denaturalizeDataset(dataset);
|
||||||
headers: {
|
|
||||||
'Content-Type': `multipart/related; type=application/dicom; boundary=${boundary}`
|
const part10Buffer = dicomDict.write();
|
||||||
}
|
const config = {
|
||||||
|
url,
|
||||||
|
headers: OHIF.DICOMWeb.getAuthorizationHeader()
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
const dicomWeb = new DICOMwebClient.api.DICOMwebClient(config);
|
||||||
await DICOMWeb.makeRequest(serverUrl, options);
|
const options = {
|
||||||
return Promise.resolve();
|
datasets: [part10Buffer]
|
||||||
} catch(error) {
|
};
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
return dicomWeb.storeInstances(options);
|
||||||
};
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|||||||
@ -55,7 +55,7 @@ const getLatestSRSeries = () => {
|
|||||||
if (supportedSopClassUIDs.includes(sopClassUid)) {
|
if (supportedSopClassUIDs.includes(sopClassUid)) {
|
||||||
if(!latestSeries) {
|
if(!latestSeries) {
|
||||||
latestSeries = series;
|
latestSeries = series;
|
||||||
} else if (series._data.seriesDate > latestSeries._data.seriesDate ||
|
} else if (series._data.seriesDate > latestSeries._data.seriesDate ||
|
||||||
(series._data.seriesDate === latestSeries._data.seriesDate && series._data.seriesTime > latestSeries._data.seriesTime)) {
|
(series._data.seriesDate === latestSeries._data.seriesDate && series._data.seriesTime > latestSeries._data.seriesTime)) {
|
||||||
latestSeries = series;
|
latestSeries = series;
|
||||||
}
|
}
|
||||||
@ -70,36 +70,10 @@ const stringToArray = (string) => {
|
|||||||
return Uint8Array.from(Array.from(string).map(letter => letter.charCodeAt(0)))
|
return Uint8Array.from(Array.from(string).map(letter => letter.charCodeAt(0)))
|
||||||
};
|
};
|
||||||
|
|
||||||
const multipartEncode = (dataset, boundary) => {
|
|
||||||
|
|
||||||
const denaturalizedMetaheader = dcmjs.data.DicomMetaDictionary.denaturalizeDataset(dataset._meta);
|
|
||||||
const dicomDict = new dcmjs.data.DicomDict(denaturalizedMetaheader);
|
|
||||||
|
|
||||||
dicomDict.dict = dcmjs.data.DicomMetaDictionary.denaturalizeDataset(dataset);
|
|
||||||
|
|
||||||
const part10Buffer = dicomDict.write();
|
|
||||||
|
|
||||||
const header = `\r\n--${boundary}\r\nContent-Type: application/dicom\r\n\r\n`;
|
|
||||||
const footer = `\r\n--${boundary}--`;
|
|
||||||
|
|
||||||
headerArray = stringToArray(header);
|
|
||||||
contentArray = new Uint8Array(part10Buffer);
|
|
||||||
footerArray = stringToArray(footer);
|
|
||||||
|
|
||||||
const multipartArray = new Uint8Array(headerArray.length + contentArray.length + footerArray.length);
|
|
||||||
|
|
||||||
multipartArray.set(headerArray, 0);
|
|
||||||
multipartArray.set(contentArray, headerArray.length);
|
|
||||||
multipartArray.set(footerArray, headerArray.length + contentArray.length);
|
|
||||||
|
|
||||||
return(multipartArray.buffer);
|
|
||||||
};
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
codeMeaningEquals,
|
codeMeaningEquals,
|
||||||
getAllDisplaySets,
|
getAllDisplaySets,
|
||||||
getInstanceMetadata,
|
getInstanceMetadata,
|
||||||
getLatestSRSeries,
|
getLatestSRSeries,
|
||||||
multipartEncode,
|
|
||||||
toArray
|
toArray
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,13 @@ Package.describe({
|
|||||||
version: '0.0.1'
|
version: '0.0.1'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Npm.depends({
|
||||||
|
'dicomweb-client': '0.3.2',
|
||||||
|
'xhr2': '0.1.4'
|
||||||
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.6');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
api.use('ecmascript');
|
api.use('ecmascript');
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,7 @@ Package.describe({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.4');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
api.use('ecmascript');
|
api.use('ecmascript');
|
||||||
api.use('standard-app-packages');
|
api.use('standard-app-packages');
|
||||||
|
|||||||
@ -5,7 +5,7 @@ Package.describe({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.4');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
api.use('ecmascript');
|
api.use('ecmascript');
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ Package.describe({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.4');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
// Meteor packages
|
// Meteor packages
|
||||||
api.use('ecmascript');
|
api.use('ecmascript');
|
||||||
|
|||||||
@ -5,7 +5,7 @@ Package.describe({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.4');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
// Meteor packages
|
// Meteor packages
|
||||||
api.use([
|
api.use([
|
||||||
|
|||||||
@ -64,15 +64,15 @@ export const DICOMWebServer = new SimpleSchema({
|
|||||||
imageRendering: {
|
imageRendering: {
|
||||||
type: String,
|
type: String,
|
||||||
label: 'Image rendering',
|
label: 'Image rendering',
|
||||||
allowedValues: ['wadouri', 'wadors', 'orthanc'],
|
allowedValues: ['wadouri', 'wadors'],
|
||||||
valuesLabels: ['WADO URI', 'WADO RS', 'ORTHANC'],
|
valuesLabels: ['WADO URI', 'WADO RS'],
|
||||||
defaultValue: 'wadouri'
|
defaultValue: 'wadouri'
|
||||||
},
|
},
|
||||||
thumbnailRendering: {
|
thumbnailRendering: {
|
||||||
type: String,
|
type: String,
|
||||||
label: 'Thumbnail rendering',
|
label: 'Thumbnail rendering',
|
||||||
allowedValues: ['wadouri', 'wadors', 'orthanc'],
|
allowedValues: ['wadouri', 'wadors'],
|
||||||
valuesLabels: ['WADO URI', 'WADO RS', 'ORTHANC'],
|
valuesLabels: ['WADO URI', 'WADO RS'],
|
||||||
defaultValue: 'wadouri'
|
defaultValue: 'wadouri'
|
||||||
},
|
},
|
||||||
qidoRoot: {
|
qidoRoot: {
|
||||||
|
|||||||
@ -14,7 +14,6 @@ if (Meteor.settings &&
|
|||||||
const endpoints = servers[serverType];
|
const endpoints = servers[serverType];
|
||||||
endpoints.forEach((endpoint) => {
|
endpoints.forEach((endpoint) => {
|
||||||
const server = Object.assign({}, endpoint);
|
const server = Object.assign({}, endpoint);
|
||||||
server.origin = 'json';
|
|
||||||
server.type = serverType;
|
server.type = serverType;
|
||||||
|
|
||||||
Servers.insert(server);
|
Servers.insert(server);
|
||||||
|
|||||||
@ -5,14 +5,14 @@ Package.describe({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.4');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
api.use('ecmascript');
|
api.use('ecmascript');
|
||||||
api.use('templating');
|
api.use('templating', 'client');
|
||||||
api.use('jquery');
|
api.use('jquery', 'client');
|
||||||
api.use('stylus');
|
api.use('stylus', 'client');
|
||||||
api.use('aldeed:simple-schema');
|
api.use('aldeed:simple-schema@1.5.4');
|
||||||
api.use('aldeed:collection2');
|
api.use('aldeed:collection2@2.10.0');
|
||||||
|
|
||||||
// Our custom packages
|
// Our custom packages
|
||||||
api.use('ohif:core');
|
api.use('ohif:core');
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import { Meteor } from 'meteor/meteor';
|
|||||||
import { _ } from 'meteor/underscore';
|
import { _ } from 'meteor/underscore';
|
||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
import { Servers } from 'meteor/ohif:servers/both/collections';
|
import { Servers } from 'meteor/ohif:servers/both/collections';
|
||||||
import { ServerConfiguration } from 'meteor/ohif:servers/both/schema/servers.js';
|
|
||||||
|
|
||||||
// Check the servers on meteor startup
|
// Check the servers on meteor startup
|
||||||
if (Meteor.settings &&
|
if (Meteor.settings &&
|
||||||
|
|||||||
@ -1,18 +0,0 @@
|
|||||||
/**
|
|
||||||
* Converts the properties to URL query parameters. Based on:
|
|
||||||
* http://stackoverflow.com/questions/111529/create-query-parameters-in-javascript
|
|
||||||
*
|
|
||||||
* @param data
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
encodeQueryData = function(data) {
|
|
||||||
var ret = [];
|
|
||||||
|
|
||||||
for (var d in data) {
|
|
||||||
if (data[d]) {
|
|
||||||
ret.push(encodeURIComponent(d) + '=' + encodeURIComponent(data[d]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret.join('&');
|
|
||||||
};
|
|
||||||
@ -1,2 +1 @@
|
|||||||
import './encodeQueryData.js';
|
|
||||||
import './parseFloatArray.js';
|
import './parseFloatArray.js';
|
||||||
|
|||||||
@ -1,15 +1,7 @@
|
|||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
import { DICOMWeb } from 'meteor/ohif:dicomweb-client';
|
import DICOMwebClient from 'dicomweb-client';
|
||||||
|
|
||||||
/**
|
const { DICOMWeb } = OHIF;
|
||||||
* Creates a QIDO URL given the server settings and a study instance UID
|
|
||||||
* @param server
|
|
||||||
* @param studyInstanceUid
|
|
||||||
* @returns {string} URL to be used for QIDO calls
|
|
||||||
*/
|
|
||||||
function buildUrl(server, studyInstanceUid) {
|
|
||||||
return server.qidoRoot + '/studies/' + studyInstanceUid + '/instances';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses data returned from a QIDO search and transforms it into
|
* Parses data returned from a QIDO search and transforms it into
|
||||||
@ -76,20 +68,23 @@ function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
|
|||||||
* @returns {{wadoUriRoot: String, studyInstanceUid: String, seriesList: Array}}
|
* @returns {{wadoUriRoot: String, studyInstanceUid: String, seriesList: Array}}
|
||||||
*/
|
*/
|
||||||
OHIF.studies.services.QIDO.Instances = function(server, studyInstanceUid) {
|
OHIF.studies.services.QIDO.Instances = function(server, studyInstanceUid) {
|
||||||
var url = buildUrl(server, studyInstanceUid);
|
// TODO: Are we using this function anywhere?? Can we remove it?
|
||||||
|
|
||||||
try {
|
const config = {
|
||||||
var result = DICOMWeb.getJSON(url, server.requestOptions);
|
url: server.qidoRoot,
|
||||||
|
headers: OHIF.DICOMWeb.getAuthorizationHeader()
|
||||||
|
};
|
||||||
|
const dicomWeb = new DICOMwebClient.api.DICOMwebClient(config);
|
||||||
|
const queryParams = getQIDOQueryParams(filter, server.qidoSupportsIncludeField);
|
||||||
|
const options = {
|
||||||
|
studyInstanceUID: studyInstanceUid
|
||||||
|
};
|
||||||
|
|
||||||
|
return dicomWeb.searchForInstances(options).then(result => {
|
||||||
return {
|
return {
|
||||||
wadoUriRoot: server.wadoUriRoot,
|
wadoUriRoot: server.wadoUriRoot,
|
||||||
studyInstanceUid: studyInstanceUid,
|
studyInstanceUid: studyInstanceUid,
|
||||||
seriesList: resultDataToStudyMetadata(server, studyInstanceUid, result.data)
|
seriesList: resultDataToStudyMetadata(server, studyInstanceUid, result.data)
|
||||||
};
|
};
|
||||||
} catch (error) {
|
});
|
||||||
OHIF.log.trace();
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,14 @@
|
|||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
import { DICOMWeb } from 'meteor/ohif:dicomweb-client';
|
import DICOMwebClient from 'dicomweb-client';
|
||||||
|
|
||||||
|
const { DICOMWeb } = OHIF;
|
||||||
|
|
||||||
|
// TODO: Is there an easier way to do this?
|
||||||
|
if (Meteor.isServer) {
|
||||||
|
var XMLHttpRequest = require('xhr2');
|
||||||
|
|
||||||
|
global.XMLHttpRequest = XMLHttpRequest;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a QIDO date string for a date range query
|
* Creates a QIDO date string for a date range query
|
||||||
@ -27,7 +36,7 @@ function dateToString(date) {
|
|||||||
* @param filter
|
* @param filter
|
||||||
* @returns {string} The URL with encoded filter query data
|
* @returns {string} The URL with encoded filter query data
|
||||||
*/
|
*/
|
||||||
function filterToQIDOURL(server, filter) {
|
function getQIDOQueryParams(filter, serverSupportsQIDOIncludeField) {
|
||||||
const commaSeparatedFields = [
|
const commaSeparatedFields = [
|
||||||
'00081030', // Study Description
|
'00081030', // Study Description
|
||||||
'00080060' //Modality
|
'00080060' //Modality
|
||||||
@ -41,7 +50,7 @@ function filterToQIDOURL(server, filter) {
|
|||||||
StudyDescription: filter.studyDescription,
|
StudyDescription: filter.studyDescription,
|
||||||
ModalitiesInStudy: filter.modalitiesInStudy,
|
ModalitiesInStudy: filter.modalitiesInStudy,
|
||||||
limit: filter.limit,
|
limit: filter.limit,
|
||||||
includefield: server.qidoSupportsIncludeField ? 'all' : commaSeparatedFields
|
includefield: serverSupportsQIDOIncludeField ? commaSeparatedFields : 'all'
|
||||||
};
|
};
|
||||||
|
|
||||||
// build the StudyDate range parameter
|
// build the StudyDate range parameter
|
||||||
@ -59,7 +68,16 @@ function filterToQIDOURL(server, filter) {
|
|||||||
parameters.StudyInstanceUID = studyUids;
|
parameters.StudyInstanceUID = studyUids;
|
||||||
}
|
}
|
||||||
|
|
||||||
return server.qidoRoot + '/studies?' + encodeQueryData(parameters);
|
// Clean query params of undefined values.
|
||||||
|
const params = {};
|
||||||
|
Object.keys(parameters).forEach(key => {
|
||||||
|
if (parameters[key] !== undefined &&
|
||||||
|
parameters[key] !== "") {
|
||||||
|
params[key] = parameters[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -98,13 +116,16 @@ function resultDataToStudies(resultData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
OHIF.studies.services.QIDO.Studies = (server, filter) => {
|
OHIF.studies.services.QIDO.Studies = (server, filter) => {
|
||||||
const url = filterToQIDOURL(server, filter);
|
const config = {
|
||||||
|
url: server.qidoRoot,
|
||||||
|
headers: OHIF.DICOMWeb.getAuthorizationHeader()
|
||||||
|
};
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
const dicomWeb = new DICOMwebClient.api.DICOMwebClient(config);
|
||||||
DICOMWeb.getJSON(url, server.requestOptions).then(result => {
|
const queryParams = getQIDOQueryParams(filter, server.qidoSupportsIncludeField);
|
||||||
const studies = resultDataToStudies(result);
|
const options = {
|
||||||
|
queryParams
|
||||||
|
};
|
||||||
|
|
||||||
resolve(studies);
|
return dicomWeb.searchForStudies(options).then(resultDataToStudies);
|
||||||
}, reject);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
import { DICOMWeb } from 'meteor/ohif:dicomweb-client';
|
import DICOMwebClient from 'dicomweb-client';
|
||||||
|
|
||||||
import { parseFloatArray } from '../../lib/parseFloatArray';
|
import { parseFloatArray } from '../../lib/parseFloatArray';
|
||||||
|
|
||||||
|
const { DICOMWeb } = OHIF;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple cache schema for retrieved color palettes.
|
* Simple cache schema for retrieved color palettes.
|
||||||
*/
|
*/
|
||||||
@ -39,17 +42,6 @@ const paletteColorCache = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a URL for a WADO search
|
|
||||||
*
|
|
||||||
* @param server
|
|
||||||
* @param studyInstanceUid
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
function buildUrl(server, studyInstanceUid) {
|
|
||||||
return server.wadoRoot + '/studies/' + studyInstanceUid + '/metadata';
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns a WADO url for an instance
|
/** Returns a WADO url for an instance
|
||||||
*
|
*
|
||||||
* @param studyInstanceUid
|
* @param studyInstanceUid
|
||||||
@ -58,6 +50,7 @@ function buildUrl(server, studyInstanceUid) {
|
|||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function buildInstanceWadoUrl(server, studyInstanceUid, seriesInstanceUid, sopInstanceUid) {
|
function buildInstanceWadoUrl(server, studyInstanceUid, seriesInstanceUid, sopInstanceUid) {
|
||||||
|
// TODO: This can be removed, since DICOMWebClient has the same function. Not urgent, though
|
||||||
const params = [];
|
const params = [];
|
||||||
|
|
||||||
params.push('requestType=WADO');
|
params.push('requestType=WADO');
|
||||||
@ -102,23 +95,47 @@ function getSourceImageInstanceUid(instance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getPaletteColor(server, instance, tag, lutDescriptor) {
|
function getPaletteColor(server, instance, tag, lutDescriptor) {
|
||||||
const lut = [];
|
|
||||||
const numLutEntries = lutDescriptor[0];
|
const numLutEntries = lutDescriptor[0];
|
||||||
const bits = lutDescriptor[2];
|
const bits = lutDescriptor[2];
|
||||||
const uri = WADOProxy.convertURL(instance[tag].BulkDataURI, server)
|
|
||||||
const bulkDataPromise = DICOMWeb.getBulkData(uri);
|
|
||||||
|
|
||||||
return bulkDataPromise.then(data => {
|
let uri = WADOProxy.convertURL(instance[tag].BulkDataURI, server)
|
||||||
for (var i = 0; i < numLutEntries; i++) {
|
|
||||||
if(bits === 16) {
|
// TODO: Workaround for dcm4chee behind SSL-terminating proxy returning
|
||||||
lut[i] = data[i * 65536] + data[i + 1];
|
// incorrect bulk data URIs
|
||||||
|
if (server.wadoRoot.indexOf('https') === 0 &&
|
||||||
|
!uri.includes('https')) {
|
||||||
|
uri = uri.replace('http', 'https');
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
url: server.wadoRoot, //BulkDataURI is absolute, so this isn't used
|
||||||
|
headers: OHIF.DICOMWeb.getAuthorizationHeader()
|
||||||
|
};
|
||||||
|
const dicomWeb = new DICOMwebClient.api.DICOMwebClient(config);
|
||||||
|
const options = {
|
||||||
|
BulkDataURI: uri
|
||||||
|
};
|
||||||
|
|
||||||
|
const readUInt16 = (byteArray, position) => {
|
||||||
|
return byteArray[position] + (byteArray[position + 1] * 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
const arrayBufferToPaletteColorLUT = (arraybuffer) =>{
|
||||||
|
const byteArray = new Uint8Array(arraybuffer);
|
||||||
|
const lut = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < numLutEntries; i++) {
|
||||||
|
if (bits === 16) {
|
||||||
|
lut[i] = readUInt16(byteArray, i * 2);
|
||||||
} else {
|
} else {
|
||||||
lut[i] = data[i];
|
lut[i] = byteArray[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return lut;
|
return lut;
|
||||||
})
|
}
|
||||||
|
|
||||||
|
return dicomWeb.retrieveBulkData(options).then(arrayBufferToPaletteColorLUT)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -129,13 +146,15 @@ function getPaletteColor(server, instance, tag, lutDescriptor) {
|
|||||||
* @returns {String} The ReferenceSOPInstanceUID
|
* @returns {String} The ReferenceSOPInstanceUID
|
||||||
*/
|
*/
|
||||||
async function getPaletteColors(server, instance, lutDescriptor) {
|
async function getPaletteColors(server, instance, lutDescriptor) {
|
||||||
let entry = null;
|
|
||||||
let paletteUID = DICOMWeb.getString(instance['00281199']);
|
let paletteUID = DICOMWeb.getString(instance['00281199']);
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (paletteColorCache.isValidUID(paletteUID)) {
|
if (paletteColorCache.isValidUID(paletteUID)) {
|
||||||
entry = paletteColorCache.get(paletteUID);
|
const entry = paletteColorCache.get(paletteUID);
|
||||||
return resolve(entry);
|
|
||||||
|
if (entry) {
|
||||||
|
return resolve(entry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// no entry in cache... Fetch remote data.
|
// no entry in cache... Fetch remote data.
|
||||||
@ -146,7 +165,11 @@ async function getPaletteColors(server, instance, lutDescriptor) {
|
|||||||
const promises = [r, g, b];
|
const promises = [r, g, b];
|
||||||
|
|
||||||
Promise.all(promises).then((args) => {
|
Promise.all(promises).then((args) => {
|
||||||
entry = { red: r, green: g, blue: b };
|
entry = {
|
||||||
|
red: args[0],
|
||||||
|
green: args[1],
|
||||||
|
blue: args[2]
|
||||||
|
};
|
||||||
|
|
||||||
// when paletteUID is present, the entry can be cached...
|
// when paletteUID is present, the entry can be cached...
|
||||||
entry.uid = paletteUID;
|
entry.uid = paletteUID;
|
||||||
@ -202,9 +225,6 @@ function getRadiopharmaceuticalInfo(instance) {
|
|||||||
* @returns {{seriesList: Array, patientName: *, patientId: *, accessionNumber: *, studyDate: *, modalities: *, studyDescription: *, imageCount: *, studyInstanceUid: *}}
|
* @returns {{seriesList: Array, patientName: *, patientId: *, accessionNumber: *, studyDate: *, modalities: *, studyDescription: *, imageCount: *, studyInstanceUid: *}}
|
||||||
*/
|
*/
|
||||||
async function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
|
async function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
|
||||||
const seriesMap = {};
|
|
||||||
const seriesList = [];
|
|
||||||
|
|
||||||
if (!resultData.length) {
|
if (!resultData.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -215,7 +235,9 @@ async function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const studyData = {
|
const studyData = {
|
||||||
seriesList,
|
seriesList: [],
|
||||||
|
studyInstanceUid,
|
||||||
|
wadoUriRoot: server.wadoUriRoot,
|
||||||
patientName: DICOMWeb.getName(anInstance['00100010']),
|
patientName: DICOMWeb.getName(anInstance['00100010']),
|
||||||
patientId: DICOMWeb.getString(anInstance['00100020']),
|
patientId: DICOMWeb.getString(anInstance['00100020']),
|
||||||
patientAge: DICOMWeb.getNumber(anInstance['00101010']),
|
patientAge: DICOMWeb.getNumber(anInstance['00101010']),
|
||||||
@ -230,9 +252,12 @@ async function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
|
|||||||
institutionName: DICOMWeb.getString(anInstance['00080080'])
|
institutionName: DICOMWeb.getString(anInstance['00080080'])
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const seriesMap = {};
|
||||||
|
|
||||||
await Promise.all(resultData.map(async function(instance) {
|
await Promise.all(resultData.map(async function(instance) {
|
||||||
var seriesInstanceUid = DICOMWeb.getString(instance['0020000E']);
|
const seriesInstanceUid = DICOMWeb.getString(instance['0020000E']);
|
||||||
var series = seriesMap[seriesInstanceUid];
|
let series = seriesMap[seriesInstanceUid];
|
||||||
|
|
||||||
if (!series) {
|
if (!series) {
|
||||||
series = {
|
series = {
|
||||||
seriesDescription: DICOMWeb.getString(instance['0008103E']),
|
seriesDescription: DICOMWeb.getString(instance['0008103E']),
|
||||||
@ -244,7 +269,7 @@ async function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
|
|||||||
instances: []
|
instances: []
|
||||||
};
|
};
|
||||||
seriesMap[seriesInstanceUid] = series;
|
seriesMap[seriesInstanceUid] = series;
|
||||||
seriesList.push(series);
|
studyData.seriesList.push(series);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sopInstanceUid = DICOMWeb.getString(instance['00080018']);
|
const sopInstanceUid = DICOMWeb.getString(instance['00080018']);
|
||||||
@ -331,22 +356,23 @@ async function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieved Study MetaData from a DICOM server using a WADO call
|
* Retrieve Study MetaData from a DICOM server using a WADO call
|
||||||
|
*
|
||||||
* @param server
|
* @param server
|
||||||
* @param studyInstanceUid
|
* @param studyInstanceUid
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
OHIF.studies.services.WADO.RetrieveMetadata = async function(server, studyInstanceUid) {
|
OHIF.studies.services.WADO.RetrieveMetadata = async function(server, studyInstanceUid) {
|
||||||
const url = buildUrl(server, studyInstanceUid);
|
const config = {
|
||||||
|
url: server.wadoRoot,
|
||||||
|
headers: OHIF.DICOMWeb.getAuthorizationHeader()
|
||||||
|
};
|
||||||
|
const dicomWeb = new DICOMwebClient.api.DICOMwebClient(config);
|
||||||
|
const options = {
|
||||||
|
studyInstanceUID: studyInstanceUid
|
||||||
|
};
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return dicomWeb.retrieveStudyMetadata(options).then(result => {
|
||||||
DICOMWeb.getJSON(url, server.requestOptions).then(result => {
|
return resultDataToStudyMetadata(server, studyInstanceUid, result);
|
||||||
resultDataToStudyMetadata(server, studyInstanceUid, result).then((study) => {
|
|
||||||
study.wadoUriRoot = server.wadoUriRoot;
|
|
||||||
study.studyInstanceUid = studyInstanceUid;
|
|
||||||
|
|
||||||
resolve(study);
|
|
||||||
}, reject);
|
|
||||||
}, reject);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,11 +5,13 @@ Package.describe({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Npm.depends({
|
Npm.depends({
|
||||||
dimse: '0.0.2'
|
dimse: '0.0.2',
|
||||||
})
|
'dicomweb-client': '0.3.2',
|
||||||
|
'xhr2': '0.1.4'
|
||||||
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.6');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
api.use([
|
api.use([
|
||||||
'ecmascript',
|
'ecmascript',
|
||||||
@ -24,7 +26,6 @@ Package.onUse(function(api) {
|
|||||||
'ohif:core',
|
'ohif:core',
|
||||||
'ohif:log',
|
'ohif:log',
|
||||||
'ohif:servers',
|
'ohif:servers',
|
||||||
'ohif:dicomweb-client',
|
|
||||||
'ohif:viewerbase',
|
'ohif:viewerbase',
|
||||||
'ohif:wadoproxy'
|
'ohif:wadoproxy'
|
||||||
]);
|
]);
|
||||||
|
|||||||
@ -15,7 +15,6 @@ Template.studylistResult.helpers({
|
|||||||
*/
|
*/
|
||||||
studies() {
|
studies() {
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
let studies;
|
|
||||||
let sortOption = {
|
let sortOption = {
|
||||||
patientName: 1,
|
patientName: 1,
|
||||||
studyDate: 1
|
studyDate: 1
|
||||||
@ -32,7 +31,7 @@ Template.studylistResult.helpers({
|
|||||||
const offset = rowsPerPage * currentPage;
|
const offset = rowsPerPage * currentPage;
|
||||||
const limit = offset + rowsPerPage;
|
const limit = offset + rowsPerPage;
|
||||||
|
|
||||||
studies = OHIF.studylist.collections.Studies.find({}, {
|
const studies = OHIF.studylist.collections.Studies.find({}, {
|
||||||
sort: sortOption
|
sort: sortOption
|
||||||
}).fetch();
|
}).fetch();
|
||||||
|
|
||||||
@ -90,17 +89,6 @@ function getFilter(filter) {
|
|||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Search for a value in a string
|
|
||||||
*/
|
|
||||||
function isIndexOf(mainVal, searchVal) {
|
|
||||||
if (mainVal === undefined || mainVal === '' || mainVal.indexOf(searchVal) > -1){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replace object if undefined
|
* Replace object if undefined
|
||||||
*/
|
*/
|
||||||
@ -167,10 +155,21 @@ function search() {
|
|||||||
|
|
||||||
// Loop through all identified studies
|
// Loop through all identified studies
|
||||||
studies.forEach(study => {
|
studies.forEach(study => {
|
||||||
|
// TODO: Why is this Modality filter different from QIDO?
|
||||||
|
if (modality !== "" && study.modalities.includes(modality)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sometimes DICOM studies have incorrect Date entries with
|
||||||
|
// periods such as '1990.10.04'
|
||||||
|
let studyDate = study.studyDate;
|
||||||
|
if (studyDate && studyDate.includes('.')) {
|
||||||
|
studyDate = studyDate.replace('.', '');
|
||||||
|
}
|
||||||
|
|
||||||
// Search the rest of the parameters that aren't done via the server call
|
// Search the rest of the parameters that aren't done via the server call
|
||||||
if (isIndexOf(study.modalities, modality) &&
|
if ((new Date(studyDateFrom).setHours(0, 0, 0, 0) <= studyDate || !studyDateFrom ) &&
|
||||||
(new Date(studyDateFrom).setHours(0, 0, 0, 0) <= convertStringToStudyDate(study.studyDate) || !studyDateFrom || studyDateFrom === '') &&
|
(studyDate <= new Date(studyDateTo).setHours(0, 0, 0, 0) || !studyDateTo || studyDateTo === '')) {
|
||||||
(convertStringToStudyDate(study.studyDate) <= new Date(studyDateTo).setHours(0, 0, 0, 0) || !studyDateTo || studyDateTo === '')) {
|
|
||||||
|
|
||||||
// Convert numberOfStudyRelatedInstance string into integer
|
// Convert numberOfStudyRelatedInstance string into integer
|
||||||
study.numberOfStudyRelatedInstances = !isNaN(study.numberOfStudyRelatedInstances) ? parseInt(study.numberOfStudyRelatedInstances) : undefined;
|
study.numberOfStudyRelatedInstances = !isNaN(study.numberOfStudyRelatedInstances) ? parseInt(study.numberOfStudyRelatedInstances) : undefined;
|
||||||
|
|||||||
@ -10,7 +10,7 @@ Package.describe({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.4');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
api.use('ecmascript');
|
api.use('ecmascript');
|
||||||
api.use('standard-app-packages');
|
api.use('standard-app-packages');
|
||||||
|
|||||||
@ -5,7 +5,7 @@ Package.describe({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.4.2.3');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
api.use('ecmascript');
|
api.use('ecmascript');
|
||||||
api.use('templating');
|
api.use('templating');
|
||||||
|
|||||||
@ -5,7 +5,7 @@ Package.describe({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.4.2.3');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
api.use('stylus');
|
api.use('stylus');
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ Package.describe({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.4');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
api.use('ecmascript');
|
api.use('ecmascript');
|
||||||
api.use('standard-app-packages');
|
api.use('standard-app-packages');
|
||||||
|
|||||||
@ -5,7 +5,7 @@ Package.describe({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.4');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
api.use(['ecmascript',
|
api.use(['ecmascript',
|
||||||
'standard-app-packages',
|
'standard-app-packages',
|
||||||
@ -218,7 +218,7 @@ Package.onUse(function(api) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onTest(function(api) {
|
Package.onTest(function(api) {
|
||||||
api.versionsFrom('1.4');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Really important dependencies to the project
|
* Really important dependencies to the project
|
||||||
|
|||||||
@ -10,7 +10,7 @@ Npm.depends({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.4');
|
api.versionsFrom('1.7');
|
||||||
|
|
||||||
api.use('ecmascript');
|
api.use('ecmascript');
|
||||||
api.use('clinical:router@2.0.19');
|
api.use('clinical:router@2.0.19');
|
||||||
@ -22,7 +22,7 @@ Package.onUse(function(api) {
|
|||||||
api.addFiles('both/convertURL.js', ['client', 'server']);
|
api.addFiles('both/convertURL.js', ['client', 'server']);
|
||||||
api.addFiles('both/initialize.js', ['client', 'server']);
|
api.addFiles('both/initialize.js', ['client', 'server']);
|
||||||
api.addFiles('server/routes.js', 'server');
|
api.addFiles('server/routes.js', 'server');
|
||||||
|
|
||||||
// Global exports
|
// Global exports
|
||||||
api.export('WADOProxy');
|
api.export('WADOProxy');
|
||||||
});
|
});
|
||||||
|
|||||||
@ -27,7 +27,6 @@ ohif:cornerstone-settings
|
|||||||
ohif:viewerbase
|
ohif:viewerbase
|
||||||
ohif:metadata
|
ohif:metadata
|
||||||
ohif:study-list
|
ohif:study-list
|
||||||
ohif:dicomweb-client
|
|
||||||
ohif:measurement-table
|
ohif:measurement-table
|
||||||
|
|
||||||
aldeed:template-extension
|
aldeed:template-extension
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
accounts-base@1.4.2
|
|
||||||
aldeed:collection2@2.10.0
|
aldeed:collection2@2.10.0
|
||||||
aldeed:collection2-core@1.2.0
|
aldeed:collection2-core@1.2.0
|
||||||
aldeed:schema-deny@1.1.0
|
aldeed:schema-deny@1.1.0
|
||||||
@ -28,7 +27,6 @@ cultofcoders:persistent-session@0.4.5
|
|||||||
ddp@1.4.0
|
ddp@1.4.0
|
||||||
ddp-client@2.3.3
|
ddp-client@2.3.3
|
||||||
ddp-common@1.4.0
|
ddp-common@1.4.0
|
||||||
ddp-rate-limiter@1.0.7
|
|
||||||
ddp-server@2.2.0
|
ddp-server@2.2.0
|
||||||
deps@1.0.12
|
deps@1.0.12
|
||||||
diff-sequence@1.1.0
|
diff-sequence@1.1.0
|
||||||
@ -54,7 +52,6 @@ iron:layout@1.0.12
|
|||||||
jquery@1.11.11
|
jquery@1.11.11
|
||||||
launch-screen@1.1.1
|
launch-screen@1.1.1
|
||||||
livedata@1.0.18
|
livedata@1.0.18
|
||||||
localstorage@1.2.0
|
|
||||||
logging@1.1.20
|
logging@1.1.20
|
||||||
mdg:validation-error@0.5.1
|
mdg:validation-error@0.5.1
|
||||||
meteor@1.9.2
|
meteor@1.9.2
|
||||||
@ -81,7 +78,6 @@ ohif:core@0.0.1
|
|||||||
ohif:cornerstone@0.0.1
|
ohif:cornerstone@0.0.1
|
||||||
ohif:cornerstone-settings@0.0.1
|
ohif:cornerstone-settings@0.0.1
|
||||||
ohif:design@0.0.1
|
ohif:design@0.0.1
|
||||||
ohif:dicomweb-client@0.0.1
|
|
||||||
ohif:hanging-protocols@0.0.1
|
ohif:hanging-protocols@0.0.1
|
||||||
ohif:header@0.0.1
|
ohif:header@0.0.1
|
||||||
ohif:hotkeys@0.0.1
|
ohif:hotkeys@0.0.1
|
||||||
@ -102,13 +98,11 @@ ordered-dict@1.1.0
|
|||||||
promise@0.11.1
|
promise@0.11.1
|
||||||
raix:eventemitter@0.1.3
|
raix:eventemitter@0.1.3
|
||||||
random@1.1.0
|
random@1.1.0
|
||||||
rate-limit@1.0.9
|
|
||||||
reactive-dict@1.2.0
|
reactive-dict@1.2.0
|
||||||
reactive-var@1.0.11
|
reactive-var@1.0.11
|
||||||
reload@1.2.0
|
reload@1.2.0
|
||||||
retry@1.1.0
|
retry@1.1.0
|
||||||
routepolicy@1.0.13
|
routepolicy@1.0.13
|
||||||
service-configuration@1.0.11
|
|
||||||
session@1.1.7
|
session@1.1.7
|
||||||
shell-server@0.3.1
|
shell-server@0.3.1
|
||||||
silentcicero:jszip@0.0.4
|
silentcicero:jszip@0.0.4
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
"wadoUriRoot": "http://localhost:8042/wado",
|
"wadoUriRoot": "http://localhost:8042/wado",
|
||||||
"qidoRoot": "http://localhost:8042/dicom-web",
|
"qidoRoot": "http://localhost:8042/dicom-web",
|
||||||
"wadoRoot": "http://localhost:8042/dicom-web",
|
"wadoRoot": "http://localhost:8042/dicom-web",
|
||||||
"qidoSupportsIncludeField": false,
|
"qidoSupportsIncludeField": true,
|
||||||
"imageRendering": "wadouri",
|
"imageRendering": "wadouri",
|
||||||
"thumbnailRendering": "wadouri",
|
"thumbnailRendering": "wadouri",
|
||||||
"requestOptions": {
|
"requestOptions": {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user