function loadImage(imageId) {
// create a deferred object
var deferred = $.Deferred();
// Make the request for the DICOM data
var oReq = new XMLHttpRequest();
oReq.open("get", imageId, true);
oReq.responseType = "arraybuffer";
oReq.onreadystatechange = function(oEvent) {
if (oReq.readyState === 4)
{
if (oReq.status == 200) {
// request succeeded, create an image object and resolve the deferred
// Code to parse the response and return an image object omitted.....
var image = createImageObject(oReq.response);
// return the image object by resolving the deferred
deferred.resolve(image);
}
else {
// an error occurred, return an object describing the error by rejecting
// the deferred
deferred.reject({error: oReq.statusText});
}
}
};
oReq.send();
// return the pending deferred object to cornerstone so it can setup callbacks to be
// invoked asynchronously for the success/resolve and failure/reject scenarios.
return deferred;
}
export function putImageLoadObject (imageId, imageLoadObject) {
// 是否有imageId
if (imageId === undefined) {
throw new Error('putImageLoadObject: imageId must not be undefined');
}
// imageLoadObject是否合法
if (imageLoadObject.promise === undefined) {
throw new Error('putImageLoadObject: imageLoadObject.promise must not be undefined');
}
// imageLoadObject是否已经在缓存中
if (imageCacheDict.hasOwnProperty(imageId) === true) {
throw new Error('putImageLoadObject: imageId already in cache');
}
// 是否可被取消缓存
if (imageLoadObject.cancelFn && typeof imageLoadObject.cancelFn !== 'function') {
throw new Error('putImageLoadObject: imageLoadObject.cancelFn must be a function');
}
// 缓存需要记录当前是否被加载,时间戳等信息
const cachedImage = {
loaded: false,
imageId,
sharedCacheKey: undefined, // The sharedCacheKey for this imageId. undefined by default
imageLoadObject,
timeStamp: Date.now(),
sizeInBytes: 0
};
// 放入缓存
imageCacheDict[imageId] = cachedImage;
cachedImages.push(cachedImage);
// 开始加载,因为缓存就不需要手动设定了,我们直接开始加载
imageLoadObject.promise.then(function (image) {
// 如果已经加载过了,直接返回
if (cachedImages.indexOf(cachedImage) === -1) {
// If the image has been purged before being loaded, we stop here.
return;
}
// 否则开始加载
cachedImage.loaded = true;
cachedImage.image = image;
if (image.sizeInBytes === undefined) {
throw new Error('putImageLoadObject: image.sizeInBytes must not be undefined');
}
if (image.sizeInBytes.toFixed === undefined) {
throw new Error('putImageLoadObject: image.sizeInBytes is not a number');
}
cachedImage.sizeInBytes = image.sizeInBytes;
cacheSizeInBytes += cachedImage.sizeInBytes;
const eventDetails = {
action: 'addImage',
image: cachedImage
};
triggerEvent(events, 'cornerstoneimagecachechanged', eventDetails);
cachedImage.sharedCacheKey = image.sharedCacheKey;
purgeCacheIfNecessary();
}, () => {
// 如果出现异常,会把字典内的相关对象删除
const cachedImage = imageCacheDict[imageId];
cachedImages.splice(cachedImages.indexOf(cachedImage), 1);
delete imageCacheDict[imageId];
});
}
用了这么久的cornerstone,恰好这又是我的毕设题目,而且个人觉得
cornerstone
的代码写的算是比较优秀,所以打算从阅读源码的过程中多学习一点东西。cornerstone加载医学影像显示的全过程
在cornerstone,一个
enabled element
就是一个HTML DOM
节点(例如,一个div
),cornerstone会在其中展示一些交互式的医学影像。为了展示这些影像,开发者需要做以下事情:script
标签引入你的web
页面中。web
页面中,图片加载器会使用WADO
、WADO-RS
或custom
协议加载医学影像图片并提供给web
页面使用。enabled element
这个DOM
节点加入到你的页面中去,在这个DOM
节点内会展示医学影像。CSS
为这个element
固定好宽度和高度。(切记一定要固定宽高)看imageLoader
imageLoader一共有下列几个方法:
loadImageFromImageLoader(imageId, options)
loadImage(imageId, options)
loadAndCacheImage(imageId, options)
registerImageLoader(scheme, imageLoader)
registerUnknownImageLoader(imageLoader)
registerImageLoader(scheme, imageLoader)
对于
cornerstone
,dicom
影像的加载协议一般有以下几种:WADO
协议或WADO-RS
协议这个方法就是用于注册
dicom
加载的方法,传入两个参数,一个是协议名称scheme
,另一个则是加载方法imageLoader
,这个方法可以自行注册,也可以使用cornerstoneWADOImageLoader或者cornerstoneWebImageLoader示例:官方写的一个
imageLoader
:cornerstone
首先声明一个imageLoaders
字典,每次注册加载方法则往字典里写入这个加载方法loadImage(imageId, options)
和loadAndCacheImage(imageId, options)
loadImage(imageId, options)
和loadAndCacheImage(imageId, options)
的差别在于是否缓存图片image obj
,对于loadAndCacheImage(imageId, options)
,则会执行下列代码,把加载过的图片信息存入缓存:至于如何存缓存,则深入
putImageLoadObject(imageId, imageLoadObject)
内部:函数首先进行一系列的判断逻辑,检查传入的
imageId
是否合法,之后会根据相关协议进行加载,加载完毕后发出cornerstoneimagecachechanged
事件。下面来看图片加载的代码:
由于图片加载是异步的,则我们返回的是一个符合
Promise A+
的Promise obj
。而我们真正的图片加载是在getImageLoadObject(imageId)
这样一个私有方法中做的,接下来会讲到。loadImageFromImageLoader(imageId, options)
在示例中,我们的
imageId
会是example://1
,这样的格式,这时,我们的scheme
则是example
,colonIndex
则是1
,对于wado
协议来说,例如传入的图片ID为wado://example.dicom.com/1.dcm
,这样的格式,显然我们则会根据wado
协议来进行加载。这里需要注意的是对于正常加载和异常加载时,则会分别发出
cornerstoneimageloaded
和cornerstoneimageloadfailed
事件,这都是基于发布订阅模式的。此外,如果没有找到对应协议的
imageLoader
,则会使用unknownImageLoader
进行加载,这就是为什么我们可以注册unknownImageLoader
方法的原因。