/** * Loads an image given an imageId and optional priority and returns a promise which will resolve to * the loaded image object or fail if an error occurred. The loaded image is not stored in the cache. * * @param {String} imageId A Cornerstone Image Object's imageId * @param {Object} [options] Options to be passed to the Image Loader * * @returns {ImageLoadObject} An Object which can be used to act after an image is loaded or loading fails * @memberofImageLoader */ exportfunctionloadImage (imageId, options) { if (imageId === undefined) { thrownewError('loadImage: parameter imageId must not be undefined'); }
/** * Load an image using a registered Cornerstone Image Loader. * * The image loader that is used will be * determined by the image loader scheme matching against the imageId. * * @param {String} imageId A Cornerstone Image Object's imageId * @param {Object} [options] Options to be passed to the Image Loader * * @returns {ImageLoadObject} An Object which can be used to act after an image is loaded or loading fails * @memberofImageLoader */ functionloadImageFromImageLoader (imageId, options) { const colonIndex = imageId.indexOf(':'); const scheme = imageId.substring(0, colonIndex); const loader = imageLoaders[scheme];
if (loader === undefined || loader === null) { if (unknownImageLoader !== undefined) { returnunknownImageLoader(imageId); }
thrownewError('loadImageFromImageLoader: no image loader for imageId'); }
const imageLoadObject = loader(imageId, options);
// Broadcast an image loaded event once the image is loaded imageLoadObject.promise.then(function (image) { triggerEvent(events, EVENTS.IMAGE_LOADED, { image }); }, function (error) { const errorObject = { imageId, error };
/** * Sets a new image object for a given element. * * Will also apply an optional viewport setting. * * @param {HTMLElement} element An HTML Element enabled for Cornerstone * @param {Object} image An Image loaded by a Cornerstone Image Loader * @param {Object} [viewport] A set of Cornerstone viewport parameters * @returns {void} * @memberofDrawing */ exportdefaultfunction (element, image, viewport) { if (element === undefined) { thrownewError('displayImage: parameter element must not be undefined'); } if (image === undefined) { thrownewError('displayImage: parameter image must not be undefined'); }
/** * Forces the image to be updated/redrawn for the specified enabled element * @param {HTMLElement} element An HTML Element enabled for Cornerstone * @param {Boolean} [invalidated=false] Whether or not the image pixel data has been changed, necessitating a redraw * * @returns {void} * @memberofDrawing */ exportdefaultfunction (element, invalidated = false) { const enabledElement = getEnabledElement(element);
if (enabledElement.image === undefined && !enabledElement.layers.length) { thrownewError('updateImage: image has not been loaded yet'); }
drawImage(enabledElement, invalidated); }
强制更新/重绘指定启用元素的图像
2.1.1 drawImage
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/** * Internal API function to draw an image to a given enabled element * * @param {EnabledElement} enabledElement The Cornerstone Enabled Element to redraw * @param {Boolean} [invalidated = false] - true if pixel data has been invalidated and cached rendering should not be used * @returns {void} * @memberofInternal */ exportdefaultfunction (enabledElement, invalidated = false) { enabledElement.needsRedraw = true; if (invalidated) { enabledElement.invalid = true; } }
内部API函数,用于向给定的启用元素绘制图像
enable.js
needsRedraw 改变后,在渲染循环中触发重新渲染
1 2 3
if (enabledElement.needsRedraw && hasImageOrLayers(enabledElement)) { drawImageSync(enabledElement, enabledElement.invalid); }
/** * Draw an image to a given enabled element synchronously * * @param {EnabledElement} enabledElement An enabled element to draw into * @param {Boolean} invalidated - true if pixel data has been invalidated and cached rendering should not be used * @returns {void} * @memberofInternal */ exportdefaultfunction (enabledElement, invalidated) { const image = enabledElement.image; const element = enabledElement.element; const layers = enabledElement.layers || [];
// Check if enabledElement can be redrawn if (!enabledElement.canvas || !(enabledElement.image || layers.length)) { return; }
// Start measuring the time needed to draw the image/layers const start = now();
/** * API function to draw a grayscale image to a given enabledElement * * @param {EnabledElement} enabledElement The Cornerstone Enabled Element to redraw * @param {Boolean} invalidated - true if pixel data has been invalidated and cached rendering should not be used * @returns {void} * @memberofrendering */ exportfunctionrenderGrayscaleImage (enabledElement, invalidated) { if (enabledElement === undefined) { thrownewError('drawImage: enabledElement parameter must not be undefined'); }
const image = enabledElement.image;
if (image === undefined) { thrownewError('drawImage: image must be loaded before it can be drawn'); }
// Get the canvas context and reset the transform const context = enabledElement.canvas.getContext('2d');
// Turn off image smooth/interpolation if pixelReplication is set in the viewport context.imageSmoothingEnabled = !enabledElement.viewport.pixelReplication; context.mozImageSmoothingEnabled = context.imageSmoothingEnabled;
// Save the canvas context state and apply the viewport properties setToPixelCoordinateSystem(enabledElement, context);
let renderCanvas;
if (enabledElement.options && enabledElement.options.renderer && enabledElement.options.renderer.toLowerCase() === 'webgl') { // If this enabled element has the option set for WebGL, we should // User it as our renderer. renderCanvas = webGL.renderer.render(enabledElement); } else { // If no options are set we will retrieve the renderCanvas through the // Normal Canvas rendering path renderCanvas = getRenderCanvas(enabledElement, image, invalidated); }
/** * Returns an appropriate canvas to render the Image. If the canvas available in the cache is appropriate * it is returned, otherwise adjustments are made. It also sets the color transfer functions. * * @param {Object} enabledElement The cornerstone enabled element * @param {Object} image The image to be rendered * @param {Boolean} invalidated Is pixel data valid * @param {Boolean} [useAlphaChannel = true] Will an alpha channel be used * @returns {HTMLCanvasElement} An appropriate canvas for rendering the image * @memberofrendering */ functiongetRenderCanvas (enabledElement, image, invalidated, useAlphaChannel = true) { const canvasWasColor = enabledElement.renderingTools.lastRenderedIsColor === true;
// If our render canvas does not match the size of this image reset it // NOTE: This might be inefficient if we are updating multiple images of different // Sizes frequently. if (renderCanvas.width !== image.width || renderCanvas.height !== image.height) { initializeRenderCanvas(enabledElement, image); }
// Get the lut to use let start = now(); const lut = getLut(image, enabledElement.viewport, invalidated);
// Gray scale image - apply the lut and put the resulting image onto the render canvas if (useAlphaChannel) { storedPixelDataToCanvasImageData(image, lut, renderCanvasData.data); } else { storedPixelDataToCanvasImageDataRGBA(image, lut, renderCanvasData.data); }
/** * This function transforms stored pixel values into a canvas image data buffer * by using a LUT. * * @param {Image} image A Cornerstone Image Object * @param {Array} lut Lookup table array * @param {Uint8ClampedArray} canvasImageDataData canvasImageData.data buffer filled with white pixels * * @returns {void} * @memberofInternal */ exportdefaultfunction (image, lut, canvasImageDataData) { let start = now(); const pixelData = image.getPixelData();
image.stats.lastGetPixelDataTime = now() - start;
const numPixels = pixelData.length; const minPixelValue = image.minPixelValue; let canvasImageDataIndex = 0; let storedPixelDataIndex = 0; let pixelValue;
// NOTE: As of Nov 2014, most javascript engines have lower performance when indexing negative indexes. // We have a special code path for this case that improves performance. Thanks to @jpambrun for this enhancement
/** * Retrieve or generate a LUT Array for an Image and Viewport * * @param {Image} image An Image Object * @param {Viewport} viewport An Viewport Object * @param {Boolean} invalidated Whether or not the LUT data has been invalidated * (e.g. by a change to the windowWidth, windowCenter, or invert viewport parameters). * @return {Uint8ClampedArray} LUT Array * @memberofrendering */ exportdefaultfunction (image, viewport, invalidated) { // If we have a cached lut and it has the right values, return it immediately if (image.cachedLut !== undefined && image.cachedLut.windowCenter === viewport.voi.windowCenter && image.cachedLut.windowWidth === viewport.voi.windowWidth && lutMatches(image.cachedLut.modalityLUT, viewport.modalityLUT) && lutMatches(image.cachedLut.voiLUT, viewport.voiLUT) && image.cachedLut.invert === viewport.invert && invalidated !== true) { return image.cachedLut.lutArray; }
computeAutoVoi(viewport, image);
// Lut is invalid or not present, regenerate it and cache it generateLut(image, viewport.voi.windowWidth, viewport.voi.windowCenter, viewport.invert, viewport.modalityLUT, viewport.voiLUT);
/** * Creates a LUT used while rendering to convert stored pixel values to * display pixels * * @param {Image} image A Cornerstone Image Object * @param {Number} windowWidth The Window Width * @param {Number} windowCenter The Window Center * @param {Boolean} invert A boolean describing whether or not the image has been inverted * @param {Array} [modalityLUT] A modality Lookup Table * @param {Array} [voiLUT] A Volume of Interest Lookup Table * * @returns {Uint8ClampedArray} A lookup table to apply to the image * @memberofInternal */ exportdefaultfunction (image, windowWidth, windowCenter, invert, modalityLUT, voiLUT) { const maxPixelValue = image.maxPixelValue; const minPixelValue = image.minPixelValue; const offset = Math.min(minPixelValue, 0);