Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified bun.lockb
Binary file not shown.
30 changes: 16 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,29 @@
"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"
"engines": {
"node": ">=20"
},
"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",
"dcmjs": "0.49.4",
"dicom-parser": "1.8.21",
"dicomweb-client": "0.10.4",
"dicomweb-client": "0.11.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"vite-plugin-wasm": "^3.3.0"
},
"devDependencies": {
"@babel/preset-react": "^7.25.9",
"@babel/preset-react": "7.26.3",
"@originjs/vite-plugin-commonjs": "^1.0.3",
"@rollup/plugin-babel": "^6.0.4",
"@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-node-resolve": "15.3.1",
"@rollup/plugin-typescript": "11.1.6",
"@rollup/plugin-wasm": "^6.2.2",
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
Expand All @@ -43,9 +40,14 @@
"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",
"typescript": "5.5.4",
"vite": "^5.2.0",
"vite-plugin-static-copy": "^1.0.5"
},
"scripts": {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We generally have our scripts "higher" in the package.json file. Consider moving them.

"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
}
}
}
13 changes: 7 additions & 6 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,19 @@ function App() {
}
running.current = true

// 4.x: init() unchanged. For 3.x-style viewport padding use init({ rendering: { useLegacyCameraFOV: true } })
await csRenderInit()
await csToolsInit()
dicomImageLoaderInit({maxWebWorkers:1})
dicomImageLoaderInit({ maxWebWorkers: 1 })

// Get Cornerstone imageIds and fetch metadata into RAM
// Same study/series UIDs; base URL from CS3D examples (old backend may have moved)
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://d3t6nz73ql33tx.cloudfront.net/dicomweb",
wadoRsRoot: "https://d14fa38qiwhyfd.cloudfront.net/dicomweb",
})

// Instantiate a rendering engine
Expand Down Expand Up @@ -60,12 +62,11 @@ function App() {
imageIds,
})

// Set the volume to load
// @ts-ignore
// Start loading the volume (streaming)
volume.load()

// Set the volume on the viewport and it's default properties
viewport.setVolumes([{ volumeId}])
// Set the volume on the viewport (4.x: setVolumes is async)
await viewport.setVolumes([{ volumeId }], true)

// Render the image
viewport.render()
Expand Down
1 change: 0 additions & 1 deletion src/lib/createImageIdsAndCacheMetaData.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
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.
Expand Down
9 changes: 9 additions & 0 deletions src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import { setConfiguration } from '@cornerstonejs/core';
import { getWasmBasePath } from 'virtual:cornerstone-wasm-config';
import App from './App.tsx'
import Nifti from './Nifti.tsx'
import './index.css'

// Set WASM loading base path (for subpath deployment). Use plugin's value or Vite's base.
const wasmBase = getWasmBasePath() || import.meta.env.BASE_URL
if (wasmBase) {
// @ts-ignore
setConfiguration({ wasmBasePath: wasmBase })
}

ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
Expand Down
4 changes: 4 additions & 0 deletions src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
/// <reference types="vite/client" />

declare module 'virtual:cornerstone-wasm-config' {
export function getWasmBasePath(): string;
}
55 changes: 55 additions & 0 deletions vite-plugin-cornerstone-wasm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import type { Plugin } from 'vite';

const VIRTUAL_MODULE_ID = 'virtual:cornerstone-wasm-config';
const RESOLVED_VIRTUAL_MODULE_ID = '\0' + VIRTUAL_MODULE_ID;

export interface VitePluginCornerstoneWasmOptions {
/**
* Base path (or URL prefix) for loading WASM binaries.
* When set, this is passed to Cornerstone's config so WASM URLs are resolved
* correctly when the app is served under a subpath (e.g. base '/subpath/').
* If not set, the plugin does not inject a base path (app can use setConfiguration({ wasmBasePath: import.meta.env.BASE_URL }) instead).
*/
wasmBasePath?: string;
}

/**
* Vite plugin that allows replacing the WASM loading path used by Cornerstone
* (e.g. @cornerstonejs/dicom-image-loader codecs). Use when the app is served
* under a subpath or you need to point WASM to a custom URL.
*
* Usage:
* 1. Add the plugin with optional wasmBasePath:
* cornerstoneWasm({ wasmBasePath: '/subpath/' })
* 2. In your app entry (e.g. main.tsx), before loading any images:
* import { getWasmBasePath } from 'virtual:cornerstone-wasm-config';
* import { setConfiguration } from '@cornerstonejs/core';
* const base = getWasmBasePath();
* if (base) setConfiguration({ wasmBasePath: base });
*
* If you don't use the virtual module, you can instead call
* setConfiguration({ wasmBasePath: import.meta.env.BASE_URL }) for subpath support.
*/
export function vitePluginCornerstoneWasm(
options: VitePluginCornerstoneWasmOptions = {}
): Plugin {
const { wasmBasePath = '' } = options;

return {
name: 'vite-plugin-cornerstone-wasm',
resolveId(id: string) {
if (id === VIRTUAL_MODULE_ID) return RESOLVED_VIRTUAL_MODULE_ID;
return null;
},
load(id: string) {
if (id !== RESOLVED_VIRTUAL_MODULE_ID) return null;
return `
export function getWasmBasePath() {
return ${JSON.stringify(wasmBasePath)};
}
`;
},
};
}

export default vitePluginCornerstoneWasm;
18 changes: 13 additions & 5 deletions vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { defineConfig } from "vite"
import react from "@vitejs/plugin-react"
import { viteCommonjs } from "@originjs/vite-plugin-commonjs"
import { vitePluginCornerstoneWasm } from "./vite-plugin-cornerstone-wasm"

/**
* Vite configuration for the application.
Expand Down Expand Up @@ -30,20 +31,27 @@ import { viteCommonjs } from "@originjs/vite-plugin-commonjs"
* ```
*/
export default defineConfig({
base: '/subpath/',
plugins: [
react(),
// for dicom-parser
viteCommonjs(),
// Optional: pass wasmBasePath to override WASM loading path (e.g. for subpath deployment).
// When not set, use setConfiguration({ wasmBasePath: import.meta.env.BASE_URL }) in main.tsx.
vitePluginCornerstoneWasm({ wasmBasePath: '' }),
],
// seems like only required in dev mode
optimizeDeps: {
exclude: ["@cornerstonejs/dicom-image-loader"],
include: ["dicom-parser"],
exclude: ['@cornerstonejs/dicom-image-loader'],
include: ['dicom-parser'],
},
build: {
minify: false,
},
worker: {
format: "es",
format: 'es',
rollupOptions: {
external: ["@icr/polyseg-wasm"],
external: ['@icr/polyseg-wasm'],
},
},
})
});