diff --git a/.circleci/config.yml b/.circleci/config.yml index bf44ab79e..c8c7afabe 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,7 +6,7 @@ orbs: defaults: &defaults docker: - - image: cimg/node:18.18 + - image: cimg/node:20.18.1 environment: TERM: xterm QUICK_BUILD: true diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 83577dd7c..36a22e979 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -64,7 +64,7 @@ body: attributes: label: 'Node version' description: 'Your Node.js version.' - placeholder: 'e.g., 18.16.1' + placeholder: 'e.g., 20.18.1' validations: required: true - type: input diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 259101988..513d5c93a 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -22,7 +22,7 @@ jobs: - uses: oven-sh/setup-bun@v2 - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Install dependencies run: bun install --frozen-lockfile - name: Set up Git safe directory @@ -53,7 +53,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Install dependencies run: bun install --frozen-lockfile - name: Set up Git safe directory diff --git a/.node-version b/.node-version index 3876fd498..f3f52b42d 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -18.16.1 +20.9.0 diff --git a/Dockerfile b/Dockerfile index e6310c3ba..141b139a4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,7 +21,7 @@ # Stage 1: Build the application # docker build -t ohif/viewer:latest . -FROM node:18.16.1-slim as json-copier +FROM node:20.18.1-slim as json-copier RUN mkdir /usr/src/app WORKDIR /usr/src/app @@ -37,7 +37,7 @@ COPY platform /usr/src/app/platform #RUN find platform \! -name "package.json" -mindepth 2 -maxdepth 2 -print | xargs rm -rf # Copy Files -FROM node:18.16.1-slim as builder +FROM node:20.18.1-slim as builder RUN apt-get update && apt-get install -y build-essential python3 RUN mkdir /usr/src/app WORKDIR /usr/src/app diff --git a/bun.lockb b/bun.lockb index 14533e521..ed61f2956 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/extensions/cornerstone-dicom-pmap/package.json b/extensions/cornerstone-dicom-pmap/package.json index fd95a1ff1..080e3dd85 100644 --- a/extensions/cornerstone-dicom-pmap/package.json +++ b/extensions/cornerstone-dicom-pmap/package.json @@ -46,8 +46,8 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^2.7.3", - "@cornerstonejs/core": "^2.7.3", + "@cornerstonejs/adapters": "^2.11.2", + "@cornerstonejs/core": "^2.11.2", "@kitware/vtk.js": "32.1.1", "react-color": "^2.19.3" } diff --git a/extensions/cornerstone-dicom-seg/package.json b/extensions/cornerstone-dicom-seg/package.json index 33b726a5d..704cd5ea8 100644 --- a/extensions/cornerstone-dicom-seg/package.json +++ b/extensions/cornerstone-dicom-seg/package.json @@ -46,8 +46,8 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^2.7.3", - "@cornerstonejs/core": "^2.7.3", + "@cornerstonejs/adapters": "^2.11.2", + "@cornerstonejs/core": "^2.11.2", "@kitware/vtk.js": "32.1.1", "react-color": "^2.19.3" } diff --git a/extensions/cornerstone-dicom-sr/package.json b/extensions/cornerstone-dicom-sr/package.json index 28840d077..5259535cd 100644 --- a/extensions/cornerstone-dicom-sr/package.json +++ b/extensions/cornerstone-dicom-sr/package.json @@ -46,9 +46,9 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^2.7.3", - "@cornerstonejs/core": "^2.7.3", - "@cornerstonejs/tools": "^2.7.3", + "@cornerstonejs/adapters": "^2.11.2", + "@cornerstonejs/core": "^2.11.2", + "@cornerstonejs/tools": "^2.11.2", "classnames": "^2.3.2" } } diff --git a/extensions/cornerstone-dynamic-volume/package.json b/extensions/cornerstone-dynamic-volume/package.json index 5f673577a..37995d236 100644 --- a/extensions/cornerstone-dynamic-volume/package.json +++ b/extensions/cornerstone-dynamic-volume/package.json @@ -42,8 +42,8 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/core": "^2.7.3", - "@cornerstonejs/tools": "^2.7.3", + "@cornerstonejs/core": "^2.11.2", + "@cornerstonejs/tools": "^2.11.2", "classnames": "^2.3.2" } } diff --git a/extensions/cornerstone/package.json b/extensions/cornerstone/package.json index 0337fa230..703fe5646 100644 --- a/extensions/cornerstone/package.json +++ b/extensions/cornerstone/package.json @@ -38,7 +38,7 @@ "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjph": "^2.4.5", - "@cornerstonejs/dicom-image-loader": "^2.7.3", + "@cornerstonejs/dicom-image-loader": "^2.11.2", "@icr/polyseg-wasm": "^0.4.0", "@ohif/core": "3.10.0-beta.20", "@ohif/ui": "3.10.0-beta.20", @@ -55,9 +55,9 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^2.7.3", - "@cornerstonejs/core": "^2.7.3", - "@cornerstonejs/tools": "^2.7.3", + "@cornerstonejs/adapters": "^2.11.2", + "@cornerstonejs/core": "^2.11.2", + "@cornerstonejs/tools": "^2.11.2", "@icr/polyseg-wasm": "^0.4.0", "@kitware/vtk.js": "32.1.1", "html2canvas": "^1.4.1", diff --git a/extensions/cornerstone/src/panels/PanelSegmentation.tsx b/extensions/cornerstone/src/panels/PanelSegmentation.tsx index 8298d4e44..a402531b8 100644 --- a/extensions/cornerstone/src/panels/PanelSegmentation.tsx +++ b/extensions/cornerstone/src/panels/PanelSegmentation.tsx @@ -171,51 +171,61 @@ export default function PanelSegmentation({ onSegmentationDownload, onSegmentationDownloadRTSS, t, - }) => ( - - onSegmentationAdd(activeSegmentation.id)}> - - {t('Create New Segmentation')} - - - {t('Manage Current Segmentation')} - onSegmentationRemoveFromViewport(activeSegmentation.id)}> - - {t('Remove from Viewport')} - - onSegmentationEdit(activeSegmentation.id)}> - - {t('Rename')} - - - { + return ( + + onSegmentationAdd(activeSegmentation.segmentationId)}> + + {t('Create New Segmentation')} + + + {t('Manage Current Segmentation')} + onSegmentationRemoveFromViewport(activeSegmentation.segmentationId)} > - - {t('Export & Download')} - - - - storeSegmentation(activeSegmentation.id)}> - {t('Export DICOM SEG')} - - onSegmentationDownload(activeSegmentation.id)}> - {t('Download DICOM SEG')} - - onSegmentationDownloadRTSS(activeSegmentation.id)}> - {t('Download DICOM RTSTRUCT')} - - - - - - onSegmentationDelete(activeSegmentation.id)}> - - {t('Delete')} - - - ) + + {t('Remove from Viewport')} + + onSegmentationEdit(activeSegmentation.segmentationId)}> + + {t('Rename')} + + + + + {t('Export & Download')} + + + + storeSegmentation(activeSegmentation.segmentationId)} + > + {t('Export DICOM SEG')} + + onSegmentationDownload(activeSegmentation.segmentationId)} + > + {t('Download DICOM SEG')} + + {/* onSegmentationDownloadRTSS(activeSegmentation.segmentationId)} + > + {t('Download DICOM RTSTRUCT')} + */} + + + + + onSegmentationDelete(activeSegmentation.segmentationId)}> + + {t('Delete')} + + + ); + } ); const exportOptions = segmentationsWithRepresentations.map(({ segmentation }) => { diff --git a/extensions/measurement-tracking/package.json b/extensions/measurement-tracking/package.json index 7ed83f065..7bbb0eff5 100644 --- a/extensions/measurement-tracking/package.json +++ b/extensions/measurement-tracking/package.json @@ -32,8 +32,8 @@ "start": "yarn run dev" }, "peerDependencies": { - "@cornerstonejs/core": "^2.7.3", - "@cornerstonejs/tools": "^2.7.3", + "@cornerstonejs/core": "^2.11.2", + "@cornerstonejs/tools": "^2.11.2", "@ohif/core": "3.10.0-beta.20", "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.20", "@ohif/extension-default": "3.10.0-beta.20", diff --git a/platform/app/.recipes/Nginx-Dcm4chee-Keycloak/dockerfile b/platform/app/.recipes/Nginx-Dcm4chee-Keycloak/dockerfile index bf610e8bd..4182de82b 100644 --- a/platform/app/.recipes/Nginx-Dcm4chee-Keycloak/dockerfile +++ b/platform/app/.recipes/Nginx-Dcm4chee-Keycloak/dockerfile @@ -1,5 +1,5 @@ # Stage 1: Build the application -FROM node:18.16.1-slim as builder +FROM node:20.18.1-slim as builder # Setup the working directory RUN mkdir /usr/src/app diff --git a/platform/app/.recipes/Nginx-Dcm4chee/dockerfile b/platform/app/.recipes/Nginx-Dcm4chee/dockerfile index d28e96056..bbc6f89eb 100644 --- a/platform/app/.recipes/Nginx-Dcm4chee/dockerfile +++ b/platform/app/.recipes/Nginx-Dcm4chee/dockerfile @@ -1,5 +1,5 @@ # Stage 1: Build the application -FROM node:18.16.1-slim as builder +FROM node:20.18.1-slim as builder # Setup the working directory RUN mkdir /usr/src/app diff --git a/platform/app/.recipes/Nginx-Orthanc-Keycloak/dockerfile b/platform/app/.recipes/Nginx-Orthanc-Keycloak/dockerfile index eba4237b4..7e8613529 100644 --- a/platform/app/.recipes/Nginx-Orthanc-Keycloak/dockerfile +++ b/platform/app/.recipes/Nginx-Orthanc-Keycloak/dockerfile @@ -1,5 +1,5 @@ # Stage 1: Build the application -FROM node:18.16.1-slim as builder +FROM node:20.18.1-slim as builder # Setup the working directory RUN mkdir /usr/src/app diff --git a/platform/app/.recipes/Nginx-Orthanc/dockerfile b/platform/app/.recipes/Nginx-Orthanc/dockerfile index ac7433ac6..846c74c31 100644 --- a/platform/app/.recipes/Nginx-Orthanc/dockerfile +++ b/platform/app/.recipes/Nginx-Orthanc/dockerfile @@ -1,5 +1,5 @@ # Stage 1: Build the application -FROM node:18.16.1-slim as builder +FROM node:20.18.1-slim as builder # Setup the working directory RUN mkdir /usr/src/app diff --git a/platform/app/netlify.toml b/platform/app/netlify.toml index 9e4a6e5ee..b2bd54893 100644 --- a/platform/app/netlify.toml +++ b/platform/app/netlify.toml @@ -19,7 +19,7 @@ [build.environment] # If 'production', `yarn install` does not install devDependencies NODE_ENV = "development" - NODE_VERSION = "18.16.1" + NODE_VERSION = "20.18.1" YARN_VERSION = "1.22.5" RUBY_VERSION = "2.6.2" YARN_FLAGS = "--no-ignore-optional --pure-lockfile" diff --git a/platform/app/package.json b/platform/app/package.json index 1c1daf590..e96413d41 100644 --- a/platform/app/package.json +++ b/platform/app/package.json @@ -53,7 +53,7 @@ "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjph": "^2.4.5", - "@cornerstonejs/dicom-image-loader": "^2.7.3", + "@cornerstonejs/dicom-image-loader": "^2.11.2", "@emotion/serialize": "^1.1.3", "@ohif/core": "3.10.0-beta.20", "@ohif/extension-cornerstone": "3.10.0-beta.20", diff --git a/platform/app/public/config/local_static.js b/platform/app/public/config/local_static.js index 23e7a61ae..193ecb40c 100644 --- a/platform/app/public/config/local_static.js +++ b/platform/app/public/config/local_static.js @@ -12,41 +12,16 @@ window.config = { showLoadingIndicator: true, strictZSpacingForVolumeViewport: true, // filterQueryParam: false, - defaultDataSourceName: 'dicomweb', + defaultDataSourceName: 'local', dataSources: [ - { - namespace: '@ohif/extension-default.dataSourcesModule.dicomweb', - sourceName: 'e2e', - configuration: { - friendlyName: 'StaticWado test data', - // The most important field to set for static WADO - staticWado: true, - name: 'StaticWADO', - wadoUriRoot: '/viewer-testdata', - qidoRoot: '/viewer-testdata', - wadoRoot: '/viewer-testdata', - qidoSupportsIncludeField: false, - imageRendering: 'wadors', - thumbnailRendering: 'wadors', - enableStudyLazyLoad: true, - supportsFuzzyMatching: false, - supportsWildcard: true, - singlepart: 'video,thumbnail,pdf', - omitQuotationForMultipartRequest: true, - bulkDataURI: { - enabled: true, - relativeResolution: 'studies', - }, - }, - }, { namespace: '@ohif/extension-default.dataSourcesModule.dicomweb', sourceName: 'local', configuration: { friendlyName: 'Static WADO Local Data', name: 'DCM4CHEE', - qidoRoot: 'http://localhost:5000/dicomweb', - wadoRoot: 'http://localhost:5000/dicomweb', + qidoRoot: 'http://localhost:3001/dicomweb', + wadoRoot: 'http://localhost:3001/dicomweb', qidoSupportsIncludeField: false, supportsReject: true, supportsStow: true, diff --git a/platform/core/package.json b/platform/core/package.json index 60d8f2574..f915c0a19 100644 --- a/platform/core/package.json +++ b/platform/core/package.json @@ -37,7 +37,7 @@ "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjph": "^2.4.5", - "@cornerstonejs/dicom-image-loader": "^2.7.3", + "@cornerstonejs/dicom-image-loader": "^2.11.2", "@ohif/ui": "3.10.0-beta.20", "cornerstone-math": "0.1.9", "dicom-parser": "^1.8.21" diff --git a/platform/docs/docs/assets/img/static-dicom-web.png b/platform/docs/docs/assets/img/static-dicom-web.png new file mode 100644 index 000000000..fab41fc84 Binary files /dev/null and b/platform/docs/docs/assets/img/static-dicom-web.png differ diff --git a/platform/docs/docs/configuration/dataSources/static-files.md b/platform/docs/docs/configuration/dataSources/static-files.md index 2741e0495..ec460db2b 100644 --- a/platform/docs/docs/configuration/dataSources/static-files.md +++ b/platform/docs/docs/configuration/dataSources/static-files.md @@ -3,45 +3,98 @@ sidebar_position: 5 sidebar_label: Static Files --- -# Static Files -There is a binary DICOM to static file generator, which provides easily served -binary files. The files are all compressed in order to reduce space -significantly, and are pre-computed for the files required for OHIF, so that the -performance of serving the files is just the read from disk/write to http stream -time, without any extra processing time. +# Static DICOMweb Files for Enhanced Performance -The project for the static wado files is located here: [static-wado]: -https://github.com/OHIF/static-wado +This section describes how to generate and serve static DICOMweb files, significantly improving the performance of your OHIF Viewer setup. These files are pre-processed and compressed, minimizing storage space and reducing serving time to the bare minimum (disk read and HTTP stream write). -It can be compiled with Java and Gradle, and then run against a set of dicom, in -the example located in /dicom/study1 outputting to /dicomweb, and then a server -run against that data, like this: +## Static-DICOMWeb Project -```bash -git clone https://github.com/OHIF/static-wado -cd static-wado -./gradlew installDist -StaticWado/build/install/StaticWado/bin/StaticWado -d /dicomweb /dicom/study1 -cd /dicomweb -npx http-server -p 5000 --cors -g +The core tool for this process is the `static-wado` project, available on GitHub: -# you can use npx serve ./dist -l 8080 -c ../public/serve.json as an alternative to http-server -``` +[static-wado]: https://github.com/RadicalImaging/Static-DICOMWeb -There is then a dev environment in the platform/app directory which can be -run against those files, like this: +This project contains two main components: -``` -cd platform/app -yarn dev:static -``` +* **`static-wado-creator`:** Converts raw DICOM files into a DICOMweb-compliant directory structure, optimizing them for efficient serving. +* **`static-wado-webserver`:** A simple web server specifically designed to serve the generated static DICOMweb files. -Additional studies can be added to the dicomweb by re-running the StaticWado -command. It will create a single studies.gz index file (JSON DICOM file, -compressed) containing an index of all studies created. There is then a small -extension to OHIF which performs client side indexing. +## Prerequisites -The StaticWado command also knows how to deploy a client and dicomweb directory -to Amazon s3, which can then server files up directly. There is another build -setup build:aws in the viewer package.json to create such a deployment. +- Node.js and npm (or yarn) installed on your system. + +## Installation + +1. **Clone the Repository:** + + ```bash + git clone https://github.com/RadicalImaging/Static-DICOMWeb + cd Static-DICOMWeb + ``` + +2. **Install Dependencies:** + + ```bash + yarn install + ``` + +## Generating Static DICOMweb Files + +1. **Prepare your DICOM data:** Organize your DICOM files into a directory. For example `/Users/alireza/dicom/test-static-script/ACRIN-CT`. + +2. **Convert to DICOMweb Structure:** + Use the `mkdicomweb.js` script from the `static-wado-creator` package to create the DICOMweb directory: + + ```bash + node packages/static-wado-creator/bin/mkdicomweb.js '/Users/alireza/dicom/test-static-script/ACRIN-CT' -o '/Users/alireza/dicom/test-static-script/output' + ``` + + * **Replace:** + * `/Users/alireza/dicom/test-static-script/ACRIN-CT` with the path to your directory of DICOM files. + * `/Users/alireza/dicom/test-static-script/output` with your desired output directory for the DICOMweb structure. + + This command will generate a directory structure similar to this in your output location: + + ![alt text](../../assets/img/static-dicom-web.png) + +## Serving Static Files with the Web Server + +1. **Start the Server:** + + Run the `dicomwebserver.mjs` script from the `static-wado-webserver` package, specifying the port and the DICOMweb directory: + + ```bash + node packages/static-wado-webserver/bin/dicomwebserver.mjs -p 3001 -o /Users/alireza/dicom/test-static-script/output + ``` + + * **`-p 3001`:** Sets the server to listen on port 3001. You can change this if needed. + * **`-o /Users/alireza/dicom/test-static-script/output`:** Specifies the path to your generated DICOMweb directory. + + :::info + The `-p` (port) and `-o` (output directory) flags are used to configure the server. + ::: + +## Running OHIF Viewer with Static Data + +1. **Use the `local_static.js` Configuration:** + + Start the OHIF Viewer in development mode using the provided `local_static.js` configuration file: + + ```bash + yarn dev:static + ``` + +2. **Configuration Details:** + + The `local_static.js` configuration file is pre-configured to point to: + + ```js + qidoRoot: 'http://localhost:3001/dicomweb', + wadoRoot: 'http://localhost:3001/dicomweb', + ``` + + This matches the default port (3001) used by the `static-wado-webserver`. + + :::info + If you change the port or output directory when running the `static-wado-webserver`, you **must** also update the `qidoRoot` and `wadoRoot` values in your `local_static.js` configuration file accordingly to ensure the OHIF Viewer can access the data. + ::: diff --git a/platform/docs/netlify.toml b/platform/docs/netlify.toml index ff82abc66..7354856c5 100644 --- a/platform/docs/netlify.toml +++ b/platform/docs/netlify.toml @@ -16,7 +16,7 @@ [build.environment] # If 'production', `yarn install` does not install devDependencies NODE_ENV = "development" - NODE_VERSION = "18.16.1" + NODE_VERSION = "20.18.1" YARN_VERSION = "1.22.5" RUBY_VERSION = "2.6.2" YARN_FLAGS = "--no-ignore-optional --pure-lockfile"