|
@@ -1,21 +1,97 @@
|
|
|
import React, { useEffect, useRef } from 'react';
|
|
|
import * as cornerstone from '@cornerstonejs/core';
|
|
|
+import type { Types } from '@cornerstonejs/core';
|
|
|
import * as cornerstoneTools from '@cornerstonejs/tools';
|
|
|
import * as cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader';
|
|
|
-// import createImageIdsAndCacheMetaData from '../../createImageIdsAndCacheMetaData';
|
|
|
-import store from '@/states/store';
|
|
|
+import { useSelector } from 'react-redux';
|
|
|
+import { RootState } from '@/states/store';
|
|
|
import { SystemMode } from '@/states/systemModeSlice';
|
|
|
+import store from '@/states/store';
|
|
|
+import { clearAction } from '@/states/view/functionAreaSlice';
|
|
|
+import { useDispatch } from 'react-redux';
|
|
|
+
|
|
|
+const { PanTool, WindowLevelTool, StackScrollTool, ZoomTool, LabelTool, ToolGroupManager, Enums: csToolsEnums } = cornerstoneTools;
|
|
|
+const { MouseBindings } = csToolsEnums;
|
|
|
+let toolGroup: cornerstoneTools.Types.IToolGroup;
|
|
|
+let currentViewportId: string;
|
|
|
+
|
|
|
+function registerTools(viewportId, renderingEngineId) {
|
|
|
+ // Add tools to Cornerstone3D
|
|
|
+ cornerstoneTools.addTool(PanTool);
|
|
|
+ cornerstoneTools.addTool(WindowLevelTool);
|
|
|
+ cornerstoneTools.addTool(StackScrollTool);
|
|
|
+ cornerstoneTools.addTool(ZoomTool);
|
|
|
+ cornerstoneTools.addTool(LabelTool);
|
|
|
+ // Define a tool group
|
|
|
+ const toolGroupId = 'STACK_TOOL_GROUP_ID';
|
|
|
+ const toolGroupTmp = ToolGroupManager.createToolGroup(toolGroupId);
|
|
|
+ if (!toolGroupTmp) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ toolGroup = toolGroupTmp;
|
|
|
+ // Add tools to the tool group
|
|
|
+ toolGroup.addTool(PanTool.toolName);
|
|
|
+ toolGroup.addTool(WindowLevelTool.toolName);
|
|
|
+ toolGroup.addTool(StackScrollTool.toolName);
|
|
|
+ toolGroup.addTool(ZoomTool.toolName);
|
|
|
+ toolGroup.addTool(LabelTool.toolName);
|
|
|
+
|
|
|
+ // Set the LabelTool as active
|
|
|
+ // toolGroup.setToolActive(LabelTool.toolName, {
|
|
|
+ // bindings: [
|
|
|
+ // {
|
|
|
+ // mouseButton: MouseBindings.Primary, // Left Click
|
|
|
+ // },
|
|
|
+ // ],
|
|
|
+ // });
|
|
|
+ // Set the initial state of the tools
|
|
|
+ // toolGroup.setToolActive(WindowLevelTool.toolName, {
|
|
|
+ // bindings: [
|
|
|
+ // {
|
|
|
+ // mouseButton: MouseBindings.Primary, // Left Click
|
|
|
+ // },
|
|
|
+ // ],
|
|
|
+ // });
|
|
|
+
|
|
|
+ toolGroup.setToolActive(PanTool.toolName, {
|
|
|
+ bindings: [
|
|
|
+ {
|
|
|
+ mouseButton: MouseBindings.Auxiliary, // Middle Click
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ });
|
|
|
+
|
|
|
+ toolGroup.setToolActive(ZoomTool.toolName, {
|
|
|
+ bindings: [
|
|
|
+ {
|
|
|
+ mouseButton: MouseBindings.Secondary, // Right Click
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ });
|
|
|
+
|
|
|
+ toolGroup.setToolActive(StackScrollTool.toolName, {
|
|
|
+ bindings: [
|
|
|
+ {
|
|
|
+ mouseButton: MouseBindings.Wheel, // Mouse Wheel
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ toolGroup.addViewport(viewportId, renderingEngineId);
|
|
|
+}
|
|
|
|
|
|
const StackViewer = ({ imageIndex }) => {
|
|
|
const elementRef = useRef<HTMLDivElement>(null);
|
|
|
+ const action = useSelector((state: RootState) => state.functionArea.action);
|
|
|
+ const dispatch = useDispatch();
|
|
|
|
|
|
useEffect(() => {
|
|
|
const setup = async () => {
|
|
|
// 初始化 Cornerstone
|
|
|
cornerstone.init();
|
|
|
cornerstoneTools.init();
|
|
|
- // 注册加载器
|
|
|
- // cornerstoneDICOMImageLoader.init();
|
|
|
const state = store.getState();
|
|
|
console.log(`当前系统模式:${state.systemMode.mode}`);
|
|
|
|
|
@@ -24,19 +100,15 @@ const StackViewer = ({ imageIndex }) => {
|
|
|
? state.product.guest
|
|
|
: state.userInfo.token;
|
|
|
console.log(`token stack.image.viewer: ${token}`);
|
|
|
- // const { productName, language, source } = state.product;
|
|
|
|
|
|
cornerstoneDICOMImageLoader.init({
|
|
|
maxWebWorkers: navigator.hardwareConcurrency || 1,
|
|
|
errorInterceptor: (error) => {
|
|
|
if (error.status === 401) {
|
|
|
console.error('Authentication failed. Please refresh the token.');
|
|
|
- // Optionally, trigger token refresh
|
|
|
}
|
|
|
console.error(`请求dcm文件出错:${error}`);
|
|
|
},
|
|
|
- //startWebWorkersOnDemand: true,
|
|
|
-
|
|
|
beforeSend: (xhr, imageId, defaultHeaders) => {
|
|
|
return {
|
|
|
...defaultHeaders,
|
|
@@ -47,61 +119,193 @@ const StackViewer = ({ imageIndex }) => {
|
|
|
};
|
|
|
},
|
|
|
});
|
|
|
- // // Get Cornerstone imageIds and fetch metadata into RAM
|
|
|
- // const imageIds = await createImageIdsAndCacheMetaData({
|
|
|
- // StudyInstanceUID:
|
|
|
- // '1.3.6.1.4.1.14519.5.2.1.7009.2403.334240657131972136850343327463',
|
|
|
- // SeriesInstanceUID:
|
|
|
- // '1.3.6.1.4.1.14519.5.2.1.7009.2403.226151125820845824875394858561',
|
|
|
- // wadoRsRoot: 'https://d14fa38qiwhyfd.cloudfront.net/dicomweb',
|
|
|
- // });
|
|
|
+
|
|
|
// Instantiate a rendering engine
|
|
|
const renderingEngineId = 'myRenderingEngine';
|
|
|
- const renderingEngine = new cornerstone.RenderingEngine(
|
|
|
- renderingEngineId
|
|
|
- );
|
|
|
+ const renderingEngine = new cornerstone.RenderingEngine(renderingEngineId);
|
|
|
|
|
|
const viewportId = 'CT_AXIAL_STACK';
|
|
|
-
|
|
|
+ currentViewportId = viewportId;
|
|
|
const viewportInput: cornerstone.Types.PublicViewportInput = {
|
|
|
viewportId,
|
|
|
- // @ts-expect-error why error ?
|
|
|
- element: elementRef.current,
|
|
|
+ element: elementRef.current!,
|
|
|
type: cornerstone.Enums.ViewportType.STACK,
|
|
|
};
|
|
|
|
|
|
renderingEngine.enableElement(viewportInput);
|
|
|
+ registerTools(viewportId, renderingEngineId);
|
|
|
+
|
|
|
// Get the stack viewport that was created
|
|
|
- const viewport = renderingEngine.getViewport(
|
|
|
- viewportId
|
|
|
- ) as cornerstone.Types.IStackViewport;
|
|
|
- // 给定一个dcm文件路径,加载并显示出来
|
|
|
- const imageId1 =
|
|
|
- 'dicomweb:https://ohif-assets-new.s3.us-east-1.amazonaws.com/ACRIN-Regular/CT+CT+IMAGES/CT000000.dcm';
|
|
|
- const imageId2 =
|
|
|
- 'dicomweb:https://ohif-assets-new.s3.us-east-1.amazonaws.com/ACRIN-Regular/CT+CT+IMAGES/CT000005.dcm';
|
|
|
- const imageId3 =
|
|
|
- 'dicomweb:https://ohif-dicom-json-example.s3.amazonaws.com/LIDC-IDRI-0001/01-01-2000-30178/3000566.000000-03192/1-001.dcm';
|
|
|
- const imageId4 =
|
|
|
- 'dicomweb:http://192.168.11.12:6001/dr/api/v1/auth/image/dcm/DemoImage.dcm';
|
|
|
- const imageId5 =
|
|
|
- 'dicomweb:http://localhost:10086/dr/api/v1/pub/dcm/DemoImage.dcm';
|
|
|
- const imageId6 =
|
|
|
- 'dicomweb:http://localhost:10086/dr/api/v1/auth/image/dcm/DemoImage.dcm';
|
|
|
- const imageId7 =
|
|
|
- 'dicomweb:http://localhost:10086/dr/api/v1/pub/dcm/DemoImage.dcm';
|
|
|
- imageIndex = 5;
|
|
|
- viewport.setStack(
|
|
|
- [imageId1, imageId2, imageId3, imageId4, imageId5, imageId6, imageId7],
|
|
|
- imageIndex
|
|
|
- );
|
|
|
- // viewport.setStack(imageIds, imageIndex);
|
|
|
+ const viewport = renderingEngine.getViewport(viewportId) as cornerstone.Types.IStackViewport;
|
|
|
|
|
|
+ // 给定一个dcm文件路径,加载并显示出来
|
|
|
+ const imageId1 = 'dicomweb:https://ohif-assets-new.s3.us-east-1.amazonaws.com/ACRIN-Regular/CT+CT+IMAGES/CT000000.dcm';
|
|
|
+ const imageId2 = 'dicomweb:https://ohif-assets-new.s3.us-east-1.amazonaws.com/ACRIN-Regular/CT+CT+IMAGES/CT000005.dcm';
|
|
|
+ const imageId3 = 'dicomweb:https://ohif-dicom-json-example.s3.amazonaws.com/LIDC-IDRI-0001/01-01-2000-30178/3000566.000000-03192/1-001.dcm';
|
|
|
+ const imageId4 = 'dicomweb:http://localhost:10086/dr/api/v1/auth/image/dcm/DemoImage.dcm';
|
|
|
+ const imageId5 = 'dicomweb:http://localhost:10086/dr/api/v1/pub/dcm/DemoImage.dcm';
|
|
|
+ const imageId6 = 'dicomweb:http://localhost:10086/dr/api/v1/auth/image/dcm/DemoImage.dcm';
|
|
|
+ const imageId7 = 'dicomweb:http://localhost:10086/dr/api/v1/pub/dcm/DemoImage.dcm';
|
|
|
+ imageIndex = 6;
|
|
|
+ await viewport.setStack([imageId1, imageId2, imageId3, imageId4, imageId5, imageId6, imageId7], imageIndex);
|
|
|
viewport.render();
|
|
|
};
|
|
|
|
|
|
setup();
|
|
|
- }, [elementRef]);
|
|
|
+ }, [elementRef, imageIndex]);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (action) {
|
|
|
+ // Handle the action
|
|
|
+ switch (action) {
|
|
|
+ case 'Add L Mark':
|
|
|
+ // Implement the logic to add an L mark
|
|
|
+ console.log('Adding L Mark');
|
|
|
+ toolGroup.setToolActive(LabelTool.toolName, {
|
|
|
+ bindings: [
|
|
|
+ // {
|
|
|
+ // mouseButton: MouseBindings.Primary, // Left Click
|
|
|
+ // },
|
|
|
+ ],
|
|
|
+ });
|
|
|
+ const position: Types.Point3 = [100, 100, 0]; // Example position
|
|
|
+ const text = 'L'; // Predefined text
|
|
|
+ LabelTool.hydrate(currentViewportId, position, text);
|
|
|
+ toolGroup.setToolPassive(LabelTool.toolName, { removeAllBindings: true });
|
|
|
+ // const enabledElement = cornerstone.getEnabledElementByViewportId(currentViewportId);
|
|
|
+ // cursors.elementCursor.resetElementCursor(elementRef.current as HTMLDivElement);
|
|
|
+ break;
|
|
|
+ case 'Add R Mark':
|
|
|
+ // Implement the logic to add an R mark
|
|
|
+ console.log('Adding R Mark');
|
|
|
+ break;
|
|
|
+ case 'Delete Selected Mark':
|
|
|
+ // Implement the logic to delete the selected mark
|
|
|
+ console.log('Deleting Selected Mark');
|
|
|
+ break;
|
|
|
+ case 'Horizontal Flip':
|
|
|
+ // Implement the logic to flip the image horizontally
|
|
|
+ console.log('Flipping Image Horizontally');
|
|
|
+ break;
|
|
|
+ // case 'Vertical Flip':
|
|
|
+ // { // Implement the logic to flip the image vertically
|
|
|
+ // console.log('Flipping Image Vertically');
|
|
|
+ // }
|
|
|
+ // break;
|
|
|
+ case 'Rotate Counterclockwise 90':
|
|
|
+ // Implement the logic to rotate the image counterclockwise
|
|
|
+ console.log('Rotating Image Counterclockwise 90°');
|
|
|
+ break;
|
|
|
+ case 'Rotate Clockwise 90':
|
|
|
+ // Implement the logic to rotate the image clockwise
|
|
|
+ console.log('Rotating Image Clockwise 90°');
|
|
|
+ break;
|
|
|
+ case 'Rotate Any Angle':
|
|
|
+ // Implement the logic to rotate the image by any angle
|
|
|
+ console.log('Rotating Image by Any Angle');
|
|
|
+ break;
|
|
|
+ case 'Crop Image':
|
|
|
+ // Implement the logic to crop the image
|
|
|
+ console.log('Cropping Image');
|
|
|
+ break;
|
|
|
+ case 'Delete Digital Mask':
|
|
|
+ // Implement the logic to delete the digital mask
|
|
|
+ console.log('Deleting Digital Mask');
|
|
|
+ break;
|
|
|
+ case 'Adjust Brightness and Contrast':
|
|
|
+ // Implement the logic to adjust brightness and contrast
|
|
|
+ console.log('Adjusting Brightness and Contrast');
|
|
|
+ break;
|
|
|
+ case 'Crop Selected Area':
|
|
|
+ // Implement the logic to crop the selected area
|
|
|
+ console.log('Cropping Selected Area');
|
|
|
+ break;
|
|
|
+ case 'Delete Mask':
|
|
|
+ // Implement the logic to delete the mask
|
|
|
+ console.log('Deleting Mask');
|
|
|
+ break;
|
|
|
+ case 'Image Comparison':
|
|
|
+ // Implement the logic for image comparison
|
|
|
+ console.log('Comparing Images');
|
|
|
+ break;
|
|
|
+ case 'Invert Contrast':
|
|
|
+ // Implement the logic to invert the contrast
|
|
|
+ console.log('Inverting Contrast');
|
|
|
+ break;
|
|
|
+ case '1x1 Layout':
|
|
|
+ // Implement the logic for 1x1 layout
|
|
|
+ console.log('Setting 1x1 Layout');
|
|
|
+ break;
|
|
|
+ case '1x2 Layout':
|
|
|
+ // Implement the logic for 1x2 layout
|
|
|
+ console.log('Setting 1x2 Layout');
|
|
|
+ break;
|
|
|
+ case '2x2 Layout':
|
|
|
+ // Implement the logic for 2x2 layout
|
|
|
+ console.log('Setting 2x2 Layout');
|
|
|
+ break;
|
|
|
+ case '4x4 Layout':
|
|
|
+ // Implement the logic for 4x4 layout
|
|
|
+ console.log('Setting 4x4 Layout');
|
|
|
+ break;
|
|
|
+ case 'Magnifier':
|
|
|
+ // Implement the logic for magnifier
|
|
|
+ console.log('Activating Magnifier');
|
|
|
+ break;
|
|
|
+ case 'Fit Size':
|
|
|
+ // Implement the logic to fit the image size
|
|
|
+ console.log('Fitting Image Size');
|
|
|
+ break;
|
|
|
+ case 'Original Size':
|
|
|
+ // Implement the logic to set the image to original size
|
|
|
+ console.log('Setting Image to Original Size');
|
|
|
+ break;
|
|
|
+ case 'Zoom Image':
|
|
|
+ // Implement the logic to zoom the image
|
|
|
+ console.log('Zooming Image');
|
|
|
+ break;
|
|
|
+ case 'Reset Cursor':
|
|
|
+ // Implement the logic to reset the cursor
|
|
|
+ console.log('Resetting Cursor');
|
|
|
+ break;
|
|
|
+ case 'Pan':
|
|
|
+ // Implement the logic to pan the image
|
|
|
+ console.log('Panning Image');
|
|
|
+ break;
|
|
|
+ case 'Invert Image':
|
|
|
+ // Implement the logic to invert the image
|
|
|
+ console.log('Inverting Image');
|
|
|
+ break;
|
|
|
+ case 'Reset Image':
|
|
|
+ // Implement the logic to reset the image
|
|
|
+ console.log('Resetting Image');
|
|
|
+ break;
|
|
|
+ case 'Snapshot':
|
|
|
+ // Implement the logic to take a snapshot
|
|
|
+ console.log('Taking Snapshot');
|
|
|
+ break;
|
|
|
+ case 'Advanced Processing':
|
|
|
+ // Implement the logic for advanced processing
|
|
|
+ console.log('Performing Advanced Processing');
|
|
|
+ break;
|
|
|
+ case 'Musician':
|
|
|
+ // Implement the logic for musician
|
|
|
+ console.log('Activating Musician');
|
|
|
+ break;
|
|
|
+ case 'Image Measurement':
|
|
|
+ // Implement the logic for image measurement
|
|
|
+ console.log('Measuring Image');
|
|
|
+ break;
|
|
|
+ case 'More':
|
|
|
+ // Implement the logic for more options
|
|
|
+ console.log('Showing More Options');
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ dispatch(clearAction());//清理后可连续同一个action触发响应
|
|
|
+ }
|
|
|
+ }, [action]);
|
|
|
|
|
|
return (
|
|
|
<div
|