feat(ImageOverlayViewerTool): add ImageOverlayViewer tool that can render image overlay (pixel overlay) of the DICOM images (#3163)

Co-authored-by: Joe Boccanfuso <joe.boccanfuso@radicalimaging.com>
This commit is contained in:
M.D 2023-09-06 09:24:17 -04:00 committed by GitHub
parent ef58893c27
commit 69115da06d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 355 additions and 46 deletions

View File

@ -44,9 +44,9 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^1.11.4",
"@cornerstonejs/core": "^1.11.4",
"@cornerstonejs/tools": "^1.11.4",
"@cornerstonejs/adapters": "^1.13.2",
"@cornerstonejs/core": "^1.13.2",
"@cornerstonejs/tools": "^1.13.2",
"classnames": "^2.3.2"
}
}

View File

@ -36,7 +36,7 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.2",
"@cornerstonejs/codec-openjph": "^2.4.2",
"@cornerstonejs/dicom-image-loader": "^1.11.4",
"@cornerstonejs/dicom-image-loader": "^1.13.2",
"@ohif/core": "3.7.0-beta.64",
"@ohif/ui": "3.7.0-beta.64",
"dcmjs": "^0.29.6",
@ -52,10 +52,10 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^1.11.4",
"@cornerstonejs/core": "^1.11.4",
"@cornerstonejs/streaming-image-volume-loader": "^1.11.4",
"@cornerstonejs/tools": "^1.11.4",
"@cornerstonejs/adapters": "^1.13.2",
"@cornerstonejs/core": "^1.13.2",
"@cornerstonejs/streaming-image-volume-loader": "^1.13.2",
"@cornerstonejs/tools": "^1.13.2",
"@kitware/vtk.js": "27.3.1",
"html2canvas": "^1.4.1",
"lodash.debounce": "4.0.8",

View File

