@cornerstonejs/core
Version:
Cornerstone3D Core
114 lines (113 loc) • 4.86 kB
JavaScript
import { vec3 } from 'gl-matrix';
import getOrCreateCanvas, { EPSILON, } from '../RenderingEngine/helpers/getOrCreateCanvas.js';
import { ViewportType, Events } from '../enums/index.js';
import { getRenderingEngine } from '../RenderingEngine/getRenderingEngine.js';
import TiledRenderingEngine from '../RenderingEngine/TiledRenderingEngine.js';
import isPTPrescaledWithSUV from './isPTPrescaledWithSUV.js';
export default function renderToCanvasGPU(canvas, imageOrVolume, modality = undefined, renderingEngineId = '_thumbnails', viewportOptions = {
displayArea: { imageArea: [1, 1] },
}) {
if (!canvas || !(canvas instanceof HTMLCanvasElement)) {
throw new Error('canvas element is required');
}
const isVolume = !imageOrVolume.imageId;
const image = !isVolume && imageOrVolume;
const volume = isVolume && imageOrVolume;
const imageIdToPrint = image.imageId || volume.volumeId;
const viewportId = `renderGPUViewport-${imageIdToPrint}`;
const element = document.createElement('div');
const devicePixelRatio = window.devicePixelRatio || 1;
if (!viewportOptions.displayArea) {
viewportOptions.displayArea = { imageArea: [1, 1] };
}
const originalWidth = canvas.width;
const originalHeight = canvas.height;
element.style.width = `${originalWidth / devicePixelRatio + EPSILON}px`;
element.style.height = `${originalHeight / devicePixelRatio + EPSILON}px`;
element.style.visibility = 'hidden';
element.style.position = 'absolute';
document.body.appendChild(element);
const uniqueId = viewportId.split(':').join('-');
element.setAttribute('viewport-id-for-remove', uniqueId);
const temporaryCanvas = getOrCreateCanvas(element);
const renderingEngine = getRenderingEngine(renderingEngineId) ||
new TiledRenderingEngine(renderingEngineId);
let viewport = renderingEngine.getViewport(viewportId);
if (!viewport) {
const viewportInput = {
viewportId,
type: isVolume ? ViewportType.ORTHOGRAPHIC : ViewportType.STACK,
element,
defaultOptions: {
...viewportOptions,
suppressEvents: true,
},
};
renderingEngine.enableElement(viewportInput);
viewport = renderingEngine.getViewport(viewportId);
}
return new Promise((resolve) => {
let elementRendered = false;
let { viewReference } = viewportOptions;
const onImageRendered = (eventDetail) => {
if (elementRendered) {
return;
}
if (viewReference) {
const useViewRef = viewReference;
viewReference = null;
viewport.setViewReference(useViewRef);
viewport.render();
return;
}
const context = canvas.getContext('2d');
context.drawImage(temporaryCanvas, 0, 0, temporaryCanvas.width, temporaryCanvas.height, 0, 0, canvas.width, canvas.height);
const origin = viewport.canvasToWorld([0, 0]);
const topRight = viewport.canvasToWorld([
temporaryCanvas.width / devicePixelRatio,
0,
]);
const bottomLeft = viewport.canvasToWorld([
0,
temporaryCanvas.height / devicePixelRatio,
]);
const rightVector = vec3.sub([0, 0, 0], viewport.canvasToWorld([1 / devicePixelRatio, 0]), origin);
const downVector = vec3.sub([0, 0, 0], viewport.canvasToWorld([0, 1 / devicePixelRatio]), origin);
const thicknessMm = 1;
elementRendered = true;
element.removeEventListener(Events.IMAGE_RENDERED, onImageRendered);
setTimeout(() => {
renderingEngine.disableElement(viewportId);
const elements = document.querySelectorAll(`[viewport-id-for-remove="${uniqueId}"]`);
elements.forEach((element) => {
element.remove();
});
}, 0);
resolve({
origin,
bottomLeft,
topRight,
thicknessMm,
rightVector,
downVector,
});
};
element.addEventListener(Events.IMAGE_RENDERED, onImageRendered);
if (isVolume) {
viewport.setVolumes([volume], false, true);
}
else {
viewport.renderImageObject(imageOrVolume);
}
viewport.resetCamera();
if (modality === 'PT' && !isPTPrescaledWithSUV(image)) {
viewport.setProperties({
voiRange: {
lower: image.minPixelValue,
upper: image.maxPixelValue,
},
});
}
viewport.render();
});
}