start a c3d viewer
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: { browser: true, es2020: true },
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
],
|
||||
ignorePatterns: ['dist', '.eslintrc.cjs'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['react-refresh'],
|
||||
rules: {
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
@@ -0,0 +1,3 @@
|
||||
# React + Vite + Cornerstone3D
|
||||
|
||||
see code
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 151 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
Executable
BIN
Binary file not shown.
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + React + TS</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
Generated
+6541
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "vite-react-cornerstone-3d",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cornerstonejs/calculate-suv": "1.1.0",
|
||||
"@cornerstonejs/core": "^2.1.16",
|
||||
"@cornerstonejs/dicom-image-loader": "^2.1.16",
|
||||
"@cornerstonejs/nifti-volume-loader": "^2.1.16",
|
||||
"@cornerstonejs/tools": "^2.1.16",
|
||||
"dcmjs": "0.33.0",
|
||||
"dicom-parser": "1.8.21",
|
||||
"dicomweb-client": "0.10.4",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"vite-plugin-wasm": "^3.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/preset-react": "^7.25.9",
|
||||
"@originjs/vite-plugin-commonjs": "^1.0.3",
|
||||
"@rollup/plugin-babel": "^6.0.4",
|
||||
"@rollup/plugin-commonjs": "^28.0.1",
|
||||
"@rollup/plugin-node-resolve": "^15.3.0",
|
||||
"@rollup/plugin-typescript": "^12.1.1",
|
||||
"@rollup/plugin-wasm": "^6.2.2",
|
||||
"@types/react": "^18.2.66",
|
||||
"@types/react-dom": "^18.2.22",
|
||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||
"@typescript-eslint/parser": "^7.2.0",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.6",
|
||||
"rollup": "^4.24.3",
|
||||
"rollup-plugin-copy": "^3.5.0",
|
||||
"rollup-plugin-dts": "^6.1.1",
|
||||
"rollup-plugin-peer-deps-external": "^2.2.4",
|
||||
"rollup-plugin-postcss": "^4.0.2",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"typescript": "^5.6.3",
|
||||
"vite": "^5.2.0",
|
||||
"vite-plugin-static-copy": "^1.0.5"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 87 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 130 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
+5
@@ -0,0 +1,5 @@
|
||||
#HSQL Database Engine 2.7.2
|
||||
#Mon May 19 12:05:18 BST 2025
|
||||
modified=no
|
||||
tx_timestamp=159
|
||||
version=2.7.2
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
SET DATABASE UNIQUE NAME HSQLDB96E8381E30
|
||||
SET DATABASE DEFAULT RESULT MEMORY ROWS 0
|
||||
SET DATABASE EVENT LOG LEVEL 0
|
||||
SET DATABASE TRANSACTION CONTROL LOCKS
|
||||
SET DATABASE DEFAULT ISOLATION LEVEL READ COMMITTED
|
||||
SET DATABASE TRANSACTION ROLLBACK ON CONFLICT TRUE
|
||||
SET DATABASE TEXT TABLE DEFAULTS ''
|
||||
SET DATABASE SQL NAMES FALSE
|
||||
SET DATABASE SQL RESTRICT EXEC FALSE
|
||||
SET DATABASE SQL REFERENCES FALSE
|
||||
SET DATABASE SQL SIZE FALSE
|
||||
SET DATABASE SQL TYPES FALSE
|
||||
SET DATABASE SQL TDC DELETE TRUE
|
||||
SET DATABASE SQL TDC UPDATE TRUE
|
||||
SET DATABASE SQL SYS INDEX NAMES TRUE
|
||||
SET DATABASE SQL CONCAT NULLS TRUE
|
||||
SET DATABASE SQL UNIQUE NULLS TRUE
|
||||
SET DATABASE SQL CONVERT TRUNCATE TRUE
|
||||
SET DATABASE SQL AVG SCALE 0
|
||||
SET DATABASE SQL DOUBLE NAN TRUE
|
||||
SET FILES WRITE DELAY 500 MILLIS
|
||||
SET FILES BACKUP INCREMENT TRUE
|
||||
SET FILES CACHE SIZE 10000
|
||||
SET FILES CACHE ROWS 50000
|
||||
SET FILES SCALE 32
|
||||
SET FILES LOB SCALE 32
|
||||
SET FILES DEFRAG 0
|
||||
SET FILES NIO TRUE
|
||||
SET FILES NIO SIZE 256
|
||||
SET FILES LOG TRUE
|
||||
SET FILES LOG SIZE 50
|
||||
SET FILES CHECK 159
|
||||
SET DATABASE COLLATION "SQL_TEXT" PAD SPACE
|
||||
CREATE USER SA PASSWORD DIGEST 'd41d8cd98f00b204e9800998ecf8427e'
|
||||
ALTER USER SA SET LOCAL TRUE
|
||||
CREATE SCHEMA PUBLIC AUTHORIZATION DBA
|
||||
CREATE CACHED TABLE PUBLIC.PATIENT(LOCALPRIMARYKEY VARCHAR(32768) PRIMARY KEY,RECORDINSERTIONTIME BIGINT,PATIENTNAME VARCHAR(32768),PM_PATIENTNAME_CANONICAL VARCHAR(32768),PM_PATIENTNAME_PHONETICCANONICAL VARCHAR(32768),PATIENTID VARCHAR(32768),PATIENTBIRTHDATE VARCHAR(32768),PATIENTBIRTHTIME VARCHAR(32768),PATIENTSEX VARCHAR(32768),OTHERPATIENTNAMES VARCHAR(32768),PM_OTHERPATIENTNAMES_CANONICAL VARCHAR(32768),PM_OTHERPATIENTNAMES_PHONETICCANONICAL VARCHAR(32768),ETHNICGROUP VARCHAR(32768),PATIENTCOMMENTS VARCHAR(32768),PM_USER1 VARCHAR(32768),PM_USER2 VARCHAR(32768),PM_USER3 VARCHAR(32768),PM_USER4 VARCHAR(32768))
|
||||
CREATE INDEX PATIENT_PM_PATIENTNAME_PHONETICCANONICAL_IDX ON PUBLIC.PATIENT(PM_PATIENTNAME_PHONETICCANONICAL)
|
||||
CREATE INDEX PATIENT_PM_PATIENTNAME_CANONICAL_IDX ON PUBLIC.PATIENT(PM_PATIENTNAME_CANONICAL)
|
||||
CREATE INDEX PATIENT_PM_OTHERPATIENTNAMES_PHONETICCANONICAL_IDX ON PUBLIC.PATIENT(PM_OTHERPATIENTNAMES_PHONETICCANONICAL)
|
||||
CREATE INDEX PATIENT_PM_OTHERPATIENTNAMES_CANONICAL_IDX ON PUBLIC.PATIENT(PM_OTHERPATIENTNAMES_CANONICAL)
|
||||
CREATE INDEX PATIENT_ID_IDX ON PUBLIC.PATIENT(PATIENTID)
|
||||
CREATE INDEX PATIENT_NAME_IDX ON PUBLIC.PATIENT(PATIENTNAME)
|
||||
CREATE CACHED TABLE PUBLIC.STUDY(LOCALPRIMARYKEY VARCHAR(32768) PRIMARY KEY,LOCALPARENTREFERENCE VARCHAR(32768),RECORDINSERTIONTIME BIGINT,STUDYDATE VARCHAR(32768),STUDYTIME VARCHAR(32768),ACCESSIONNUMBER VARCHAR(32768),REFERRINGPHYSICIANNAME VARCHAR(32768),PM_REFERRINGPHYSICIANNAME_CANONICAL VARCHAR(32768),PM_REFERRINGPHYSICIANNAME_PHONETICCANONICAL VARCHAR(32768),STUDYDESCRIPTION VARCHAR(32768),PHYSICIANSOFRECORD VARCHAR(32768),PM_PHYSICIANSOFRECORD_CANONICAL VARCHAR(32768),PM_PHYSICIANSOFRECORD_PHONETICCANONICAL VARCHAR(32768),NAMEOFPHYSICIANSREADINGSTUDY VARCHAR(32768),PM_NAMEOFPHYSICIANSREADINGSTUDY_CANONICAL VARCHAR(32768),PM_NAMEOFPHYSICIANSREADINGSTUDY_PHONETICCANONICAL VARCHAR(32768),ADMITTINGDIAGNOSESDESCRIPTION VARCHAR(32768),PATIENTAGE VARCHAR(32768),PATIENTSIZE VARCHAR(32768),PATIENTWEIGHT VARCHAR(32768),OCCUPATION VARCHAR(32768),ADDITIONALPATIENTHISTORY VARCHAR(32768),STUDYINSTANCEUID VARCHAR(32768),STUDYID VARCHAR(32768),OTHERSTUDYNUMBERS INTEGER,INTERPRETATIONAUTHOR VARCHAR(32768),PM_INTERPRETATIONAUTHOR_CANONICAL VARCHAR(32768),PM_INTERPRETATIONAUTHOR_PHONETICCANONICAL VARCHAR(32768),PM_STUDYDATETIME TIMESTAMP,PM_USER1 VARCHAR(32768),PM_USER2 VARCHAR(32768),PM_USER3 VARCHAR(32768),PM_USER4 VARCHAR(32768))
|
||||
CREATE INDEX STUDY_PREFIDX ON PUBLIC.STUDY(LOCALPARENTREFERENCE)
|
||||
CREATE INDEX STUDY_PM_PHYSICIANSOFRECORD_CANONICAL_IDX ON PUBLIC.STUDY(PM_PHYSICIANSOFRECORD_CANONICAL)
|
||||
CREATE INDEX STUDY_PM_PHYSICIANSOFRECORD_PHONETICCANONICAL_IDX ON PUBLIC.STUDY(PM_PHYSICIANSOFRECORD_PHONETICCANONICAL)
|
||||
CREATE INDEX STUDY_PM_INTERPRETATIONAUTHOR_PHONETICCANONICAL_IDX ON PUBLIC.STUDY(PM_INTERPRETATIONAUTHOR_PHONETICCANONICAL)
|
||||
CREATE INDEX STUDY_PM_NAMEOFPHYSICIANSREADINGSTUDY_CANONICAL_IDX ON PUBLIC.STUDY(PM_NAMEOFPHYSICIANSREADINGSTUDY_CANONICAL)
|
||||
CREATE INDEX STUDY_PM_REFERRINGPHYSICIANNAME_CANONICAL_IDX ON PUBLIC.STUDY(PM_REFERRINGPHYSICIANNAME_CANONICAL)
|
||||
CREATE INDEX STUDY_PM_REFERRINGPHYSICIANNAME_PHONETICCANONICAL_IDX ON PUBLIC.STUDY(PM_REFERRINGPHYSICIANNAME_PHONETICCANONICAL)
|
||||
CREATE INDEX STUDY_PM_INTERPRETATIONAUTHOR_CANONICAL_IDX ON PUBLIC.STUDY(PM_INTERPRETATIONAUTHOR_CANONICAL)
|
||||
CREATE INDEX STUDY_PM_NAMEOFPHYSICIANSREADINGSTUDY_PHONETICCANONICAL_IDX ON PUBLIC.STUDY(PM_NAMEOFPHYSICIANSREADINGSTUDY_PHONETICCANONICAL)
|
||||
CREATE INDEX STUDY_UID_IDX ON PUBLIC.STUDY(STUDYINSTANCEUID)
|
||||
CREATE CACHED TABLE PUBLIC.SERIES(LOCALPRIMARYKEY VARCHAR(32768) PRIMARY KEY,LOCALPARENTREFERENCE VARCHAR(32768),RECORDINSERTIONTIME BIGINT,SERIESDATE VARCHAR(32768),SERIESTIME VARCHAR(32768),MODALITY VARCHAR(32768),PRESENTATIONINTENTTYPE VARCHAR(32768),MANUFACTURER VARCHAR(32768),INSTITUTIONNAME VARCHAR(32768),SERIESDESCRIPTION VARCHAR(32768),INSTITUTIONALDEPARTMENTNAME VARCHAR(32768),PERFORMINGPHYSICIANNAME VARCHAR(32768),PM_PERFORMINGPHYSICIANNAME_CANONICAL VARCHAR(32768),PM_PERFORMINGPHYSICIANNAME_PHONETICCANONICAL VARCHAR(32768),OPERATORSNAME VARCHAR(32768),PM_OPERATORSNAME_CANONICAL VARCHAR(32768),PM_OPERATORSNAME_PHONETICCANONICAL VARCHAR(32768),BODYPARTEXAMINED VARCHAR(32768),PROTOCOLNAME VARCHAR(32768),SERIESINSTANCEUID VARCHAR(32768),SERIESNUMBER INTEGER,FRAMEOFREFERENCEUID VARCHAR(32768),LATERALITY VARCHAR(32768),PERFORMEDPROCEDURESTEPSTARTDATE VARCHAR(32768),PERFORMEDPROCEDURESTEPSTARTTIME VARCHAR(32768),PERFORMEDPROCEDURESTEPID VARCHAR(32768),PM_SERIESDATETIME TIMESTAMP,PM_USER1 VARCHAR(32768),PM_USER2 VARCHAR(32768),PM_USER3 VARCHAR(32768),PM_USER4 VARCHAR(32768))
|
||||
CREATE INDEX SERIES_PREFIDX ON PUBLIC.SERIES(LOCALPARENTREFERENCE)
|
||||
CREATE INDEX SERIES_PM_PERFORMINGPHYSICIANNAME_PHONETICCANONICAL_IDX ON PUBLIC.SERIES(PM_PERFORMINGPHYSICIANNAME_PHONETICCANONICAL)
|
||||
CREATE INDEX SERIES_PM_PERFORMINGPHYSICIANNAME_CANONICAL_IDX ON PUBLIC.SERIES(PM_PERFORMINGPHYSICIANNAME_CANONICAL)
|
||||
CREATE INDEX SERIES_PM_OPERATORSNAME_CANONICAL_IDX ON PUBLIC.SERIES(PM_OPERATORSNAME_CANONICAL)
|
||||
CREATE INDEX SERIES_PM_OPERATORSNAME_PHONETICCANONICAL_IDX ON PUBLIC.SERIES(PM_OPERATORSNAME_PHONETICCANONICAL)
|
||||
CREATE INDEX SERIES_UID_IDX ON PUBLIC.SERIES(SERIESINSTANCEUID)
|
||||
CREATE INDEX SERIES_FORUID_IDX ON PUBLIC.SERIES(FRAMEOFREFERENCEUID)
|
||||
CREATE CACHED TABLE PUBLIC.CONCATENATION(LOCALPRIMARYKEY VARCHAR(32768) PRIMARY KEY,LOCALPARENTREFERENCE VARCHAR(32768),RECORDINSERTIONTIME BIGINT,INSTANCENUMBER INTEGER,CONCATENATIONUID VARCHAR(32768),INCONCATENATIONTOTALNUMBER INTEGER,PM_USER1 VARCHAR(32768),PM_USER2 VARCHAR(32768),PM_USER3 VARCHAR(32768),PM_USER4 VARCHAR(32768))
|
||||
CREATE INDEX CONCATENATION_PREFIDX ON PUBLIC.CONCATENATION(LOCALPARENTREFERENCE)
|
||||
CREATE CACHED TABLE PUBLIC.INSTANCE(LOCALPRIMARYKEY VARCHAR(32768) PRIMARY KEY,LOCALPARENTREFERENCE VARCHAR(32768),RECORDINSERTIONTIME BIGINT,LOCALFILENAME VARCHAR(32768),LOCALFILEREFERENCETYPE CHARACTER(1),TRANSFERSYNTAXUID VARCHAR(32768),SOURCEAPPLICATIONENTITYTITLE VARCHAR(32768),SPECIFICCHARACTERSET VARCHAR(32768),IMAGETYPE VARCHAR(32768),SOPCLASSUID VARCHAR(32768),SOPINSTANCEUID VARCHAR(32768),CONTENTDATE VARCHAR(32768),ACQUISITIONDATETIME VARCHAR(32768),DERIVATIONDESCRIPTION VARCHAR(32768),PIXELPRESENTATION VARCHAR(32768),VOLUMETRICPROPERTIES VARCHAR(32768),VOLUMEBASEDCALCULATIONTECHNIQUE VARCHAR(32768),COMPLEXIMAGECOMPONENT VARCHAR(32768),ACQUISITIONCONTRAST VARCHAR(32768),CONTRASTBOLUSAGENT VARCHAR(32768),PULSESEQUENCENAME VARCHAR(32768),ACQUISITIONNUMBER INTEGER,IMAGEPOSITIONPATIENT VARCHAR(32768),IMAGEORIENTATIONPATIENT VARCHAR(32768),IMAGELATERALITY VARCHAR(32768),IMAGECOMMENTS VARCHAR(32768),INCONCATENATIONNUMBER INTEGER,PHOTOMETRICINTERPRETATION VARCHAR(32768),NUMBEROFFRAMES INTEGER,ROWS INTEGER,COLUMNS INTEGER,BITSALLOCATED INTEGER,BITSSTORED INTEGER,PIXELREPRESENTATION INTEGER,QUALITYCONTROLIMAGE VARCHAR(32768),BURNEDINANNOTATION VARCHAR(32768),WINDOWCENTER VARCHAR(32768),WINDOWWIDTH VARCHAR(32768),LOSSYIMAGECOMPRESSION VARCHAR(32768),LOSSYIMAGECOMPRESSIONRATIO VARCHAR(32768),LOSSYIMAGECOMPRESSIONMETHOD VARCHAR(32768),INSTANCENUMBER INTEGER,PM_CONTENTDATETIME TIMESTAMP,PM_ACQUISITIONDATETIME TIMESTAMP,PM_LOSSYIMAGECOMPRESSION INTEGER,PM_USER1 VARCHAR(32768),PM_USER2 VARCHAR(32768),PM_USER3 VARCHAR(32768),PM_USER4 VARCHAR(32768))
|
||||
CREATE INDEX INSTANCE_PREFIDX ON PUBLIC.INSTANCE(LOCALPARENTREFERENCE)
|
||||
CREATE INDEX INSTANCE_UID_IDX ON PUBLIC.INSTANCE(SOPINSTANCEUID)
|
||||
ALTER SEQUENCE SYSTEM_LOBS.LOB_ID RESTART WITH 1
|
||||
SET DATABASE DEFAULT INITIAL SCHEMA PUBLIC
|
||||
GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CARDINAL_NUMBER TO PUBLIC
|
||||
GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.YES_OR_NO TO PUBLIC
|
||||
GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CHARACTER_DATA TO PUBLIC
|
||||
GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.SQL_IDENTIFIER TO PUBLIC
|
||||
GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.TIME_STAMP TO PUBLIC
|
||||
GRANT DBA TO SA
|
||||
SET SCHEMA SYSTEM_LOBS
|
||||
INSERT INTO BLOCKS VALUES(0,2147483647,0)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,373 @@
|
||||
import { useEffect, useRef, useCallback, useState } from "react"
|
||||
import createImageIdsAndCacheMetaData from "./lib/createImageIdsAndCacheMetaData"
|
||||
import {
|
||||
RenderingEngine,
|
||||
Enums,
|
||||
} from "@cornerstonejs/core"
|
||||
import { init as csRenderInit } from "@cornerstonejs/core"
|
||||
import { init as csToolsInit, addTool, ToolGroupManager, Enums as csToolsEnums, PanTool, WindowLevelTool, StackScrollTool, ZoomTool, PlanarRotateTool } from "@cornerstonejs/tools"
|
||||
import { init as dicomImageLoaderInit } from "@cornerstonejs/dicom-image-loader"
|
||||
import * as cornerstoneTools from '@cornerstonejs/tools';
|
||||
import { StackScrollOutOfBoundsEvent } from 'core/src/types/EventTypes';
|
||||
|
||||
|
||||
const { MouseBindings } = csToolsEnums;
|
||||
|
||||
const { IMAGE_RENDERED } = Enums.Events;
|
||||
|
||||
const toolGroupId = 'STACK_TOOL_GROUP_ID';
|
||||
const leftClickTools = [
|
||||
WindowLevelTool.toolName,
|
||||
PlanarRotateTool.toolName,
|
||||
StackScrollTool.toolName,
|
||||
];
|
||||
const defaultLeftClickTool = leftClickTools[0];
|
||||
let currentLeftClickTool = leftClickTools[0];
|
||||
|
||||
// Common CT presets (add more as needed)
|
||||
const WINDOW_LEVEL_PRESETS = [
|
||||
{ name: "Soft Tissue", center: 40, width: 400 },
|
||||
{ name: "Lung", center: -600, width: 1500 },
|
||||
{ name: "Bone", center: 300, width: 1500 },
|
||||
{ name: "Brain", center: 40, width: 80 },
|
||||
{ name: "Abdomen", center: 60, width: 400 },
|
||||
]
|
||||
|
||||
|
||||
|
||||
function App() {
|
||||
const elementRef = useRef<HTMLDivElement>(null)
|
||||
const viewportRef = useRef<any>(null) // Store the viewport instance
|
||||
const running = useRef(false)
|
||||
|
||||
// State for overlay info
|
||||
const [imageInfo, setImageInfo] = useState({
|
||||
index: 0,
|
||||
total: 0,
|
||||
windowCenter: "",
|
||||
windowWidth: "",
|
||||
})
|
||||
|
||||
const updateOverlay = useCallback(() => {
|
||||
console.log("updateOverlay")
|
||||
const viewport = viewportRef.current
|
||||
if (!viewport) return
|
||||
console.log(viewport)
|
||||
|
||||
// For StackViewport in Cornerstone3D v3:
|
||||
const currentIndex = typeof viewport.getCurrentImageIdIndex === "function"
|
||||
? viewport.getCurrentImageIdIndex()
|
||||
: 0
|
||||
const imageIds = typeof viewport.getImageIds === "function"
|
||||
? viewport.getImageIds()
|
||||
: []
|
||||
const total = imageIds.length
|
||||
|
||||
// Use getVOI() for current window center/width
|
||||
let windowCenter = ""
|
||||
let windowWidth = ""
|
||||
if (typeof viewport.getProperties === "function") {
|
||||
const props = viewport.getProperties()
|
||||
if (props.voiRange) {
|
||||
const { lower, upper } = props.voiRange
|
||||
windowCenter = ((upper + lower) / 2).toFixed(0)
|
||||
windowWidth = (upper - lower).toFixed(0)
|
||||
}
|
||||
}
|
||||
|
||||
setImageInfo({
|
||||
index: currentIndex + 1,
|
||||
total,
|
||||
windowCenter,
|
||||
windowWidth,
|
||||
})
|
||||
}, [])
|
||||
useEffect(() => {
|
||||
const setup = async () => {
|
||||
if (running.current) {
|
||||
return
|
||||
}
|
||||
running.current = true
|
||||
|
||||
await csRenderInit()
|
||||
await csToolsInit()
|
||||
dicomImageLoaderInit({ maxWebWorkers: 1 })
|
||||
|
||||
// Add tools to Cornerstone3D
|
||||
cornerstoneTools.addTool(PanTool);
|
||||
cornerstoneTools.addTool(WindowLevelTool);
|
||||
cornerstoneTools.addTool(StackScrollTool);
|
||||
cornerstoneTools.addTool(ZoomTool);
|
||||
cornerstoneTools.addTool(PlanarRotateTool);
|
||||
|
||||
// Define a tool group, which defines how mouse events map to tool commands for
|
||||
// Any viewport using the group
|
||||
const toolGroup = ToolGroupManager.createToolGroup(toolGroupId);
|
||||
|
||||
// Add tools to the tool group
|
||||
toolGroup.addTool(WindowLevelTool.toolName);
|
||||
toolGroup.addTool(PanTool.toolName);
|
||||
toolGroup.addTool(ZoomTool.toolName);
|
||||
toolGroup.addTool(StackScrollTool.toolName, { loop: false });
|
||||
toolGroup.addTool(PlanarRotateTool.toolName);
|
||||
|
||||
// Set the initial state of the tools, here all tools are active and bound to
|
||||
// Different mouse inputs
|
||||
toolGroup.setToolActive(defaultLeftClickTool, {
|
||||
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
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// The Stack Scroll mouse wheel is a tool using the `mouseWheelCallback`
|
||||
// and needs to be registered against the 'Wheel' binding.
|
||||
toolGroup.setToolActive(StackScrollTool.toolName, {
|
||||
bindings: [
|
||||
{
|
||||
mouseButton: MouseBindings.Wheel, // Wheel Mouse
|
||||
},
|
||||
],
|
||||
});
|
||||
toolGroup.setToolActive(PlanarRotateTool.toolName, {
|
||||
bindings: [
|
||||
{
|
||||
mouseButton: MouseBindings.Wheel, // Shift Wheel Mouse
|
||||
//modifierKey: KeyboardBindings.Shift,
|
||||
},
|
||||
{
|
||||
mouseButton: MouseBindings.Wheel_Primary, // Left Click+Wheel Mouse
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
|
||||
|
||||
const imageIds = await createImageIdsAndCacheMetaData()
|
||||
console.log("imageIds", imageIds)
|
||||
|
||||
// Instantiate a rendering engine
|
||||
const renderingEngineId = "myRenderingEngine"
|
||||
const renderingEngine = new RenderingEngine(renderingEngineId)
|
||||
const viewportId = "CT"
|
||||
|
||||
|
||||
const viewportInput = {
|
||||
viewportId,
|
||||
type: Enums.ViewportType.STACK,
|
||||
element: elementRef.current,
|
||||
}
|
||||
|
||||
renderingEngine.enableElement(viewportInput)
|
||||
|
||||
// Set the tool group on the viewport
|
||||
toolGroup.addViewport(viewportId, renderingEngineId);
|
||||
|
||||
// Get the stack viewport that was created
|
||||
const viewport = renderingEngine.getViewport(viewportId);
|
||||
viewportRef.current = viewport; // Save for later use
|
||||
|
||||
// Create a stack volume
|
||||
viewport.setStack(imageIds)
|
||||
|
||||
cornerstoneTools.utilities.stackPrefetch.enable(viewport.element);
|
||||
|
||||
function test(e) {
|
||||
console.log("test", e)
|
||||
}
|
||||
|
||||
// Render the image
|
||||
viewport.render()
|
||||
viewport.element.addEventListener(Enums.Events.IMAGE_RENDERED, updateOverlay)
|
||||
///viewport.element.addEventListener(Enums.Events.STACK_NEW_IMAGE, updateOverlay)
|
||||
//viewport.element.addEventListener(Enums.Events.CAMERA_MODIFIED, updateOverlay)
|
||||
//viewport.element.addEventListener(Enums.Events.PRESET_MODIFIED, updateOverlay)
|
||||
|
||||
// Initial overlay update
|
||||
updateOverlay()
|
||||
}
|
||||
|
||||
setup()
|
||||
|
||||
// Create a stack viewport
|
||||
}, [elementRef, updateOverlay])
|
||||
|
||||
// Handler to reset the view (camera and window/level)
|
||||
const handleResetView = useCallback(() => {
|
||||
const viewport = viewportRef.current
|
||||
if (viewport && typeof viewport.resetCamera === "function") {
|
||||
viewport.resetCamera();
|
||||
viewport.resetProperties(); // Resets window/level and other properties
|
||||
viewport.render();
|
||||
}
|
||||
}, [])
|
||||
|
||||
// Double-click handler (reuse the same logic)
|
||||
const handleDoubleClick = handleResetView
|
||||
|
||||
// Handler to apply a preset
|
||||
const handleApplyPreset = useCallback((center: number, width: number) => {
|
||||
const viewport = viewportRef.current
|
||||
if (viewport && typeof viewport.setProperties === "function") {
|
||||
const props = viewport.getProperties()
|
||||
viewport.setProperties({
|
||||
...props,
|
||||
voiRange: {
|
||||
lower: center - width / 2,
|
||||
upper: center + width / 2,
|
||||
},
|
||||
})
|
||||
viewport.render()
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div style={{ position: "relative", width: "512px", height: "512px" }}>
|
||||
{/* ...existing Reset View button and viewport div... */}
|
||||
<button
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 8,
|
||||
left: 8,
|
||||
zIndex: 10,
|
||||
padding: "6px 12px",
|
||||
background: "#222",
|
||||
color: "#fff",
|
||||
border: "none",
|
||||
borderRadius: "4px",
|
||||
cursor: "pointer",
|
||||
opacity: 0.85,
|
||||
}}
|
||||
onClick={handleResetView}
|
||||
>
|
||||
Reset View
|
||||
</button>
|
||||
<div
|
||||
ref={elementRef}
|
||||
onDoubleClick={handleDoubleClick}
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
backgroundColor: "#000",
|
||||
}}
|
||||
></div>
|
||||
{/* Overlay at bottom left */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: 8,
|
||||
bottom: 8,
|
||||
background: "rgba(0,0,0,0.7)",
|
||||
color: "#fff",
|
||||
padding: "6px 12px",
|
||||
borderRadius: "4px",
|
||||
fontSize: "14px",
|
||||
zIndex: 10,
|
||||
pointerEvents: "none",
|
||||
minWidth: "120px",
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
Image: {imageInfo.index} / {imageInfo.total}
|
||||
</div>
|
||||
<div>
|
||||
WC: {imageInfo.windowCenter} WW: {imageInfo.windowWidth}
|
||||
</div>
|
||||
</div>
|
||||
{/* Preset menu at bottom right, collapsed by default, expands on hover */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
right: 8,
|
||||
bottom: 8,
|
||||
zIndex: 10,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
background: "rgba(0,0,0,0.7)",
|
||||
color: "#fff",
|
||||
borderRadius: "4px",
|
||||
fontSize: "14px",
|
||||
minWidth: "120px",
|
||||
overflow: "hidden",
|
||||
transition: "height 0.2s",
|
||||
height: "28px",
|
||||
cursor: "pointer",
|
||||
position: "relative",
|
||||
}}
|
||||
className="preset-menu"
|
||||
>
|
||||
<div style={{ padding: "6px 12px", fontWeight: "bold" }}>
|
||||
Presets
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
background: "rgba(0,0,0,0.95)",
|
||||
borderRadius: "4px",
|
||||
padding: "6px 0 6px 0",
|
||||
display: "none",
|
||||
flexDirection: "column",
|
||||
zIndex: 11,
|
||||
}}
|
||||
className="preset-menu-content"
|
||||
>
|
||||
{WINDOW_LEVEL_PRESETS.map((preset) => (
|
||||
<button
|
||||
key={preset.name}
|
||||
style={{
|
||||
display: "block",
|
||||
width: "100%",
|
||||
margin: "2px 0",
|
||||
background: "#333",
|
||||
color: "#fff",
|
||||
border: "none",
|
||||
borderRadius: "3px",
|
||||
cursor: "pointer",
|
||||
padding: "4px 0",
|
||||
fontSize: "13px",
|
||||
opacity: 0.9,
|
||||
}}
|
||||
onClick={() => handleApplyPreset(preset.center, preset.width)}
|
||||
>
|
||||
{preset.name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{/* Inline CSS for hover effect */}
|
||||
<style>
|
||||
{`
|
||||
.preset-menu:hover .preset-menu-content {
|
||||
display: flex;
|
||||
}
|
||||
.preset-menu:hover {
|
||||
height: auto !important;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
||||
@@ -0,0 +1,82 @@
|
||||
import { useEffect, useRef } from "react"
|
||||
import createImageIdsAndCacheMetaData from "./lib/createImageIdsAndCacheMetaData"
|
||||
import {
|
||||
RenderingEngine,
|
||||
Enums,
|
||||
type Types,
|
||||
volumeLoader,
|
||||
imageLoader,
|
||||
} from "@cornerstonejs/core"
|
||||
import { init as csRenderInit } from "@cornerstonejs/core"
|
||||
import {
|
||||
cornerstoneNiftiImageLoader,
|
||||
createNiftiImageIdsAndCacheMetadata,
|
||||
} from "@cornerstonejs/nifti-volume-loader"
|
||||
import { ImageLoaderFn } from "@cornerstonejs/core/types"
|
||||
|
||||
function Nifti() {
|
||||
const elementRef = useRef<HTMLDivElement>(null)
|
||||
const running = useRef(false)
|
||||
|
||||
useEffect(() => {
|
||||
const setup = async () => {
|
||||
if (running.current) {
|
||||
return
|
||||
}
|
||||
running.current = true
|
||||
|
||||
await csRenderInit()
|
||||
|
||||
const viewportId1 = "CT_NIFTI_AXIAL"
|
||||
|
||||
const niftiURL =
|
||||
"https://ohif-assets.s3.us-east-2.amazonaws.com/nifti/CTACardio.nii.gz"
|
||||
|
||||
imageLoader.registerImageLoader(
|
||||
"nifti",
|
||||
cornerstoneNiftiImageLoader as unknown as ImageLoaderFn
|
||||
)
|
||||
|
||||
const imageIds = await createNiftiImageIdsAndCacheMetadata({
|
||||
url: niftiURL,
|
||||
})
|
||||
|
||||
const renderingEngineId = "myRenderingEngine"
|
||||
const renderingEngine = new RenderingEngine(renderingEngineId)
|
||||
|
||||
const viewportInputArray = [
|
||||
{
|
||||
viewportId: viewportId1,
|
||||
type: Enums.ViewportType.STACK,
|
||||
element: elementRef.current,
|
||||
},
|
||||
]
|
||||
|
||||
renderingEngine.setViewports(viewportInputArray)
|
||||
|
||||
const vps = renderingEngine.getStackViewports()
|
||||
const viewport = vps[0]
|
||||
|
||||
viewport.setStack(imageIds)
|
||||
|
||||
renderingEngine.render()
|
||||
}
|
||||
|
||||
setup()
|
||||
|
||||
// Create a stack viewport
|
||||
}, [elementRef, running])
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={elementRef}
|
||||
style={{
|
||||
width: "512px",
|
||||
height: "512px",
|
||||
backgroundColor: "#000",
|
||||
}}
|
||||
></div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Nifti
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
@@ -0,0 +1,74 @@
|
||||
import { api } from "dicomweb-client"
|
||||
import cornerstoneDICOMImageLoader from "@cornerstonejs/dicom-image-loader"
|
||||
|
||||
/**
|
||||
/**
|
||||
* Uses dicomweb-client to fetch metadata of a study, cache it in cornerstone,
|
||||
* and return a list of imageIds for the frames.
|
||||
*
|
||||
* Uses the app config to choose which study to fetch, and which
|
||||
* dicom-web server to fetch it from.
|
||||
*
|
||||
* @returns {string[]} An array of imageIds for instances in the study.
|
||||
*/
|
||||
|
||||
/* export default async function createImageIdsAndCacheMetaData({
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
SOPInstanceUID = null,
|
||||
wadoRsRoot,
|
||||
client = null,
|
||||
}) {
|
||||
const SOP_INSTANCE_UID = "00080018"
|
||||
const SERIES_INSTANCE_UID = "0020000E"
|
||||
|
||||
const studySearchOptions = {
|
||||
studyInstanceUID: StudyInstanceUID,
|
||||
seriesInstanceUID: SeriesInstanceUID,
|
||||
}
|
||||
|
||||
client =
|
||||
client ||
|
||||
new api.DICOMwebClient({ url: wadoRsRoot as string, singlepart: true })
|
||||
const instances = await client.retrieveSeriesMetadata(studySearchOptions)
|
||||
const imageIds = instances.map((instanceMetaData) => {
|
||||
const SeriesInstanceUID = instanceMetaData[SERIES_INSTANCE_UID].Value[0]
|
||||
const SOPInstanceUIDToUse =
|
||||
SOPInstanceUID || instanceMetaData[SOP_INSTANCE_UID].Value[0]
|
||||
|
||||
const prefix = "wadors:"
|
||||
|
||||
const imageId =
|
||||
prefix +
|
||||
wadoRsRoot +
|
||||
"/studies/" +
|
||||
StudyInstanceUID +
|
||||
"/series/" +
|
||||
SeriesInstanceUID +
|
||||
"/instances/" +
|
||||
SOPInstanceUIDToUse +
|
||||
"/frames/1"
|
||||
|
||||
cornerstoneDICOMImageLoader.wadors.metaDataManager.add(
|
||||
imageId,
|
||||
instanceMetaData
|
||||
)
|
||||
return imageId
|
||||
})
|
||||
|
||||
// we don't want to add non-pet
|
||||
// Note: for 99% of scanners SUV calculation is consistent bw slices
|
||||
|
||||
return imageIds
|
||||
} */
|
||||
|
||||
const NUM_IMAGES = 10 // set to however many images you have
|
||||
|
||||
export default async function createImageIdsAndCacheMetaData() {
|
||||
const imageIds = []
|
||||
for (let i = 1; i <= NUM_IMAGES; i++) {
|
||||
const fileName = `IMG${String(i)}.dcm`
|
||||
imageIds.push(`wadouri:/test_images/stack/${fileName}`)
|
||||
}
|
||||
return imageIds
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App.tsx'
|
||||
import Nifti from './Nifti.tsx'
|
||||
import './index.css'
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
{/* <Nifti /> */}
|
||||
</React.StrictMode>,
|
||||
)
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": false,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import { defineConfig } from "vite"
|
||||
import react from "@vitejs/plugin-react"
|
||||
import { viteCommonjs } from "@originjs/vite-plugin-commonjs"
|
||||
|
||||
/**
|
||||
* Vite configuration for the application.
|
||||
*
|
||||
* @remarks
|
||||
* This configuration is mostly standard Vite + React setup, with specific accommodations for:
|
||||
* - WASM decoders used by Cornerstone libraries
|
||||
* - DICOM parser which currently uses CommonJS format (planned migration to ESM)
|
||||
*
|
||||
* @description
|
||||
* Key configuration points:
|
||||
* - Uses vite-plugin-commonjs to handle the DICOM parser's CommonJS format
|
||||
* - Configures worker format as ES modules
|
||||
* - Excludes Cornerstone CODEC packages from dependency optimization to handle WASM properly
|
||||
* - Explicitly includes dicom-parser in optimization
|
||||
* - Ensures WASM files are properly handled as assets
|
||||
*
|
||||
* @example
|
||||
* To use additional WASM decoders, add them to the optimizeDeps.exclude array:
|
||||
* ```ts
|
||||
* optimizeDeps: {
|
||||
* exclude: [
|
||||
* "@cornerstonejs/codec-new-decoder",
|
||||
* // ... existing codecs
|
||||
* ]
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
react(),
|
||||
// for dicom-parser
|
||||
viteCommonjs(),
|
||||
],
|
||||
// seems like only required in dev mode
|
||||
optimizeDeps: {
|
||||
exclude: ["@cornerstonejs/dicom-image-loader"],
|
||||
include: ["dicom-parser"],
|
||||
},
|
||||
worker: {
|
||||
format: "es",
|
||||
rollupOptions: {
|
||||
external: ["@icr/polyseg-wasm"],
|
||||
},
|
||||
},
|
||||
})
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user