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:
parent
ef58893c27
commit
69115da06d
@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 };
|
||||
|
||||
247
extensions/cornerstone/src/tools/ImageOverlayViewerTool.tsx
Normal file
247
extensions/cornerstone/src/tools/ImageOverlayViewerTool.tsx
Normal 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;
|
||||
@ -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",
|
||||
|
||||
@ -84,6 +84,7 @@ function modeFactory({ modeConfiguration }) {
|
||||
{ toolName: toolNames.CalibrationLine },
|
||||
],
|
||||
// enabled
|
||||
enabled: [{ toolName: toolNames.ImageOverlayViewer }],
|
||||
// disabled
|
||||
};
|
||||
|
||||
|
||||
@ -38,6 +38,7 @@ function initDefaultToolGroup(extensionManager, toolGroupService, commandsManage
|
||||
{ toolName: toolNames.CalibrationLine },
|
||||
],
|
||||
// enabled
|
||||
enabled: [{ toolName: toolNames.ImageOverlayViewer }],
|
||||
// disabled
|
||||
disabled: [{ toolName: toolNames.ReferenceLines }],
|
||||
};
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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
|
||||
|
||||
8
platform/ui/src/assets/icons/toggle-dicom-overlay.svg
Normal file
8
platform/ui/src/assets/icons/toggle-dicom-overlay.svg
Normal 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 |
@ -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,
|
||||
|
||||
46
yarn.lock
46
yarn.lock
@ -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"
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user