UNPKG

@cornerstonejs/core

Version:
172 lines (171 loc) 5.98 kB
import CanvasProperties from './CanvasProperties.js'; import CanvasMapper from './CanvasMapper.js'; export default class CanvasActor { constructor(viewport, derivedImage) { this.canvasProperties = new CanvasProperties(this); this.visibility = false; this.mapper = new CanvasMapper(this); this.rasterDirty = true; this.hasCachedRaster = false; this.className = 'CanvasActor'; this.derivedImage = derivedImage; this.viewport = viewport; } renderRLE(viewport, context, voxelManager) { const { width, height } = this.image; let { canvas } = this; if (!canvas || canvas.width !== width || canvas.height !== height) { this.canvas = canvas = new window.OffscreenCanvas(width, height); this.cachedImageData = undefined; this.rasterDirty = true; } if (!this.rasterDirty) { if (this.hasCachedRaster) { context.drawImage(canvas, 0, 0); } return; } const localContext = canvas.getContext('2d'); let imageData = this.cachedImageData; if (!imageData) { imageData = localContext.createImageData(width, height); this.cachedImageData = imageData; } const { data: imageArray } = imageData; imageArray.fill(0); const { map } = voxelManager; let hasVisiblePixels = false; for (let y = 0; y < height; y++) { const row = map.getRun(y, 0); if (!row) { continue; } const baseOffset = (y * width) << 2; for (const run of row) { const { start, end, value: segmentIndex } = run; if (segmentIndex === 0) { continue; } hasVisiblePixels = true; let startOffset = baseOffset + (start << 2); for (let i = start; i < end; i++) { this.canvasProperties.getColorBytes(segmentIndex, imageArray, startOffset); startOffset += 4; } } } if (!hasVisiblePixels) { localContext.clearRect(0, 0, width, height); this.hasCachedRaster = false; this.rasterDirty = false; return; } localContext.putImageData(imageData, 0, 0); this.hasCachedRaster = true; this.rasterDirty = false; context.drawImage(canvas, 0, 0); } setMapper(mapper) { this.mapper = mapper; } render(viewport, context) { if (!this.visibility) { return; } const image = this.image || this.getImage(); const { width, height } = image; const data = image.getScalarData(); if (!data) { return; } const { voxelManager } = image; if (voxelManager?.map?.getRun) { this.renderRLE(viewport, context, voxelManager); return; } let { canvas } = this; if (!canvas || canvas.width !== width || canvas.height !== height) { this.canvas = canvas = new window.OffscreenCanvas(width, height); this.cachedImageData = undefined; this.rasterDirty = true; } if (!this.rasterDirty) { if (this.hasCachedRaster) { context.drawImage(canvas, 0, 0); } return; } const localContext = canvas.getContext('2d'); let imageData = this.cachedImageData; if (!imageData) { imageData = localContext.createImageData(width, height); this.cachedImageData = imageData; } const { data: imageArray } = imageData; imageArray.fill(0); let offset = 0; let destOffset = 0; let hasVisiblePixels = false; for (let y = 0; y < height; y++) { for (let x = 0; x < width; x++) { const segmentIndex = data[offset++]; if (segmentIndex) { hasVisiblePixels = true; this.canvasProperties.getColorBytes(segmentIndex, imageArray, destOffset); } destOffset += 4; } } if (!hasVisiblePixels) { localContext.clearRect(0, 0, width, height); this.hasCachedRaster = false; this.rasterDirty = false; return; } localContext.putImageData(imageData, 0, 0); this.hasCachedRaster = true; this.rasterDirty = false; context.drawImage(canvas, 0, 0); } getClassName() { return this.className; } getProperty() { return this.canvasProperties; } setVisibility(visibility) { this.visibility = visibility; } getMapper() { return this.mapper; } isA(actorType) { return actorType === this.className; } modified() { this.rasterDirty = true; } getImage() { if (this.image) { return this.image; } this.image = { ...this.derivedImage }; const imageData = this.viewport.getImageData(); Object.assign(this.image, { worldToIndex: (worldPos) => imageData.imageData.worldToIndex(worldPos), indexToWorld: (index, destPoint) => imageData.imageData.indexToWorld(index, destPoint), getDimensions: () => imageData.dimensions, getScalarData: () => this.derivedImage?.getPixelData(), getDirection: () => imageData.direction, getSpacing: () => imageData.spacing, setOrigin: () => null, setDerivedImage: (image) => { this.derivedImage = image; this.image = null; this.modified(); }, modified: () => null, }); return this.image; } }