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 { 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'; import { IP_PORT } from '@/API/config'; 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); } function addRLabel(viewportId) { toolGroup.setToolActive(LabelTool.toolName, { bindings: [], }); const element = document.getElementById(viewportId); const elementHeight = element ? element.getBoundingClientRect().height : 0; const position: Types.Point3 = [100, elementHeight / 2, 0]; // Example position const text = 'R'; // Predefined text LabelTool.hydrate(viewportId, position, text); toolGroup.setToolPassive(LabelTool.toolName, { removeAllBindings: true }); } const StackViewer = ({ imageIndex }) => { const elementRef = useRef(null); const action = useSelector((state: RootState) => state.functionArea.action); const dispatch = useDispatch(); useEffect(() => { const setup = async () => { // 初始化 Cornerstone cornerstone.init(); cornerstoneTools.init(); const state = store.getState(); console.log(`当前系统模式:${state.systemMode.mode}`); const token = state.systemMode.mode === SystemMode.Emergency ? state.product.guest : state.userInfo.token; console.log(`token stack.image.viewer: ${token}`); cornerstoneDICOMImageLoader.init({ maxWebWorkers: navigator.hardwareConcurrency || 1, errorInterceptor: (error) => { if (error.status === 401) { console.error('Authentication failed. Please refresh the token.'); } console.error(`请求dcm文件出错:${error}`); }, beforeSend: (xhr, imageId, defaultHeaders) => { return { ...defaultHeaders, Authorization: `Bearer ${token}`, Language: 'en', Product: 'DROS', Source: 'Electron', }; }, }); // Instantiate a rendering engine const renderingEngineId = 'myRenderingEngine'; const renderingEngine = new cornerstone.RenderingEngine(renderingEngineId); const viewportId = 'CT_AXIAL_STACK'; currentViewportId = viewportId; const viewportInput: cornerstone.Types.PublicViewportInput = { viewportId, 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:${IP_PORT}/dr/api/v1/auth/image/dcm/CTImage.dcm`; const imageId5 = `dicomweb:${IP_PORT}/dr/api/v1/pub/dcm/CTImage.dcm`; const imageId6 = `dicomweb:${IP_PORT}/dr/api/v1/auth/image/dcm/CTImage.dcm`; const imageId7 = `dicomweb:${IP_PORT}/dr/api/v1/pub/dcm/CTImage.dcm`; imageIndex = 6; await viewport.setStack([imageId1, imageId2, imageId3, imageId4, imageId5, imageId6, imageId7], imageIndex); viewport.render(); }; setup(); }, [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 addRLabel(currentViewportId); console.log('Adding R Mark'); break; case 'Delete Selected Mark': // Implement the logic to delete the selected mark const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId).viewport; const allAnnotations = cornerstoneTools.annotation.state.getAllAnnotations(); // const allAnnotations = cornerstoneTools.annotation.state.getAnnotations(LabelTool.toolName, element.element); console.log(`allAnnotations 数量:${allAnnotations.length}`); for (const annotation of allAnnotations) { if (annotation.data.text === 'L' || annotation.data.text === 'R') { console.log(`Deleting annotation with UID: ${annotation.annotationUID}`); cornerstoneTools.annotation.state.removeAnnotation(annotation.annotationUID!); } // cornerstoneTools.annotation.state.removeAnnotation(annotation.annotationUID!); } // 触发视口重新渲染 viewport.render(); 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 { const viewport = cornerstone.getEnabledElementByViewportId(currentViewportId).viewport; const targetBool = !viewport.getProperties().invert; viewport.setProperties({ invert: targetBool, }); viewport.render(); } 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 (
); }; export default StackViewer;