// add a decache callback function to clear out our dataSetCacheManager
function addDecache(image) {
image.decache = function() {
//console.log('decache');
var parsedImageId = cornerstoneWADOImageLoader.wadouri.parseImageId(image.imageId);
cornerstoneWADOImageLoader.wadouri.dataSetCacheManager.unload(parsedImageId.url);
};
}
function getPixelData(dataSet, frameIndex) {
var pixelDataElement = dataSet.elements.x7fe00010;
function loadImage(imageId, options) {
var parsedImageId = cornerstoneWADOImageLoader.wadouri.parseImageId(imageId);
var loader = getLoaderForScheme(parsedImageId.scheme);
// if the dataset for this url is already loaded, use it
if(cornerstoneWADOImageLoader.wadouri.dataSetCacheManager.isLoaded(parsedImageId.url)) {
return loadDataSetFromPromise(cornerstoneWADOImageLoader.wadouri.dataSetCacheManager.load(parsedImageId.url, loader, imageId), imageId, parsedImageId.frame, parsedImageId.url, options);
}
// load the dataSet via the dataSetCacheManager
return loadDataSetFromPromise(cornerstoneWADOImageLoader.wadouri.dataSetCacheManager.load(parsedImageId.url, loader, imageId), imageId, parsedImageId.frame, parsedImageId.url, options);
function convertPALETTECOLOR( imageFrame, rgbaBuffer ) {
var numPixels = imageFrame.columns * imageFrame.rows;
var palIndex=0;
var rgbaIndex=0;
var pixelData = imageFrame.pixelData;
var start = imageFrame.redPaletteColorLookupTableDescriptor[1];
var rData = imageFrame.redPaletteColorLookupTableData;
var gData = imageFrame.greenPaletteColorLookupTableData;
var bData = imageFrame.bluePaletteColorLookupTableData;
var shift = imageFrame.redPaletteColorLookupTableDescriptor[2] === 8 ? 0 : 8;
var len = imageFrame.redPaletteColorLookupTableData.length;
if(len === 0) {
len = 65535;
}
for( var i=0 ; i < numPixels ; ++i ) {
var value=pixelData[palIndex++];
if( value < start )
value=0;
else if( value > start + len -1 )
value=len-1;
else
value=value-start;
rgbaBuffer[ rgbaIndex++ ] = rData[value] >> shift;
rgbaBuffer[ rgbaIndex++ ] = gData[value] >> shift;
rgbaBuffer[ rgbaIndex++ ] = bData[value] >> shift;
rgbaBuffer[ rgbaIndex++ ] = 255;
}
function convertRGBColorByPlane(imageFrame, rgbaBuffer) {
if(imageFrame === undefined) {
throw "decodeRGB: rgbBuffer must not be undefined";
}
if(imageFrame.length % 3 !== 0) {
throw "decodeRGB: rgbBuffer length must be divisible by 3";
}
var numPixels = imageFrame.length / 3;
var rgbaIndex = 0;
var rIndex = 0;
var gIndex = numPixels;
var bIndex = numPixels*2;
for(var i= 0; i < numPixels; i++) {
rgbaBuffer[rgbaIndex++] = imageFrame[rIndex++]; // red
rgbaBuffer[rgbaIndex++] = imageFrame[gIndex++]; // green
rgbaBuffer[rgbaIndex++] = imageFrame[bIndex++]; // blue
rgbaBuffer[rgbaIndex++] = 255; //alpha
}
function convertYBRFullByPlane(imageFrame, rgbaBuffer) {
if (imageFrame === undefined) {
throw "decodeRGB: ybrBuffer must not be undefined";
}
if (imageFrame.length % 3 !== 0) {
throw "decodeRGB: ybrBuffer length must be divisble by 3";
}
var numPixels = imageFrame.length / 3;
var rgbaIndex = 0;
var yIndex = 0;
var cbIndex = numPixels;
var crIndex = numPixels * 2;
for (var i = 0; i < numPixels; i++) {
var y = imageFrame[yIndex++];
var cb = imageFrame[cbIndex++];
var cr = imageFrame[crIndex++];
rgbaBuffer[rgbaIndex++] = y + 1.40200 * (cr - 128);// red
rgbaBuffer[rgbaIndex++] = y - 0.34414 * (cb - 128) - 0.71414 * (cr - 128); // green
rgbaBuffer[rgbaIndex++] = y + 1.77200 * (cb - 128); // blue
rgbaBuffer[rgbaIndex++] = 255; //alpha
}
Helper function to set pixel data to the right typed array. This is needed because web workers
can transfer array buffers but not typed arrays
@param imageFrame
*/
function setPixelDataType(imageFrame) {
if(imageFrame.bitsAllocated === 16) {
if(imageFrame.pixelRepresentation === 0) {
imageFrame.pixelData = new Uint16Array(imageFrame.pixelData);
} else {
imageFrame.pixelData = new Int16Array(imageFrame.pixelData);
}
} else {
imageFrame.pixelData = new Uint8Array(imageFrame.pixelData);
}
}
function createImage(imageId, pixelData, transferSyntax, options) {
var deferred = $.Deferred();
var imageFrame = cornerstoneWADOImageLoader.getImageFrame(imageId);
var decodePromise = cornerstoneWADOImageLoader.decodeImageFrame(imageFrame, transferSyntax, pixelData, canvas, options);
decodePromise.then(function(imageFrame) {
//var imagePixelModule = metaDataProvider('imagePixelModule', imageId);
var imagePlaneModule = cornerstone.metaData.get('imagePlaneModule', imageId);
var voiLutModule = cornerstone.metaData.get('voiLutModule', imageId);
var modalityLutModule = cornerstone.metaData.get('modalityLutModule', imageId);
var sopCommonModule = cornerstone.metaData.get('sopCommonModule', imageId);
var isColorImage = cornerstoneWADOImageLoader.isColorImage(imageFrame.photometricInterpretation);
// JPEGBaseline (8 bits) is already returning the pixel data in the right format (rgba)
// because it's using a canvas to load and decode images.
if(!cornerstoneWADOImageLoader.isJPEGBaseline8BitColor(imageFrame, transferSyntax)) {
setPixelDataType(imageFrame);
// convert color space
if(isColorImage) {
// setup the canvas context
canvas.height = imageFrame.rows;
canvas.width = imageFrame.columns;
var context = canvas.getContext('2d');
var imageData = context.createImageData(imageFrame.columns, imageFrame.rows);
cornerstoneWADOImageLoader.convertColorSpace(imageFrame, imageData);
imageFrame.imageData = imageData;
imageFrame.pixelData = imageData.data;
}
Special decoder for 8 bit jpeg that leverages the browser's built in JPEG decoder for increased performance
*/
(function ($, cornerstoneWADOImageLoader) {
"use strict";
function arrayBufferToString(buffer) {
return binaryToString(String.fromCharCode.apply(null, Array.prototype.slice.apply(new Uint8Array(buffer))));
}
function decodeJPEGBaseline8BitColor(imageFrame, pixelData, canvas) {
var start = new Date().getTime();
var deferred = $.Deferred();
var imgBlob = new Blob([pixelData], {type: "image/jpeg"});
var r = new FileReader();
if(r.readAsBinaryString === undefined) {
r.readAsArrayBuffer(imgBlob);
}
else {
r.readAsBinaryString(imgBlob); // doesn't work on IE11
}
r.onload = function(){
var img=new Image();
img.onload = function() {
canvas.height = img.height;
canvas.width = img.width;
imageFrame.rows = img.height;
imageFrame.columns = img.width;
var context = canvas.getContext('2d');
context.drawImage(this, 0, 0);
var imageData = context.getImageData(0, 0, img.width, img.height);
var end = new Date().getTime();
imageFrame.pixelData = imageData.data;
imageFrame.imageData = imageData;
imageFrame.decodeTimeInMS = end - start;
deferred.resolve(imageFrame);
};
img.onerror = function(error) {
deferred.reject(error);
};
if(r.readAsBinaryString === undefined) {
img.src = "data:image/jpeg;base64,"+window.btoa(arrayBufferToString(r.result));
}
else {
img.src = "data:image/jpeg;base64,"+window.btoa(r.result); // doesn't work on IE11
}
};
return deferred.promise();
}
function isJPEGBaseline8BitColor(imageFrame, transferSyntax) {
transferSyntax = transferSyntax || imageFrame.transferSyntax;
function getMinMax(storedPixelData)
{
// we always calculate the min max values since they are not always
// present in DICOM and we don't want to trust them anyway as cornerstone
// depends on us providing reliable values for these
var min = storedPixelData[0];
var max = storedPixelData[0];
var storedPixel;
var numPixels = storedPixelData.length;
for(var index = 0; index < numPixels; index++) {
storedPixel = storedPixelData[index];
min = Math.min(min, storedPixel);
max = Math.max(max, storedPixel);
}
var deferred = $.Deferred();
var loadPromise = cornerstoneWADOImageLoader.internal.xhrRequest(uri, imageId, headers);
loadPromise.then(function(imageFrameAsArrayBuffer/*, xhr*/) {
// request succeeded, Parse the multi-part mime response
var response = new Uint8Array(imageFrameAsArrayBuffer);
// First look for the multipart mime header
var tokenIndex = cornerstoneWADOImageLoader.wadors.findIndexOfString(response, '\r\n\r\n');
if(tokenIndex === -1) {
deferred.reject('invalid response - no multipart mime header');
}
var header = uint8ArrayToString(response, 0, tokenIndex);
// Now find the boundary marker
var split = header.split('\r\n');
var boundary = findBoundary(split);
if(!boundary) {
deferred.reject('invalid response - no boundary marker')
}
var offset = tokenIndex + 4; // skip over the \r\n\r\n
// find the terminal boundary marker
var endIndex = cornerstoneWADOImageLoader.wadors.findIndexOfString(response, boundary, offset);
if(endIndex === -1) {
deferred.reject('invalid response - terminating boundary not found');
}
// Remove \r\n from the length
var length = endIndex - offset - 2;
// return the info for this pixel data
deferred.resolve({
contentType: findContentType(split),
imageFrame: {
pixelData: new Uint8Array(imageFrameAsArrayBuffer, offset, length)
}
});
});
return deferred.promise();
function getTransferSyntaxForContentType(contentType) {
return '1.2.840.10008.1.2'; // hard code to ILE for now
}
function loadImage(imageId, options) {
var start = new Date().getTime();
var deferred = $.Deferred();
var uri = imageId.substring(7);
// check to make sure we have metadata for this imageId
var metaData = cornerstoneWADOImageLoader.wadors.metaDataManager.get(imageId);
if(metaData === undefined) {
deferred.reject('no metadata for imageId ' + imageId);
return deferred.promise();
}
// TODO: load bulk data items that we might need
var mediaType = 'multipart/related; type="application/octet-stream"'; // 'image/dicom+jp2';
// get the pixel data from the server
cornerstoneWADOImageLoader.wadors.getPixelData(uri, imageId, mediaType).then(function(result) {
var transferSyntax = getTransferSyntaxForContentType(result.contentType);
var pixelData = result.imageFrame.pixelData;
var imagePromise = cornerstoneWADOImageLoader.createImage(imageId, pixelData, transferSyntax, options);
imagePromise.then(function(image) {
// add the loadTimeInMS property
var end = new Date().getTime();
image.loadTimeInMS = end - start;
deferred.resolve(image);
})
}).fail(function(reason) {
deferred.reject(reason);
});
return deferred;
Returns the values as an array of javascript numbers
@param element - The javascript object for the specified element in the metadata
@param [minimumLength] - the minimum number of values
@returns {}
/
function getNumberValues(element, minimumLength) {
if (!element) {
return;
}
// Value is not present if the attribute has a zero length value
if (!element.Value) {
return;
}
// make sure we have the expected length
if (minimumLength && element.Value.length < minimumLength) {
return;
}
var values = [];
for(var i=0; i < element.Value.length; i++) {
values.push(parseFloat(element.Value[i]));
}
return values;
}
@param element - The javascript object for the specified element in the metadata
@param [index] - the index of the value in a multi-valued element, default is 0
@param [defaultValue] - The default value to return if the element does not exist
@returns {}
/
function getValue(element, index, defaultValue) {
index = index || 0;
if (!element) {
return defaultValue;
}
// Value is not present if the attribute has a zero length value
if (!element.Value) {
return defaultValue;
}
// make sure we have the specified index
if (element.Value.length <= index ) {
return defaultValue;
}
return element.Value[index];
}
var getNumberValues = cornerstoneWADOImageLoader.wadors.getNumberValues;
var getValue = cornerstoneWADOImageLoader.wadors.getValue;
var getNumberValue = cornerstoneWADOImageLoader.wadors.getNumberValue;
function metaDataProvider(type, imageId) {
var metaData = cornerstoneWADOImageLoader.wadors.metaDataManager.get(imageId);
if(!metaData) {
return;
}
// if already loaded return it right away
if(loadedDataSets[uri]) {
//console.log('using loaded dataset ' + uri);
var alreadyLoadedpromise = $.Deferred();
loadedDataSets[uri].cacheCount++;
alreadyLoadedpromise.resolve(loadedDataSets[uri].dataSet);
return alreadyLoadedpromise;
}
// if we are currently loading this uri, return its promise
if(promises[uri]) {
//console.log('returning existing load promise for ' + uri);
return promises[uri];
}
//console.log('loading ' + uri);
// This uri is not loaded or being loaded, load it via an xhrRequest
var promise = loadRequest(uri, imageId);
// handle success and failure of the XHR request load
var loadDeferred = $.Deferred();
promise.then(function(dicomPart10AsArrayBuffer/, xhr/) {
var byteArray = new Uint8Array(dicomPart10AsArrayBuffer);
// Reject the promise if parsing the dicom file fails
var dataSet;
try {
dataSet = dicomParser.parseDicom(byteArray);
} catch(error) {
loadDeferred.reject(error);
return;
}
Function to deal with extracting an image frame from an encapsulated data set.
*/
(function ($, cornerstone, cornerstoneWADOImageLoader) {
"use strict";
function getUncompressedImageFrame(dataSet, frameIndex) {
var pixelDataElement = dataSet.elements.x7fe00010;
var bitsAllocated = dataSet.uint16('x00280100');
var rows = dataSet.uint16('x00280010');
var columns = dataSet.uint16('x00280011');
var samplesPerPixel = dataSet.uint16('x00280002');
var pixelDataOffset = pixelDataElement.dataOffset;
var pixelsPerFrame = rows columns samplesPerPixel;
var parsedImageId = cornerstoneWADOImageLoader.wadouri.parseImageId(uri);
var fileIndex = parseInt(parsedImageId.url);
var file = cornerstoneWADOImageLoader.wadouri.fileManager.get(fileIndex);
// create a deferred object
var deferred = $.Deferred();
var fileReader = new FileReader();
fileReader.onload = function (e) {
var dicomPart10AsArrayBuffer = e.target.result;
deferred.resolve(dicomPart10AsArrayBuffer);
};
fileReader.readAsArrayBuffer(file);
function getMinStoredPixelValue(dataSet) {
var pixelRepresentation = dataSet.uint16('x00280103');
var bitsStored = dataSet.uint16('x00280101');
if(pixelRepresentation === 0) {
return 0;
}
return -1 << (bitsStored -1);
}
// 0 = unsigned / US, 1 = signed / SS
function getModalityLUTOutputPixelRepresentation(dataSet) {
// CT SOP Classes are always signed
var sopClassUID = dataSet.string('x00080016');
if(sopClassUID === '1.2.840.10008.5.1.4.1.1.2' ||
sopClassUID === '1.2.840.10008.5.1.4.1.1.2.1') {
return 1;
}
// if rescale intercept and rescale slope are present, pass the minimum stored
// pixel value through them to see if we get a signed output range
var rescaleIntercept = dataSet.floatString('x00281052');
var rescaleSlope = dataSet.floatString('x00281053');
if(rescaleIntercept !== undefined && rescaleSlope !== undefined) {
var minStoredPixelValue = getMinStoredPixelValue(dataSet); //
var minModalityLutValue = minStoredPixelValue * rescaleSlope + rescaleIntercept;
if (minModalityLutValue < 0) {
return 1;
} else {
return 0;
}
}
// Output of non linear modality lut is always unsigned
if(dataSet.elements.x00283000 && dataSet.elements.x00283000.length > 0) {
return 0;
}
// If no modality lut transform, output is same as pixel representation
return dataSet.uint16('x00280103');
"use strict";
function parseImageId(imageId) {
// build a url by parsing out the url scheme and frame index from the imageId
var firstColonIndex = imageId.indexOf(':');
var url = imageId.substring(firstColonIndex + 1);
var frameIndex = url.indexOf('frame=');
var frame;
if(frameIndex !== -1) {
var frameStr = url.substr(frameIndex + 6);
frame = parseInt(frameStr);
url = url.substr(0, frameIndex-1);
}
return {
scheme: imageId.substr(0, firstColonIndex),
url : url,
frame: frame
};
}
function unpackBinaryFrame(byteArray, frameOffset, pixelsPerFrame) {
// Create a new pixel array given the image size
var pixelData = new Uint8Array(pixelsPerFrame);
for (var i = 0; i < pixelsPerFrame; i++) {
// Compute byte position
var bytePos = Math.floor(i / 8);
// Get the current byte
var byte = byteArray[bytePos + frameOffset];
// Bit position (0-7) within byte
var bitPos = (i % 8);
// Check whether bit at bitpos is set
pixelData[i] = isBitSet(byte, bitPos) ? 1 : 0;
}
Function to start a task on a web worker
*/
function startTaskOnWebWorker() {
// return immediately if no decode tasks to do
if(!tasks.length) {
return;
}
// look for a web worker that is ready
for(var i=0; i < webWorkers.length; i++) {
{
if(webWorkers[i].status === 'ready') {
// mark it as busy so tasks are not assigned to it
webWorkers[i].status = 'busy';
// get the highest priority task
var task = tasks.shift();
task.start = new Date().getTime();
// update stats with how long this task was delayed (waiting in queue)
var end = new Date().getTime();
statistics.totalTimeDelayedInMS += end - task.added;
// assign this task to this web worker and send the web worker
// a message to execute it
webWorkers[i].task = task;
webWorkers[i].worker.postMessage({
taskType: task.taskType,
workerIndex: i,
data: task.data
}, task.transferList);
statistics.numTasksExecuting++;
return;
}
}
}
// if no available web workers and we haven't started max web workers, start a new one
if(webWorkers.length < config.maxWebWorkers) {
spawnWebWorker();
}
}
/**
Function to handle a message from a web worker
@param msg
*/
function handleMessageFromWorker(msg) {
//console.log('handleMessageFromWorker', msg.data);
if(msg.data.taskType === 'initialize') {
webWorkers[msg.data.workerIndex].status = 'ready';
startTaskOnWebWorker();
} else {
statistics.numTasksExecuting--;
webWorkers[msg.data.workerIndex].status = 'ready';
statistics.numTasksCompleted++;
var end = new Date().getTime();
statistics.totalTaskTimeInMS += end - webWorkers[msg.data.workerIndex].task.start;
webWorkers[msg.data.workerIndex].task.deferred.resolve(msg.data.result);
webWorkers[msg.data.workerIndex].task = undefined;
startTaskOnWebWorker();
}
}
/**
Spawns a new web worker
*/
function spawnWebWorker() {
// prevent exceeding maxWebWorkers
if(webWorkers.length >= config.maxWebWorkers) {
return;
}
// spawn the webworker
var worker = new Worker(config.webWorkerPath);
webWorkers.push({
worker: worker,
status: 'initializing'
});
worker.addEventListener('message', handleMessageFromWorker);
worker.postMessage({
taskType: 'initialize',
workerIndex: webWorkers.length - 1,
config: config
});
}
/**
Initialization function for the web worker manager - spawns web workers
// Spawn new web workers
if(!config.startWebWorkersOnDemand) {
for(var i=0; i < config.maxWebWorkers; i++) {
spawnWebWorker();
}
}
}
/**
dynamically loads a web worker task
@param sourcePath
@param taskConfig
*/
function loadWebWorkerTask(sourcePath, taskConfig) {
// add it to the list of web worker tasks paths so on demand web workers
// load this properly
config.webWorkerTaskPaths.push(sourcePath);
// if a task specific configuration is provided, merge it into the config
if(taskConfig) {
config.taskConfiguration = Object.assign(config.taskConfiguration, taskConfig);
}
// tell each spawned web worker to load this task
for(var i=0; i < webWorkers.length; i++) {
webWorkers[i].worker.postMessage({
taskType: 'loadWebWorkerTask',
workerIndex: webWorkers.length - 1,
sourcePath: sourcePath,
config: config
});
}
}
/**
Function to add a decode task to be performed
@param taskType - the taskType for this task
@param data - data specific to the task
@param priority - optional priority of the task (defaults to 0), > 0 is higher, < 0 is lower
@param transferList - optional array of data to transfer to web worker
@returns {}
/
function addTask(taskType, data, priority, transferList) {
if (!config) {
initialize();
}
priority = priority || 0;
var deferred = $.Deferred();
// find the right spot to insert this decode task (based on priority)
for (var i = 0; i < tasks.length; i++) {
if (tasks[i].priority <= priority) {
break;
}
}
var taskId = nextTaskId++;
// insert the decode task at position i
tasks.splice(i, 0, {
taskId: taskId,
taskType: taskType,
status: 'ready',
added: new Date().getTime(),
data: data,
deferred: deferred,
priority: priority,
transferList: transferList
});
// try to start a task on the web worker since we just added a new task and a web worker may be available
startTaskOnWebWorker();
@param taskId - the taskId to change the priority of
@param priority - priority of the task (defaults to 0), > 0 is higher, < 0 is lower
@returns boolean - true on success, false if taskId not found
*/
function setTaskPriority(taskId, priority) {
// search for this taskId
for (var i = 0; i < tasks.length; i++) {
if (tasks[i].taskId === taskId) {
// taskId found, remove it
var task = tasks.splice(i, 1)[0];
// set its prioirty
task.priority = priority;
// find the right spot to insert this decode task (based on priority)
for (i = 0; i < tasks.length; i++) {
if (tasks[i].priority <= priority) {
break;
}
}
// insert the decode task at position i
tasks.splice(i, 0, task);
return true;
}
}
return false;
}
/**
Cancels a queued task and rejects
@param taskId - the taskId to cancel
@param reason - optional reason the task was rejected
@returns boolean - true on success, false if taskId not found
*/
function cancelTask(taskId, reason) {
// search for this taskId
for (var i = 0; i < tasks.length; i++) {
if (tasks[i].taskId === taskId) {
// taskId found, remove it
var task = tasks.splice(i, 1);
task.promise.reject(reason);
return true;
}
}
return false;
}
/**
Function to return the statistics on running web workers
function xhrRequest(url, imageId, headers) {
headers = headers || {};
var deferred = $.Deferred();
// Make the request for the DICOM P10 SOP Instance
var xhr = new XMLHttpRequest();
xhr.open("get", url, true);
xhr.responseType = "arraybuffer";
cornerstoneWADOImageLoader.internal.options.beforeSend(xhr);
Object.keys(headers).forEach(function (key) {
xhr.setRequestHeader(key, headers[key]);
});
// handle response data
xhr.onreadystatechange = function () {
// TODO: consider sending out progress messages here as we receive the pixel data
if (xhr.readyState === 4) {
if (xhr.status === 200) {
deferred.resolve(xhr.response, xhr);
}
else {
// request failed, reject the deferred
deferred.reject(xhr);
}
}
};
xhr.onprogress = function (oProgress) {
// console.log('progress:',oProgress)
if (oProgress.lengthComputable) { //evt.loaded the bytes browser receive
//evt.total the total bytes seted by the header
//
var loaded = oProgress.loaded;
var total = oProgress.total;
var percentComplete = Math.round((loaded / total) * 100);
$(cornerstone).trigger('CornerstoneImageLoadProgress', {
imageId: imageId,
loaded: loaded,
total: total,
percentComplete: percentComplete
});
}
};
xhr.send();
return deferred.promise();
/! cornerstone-wado-image-loader - v0.14.3 - 2017-04-04 | (c) 2016 Chris Hafey | https://github.com/chafey/cornerstoneWADOImageLoader / // // This is a cornerstone image loader for WADO-URI requests. //
if(typeof cornerstone === 'undefined'){ cornerstone = {}; } if(typeof cornerstoneWADOImageLoader === 'undefined'){ cornerstoneWADOImageLoader = { wadouri: {
}; }
(function ($, cornerstone, cornerstoneWADOImageLoader) {
"use strict";
// add a decache callback function to clear out our dataSetCacheManager function addDecache(image) { image.decache = function() { //console.log('decache'); var parsedImageId = cornerstoneWADOImageLoader.wadouri.parseImageId(image.imageId); cornerstoneWADOImageLoader.wadouri.dataSetCacheManager.unload(parsedImageId.url); }; }
function getPixelData(dataSet, frameIndex) { var pixelDataElement = dataSet.elements.x7fe00010;
}
function loadDataSetFromPromise(xhrRequestPromise, imageId, frame, sharedCacheKey, options) {
}
function getLoaderForScheme(scheme) { if(scheme === 'dicomweb' || scheme === 'wadouri') { return cornerstoneWADOImageLoader.internal.xhrRequest; } else if(scheme === 'dicomfile') { return cornerstoneWADOImageLoader.wadouri.loadFileRequest; } }
function loadImage(imageId, options) { var parsedImageId = cornerstoneWADOImageLoader.wadouri.parseImageId(imageId);
}
// register dicomweb and wadouri image loader prefixes cornerstone.registerImageLoader('dicomweb', loadImage); cornerstone.registerImageLoader('wadouri', loadImage); cornerstone.registerImageLoader('dicomfile', loadImage); }($, cornerstone, cornerstoneWADOImageLoader)); (function (cornerstoneWADOImageLoader) {
"use strict";
function convertPALETTECOLOR( imageFrame, rgbaBuffer ) { var numPixels = imageFrame.columns * imageFrame.rows; var palIndex=0; var rgbaIndex=0; var pixelData = imageFrame.pixelData; var start = imageFrame.redPaletteColorLookupTableDescriptor[1]; var rData = imageFrame.redPaletteColorLookupTableData; var gData = imageFrame.greenPaletteColorLookupTableData; var bData = imageFrame.bluePaletteColorLookupTableData; var shift = imageFrame.redPaletteColorLookupTableDescriptor[2] === 8 ? 0 : 8; var len = imageFrame.redPaletteColorLookupTableData.length; if(len === 0) { len = 65535; }
}
// module exports cornerstoneWADOImageLoader.convertPALETTECOLOR = convertPALETTECOLOR;
}(cornerstoneWADOImageLoader)); /* / (function (cornerstoneWADOImageLoader) {
}(cornerstoneWADOImageLoader)); /* / (function (cornerstoneWADOImageLoader) {
"use strict";
function convertRGBColorByPlane(imageFrame, rgbaBuffer) { if(imageFrame === undefined) { throw "decodeRGB: rgbBuffer must not be undefined"; } if(imageFrame.length % 3 !== 0) { throw "decodeRGB: rgbBuffer length must be divisible by 3"; }
}
// module exports cornerstoneWADOImageLoader.convertRGBColorByPlane = convertRGBColorByPlane; }(cornerstoneWADOImageLoader)); /* / (function (cornerstoneWADOImageLoader) {
}(cornerstoneWADOImageLoader)); /* / (function (cornerstoneWADOImageLoader) {
"use strict";
function convertYBRFullByPlane(imageFrame, rgbaBuffer) { if (imageFrame === undefined) { throw "decodeRGB: ybrBuffer must not be undefined"; } if (imageFrame.length % 3 !== 0) { throw "decodeRGB: ybrBuffer length must be divisble by 3"; }
} // module exports cornerstoneWADOImageLoader.convertYBRFullByPlane = convertYBRFullByPlane; }(cornerstoneWADOImageLoader)); (function (cornerstoneWADOImageLoader) {
"use strict";
function configure(options) { cornerstoneWADOImageLoader.internal.options = options; }
// module exports cornerstoneWADOImageLoader.configure = configure;
}(cornerstoneWADOImageLoader)); (function (cornerstoneWADOImageLoader) {
"use strict";
function convertRGB(imageFrame, rgbaBuffer) { if(imageFrame.planarConfiguration === 0) { cornerstoneWADOImageLoader.convertRGBColorByPixel(imageFrame.pixelData, rgbaBuffer); } else { cornerstoneWADOImageLoader.convertRGBColorByPlane(imageFrame.pixelData, rgbaBuffer); } }
function convertYBRFull(imageFrame, rgbaBuffer) { if(imageFrame.planarConfiguration === 0) { cornerstoneWADOImageLoader.convertYBRFullByPixel(imageFrame.pixelData, rgbaBuffer); } else { cornerstoneWADOImageLoader.convertYBRFullByPlane(imageFrame.pixelData, rgbaBuffer); } }
function convertColorSpace(imageFrame, imageData) { var rgbaBuffer = imageData.data; console.time('convertColorSpace'); // convert based on the photometric interpretation if (imageFrame.photometricInterpretation === "RGB" ) { convertRGB(imageFrame, rgbaBuffer); } else if (imageFrame.photometricInterpretation === "YBR_RCT") { convertRGB(imageFrame, rgbaBuffer); } else if (imageFrame.photometricInterpretation === "YBR_ICT") { convertRGB(imageFrame, rgbaBuffer); } else if( imageFrame.photometricInterpretation === "PALETTE COLOR" ) { cornerstoneWADOImageLoader.convertPALETTECOLOR(imageFrame, rgbaBuffer); } else if( imageFrame.photometricInterpretation === "YBR_FULL_422" ) { convertRGB(imageFrame, rgbaBuffer); } else if(imageFrame.photometricInterpretation === "YBR_FULL" ) { convertYBRFull(imageFrame, rgbaBuffer); } else { throw "no color space conversion for photometric interpretation " + imageFrame.photometricInterpretation; } console.timeEnd('convertColorSpace'); }
// module exports cornerstoneWADOImageLoader.convertColorSpace = convertColorSpace;
}(cornerstoneWADOImageLoader)); /* / (function ($, cornerstone, cornerstoneWADOImageLoader) {
"use strict";
var canvas = document.createElement('canvas'); var lastImageIdDrawn = "";
function isModalityLUTForDisplay(sopClassUid) { // special case for XA and XRF // https://groups.google.com/forum/#!searchin/comp.protocols.dicom/Modality$20LUT$20XA/comp.protocols.dicom/UBxhOZ2anJ0/D0R_QP8V2wIJ return sopClassUid !== '1.2.840.10008.5.1.4.1.1.12.1' && // XA sopClassUid !== '1.2.840.10008.5.1.4.1.1.12.2.1 '; // XRF }
/**
@param imageFrame */ function setPixelDataType(imageFrame) { if(imageFrame.bitsAllocated === 16) { if(imageFrame.pixelRepresentation === 0) { imageFrame.pixelData = new Uint16Array(imageFrame.pixelData); } else { imageFrame.pixelData = new Int16Array(imageFrame.pixelData); } } else { imageFrame.pixelData = new Uint8Array(imageFrame.pixelData); } }
function createImage(imageId, pixelData, transferSyntax, options) { var deferred = $.Deferred(); var imageFrame = cornerstoneWADOImageLoader.getImageFrame(imageId); var decodePromise = cornerstoneWADOImageLoader.decodeImageFrame(imageFrame, transferSyntax, pixelData, canvas, options); decodePromise.then(function(imageFrame) { //var imagePixelModule = metaDataProvider('imagePixelModule', imageId); var imagePlaneModule = cornerstone.metaData.get('imagePlaneModule', imageId); var voiLutModule = cornerstone.metaData.get('voiLutModule', imageId); var modalityLutModule = cornerstone.metaData.get('modalityLutModule', imageId); var sopCommonModule = cornerstone.metaData.get('sopCommonModule', imageId); var isColorImage = cornerstoneWADOImageLoader.isColorImage(imageFrame.photometricInterpretation);
// JPEGBaseline (8 bits) is already returning the pixel data in the right format (rgba) // because it's using a canvas to load and decode images. if(!cornerstoneWADOImageLoader.isJPEGBaseline8BitColor(imageFrame, transferSyntax)) { setPixelDataType(imageFrame);
}
var image = { imageId: imageId, color: isColorImage, columnPixelSpacing: imagePlaneModule.pixelSpacing ? imagePlaneModule.pixelSpacing[1] : undefined, columns: imageFrame.columns, height: imageFrame.rows, intercept: modalityLutModule.rescaleIntercept ? modalityLutModule.rescaleIntercept: 0, invert: imageFrame.photometricInterpretation === "MONOCHROME1", minPixelValue :imageFrame.smallestPixelValue ? imageFrame.smallestPixelValue : undefined,//undefined,//imageFrame.smallestPixelValue, maxPixelValue :imageFrame.largestPixelValue ? imageFrame.largestPixelValue : undefined,//undefined,//imageFrame.largestPixelValue, render: undefined, // set below rowPixelSpacing: imagePlaneModule.pixelSpacing ? imagePlaneModule.pixelSpacing[0] : undefined, rows: imageFrame.rows, sizeInBytes: imageFrame.pixelData.length, slope: modalityLutModule.rescaleSlope ? modalityLutModule.rescaleSlope: 1, width: imageFrame.columns, windowCenter: voiLutModule.windowCenter ? voiLutModule.windowCenter[0] : undefined, windowWidth: voiLutModule.windowWidth ? voiLutModule.windowWidth[0] : undefined, decodeTimeInMS : imageFrame.decodeTimeInMS, webWorkerTimeInMS: imageFrame.webWorkerTimeInMS };
// add function to return pixel data image.getPixelData = function() { return imageFrame.pixelData; };
// Setup the renderer if(image.color) { image.render = cornerstone.renderColorImage; image.getCanvas = function() { if(lastImageIdDrawn === imageId) { return canvas; }
} else { image.render = cornerstone.renderGrayscaleImage; }
// calculate min/max if not supplied if(image.minPixelValue === undefined || image.maxPixelValue === undefined) { var minMax = cornerstoneWADOImageLoader.getMinMax(imageFrame.pixelData); image.minPixelValue = minMax.min; image.maxPixelValue = minMax.max; }
// Modality LUT if(modalityLutModule.modalityLUTSequence && modalityLutModule.modalityLUTSequence.length > 0 && isModalityLUTForDisplay(sopCommonModule.sopClassUID)) { image.modalityLUT = modalityLutModule.modalityLUTSequence[0]; }
// VOI LUT if(voiLutModule.voiLUTSequence && voiLutModule.voiLUTSequence.length > 0) { image.voiLUT = voiLutModule.voiLUTSequence[0]; }
// set the ww/wc to cover the dynamic range of the image if no values are supplied if(image.windowCenter === undefined || image.windowWidth === undefined) { if(image.color) { image.windowWidth = 255; image.windowCenter = 128; } else { var maxVoi = image.maxPixelValue image.slope + image.intercept; var minVoi = image.minPixelValue image.slope + image.intercept; image.windowWidth = maxVoi - minVoi; image.windowCenter = (maxVoi + minVoi) / 2; } } deferred.resolve(image); }); return deferred.promise(); }
cornerstoneWADOImageLoader.createImage = createImage; }($, cornerstone, cornerstoneWADOImageLoader)); /* / (function ($, cornerstone, cornerstoneWADOImageLoader) {
"use strict";
function addDecodeTask(imageFrame, transferSyntax, pixelData, options) { var priority = options.priority || undefined; var transferList = options.transferPixelData ? [pixelData.buffer] : undefined;
return cornerstoneWADOImageLoader.webWorkerManager.addTask( 'decodeTask', { imageFrame : imageFrame, transferSyntax : transferSyntax, pixelData : pixelData, options: options }, priority, transferList).promise; }
function decodeImageFrame(imageFrame, transferSyntax, pixelData, canvas, options) { options = options || {};
// Implicit VR Little Endian if(transferSyntax === "1.2.840.10008.1.2") { return addDecodeTask(imageFrame, transferSyntax, pixelData, options); } // Explicit VR Little Endian else if(transferSyntax === "1.2.840.10008.1.2.1") { return addDecodeTask(imageFrame, transferSyntax, pixelData, options); } // Explicit VR Big Endian (retired) else if (transferSyntax === "1.2.840.10008.1.2.2" ) { return addDecodeTask(imageFrame, transferSyntax, pixelData, options); } // Deflate transfer syntax (deflated by dicomParser) else if(transferSyntax === '1.2.840.10008.1.2.1.99') { return addDecodeTask(imageFrame, transferSyntax, pixelData, options); } // RLE Lossless else if (transferSyntax === "1.2.840.10008.1.2.5" ) { return addDecodeTask(imageFrame, transferSyntax, pixelData, options); } // JPEG Baseline lossy process 1 (8 bit) else if (transferSyntax === "1.2.840.10008.1.2.4.50") { // Handle 8-bit JPEG Baseline color images using the browser's built-in // JPEG decoding if(imageFrame.bitsAllocated === 8 && (imageFrame.samplesPerPixel === 3 || imageFrame.samplesPerPixel === 4)) { return cornerstoneWADOImageLoader.decodeJPEGBaseline8BitColor(imageFrame, pixelData, canvas); } else { return addDecodeTask(imageFrame, transferSyntax, pixelData, options); } } // JPEG Baseline lossy process 2 & 4 (12 bit) else if (transferSyntax === "1.2.840.10008.1.2.4.51") { return addDecodeTask(imageFrame, transferSyntax, pixelData, options); } // JPEG Lossless, Nonhierarchical (Processes 14) else if (transferSyntax === "1.2.840.10008.1.2.4.57") { return addDecodeTask(imageFrame, transferSyntax, pixelData, options); } // JPEG Lossless, Nonhierarchical (Processes 14 [Selection 1]) else if (transferSyntax === "1.2.840.10008.1.2.4.70" ) { return addDecodeTask(imageFrame, transferSyntax, pixelData, options); } // JPEG-LS Lossless Image Compression else if (transferSyntax === "1.2.840.10008.1.2.4.80" ) { return addDecodeTask(imageFrame, transferSyntax, pixelData, options); } // JPEG-LS Lossy (Near-Lossless) Image Compression else if (transferSyntax === "1.2.840.10008.1.2.4.81" ) { return addDecodeTask(imageFrame, transferSyntax, pixelData, options); } // JPEG 2000 Lossless else if (transferSyntax === "1.2.840.10008.1.2.4.90") { return addDecodeTask(imageFrame, transferSyntax, pixelData, options); } // JPEG 2000 Lossy else if (transferSyntax === "1.2.840.10008.1.2.4.91") { return addDecodeTask(imageFrame, transferSyntax, pixelData, options); } / Don't know if these work... // JPEG 2000 Part 2 Multicomponent Image Compression (Lossless Only) else if(transferSyntax === "1.2.840.10008.1.2.4.92") { return cornerstoneWADOImageLoader.decodeJPEG2000(dataSet, frame); } // JPEG 2000 Part 2 Multicomponent Image Compression else if(transferSyntax === "1.2.840.10008.1.2.4.93") { return cornerstoneWADOImageLoader.decodeJPEG2000(dataSet, frame); } / else { if(console && console.log) { console.log("Image cannot be decoded due to Unsupported transfer syntax " + transferSyntax); } throw "no decoder for transfer syntax " + transferSyntax; } }
cornerstoneWADOImageLoader.decodeImageFrame = decodeImageFrame; }($, cornerstone, cornerstoneWADOImageLoader)); /**
"use strict";
function arrayBufferToString(buffer) { return binaryToString(String.fromCharCode.apply(null, Array.prototype.slice.apply(new Uint8Array(buffer)))); }
function binaryToString(binary) { var error;
try { return decodeURIComponent(escape(binary)); } catch (_error) { error = _error; if (error instanceof URIError) { return binary; } else { throw error; } } }
function decodeJPEGBaseline8BitColor(imageFrame, pixelData, canvas) { var start = new Date().getTime(); var deferred = $.Deferred();
var imgBlob = new Blob([pixelData], {type: "image/jpeg"});
var r = new FileReader(); if(r.readAsBinaryString === undefined) { r.readAsArrayBuffer(imgBlob); } else { r.readAsBinaryString(imgBlob); // doesn't work on IE11 }
r.onload = function(){ var img=new Image(); img.onload = function() { canvas.height = img.height; canvas.width = img.width; imageFrame.rows = img.height; imageFrame.columns = img.width; var context = canvas.getContext('2d'); context.drawImage(this, 0, 0); var imageData = context.getImageData(0, 0, img.width, img.height); var end = new Date().getTime(); imageFrame.pixelData = imageData.data; imageFrame.imageData = imageData; imageFrame.decodeTimeInMS = end - start; deferred.resolve(imageFrame); }; img.onerror = function(error) { deferred.reject(error); }; if(r.readAsBinaryString === undefined) { img.src = "data:image/jpeg;base64,"+window.btoa(arrayBufferToString(r.result)); } else { img.src = "data:image/jpeg;base64,"+window.btoa(r.result); // doesn't work on IE11 }
}; return deferred.promise(); }
function isJPEGBaseline8BitColor(imageFrame, transferSyntax) { transferSyntax = transferSyntax || imageFrame.transferSyntax;
if(imageFrame.bitsAllocated === 8 && transferSyntax === "1.2.840.10008.1.2.4.50" && (imageFrame.samplesPerPixel === 3 || imageFrame.samplesPerPixel === 4)) { return true; }
}
// module exports cornerstoneWADOImageLoader.decodeJPEGBaseline8BitColor = decodeJPEGBaseline8BitColor; cornerstoneWADOImageLoader.isJPEGBaseline8BitColor = isJPEGBaseline8BitColor;
}($, cornerstoneWADOImageLoader)); /* / (function ($, cornerstone, cornerstoneWADOImageLoader) {
"use strict";
function getImageFrame(imageId) { var imagePixelModule = cornerstone.metaData.get('imagePixelModule', imageId);
}
cornerstoneWADOImageLoader.getImageFrame = getImageFrame; }($, cornerstone, cornerstoneWADOImageLoader)); (function (cornerstoneWADOImageLoader) {
"use strict";
function getMinMax(storedPixelData) { // we always calculate the min max values since they are not always // present in DICOM and we don't want to trust them anyway as cornerstone // depends on us providing reliable values for these var min = storedPixelData[0]; var max = storedPixelData[0]; var storedPixel; var numPixels = storedPixelData.length; for(var index = 0; index < numPixels; index++) { storedPixel = storedPixelData[index]; min = Math.min(min, storedPixel); max = Math.max(max, storedPixel); }
}
// module exports cornerstoneWADOImageLoader.getMinMax = getMinMax;
}(cornerstoneWADOImageLoader));
(function (cornerstoneWADOImageLoader) {
"use strict";
function isColorImage(photoMetricInterpretation) { if(photoMetricInterpretation === "RGB" || photoMetricInterpretation === "PALETTE COLOR" || photoMetricInterpretation === "YBR_FULL" || photoMetricInterpretation === "YBR_FULL_422" || photoMetricInterpretation === "YBR_PARTIAL_422" || photoMetricInterpretation === "YBR_PARTIAL_420" || photoMetricInterpretation === "YBR_RCT" || photoMetricInterpretation === "YBR_ICT") { return true; } else { return false; } }
cornerstoneWADOImageLoader.isColorImage = isColorImage;
}(cornerstoneWADOImageLoader)); (function (cornerstoneWADOImageLoader) {
"use strict";
// module exports cornerstoneWADOImageLoader.version = '0.13.3';
}(cornerstoneWADOImageLoader)); (function (cornerstoneWADOImageLoader) {
function checkToken(token, data, dataOffset) {
}
function stringToUint8Array(str) { var uint=new Uint8Array(str.length); for(var i=0,j=str.length;i<j;i++){ uint[i]=str.charCodeAt(i); } return uint; }
function findIndexOfString(data, str, offset) {
} cornerstoneWADOImageLoader.wadors.findIndexOfString = findIndexOfString;
}(cornerstoneWADOImageLoader)); (function (cornerstoneWADOImageLoader) {
"use strict";
function findBoundary(header) { for(var i=0; i < header.length; i++) { if(header[i].substr(0,2) === '--') { return header[i]; } } return undefined; }
function findContentType(header) { for(var i=0; i < header.length; i++) { if(header[i].substr(0,13) === 'Content-Type:') { return header[i].substr(13).trim(); } } return undefined; }
function uint8ArrayToString(data, offset, length) { offset = offset || 0; length = length || data.length - offset; var str = ""; for(var i=offset; i < offset + length; i++) { str += String.fromCharCode(data[i]); } return str; }
cornerstoneWADOImageLoader.wadors.getPixelData = function(uri, imageId, mediaType) { mediaType = mediaType || 'application/octet-stream'; var headers = { accept : mediaType };
}; }(cornerstoneWADOImageLoader));
(function ($, cornerstone, cornerstoneWADOImageLoader) {
"use strict";
function getTransferSyntaxForContentType(contentType) { return '1.2.840.10008.1.2'; // hard code to ILE for now }
function loadImage(imageId, options) { var start = new Date().getTime();
}
// register wadors scheme cornerstone.registerImageLoader('wadors', loadImage);
}($, cornerstone, cornerstoneWADOImageLoader)); /* / (function ($, cornerstone, cornerstoneWADOImageLoader) {
"use strict"; /**
@returns {} / function getNumberString(element, index, defaultValue) { var value = cornerstoneWADOImageLoader.wadors.getValue(element, index, defaultValue); if(value === undefined) { return; } return parseFloat(value); }
cornerstoneWADOImageLoader.wadors.getNumberString = getNumberString; }($, cornerstone, cornerstoneWADOImageLoader)); /* / (function (cornerstoneWADOImageLoader) {
"use strict";
function getNumberValue(element, index) { var value = cornerstoneWADOImageLoader.wadors.getValue(element, index); if(value === undefined) { return; } return parseFloat(value); }
// module exports cornerstoneWADOImageLoader.wadors.getNumberValue = getNumberValue
}(cornerstoneWADOImageLoader)); /* / (function ($, cornerstone, cornerstoneWADOImageLoader) {
"use strict"; /**
@returns {} / function getNumberValues(element, minimumLength) { if (!element) { return; } // Value is not present if the attribute has a zero length value if (!element.Value) { return; } // make sure we have the expected length if (minimumLength && element.Value.length < minimumLength) { return; }
var values = []; for(var i=0; i < element.Value.length; i++) { values.push(parseFloat(element.Value[i])); } return values; }
cornerstoneWADOImageLoader.wadors.getNumberValues = getNumberValues; }($, cornerstone, cornerstoneWADOImageLoader)); /* / (function ($, cornerstone, cornerstoneWADOImageLoader) {
"use strict"; /**
@returns {} / function getValue(element, index, defaultValue) { index = index || 0; if (!element) { return defaultValue; } // Value is not present if the attribute has a zero length value if (!element.Value) { return defaultValue; } // make sure we have the specified index if (element.Value.length <= index ) { return defaultValue; } return element.Value[index]; }
cornerstoneWADOImageLoader.wadors.getValue = getValue; }($, cornerstone, cornerstoneWADOImageLoader)); /* / (function (cornerstone, cornerstoneWADOImageLoader) {
"use strict";
var getNumberValues = cornerstoneWADOImageLoader.wadors.getNumberValues; var getValue = cornerstoneWADOImageLoader.wadors.getValue; var getNumberValue = cornerstoneWADOImageLoader.wadors.getNumberValue;
function metaDataProvider(type, imageId) { var metaData = cornerstoneWADOImageLoader.wadors.metaDataManager.get(imageId); if(!metaData) { return; }
if(type === 'generalSeriesModule') { return { modality: getValue(metaData['00080060']), seriesInstanceUID: getValue(metaData['0020000e']), seriesNumber: getNumberValue(metaData['00200011']), studyInstanceUID: getValue(metaData['0020000d']), seriesDate: dicomParser.parseDA(getValue(metaData['00080021'])), seriesTime: dicomParser.parseTM(getValue(metaData['00080031'], 0, '')) }; }
if(type === 'patientStudyModule') { return { patientAge: getNumberValue(metaData['00101010']), patientSize: getNumberValue(metaData['00101020']), patientWeight: getNumberValue(metaData['00101030']) } }
if (type === 'imagePlaneModule') { return { pixelSpacing: getNumberValues(metaData['00280030'], 2), imageOrientationPatient: getNumberValues(metaData['00200037'], 6), imagePositionPatient: getNumberValues(metaData['00200032'], 3), sliceThickness: getNumberValue(metaData['00180050']), sliceLocation: getNumberValue(metaData['00201041']) }; }
if (type === 'imagePixelModule') { return { samplesPerPixel: getValue(metaData['00280002']), photometricInterpretation: getValue(metaData['00280004']), rows: getValue(metaData['00280010']), columns: getValue(metaData['00280011']), bitsAllocated: getValue(metaData['00280100']), bitsStored: getValue(metaData['00280101']), highBit: getValue(metaData['00280102']), pixelRepresentation: getValue(metaData['00280103']), planarConfiguration: getValue(metaData['00280006']), pixelAspectRatio: getValue(metaData['00280034']), smallestPixelValue: getValue(metaData['00280106']), largestPixelValue: getValue(metaData['00280107']), redPaletteColorLookupTableDescriptor: getNumberValues(metaData['00281101']), greenPaletteColorLookupTableDescriptor: getNumberValues(metaData['00281102']), bluePaletteColorLookupTableDescriptor: getNumberValues(metaData['00281103']), redPaletteColorLookupTableData: getNumberValues(metaData['00281201']), greenPaletteColorLookupTableData: getNumberValues(metaData['00281202']), bluePaletteColorLookupTableData: getNumberValues(metaData['00281203']) }; }
if (type === 'voiLutModule') { return { // TODO VOT LUT Sequence windowCenter : getNumberValues(metaData['00281050'], 1), windowWidth : getNumberValues(metaData['00281051'], 1) }; }
if (type === 'modalityLutModule') { return { // TODO VOT LUT Sequence rescaleIntercept : getNumberValue(metaData['00281052']), rescaleSlope : getNumberValue(metaData['00281053']), rescaleType: getValue(metaData['00281054']) }; }
if (type === 'sopCommonModule') { return { sopClassUID : getValue(metaData['00080016']), sopInstanceUID : getValue(metaData['00080018']) }; }
if (type === 'petIsotopeModule') { var radiopharmaceuticalInfo = getValue(metaData['00540016']); if (radiopharmaceuticalInfo === undefined) { return; }
return { radiopharmaceuticalInfo: { radiopharmaceuticalStartTime: dicomParser.parseTM(getValue(radiopharmaceuticalInfo['00181072'], 0, '')), radionuclideTotalDose: getNumberValue(radiopharmaceuticalInfo['00181074']), radionuclideHalfLife: getNumberValue(radiopharmaceuticalInfo['00181075']) } }; }
}
cornerstone.metaData.addProvider(metaDataProvider);
// module exports cornerstoneWADOImageLoader.wadors.metaDataProvider = metaDataProvider
}(cornerstone, cornerstoneWADOImageLoader)); /* / (function (cornerstoneWADOImageLoader) {
"use strict";
var imageIds = [];
function add(imageId, metadata) { imageIds[imageId] = metadata; }
function get(imageId) { return imageIds[imageId]; }
function remove(imageId) { imageIds[imageId] = undefined; }
function purge() { imageIds = []; }
// module exports cornerstoneWADOImageLoader.wadors.metaDataManager = { add : add, get : get, remove:remove, purge: purge };
}(cornerstoneWADOImageLoader)); /**
in a multiframe sop instance so it can create the imageId's correctly. */ (function ($, cornerstoneWADOImageLoader) {
"use strict";
var loadedDataSets = {}; var promises = {};
// returns true if the wadouri for the specified index has been loaded function isLoaded(uri) { return loadedDataSets[uri] !== undefined; }
function get(uri) {
// if already loaded return it right away if(!loadedDataSets[uri]) { return; }
return loadedDataSets[uri].dataSet; }
// loads the dicom dataset from the wadouri sp function load(uri, loadRequest, imageId) {
loadRequest = loadRequest || cornerstoneWADOImageLoader.internal.xhrRequest;
// if already loaded return it right away if(loadedDataSets[uri]) { //console.log('using loaded dataset ' + uri); var alreadyLoadedpromise = $.Deferred(); loadedDataSets[uri].cacheCount++; alreadyLoadedpromise.resolve(loadedDataSets[uri].dataSet); return alreadyLoadedpromise; }
// if we are currently loading this uri, return its promise if(promises[uri]) { //console.log('returning existing load promise for ' + uri); return promises[uri]; }
//console.log('loading ' + uri);
// This uri is not loaded or being loaded, load it via an xhrRequest var promise = loadRequest(uri, imageId);
// handle success and failure of the XHR request load var loadDeferred = $.Deferred(); promise.then(function(dicomPart10AsArrayBuffer/, xhr/) { var byteArray = new Uint8Array(dicomPart10AsArrayBuffer);
// Reject the promise if parsing the dicom file fails var dataSet; try { dataSet = dicomParser.parseDicom(byteArray); } catch(error) { loadDeferred.reject(error); return; }
loadedDataSets[uri] = { dataSet: dataSet, cacheCount: 1 }; loadDeferred.resolve(dataSet); // done loading, remove the promise delete promises[uri]; }, function () { }).always(function() { // error thrown, remove the promise delete promises[uri]; });
promises[uri] = loadDeferred; return loadDeferred; }
// remove the cached/loaded dicom dataset for the specified wadouri to free up memory function unload(uri) { //console.log('unload for ' + uri); if(loadedDataSets[uri]) { loadedDataSets[uri].cacheCount--; if(loadedDataSets[uri].cacheCount === 0) { //console.log('removing loaded dataset for ' + uri); delete loadedDataSets[uri]; } } }
// removes all cached datasets from memory function purge() { loadedDataSets = {}; promises = {}; }
// module exports cornerstoneWADOImageLoader.wadouri.dataSetCacheManager = { isLoaded: isLoaded, load: load, unload: unload, purge: purge, get: get };
}($, cornerstoneWADOImageLoader)); /* / (function (cornerstoneWADOImageLoader) {
"use strict";
var files = [];
function add(file) { var fileIndex = files.push(file); return 'dicomfile:' + (fileIndex - 1); }
function get(index) { return files[index]; }
function remove(index) { files[index] = undefined; }
function purge() { files = []; }
// module exports cornerstoneWADOImageLoader.wadouri.fileManager = { add : add, get : get, remove:remove, purge: purge };
}(cornerstoneWADOImageLoader)); /**
Function to deal with extracting an image frame from an encapsulated data set. */ (function ($, cornerstone, cornerstoneWADOImageLoader) {
"use strict";
function framesAreFragmented(dataSet) { var numberOfFrames = dataSet.intString('x00280008'); var pixelDataElement = dataSet.elements.x7fe00010; if(numberOfFrames != pixelDataElement.fragments.length) { return true; } }
function getEncodedImageFrame(dataSet, frame) { // Empty basic offset table if(!dataSet.elements.x7fe00010.basicOffsetTable.length) { if(framesAreFragmented(dataSet)) { var basicOffsetTable = dicomParser.createJPEGBasicOffsetTable(dataSet, dataSet.elements.x7fe00010); return dicomParser.readEncapsulatedImageFrame(dataSet, dataSet.elements.x7fe00010, frame, basicOffsetTable); } else { return dicomParser.readEncapsulatedPixelDataFromFragments(dataSet, dataSet.elements.x7fe00010, frame); } }
// Basic Offset Table is not empty return dicomParser.readEncapsulatedImageFrame(dataSet, dataSet.elements.x7fe00010, frame); }
function getEncapsulatedImageFrame(dataSet, frameIndex) { return getEncodedImageFrame(dataSet, frameIndex); } cornerstoneWADOImageLoader.wadouri.getEncapsulatedImageFrame = getEncapsulatedImageFrame; }($, cornerstone, cornerstoneWADOImageLoader)); /**
Function to deal with extracting an image frame from an encapsulated data set. */ (function ($, cornerstone, cornerstoneWADOImageLoader) {
"use strict";
function getUncompressedImageFrame(dataSet, frameIndex) { var pixelDataElement = dataSet.elements.x7fe00010; var bitsAllocated = dataSet.uint16('x00280100'); var rows = dataSet.uint16('x00280010'); var columns = dataSet.uint16('x00280011'); var samplesPerPixel = dataSet.uint16('x00280002');
var pixelDataOffset = pixelDataElement.dataOffset; var pixelsPerFrame = rows columns samplesPerPixel;
var frameOffset; if(bitsAllocated === 8) { frameOffset = pixelDataOffset + frameIndex pixelsPerFrame; if(frameOffset >= dataSet.byteArray.length) { throw 'frame exceeds size of pixelData'; } return new Uint8Array(dataSet.byteArray.buffer, frameOffset, pixelsPerFrame); } else if(bitsAllocated === 16) { frameOffset = pixelDataOffset + frameIndex pixelsPerFrame 2; if(frameOffset >= dataSet.byteArray.length) { throw 'frame exceeds size of pixelData'; } return new Uint8Array(dataSet.byteArray.buffer, frameOffset,pixelsPerFrame 2); } else if (bitsAllocated === 1) { frameOffset = pixelDataOffset + frameIndex pixelsPerFrame 0.125; if(frameOffset >= dataSet.byteArray.length) { throw 'frame exceeds size of pixelData'; } return cornerstoneWADOImageLoader.wadouri.unpackBinaryFrame(dataSet.byteArray, frameOffset, pixelsPerFrame); }
throw 'unsupported pixel format'; }
cornerstoneWADOImageLoader.wadouri.getUncompressedImageFrame = getUncompressedImageFrame; }($, cornerstone, cornerstoneWADOImageLoader)); (function ($, cornerstone, cornerstoneWADOImageLoader) {
"use strict";
function loadFileRequest(uri) {
var parsedImageId = cornerstoneWADOImageLoader.wadouri.parseImageId(uri); var fileIndex = parseInt(parsedImageId.url); var file = cornerstoneWADOImageLoader.wadouri.fileManager.get(fileIndex);
// create a deferred object var deferred = $.Deferred();
var fileReader = new FileReader(); fileReader.onload = function (e) { var dicomPart10AsArrayBuffer = e.target.result; deferred.resolve(dicomPart10AsArrayBuffer); }; fileReader.readAsArrayBuffer(file);
return deferred.promise(); } cornerstoneWADOImageLoader.wadouri.loadFileRequest = loadFileRequest; }($, cornerstone, cornerstoneWADOImageLoader));
/* / (function (cornerstoneWADOImageLoader) {
"use strict";
function getLutDescriptor(dataSet, tag) { if(!dataSet.elements[tag] || dataSet.elements[tag].length != 6) { return; } return [dataSet.uint16(tag, 0),dataSet.uint16(tag, 1), dataSet.uint16(tag, 2)] }
function getLutData(lutDataSet, tag, lutDescriptor) { var lut = []; var lutData = lutDataSet.elements[tag]; var numLutEntries = lutDescriptor[0]; for (var i = 0; i < numLutEntries; i++) { // Output range is always unsigned if(lutDescriptor[2] === 16) { lut[i] = lutDataSet.uint16(tag, i); } else { lut[i] = lutDataSet.byteArray[i + lutData.dataOffset]; } } return lut; }
function populatePaletteColorLut(dataSet, imagePixelModule) { // return immediately if no palette lut elements if(!dataSet.elements['x00281101']) { return; } imagePixelModule.redPaletteColorLookupTableDescriptor = getLutDescriptor(dataSet, 'x00281101'); imagePixelModule.greenPaletteColorLookupTableDescriptor = getLutDescriptor(dataSet, 'x00281102'); imagePixelModule.bluePaletteColorLookupTableDescriptor = getLutDescriptor(dataSet, 'x00281103');
}
function populateSmallestLargestPixelValues(dataSet, imagePixelModule) { var pixelRepresentation = dataSet.uint16('x00280103'); if(pixelRepresentation === 0) { imagePixelModule.smallestPixelValue = dataSet.uint16('x00280106'); imagePixelModule.largestPixelValue = dataSet.uint16('x00280107'); } else { imagePixelModule.smallestPixelValue = dataSet.int16('x00280106'); imagePixelModule.largestPixelValue = dataSet.int16('x00280107'); } }
function getImagePixelModule(dataSet) {
}
// module exports cornerstoneWADOImageLoader.wadouri.getImagePixelModule = getImagePixelModule
}(cornerstoneWADOImageLoader)); /* / (function (cornerstoneWADOImageLoader) {
"use strict";
function getLUT(pixelRepresentation, lutDataSet) { var numLUTEntries = lutDataSet.uint16('x00283002', 0); if(numLUTEntries === 0) { numLUTEntries = 65535; } var firstValueMapped = 0; if(pixelRepresentation === 0) { firstValueMapped = lutDataSet.uint16('x00283002', 1); } else { firstValueMapped = lutDataSet.int16('x00283002', 1); } var numBitsPerEntry = lutDataSet.uint16('x00283002', 2); //console.log('LUT(', numLUTEntries, ',', firstValueMapped, ',', numBitsPerEntry, ')'); var lut = { id : '1', firstValueMapped: firstValueMapped, numBitsPerEntry : numBitsPerEntry, lut : [] };
}
function getLUTs(pixelRepresentation, lutSequence) { if(!lutSequence || !lutSequence.items || !lutSequence.items.length) { return; } var luts = []; for(var i=0; i < lutSequence.items.length; i++) { var lutDataSet = lutSequence.items[i].dataSet; var lut = getLUT(pixelRepresentation, lutDataSet); if(lut) { luts.push(lut); } } return luts; }
// module exports cornerstoneWADOImageLoader.wadouri.getLUTs = getLUTs
}(cornerstoneWADOImageLoader)); /* / (function (cornerstoneWADOImageLoader) {
"use strict";
function getMinStoredPixelValue(dataSet) { var pixelRepresentation = dataSet.uint16('x00280103'); var bitsStored = dataSet.uint16('x00280101'); if(pixelRepresentation === 0) { return 0; } return -1 << (bitsStored -1); }
// 0 = unsigned / US, 1 = signed / SS function getModalityLUTOutputPixelRepresentation(dataSet) {
}
// module exports cornerstoneWADOImageLoader.wadouri.getModalityLUTOutputPixelRepresentation = getModalityLUTOutputPixelRepresentation
}(cornerstoneWADOImageLoader)); /* / (function (cornerstoneWADOImageLoader) {
"use strict";
function getNumberValues(dataSet, tag, minimumLength) { var values = []; var valueAsString = dataSet.string(tag); if(!valueAsString) { return; } var split = valueAsString.split('\'); if(minimumLength && split.length < minimumLength) { return; } for(var i=0;i < split.length; i++) { values.push(parseFloat(split[i])); } return values; }
// module exports cornerstoneWADOImageLoader.wadouri.getNumberValues = getNumberValues
}(cornerstoneWADOImageLoader)); /* / (function (cornerstone, cornerstoneWADOImageLoader) {
"use strict";
var getNumberValues = cornerstoneWADOImageLoader.wadouri.getNumberValues;
function metaDataProvider(type, imageId) { var parsedImageId = cornerstoneWADOImageLoader.wadouri.parseImageId(imageId);
}
// register our metadata provider cornerstone.metaData.addProvider(metaDataProvider);
// module exports cornerstoneWADOImageLoader.wadouri.metaDataProvider = metaDataProvider
}(cornerstone, cornerstoneWADOImageLoader)); (function (cornerstoneWADOImageLoader) {
"use strict"; function parseImageId(imageId) { // build a url by parsing out the url scheme and frame index from the imageId var firstColonIndex = imageId.indexOf(':'); var url = imageId.substring(firstColonIndex + 1); var frameIndex = url.indexOf('frame='); var frame; if(frameIndex !== -1) { var frameStr = url.substr(frameIndex + 6); frame = parseInt(frameStr); url = url.substr(0, frameIndex-1); } return { scheme: imageId.substr(0, firstColonIndex), url : url, frame: frame }; }
// module exports cornerstoneWADOImageLoader.wadouri.parseImageId = parseImageId;
}(cornerstoneWADOImageLoader)); /**
Function to deal with unpacking a binary frame */ (function ($, cornerstone, cornerstoneWADOImageLoader) {
"use strict";
function isBitSet(byte, bitPos) { return byte & (1 << bitPos); }
function unpackBinaryFrame(byteArray, frameOffset, pixelsPerFrame) { // Create a new pixel array given the image size var pixelData = new Uint8Array(pixelsPerFrame);
for (var i = 0; i < pixelsPerFrame; i++) { // Compute byte position var bytePos = Math.floor(i / 8);
// Get the current byte var byte = byteArray[bytePos + frameOffset];
// Bit position (0-7) within byte var bitPos = (i % 8);
// Check whether bit at bitpos is set pixelData[i] = isBitSet(byte, bitPos) ? 1 : 0; }
return pixelData; }
cornerstoneWADOImageLoader.wadouri.unpackBinaryFrame = unpackBinaryFrame; }($, cornerstone, cornerstoneWADOImageLoader)); (function ($, cornerstoneWADOImageLoader) {
"use strict";
// the taskId to assign to the next task added via addTask() var nextTaskId = 0;
// array of queued tasks sorted with highest priority task first var tasks = [];
// array of web workers to dispatch decode tasks to var webWorkers = [];
var defaultConfig = { maxWebWorkers: navigator.hardwareConcurrency || 1, startWebWorkersOnDemand: true, webWorkerPath : '../../dist/cornerstoneWADOImageLoaderWebWorker.js', webWorkerTaskPaths: [], taskConfiguration: { 'decodeTask' : { loadCodecsOnStartup : true, initializeCodecsOnStartup: false, codecsPath: '../dist/cornerstoneWADOImageLoaderCodecs.js', usePDFJS: false } } };
var config;
var statistics = { maxWebWorkers : 0, numWebWorkers : 0, numTasksQueued : 0, numTasksExecuting : 0, numTasksCompleted: 0, totalTaskTimeInMS: 0, totalTimeDelayedInMS: 0 };
/**
// look for a web worker that is ready for(var i=0; i < webWorkers.length; i++) { { if(webWorkers[i].status === 'ready') { // mark it as busy so tasks are not assigned to it webWorkers[i].status = 'busy';
} }
// if no available web workers and we haven't started max web workers, start a new one if(webWorkers.length < config.maxWebWorkers) { spawnWebWorker(); } }
/**
/**
// spawn the webworker var worker = new Worker(config.webWorkerPath); webWorkers.push({ worker: worker, status: 'initializing' }); worker.addEventListener('message', handleMessageFromWorker); worker.postMessage({ taskType: 'initialize', workerIndex: webWorkers.length - 1, config: config }); }
/**
// prevent being initialized more than once if(config) { throw new Error('WebWorkerManager already initialized'); }
config = configObject;
config.maxWebWorkers = config.maxWebWorkers || (navigator.hardwareConcurrency || 1);
// Spawn new web workers if(!config.startWebWorkersOnDemand) { for(var i=0; i < config.maxWebWorkers; i++) { spawnWebWorker(); } } }
/**
// if a task specific configuration is provided, merge it into the config if(taskConfig) { config.taskConfiguration = Object.assign(config.taskConfiguration, taskConfig); }
// tell each spawned web worker to load this task for(var i=0; i < webWorkers.length; i++) { webWorkers[i].worker.postMessage({ taskType: 'loadWebWorkerTask', workerIndex: webWorkers.length - 1, sourcePath: sourcePath, config: config }); } }
/**
priority = priority || 0; var deferred = $.Deferred();
// find the right spot to insert this decode task (based on priority) for (var i = 0; i < tasks.length; i++) { if (tasks[i].priority <= priority) { break; } }
var taskId = nextTaskId++;
// insert the decode task at position i tasks.splice(i, 0, { taskId: taskId, taskType: taskType, status: 'ready', added: new Date().getTime(), data: data, deferred: deferred, priority: priority, transferList: transferList });
// try to start a task on the web worker since we just added a new task and a web worker may be available startTaskOnWebWorker();
return { taskId: taskId, promise: deferred.promise() }; }
/**
@returns boolean - true on success, false if taskId not found */ function setTaskPriority(taskId, priority) { // search for this taskId for (var i = 0; i < tasks.length; i++) { if (tasks[i].taskId === taskId) { // taskId found, remove it var task = tasks.splice(i, 1)[0];
// set its prioirty task.priority = priority;
// find the right spot to insert this decode task (based on priority) for (i = 0; i < tasks.length; i++) { if (tasks[i].priority <= priority) { break; } }
// insert the decode task at position i tasks.splice(i, 0, task); return true; } } return false; }
/**
/**
// module exports cornerstoneWADOImageLoader.webWorkerManager = { initialize : initialize, loadWebWorkerTask: loadWebWorkerTask, addTask : addTask, getStatistics: getStatistics, setTaskPriority: setTaskPriority, cancelTask: cancelTask };
}($, cornerstoneWADOImageLoader)); (function ($, cornerstone, cornerstoneWADOImageLoader) {
"use strict";
function xhrRequest(url, imageId, headers) { headers = headers || {};
}
cornerstoneWADOImageLoader.internal.xhrRequest = xhrRequest; }($, cornerstone, cornerstoneWADOImageLoader));