@ -18,6 +18,7 @@ import toggleStackImageSync from './utils/stackSync/toggleStackImageSync';
import { getFirstAnnotationSelected } from './utils/measurementServiceMappings/utils/selection';
import getActiveViewportEnabledElement from './utils/getActiveViewportEnabledElement';
import { CornerstoneServices } from './types';
import ImageOverlayViewerTool from './tools/ImageOverlayViewerTool';
function commandsModule({
servicesManager,
@ -266,7 +267,7 @@ function commandsModule({
toolbarService.recordInteraction(props);
},
setToolActive: ({ toolName, toolGroupId = null }) => {
setToolActive: ({ toolName, toolGroupId = null, toggledState }) => {
if (toolName === 'Crosshairs') {
const activeViewportToolGroup = toolGroupService.getToolGroup(null);
@ -327,6 +328,14 @@ function commandsModule({
toolGroup.setToolPassive(activeToolName);
}
}
// If there is a toggle state, then simply set the enabled/disabled state without
// setting the tool active.
if (toggledState != null) {
toggledState ? toolGroup.setToolEnabled(toolName) : toolGroup.setToolDisabled(toolName);
return;
}
// Set the new toolName to be active
toolGroup.setToolActive(toolName, {
bindings: [
@ -547,17 +556,13 @@ function commandsModule({
toggledState,
});
},
toggleReferenceLines: ({ toggledState }) => {
setSourceViewportForReferenceLinesTool: ({ toggledState }) => {
const { activeViewportId } = viewportGridService.getState();
const viewportInfo = cornerstoneViewportService.getViewportInfo(activeViewportId);
const viewportId = viewportInfo.getViewportId();
const toolGroup = toolGroupService.getToolGroupForViewport(viewportId);
if (!toggledState) {
toolGroup.setToolDisabled(ReferenceLinesTool.toolName);
}
toolGroup.setToolConfiguration(
ReferenceLinesTool.toolName,
{
@ -565,7 +570,6 @@ function commandsModule({
},
true // overwrite
);
toolGroup.setToolEnabled(ReferenceLinesTool.toolName);
},
storePresentation: ({ viewportId }) => {
cornerstoneViewportService.storePresentation({ viewportId });
@ -692,8 +696,8 @@ function commandsModule({
toggleStackImageSync: {
commandFn: actions.toggleStackImageSync,
},
toggleReferenceLines: {
commandFn: actions.toggleReferenceLines,
setSourceViewportForReferenceLinesTool: {
commandFn: actions.setSourceViewportForReferenceLinesTool,
},
storePresentation: {
commandFn: actions.storePresentation,

View File

@ -28,6 +28,7 @@ import {
} from '@cornerstonejs/tools';
import CalibrationLineTool from './tools/CalibrationLineTool';
import ImageOverlayViewerTool from './tools/ImageOverlayViewerTool';
export default function initCornerstoneTools(configuration = {}) {
CrosshairsTool.isAnnotation = false;
@ -58,6 +59,7 @@ export default function initCornerstoneTools(configuration = {}) {
addTool(ReferenceLinesTool);
addTool(CalibrationLineTool);
addTool(TrackballRotateTool);
addTool(ImageOverlayViewerTool);
// Modify annotation tools to use dashed lines on SR
const annotationStyle = {
@ -99,6 +101,7 @@ const toolNames = {
ReferenceLines: ReferenceLinesTool.toolName,
CalibrationLine: CalibrationLineTool.toolName,
TrackballRotateTool: TrackballRotateTool.toolName,
ImageOverlayViewer: ImageOverlayViewerTool.toolName,
};
export { toolNames };

View File

@ -0,0 +1,247 @@
import { metaData } from '@cornerstonejs/core';
import { utilities } from '@cornerstonejs/core';
import { AnnotationDisplayTool, drawing } from '@cornerstonejs/tools';
import { guid } from '@ohif/core/src/utils';
interface CachedStat {
color: number[]; // [r, g, b, a]
overlays: {
// ...overlayPlaneModule
_id: string;
type: 'G' | 'R'; // G for Graphics, R for ROI
color?: number[]; // Rendered color [r, g, b, a]
dataUrl?: string; // Rendered image in Data URL expression
}[];
}
/**
* Image Overlay Viewer tool is not a traditional tool that requires user interactin.
* But it is used to display Pixel Overlays. And it will provide toggling capability.
*
* The documentation for Overlay Plane Module of DICOM can be found in [C.9.2 of
* Part-3 of DICOM standard](https://dicom.nema.org/medical/dicom/2018b/output/chtml/part03/sect_C.9.2.html)
*
* Image Overlay rendered by this tool can be toggled on and off using
* toolGroup.setToolEnabled() and toolGroup.setToolDisabled()
*/
class ImageOverlayViewerTool extends AnnotationDisplayTool {
static toolName = 'ImageOverlayViewer';
private _cachedOverlayMetadata: Map<string, any[]> = new Map();
private _cachedStats: { [key: string]: CachedStat } = {};
constructor(
toolProps = {},
defaultToolProps = {
supportedInteractionTypes: [],
configuration: {
fillColor: [255, 127, 127, 255],
},
}
) {
super(toolProps, defaultToolProps);
}
onSetToolDisabled = (): void => {
this._cachedStats = {};
this._cachedOverlayMetadata = new Map();
};
renderAnnotation = (enabledElement, svgDrawingHelper) => {
const { viewport } = enabledElement;
const imageId = this.getReferencedImageId(viewport);
if (!imageId) {
return;
}
const overlays =
this._cachedOverlayMetadata.get(imageId) ??
metaData.get('overlayPlaneModule', imageId)?.overlays;
// no overlays
if (!overlays?.length) {
return;
}
this._cachedOverlayMetadata.set(imageId, overlays);
this._getCachedStat(imageId, overlays, this.configuration.fillColor).then(cachedStat => {
cachedStat.overlays.forEach(overlay => {
this._renderOverlay(enabledElement, svgDrawingHelper, overlay);
});
});
return true;
};
/**
* Render to DOM
*
* @param enabledElement
* @param svgDrawingHelper
* @param overlayData
* @returns
*/
private _renderOverlay(enabledElement, svgDrawingHelper, overlayData) {
const { viewport } = enabledElement;
const imageId = this.getReferencedImageId(viewport);
if (!imageId) {
return;
}
// Decide the rendering position of the overlay image on the current canvas
const { _id, columns: width, rows: height, x, y } = overlayData;
const overlayTopLeftWorldPos = utilities.imageToWorldCoords(imageId, [
x - 1, // Remind that top-left corner's (x, y) is be (1, 1)
y - 1,
]);
const overlayTopLeftOnCanvas = viewport.worldToCanvas(overlayTopLeftWorldPos);
const overlayBottomRightWorldPos = utilities.imageToWorldCoords(imageId, [width, height]);
const overlayBottomRightOnCanvas = viewport.worldToCanvas(overlayBottomRightWorldPos);
// add image to the annotations svg layer
const svgns = 'http://www.w3.org/2000/svg';
const svgNodeHash = `image-overlay-${_id}`;
const existingImageElement = svgDrawingHelper.getSvgNode(svgNodeHash);
const attributes = {
'data-id': svgNodeHash,
width: overlayBottomRightOnCanvas[0] - overlayTopLeftOnCanvas[0],
height: overlayBottomRightOnCanvas[1] - overlayTopLeftOnCanvas[1],
x: overlayTopLeftOnCanvas[0],
y: overlayTopLeftOnCanvas[1],
href: overlayData.dataUrl,
};
if (
isNaN(attributes.x) ||
isNaN(attributes.y) ||
isNaN(attributes.width) ||
isNaN(attributes.height)
) {
console.warn('Invalid rendering attribute for image overlay', attributes['data-id']);
return false;
}
if (existingImageElement) {
drawing.setAttributesIfNecessary(attributes, existingImageElement);
svgDrawingHelper.setNodeTouched(svgNodeHash);
} else {
const newImageElement = document.createElementNS(svgns, 'image');
drawing.setNewAttributesIfValid(attributes, newImageElement);
svgDrawingHelper.appendNode(newImageElement, svgNodeHash);
}
return true;
}
private async _getCachedStat(
imageId: string,
overlayMetadata: any[],
color: number[]
): Promise<CachedStat> {
if (this._cachedStats[imageId] && this._isSameColor(this._cachedStats[imageId].color, color)) {
return this._cachedStats[imageId];
}
const overlays = await Promise.all(
overlayMetadata
.filter(overlay => overlay.pixelData)
.map(async (overlay, idx) => {
let pixelData = null;
if (overlay.pixelData.Value) {
pixelData = overlay.pixelData.Value;
} else if (overlay.pixelData.retrieveBulkData) {
pixelData = await overlay.pixelData.retrieveBulkData();
}
if (!pixelData) {
return;
}
const dataUrl = this._renderOverlayToDataUrl(
{ width: overlay.columns, height: overlay.rows },
color,
pixelData
);
return {
...overlay,
_id: guid(),
dataUrl, // this will be a data url expression of the rendered image
color,
};
})
);
this._cachedStats[imageId] = {
color: color,
overlays: overlays.filter(overlay => overlay),
};
return this._cachedStats[imageId];
}
/**
* compare two RGBA expression of colors.
*
* @param color1
* @param color2
* @returns
*/
private _isSameColor(color1: number[], color2: number[]) {
return (
color1 &&
color2 &&
color1[0] === color2[0] &&
color1[1] === color2[1] &&
color1[2] === color2[2] &&
color1[3] === color2[3]
);
}
/**
* pixelData of overlayPlane module is an array of bits corresponding
* to each of the underlying pixels of the image.
* Let's create pixel data from bit array of overlay data
*
* @param pixelDataRaw
* @param color
* @returns
*/
private _renderOverlayToDataUrl({ width, height }, color, pixelDataRaw) {
const pixelDataView = new DataView(pixelDataRaw);
const totalBits = width * height;
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, width, height); // make it transparent
ctx.globalCompositeOperation = 'copy';
const imageData = ctx.getImageData(0, 0, width, height);
const data = imageData.data;
for (let i = 0, bitIdx = 0, byteIdx = 0; i < totalBits; i++) {
if (pixelDataView.getUint8(byteIdx) & (1 << bitIdx)) {
data[i * 4] = color[0];
data[i * 4 + 1] = color[1];
data[i * 4 + 2] = color[2];
data[i * 4 + 3] = color[3];
}
// next bit, byte
if (bitIdx >= 7) {
bitIdx = 0;
byteIdx++;
} else {
bitIdx++;
}
}
ctx.putImageData(imageData, 0, 0);
return canvas.toDataURL();
}
}
export default ImageOverlayViewerTool;

View File

@ -30,8 +30,8 @@
"start": "yarn run dev"
},
"peerDependencies": {
"@cornerstonejs/core": "^1.11.4",
"@cornerstonejs/tools": "^1.11.4",
"@cornerstonejs/core": "^1.13.2",
"@cornerstonejs/tools": "^1.13.2",
"@ohif/core": "3.7.0-beta.64",
"@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.64",
"@ohif/ui": "3.7.0-beta.64",

View File

@ -84,6 +84,7 @@ function modeFactory({ modeConfiguration }) {
{ toolName: toolNames.CalibrationLine },
],
// enabled
enabled: [{ toolName: toolNames.ImageOverlayViewer }],
// disabled
};

View File

@ -38,6 +38,7 @@ function initDefaultToolGroup(extensionManager, toolGroupService, commandsManage
{ toolName: toolNames.CalibrationLine },
],
// enabled
enabled: [{ toolName: toolNames.ImageOverlayViewer }],
// disabled
disabled: [{ toolName: toolNames.ReferenceLines }],
};

View File

@ -15,7 +15,7 @@ const { windowLevelPresets } = defaults;
* @param {*} icon
* @param {*} label
*/
function _createButton(type, id, icon, label, commands, tooltip, uiType) {
function _createButton(type, id, icon, label, commands, tooltip, uiType, isActive) {
return {
id,
icon,
@ -24,6 +24,7 @@ function _createButton(type, id, icon, label, commands, tooltip, uiType) {
commands,
tooltip,
uiType,
isActive,
};
}
@ -432,14 +433,41 @@ const toolbarButtons = [
'ReferenceLines',
'tool-referenceLines', // change this with the new icon
'Reference Lines',
// two commands for the reference lines tool:
// - the first to set the source viewport for the tool when it is enabled
// - the second to toggle the tool
[
{
commandName: 'toggleReferenceLines',
commandName: 'setSourceViewportForReferenceLinesTool',
commandOptions: {},
context: 'CORNERSTONE',
},
{
commandName: 'setToolActive',
commandOptions: {
toolName: 'ReferenceLines',
},
context: 'CORNERSTONE',
},
]
),
_createToggleButton(
'ImageOverlayViewer',
'toggle-dicom-overlay',
'Image Overlay',
[
{
commandName: 'setToolActive',
commandOptions: {
toolName: 'ImageOverlayViewer',
},
context: 'CORNERSTONE',
},
],
'Image Overlay',
null,
true
),
_createToolButton(
'StackScroll',
'tool-stack-scroll',

View File

@ -50,7 +50,7 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.2",
"@cornerstonejs/codec-openjph": "^2.4.2",
"@cornerstonejs/dicom-image-loader": "^1.11.4",
"@cornerstonejs/dicom-image-loader": "^1.13.2",
"@ohif/core": "3.7.0-beta.64",
"@ohif/extension-cornerstone": "3.7.0-beta.64",
"@ohif/extension-cornerstone-dicom-rt": "3.7.0-beta.64",

View File

@ -35,7 +35,7 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.2",
"@cornerstonejs/codec-openjph": "^2.4.2",
"@cornerstonejs/dicom-image-loader": "^1.11.4",
"@cornerstonejs/dicom-image-loader": "^1.13.2",
"@ohif/ui": "3.7.0-beta.64",
"cornerstone-math": "0.1.9",
"dicom-parser": "^1.8.21"

View File

@ -265,11 +265,26 @@ export default class ToolbarService extends PubSubService {
if (!this.buttons[button.id]) {
this.buttons[button.id] = button;
}
this._setTogglesForButtonItems(button.props?.items);
});
this._broadcastEvent(this.EVENTS.TOOL_BAR_MODIFIED, {});
}
_setTogglesForButtonItems(buttonItems) {
if (!buttonItems) {
return;
}
buttonItems.forEach(buttonItem => {
if (buttonItem.type === 'toggle') {
this.state.toggles[buttonItem.id] = buttonItem.isActive;
} else {
this._setTogglesForButtonItems(buttonItem.props?.items);
}
});
}
/**
*
* @param {*} btn

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="25px" height="25px" viewBox="0 0 25 25" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>toggle-dicom-overlay</title>
<g id="toggle-dicom-overlay" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M19.5629346,17.375 C19.9081126,17.375 20.1879346,17.654822 20.1879346,18 C20.1879346,18.345178 19.9081126,18.625 19.5629346,18.625 L18.2129346,18.625 C17.8677566,18.625 17.5879346,18.345178 17.5879346,18 C17.5879346,17.654822 17.8677566,17.375 18.2129346,17.375 L19.5629346,17.375 Z M15.4829346,17.375 C15.8281125,17.375 16.1079346,17.654822 16.1079346,18 C16.1079346,18.345178 15.8281125,18.625 15.4829346,18.625 L14.1329346,18.625 C13.7877566,18.625 13.5079346,18.345178 13.5079346,18 C13.5079346,17.654822 13.7877566,17.375 14.1329346,17.375 L15.4829346,17.375 Z M11.4029345,17.375 C11.7481125,17.375 12.0279345,17.654822 12.0279345,18 C12.0279345,18.345178 11.7481125,18.625 11.4029345,18.625 L10.0529345,18.625 C9.70775654,18.625 9.42793451,18.345178 9.42793451,18 C9.42793451,17.654822 9.70775654,17.375 10.0529345,17.375 L11.4029345,17.375 Z M6.98988002,15.409041 C7.33501017,15.4032959 7.61945075,15.6784219 7.62519584,16.023552 C7.63057519,16.3467108 7.74731641,16.6500986 7.95299373,16.8913531 C8.17693365,17.1540292 8.14553176,17.5485095 7.88285564,17.7724494 C7.62017952,17.9963893 7.22569928,17.9649874 7.00175936,17.7023113 C6.60957687,17.2422907 6.38562164,16.6602745 6.37536899,16.0443568 C6.3696239,15.6992267 6.64474986,15.4147861 6.98988002,15.409041 Z M22,14.7935328 C22.345178,14.7935328 22.625,15.0733548 22.625,15.4185328 L22.625,16 C22.625,16.3431799 22.5587904,16.678203 22.431654,16.9901793 C22.3013887,17.3098335 21.936657,17.4633635 21.6170028,17.3330982 C21.2973486,17.2028329 21.1438186,16.8381012 21.2740839,16.518447 C21.3404391,16.3556197 21.375,16.1807405 21.375,16 L21.375,15.4185328 C21.375,15.0733548 21.654822,14.7935328 22,14.7935328 Z M7,11.3294019 C7.34517797,11.3294019 7.625,11.6092239 7.625,11.9544019 L7.625,13.3044019 C7.625,13.6495799 7.34517797,13.9294019 7,13.9294019 C6.65482203,13.9294019 6.375,13.6495799 6.375,13.3044019 L6.375,11.9544019 C6.375,11.6092239 6.65482203,11.3294019 7,11.3294019 Z M22,10.7135328 C22.345178,10.7135328 22.625,10.9933548 22.625,11.3385328 L22.625,12.6885328 C22.625,13.0337107 22.345178,13.3135328 22,13.3135328 C21.654822,13.3135328 21.375,13.0337107 21.375,12.6885328 L21.375,11.3385328 C21.375,10.9933548 21.654822,10.7135328 22,10.7135328 Z M7,7.24940184 C7.34517797,7.24940184 7.625,7.52922387 7.625,7.87440184 L7.625,9.22440186 C7.625,9.56957983 7.34517797,9.84940186 7,9.84940186 C6.65482203,9.84940186 6.375,9.56957983 6.375,9.22440186 L6.375,7.87440184 C6.375,7.52922387 6.65482203,7.24940184 7,7.24940184 Z M22,6.63353271 C22.345178,6.63353271 22.625,6.91335474 22.625,7.25853271 L22.625,8.60853274 C22.625,8.95371071 22.345178,9.23353274 22,9.23353274 C21.654822,9.23353274 21.375,8.95371071 21.375,8.60853274 L21.375,7.25853271 C21.375,6.91335474 21.654822,6.63353271 22,6.63353271 Z M6.85203131,3.49078232 C7.05066164,3.20848137 7.44053346,3.14065293 7.72283441,3.33928326 C8.00513536,3.53791358 8.0729638,3.92778541 7.87433347,4.21008635 C7.71277357,4.43970142 7.625,4.71244835 7.625,5 L7.625,5.14440182 C7.625,5.48957979 7.34517797,5.76940182 7,5.76940182 C6.65482203,5.76940182 6.375,5.48957979 6.375,5.14440182 L6.375,5 C6.375,4.45283578 6.54347711,3.92931124 6.85203131,3.49078232 Z M20.6742845,3.01542222 C20.8779596,2.73673907 21.2689882,2.67593301 21.5476713,2.87960808 C22.037257,3.23742093 22.3909544,3.7550285 22.5426114,4.34556314 C22.6284714,4.67989214 22.4270475,5.02052267 22.0927185,5.10638272 C21.7583895,5.19224277 21.417759,4.99081889 21.331899,4.65648989 C21.2527262,4.3482005 21.0672181,4.07672435 20.8100986,3.88880903 C20.5314155,3.68513396 20.4706094,3.29410536 20.6742845,3.01542222 Z M10.35,2.375 C10.695178,2.375 10.975,2.65482203 10.975,3 C10.975,3.34517797 10.695178,3.625 10.35,3.625 L9,3.625 C8.65482203,3.625 8.375,3.34517797 8.375,3 C8.375,2.65482203 8.65482203,2.375 9,2.375 L10.35,2.375 Z M14.4300001,2.375 C14.775178,2.375 15.0550001,2.65482203 15.0550001,3 C15.0550001,3.34517797 14.775178,3.625 14.4300001,3.625 L13.08,3.625 C12.7348221,3.625 12.455,3.34517797 12.455,3 C12.455,2.65482203 12.7348221,2.375 13.08,2.375 L14.4300001,2.375 Z M18.5100001,2.375 C18.8551781,2.375 19.1350001,2.65482203 19.1350001,3 C19.1350001,3.34517797 18.8551781,3.625 18.5100001,3.625 L17.1600001,3.625 C16.8148221,3.625 16.5350001,3.34517797 16.5350001,3 C16.5350001,2.65482203 16.8148221,2.375 17.1600001,2.375 L18.5100001,2.375 Z" id="Rectangle" fill="currentColor" fill-rule="nonzero" transform="translate(14.5, 10.5) rotate(180) translate(-14.5, -10.5)"></path>
<path d="M4.1678365,7.5 L3.5,7.5 C2.3954305,7.5 1.5,8.3954305 1.5,9.5 L1.5,20.5 C1.5,21.6045695 2.3954305,22.5 3.5,22.5 L14.5,22.5 C15.6045695,22.5 16.5,21.6045695 16.5,20.5 L16.5,20.3293874 L16.5,20.3293874" id="Path-9" stroke="currentColor" stroke-width="1.25" stroke-linecap="round"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -80,6 +80,7 @@ import notificationsError from './../../assets/icons/notifications-error.svg';
import notificationsSuccess from './../../assets/icons/notifications-success.svg';
/** Tools */
import toggleDicomOverlay from './../../assets/icons/toggle-dicom-overlay.svg';
import toolZoom from './../../assets/icons/tool-zoom.svg';
import toolCapture from './../../assets/icons/tool-capture.svg';
import toolLayout from './../../assets/icons/tool-layout.svg';
@ -209,6 +210,7 @@ const ICONS = {
'notifications-warning': notificationsWarning,
/** Tools */
'toggle-dicom-overlay': toggleDicomOverlay,
'tool-zoom': toolZoom,
'tool-capture': toolCapture,
'tool-layout': toolLayout,

View File

@ -1376,10 +1376,10 @@
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
"@cornerstonejs/adapters@^1.11.4":
version "1.11.4"
resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-1.11.4.tgz#b318fe3180b7ceda5537420e8cd4e8d2ddac68f3"
integrity sha512-Qb7qfg0HD06yvpu8KgXkstvmrTUIbFft2HWblUbLe0gxO3ze+1LE2ZAT2qXyvC+nfchPTH2Ybo1D3yBxO7CPdQ==
"@cornerstonejs/adapters@^1.13.2":
version "1.13.2"
resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-1.13.2.tgz#4c7a40b652a6c6c9572186852f0c87a8121479bf"
integrity sha512-YpMBWLIGbLIVwzQ8gtOE0fE0KW5gH8DGEdXUV0gvKGjsygsKFIdTw3xDC6RJr5n/cpVT0pJHXNhk2bbpiZmfkQ==
dependencies:
"@babel/runtime-corejs2" "^7.17.8"
buffer "^6.0.3"
@ -1428,43 +1428,43 @@
resolved "https://registry.yarnpkg.com/@cornerstonejs/codec-openjph/-/codec-openjph-2.4.2.tgz#e96721d56f6ec96f7f95c16321d88cc8467d8d81"
integrity sha512-lgdvBvvNezleY+4pIe2ceUsJzlZe/0PipdeubQ3vZZOz3xxtHHMR1XFCl4fgd8gosR8COHuD7h6q+MwgrwBsng==
"@cornerstonejs/core@^1.11.4":
version "1.11.4"
resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-1.11.4.tgz#035a950a04641a103924ab93b30f257fd884fc8c"
integrity sha512-5kS6xgBimkfjjvd/o+6o4c0NvYVw2lCGDvow3hC5V7aCd6Pn8eo2BaU45QJ8y0A0NJ9xmtr37yb3v8+7lfkGSw==
"@cornerstonejs/core@^1.13.2":
version "1.13.2"
resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-1.13.2.tgz#15c144ca4da9db257e96fe9f95643b4eb8f707d1"
integrity sha512-w2ZonXmOoE8GcDQ0/mY1m/P9CYORH51kh9e26sTQ3CmrvHmAtHI7se4oqcDcUKvSdsA0luw1XKR+TqBR0VcAqQ==
dependencies:
"@kitware/vtk.js" "27.3.1"
detect-gpu "^5.0.22"
gl-matrix "^3.4.3"
lodash.clonedeep "4.5.0"
"@cornerstonejs/dicom-image-loader@^1.11.4":
version "1.11.4"
resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-1.11.4.tgz#4daa4f91e9a5f23fa8f39ebb3c73dcc148184b68"
integrity sha512-Hw5XS+SN7VF/C70CzYd8alK/91SccSbNArVc9erwrBP4EmLWOj9XmKMNiV7KXS7d60G0nEAzCKo+e0wQWOvxWA==
"@cornerstonejs/dicom-image-loader@^1.13.2":
version "1.13.2"
resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-1.13.2.tgz#8f525d246efc1188c15eb1630969524e2002deac"
integrity sha512-FyAY7AGU7iQocmmRGYZdoyhSGyNlonpM1qMwhUjA5OoA6hJcWilVW05R0SFrHAbV9DulASaXWsf1Ue0giS0xog==
dependencies:
"@cornerstonejs/codec-charls" "^1.2.3"
"@cornerstonejs/codec-libjpeg-turbo-8bit" "^1.2.2"
"@cornerstonejs/codec-openjpeg" "^1.2.2"
"@cornerstonejs/codec-openjph" "^2.4.2"
"@cornerstonejs/core" "^1.11.4"
"@cornerstonejs/core" "^1.13.2"
dicom-parser "^1.8.9"
pako "^2.0.4"
uuid "^9.0.0"
"@cornerstonejs/streaming-image-volume-loader@^1.11.4":
version "1.11.4"
resolved "https://registry.yarnpkg.com/@cornerstonejs/streaming-image-volume-loader/-/streaming-image-volume-loader-1.11.4.tgz#ca166f7488e8bba78e8e2216b5fc00e36ed2000b"
integrity sha512-gucQKRjU+UET1BGho4gOi0iy9iT0WoUnuXqb3zS9y7FrBr10VW6F51kbm+BaS0H0PTHqlC5nwHNrsxWavOqleg==
"@cornerstonejs/streaming-image-volume-loader@^1.13.2":
version "1.13.2"
resolved "https://registry.yarnpkg.com/@cornerstonejs/streaming-image-volume-loader/-/streaming-image-volume-loader-1.13.2.tgz#4b4ba637d79bfd194367a88697e6d3dc2440505d"
integrity sha512-V+2nQmIXQZQvHL6wYMHuW6NsIWi/sDmsJRyXvWKUSJvrCmj7JIxfeECr1+Mn11yizy3bYeA6eDWWGyapFh/2iw==
dependencies:
"@cornerstonejs/core" "^1.11.4"
"@cornerstonejs/core" "^1.13.2"
"@cornerstonejs/tools@^1.11.4":
version "1.11.4"
resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-1.11.4.tgz#20ae1501d6f18346230f4b9bf62e23e30343407a"
integrity sha512-OLo69mbL2mgAUKuXSFLif+aJtbqT6hlWI5F6MsqgVun0BP1qLn2FgCfNwSphco4ejjiJG9CSnPBhfdcCxveaoA==
"@cornerstonejs/tools@^1.13.2":
version "1.13.2"
resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-1.13.2.tgz#2074d0d7f1dba61295fcb81616bf48ea530d747f"
integrity sha512-DI8GpbygBWG5ha9mawk0gSUfT+xBn/NE6gwo9jjjN2MTpiI1N8AcsNktLG2mlmq89wRMZhu4xvmo9QQDlf2dPQ==
dependencies:
"@cornerstonejs/core" "^1.11.4"
"@cornerstonejs/core" "^1.13.2"
lodash.clonedeep "4.5.0"
lodash.get "^4.4.2"