Technical Documentation: OHIF/Viewers
ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference
Overview (README.md)
| Measurement Tracking | Demo | |
| Labelmap Segmentations | Demo | |
| Fusion and Custom Hanging protocols | Demo | |
| Volume Rendering | Demo | |
| Demo | ||
| RT STRUCT | Demo | |
| 4D | Demo | |
| Video | Demo | |
| Slide Microscopy | Demo | |
| ECG Waveform | Demo |
About
The OHIF Viewer can retrieve
and load images from most sources and formats, render sets in 2D, 3D, and
reconstructed representations; allows for the manipulation, annotation, and
serialization of observations; supports internationalization, OpenID Connect,
offline use, hotkeys, and many more features.
Almost everything offers some degree of customization and configuration. If it
doesn't support something you need, we accept pull requests and have an ever
improving Extension System.
Why Choose Us
Community & Experience
The OHIF Viewer is a collaborative effort that has served as the basis for many
active, production, and FDA Cleared medical imaging viewers. It benefits from
our extensive community's collective experience, and from the sponsored
contributions of individuals, research groups, and commercial organizations.
Built to Adapt
After more than 8-years of integrating with many companies and organizations,
The OHIF Viewer has been rebuilt from the ground up to better address the
varying workflow and configuration needs of its many users. All of the Viewer's
core features are built using its own extension system. The same extensibility
that allows us to offer:
- 2D and 3D medical image viewing
- Multiplanar Reconstruction (MPR)
- Maximum Intensity Project (MIP)
- Whole slide microscopy viewing
- PDF and Dicom Structured Report rendering
- Segmentation rendering as labelmaps and contours
- User Access Control (UAC)
- Context specific toolbar and side panel content
- and many others
Can be leveraged by you to customize the viewer for your workflow, and to add
any new functionality you may need (and wish to maintain privately without
forking).
Support
For commercial support, academic collaborations, and answers to common
questions; please use Get Support to contact
us.
Developing
Branches
`master` branch - The latest dev (beta) release
master- The latest dev release
This is typically where the latest development happens. Code that is in the master branch has passed code reviews and automated tests, but it may not be deemed ready for production. This branch usually contains the most recent changes and features being worked on by the development team. It's often the starting point for creating feature branches (where new features are developed) and hotfix branches (for urgent fixes).
Each package is tagged with beta version numbers, and published to npm such as @ohif/[email protected]
`release/*` branches - The latest stable releases
Once the master branch code reaches a stable, release-ready state, we conduct a comprehensive code review and QA testing. Upon approval, we create a new release branch from master. These branches represent the latest stable version considered ready for production.
For example, release/3.5 is the branch for version 3.5.0, and release/3.6 is for version 3.6.0. After each release, we wait a few days to ensure no critical bugs. If any are found, we fix them in the release branch and create a new release with a minor version bump, e.g., 3.5.1 in the release/3.5 branch.
Each package is tagged with version numbers and published to npm, such as @ohif/[email protected]. Note that master is always ahead of the release branch. We publish docker builds for both beta and stable releases.
Here is a schematic representation of our development workflow:
Requirements
- Yarn 1.20.0+
- Node 18+
- Yarn Workspaces should be enabled on your machine:
yarn config set workspaces-experimental true
Getting Started
- Fork this repository
- Clone your forked repository
git clone https://github.com/YOUR-USERNAME/Viewers.git
- Navigate to the cloned project's directory
- Add this repo as a
remotenamedupstreamgit remote add upstream https://github.com/OHIF/Viewers.git
yarn install --frozen-lockfileto restore dependencies and link projects
:::danger
In general run yarn install with the --frozen-lockfile flag to help avoid
supply chain attacks by enforcing reproducible dependencies. That is, if theyarn.lock file is clean and does NOT reference compromised packages, then
no compromised packages should land on your machine by using this flag.
:::
To Develop
From this repository's root directory:
# Enable Yarn Workspaces
yarn config set workspaces-experimental true
# Restore dependencies
yarn install --frozen-lockfileCornerstone3D Integration Testing
OHIF's Playwright end-to-end tests can run against a CS3D branch or a
published CS3D version, allowing changes that span both repositories to be
validated together before merging.
Setting up an integration build
Add a CS3D_REF: line to the PR body. No label is involved — the line itself is
the request.
The line must sit at the top level of the body. A line inside a fenced code
block, inside an indented code block (four spaces or more), or inside an HTML
comment is an example rather than a request, so you can document this syntax in
a PR without triggering it. The PR template is mostly HTML comments, so write
the line outside them. The workflow prints a warning when it ignores aCS3D_REF: line for one of these reasons, and it fails when the block that
hides the line is never closed.
CS3D_REF: feat/my-featureThe line takes one of three forms:
| Form | Meaning |
|---|---|
CS3D_REF: feat/my-feature |
A branch or tag in cornerstonejs/cornerstone3D. The workflow clones it, builds CS3D from source with pnpm run build:esm, and symlinks the built packages into OHIF's node_modules. |
CS3D_REF: 5.10.6 |
A published version. The workflow rewrites every @cornerstonejs/* entry across the workspace to that version and reinstalls. The accepted forms are 5.10.6, 5.11.0-beta.1, 5.x, 5.10.x and 4.19+. A two-part number such as 5.10 is not one of them; write 5.10.x. |
CS3D_REF: feat/my-feature now 5.10.6 |
The branch, and the concrete release it became. See Retiring a branch ref below. |
Three rules are worth knowing:
- The branch must live in
cornerstonejs/cornerstone3D. The<owner>:form is no longer accepted: it let a PR point the clone at
any GitHub account and run that account's install scripts on the shared
self-hosted runner. Push your branch to the CS3D repository instead. - There is no default. A PR with no
CS3D_REFline runs the ordinary
Playwright suite against the CS3D version this repo already pins. The same
holds for a manual run with an emptycs3d_refbox. - From a fork, an integration run needs approval. The run waits on the
cs3d-integrationenvironment until one of the named reviewers approves that
specific run, because it builds and executes CS3D code on a shared machine.
A PR from a branch in this repository proceeds unattended.
The workflow can also be triggered manually via workflow_dispatch with acs3d_ref input, which accepts the same three forms.
What happens in CI
The Playwright workflow runs three jobs:
| Job | Purpose |
|---|---|
| Gate | Runs on GitHub's own runners and never checks out the repository. It decides whether the PR may reach the self-hosted runner at all, reads and validates any CS3D_REF line, and decides whether the run needs a reviewer's approval. |
| Playwright Tests | Builds OHIF (with CS3D linked or version-swapped), runs the full Playwright suite, and uploads test results and coverage. When a CS3D_REF line changes the tree under test, it also deploys a Netlify preview. |
| CS3D Branch Merge Guard | Reports when CS3D_REF names a branch rather than a published version, because merging would leave master depending on unreleased CS3D code. It is advisory: it reports a red result, but it does not block the merge button. |
Playwright does not run on every fork PR
A PR from a fork that changes a CI-defining file does not run Playwright on the
self-hosted runner. It runs once the change is reviewed and merged. The affected
paths are .github/, .scripts/, pnpm-workspace.yaml, preinstall.js, any
root pnpmfile, and every .npmrc in the workspace, not only the one in the
root directory.
package.json and pnpm-lock.yaml are not on the list, so a fork PR that adds
a dependency or moves a module between workspace packages runs Playwright as
usual. Changes to the root package.json and pnpm-lock.yaml still need a code
owner's review before merge. A PR from a branch in this repository is not
affected by either rule.
Testing changes that span both repos
If a feature requires changes in both Cornerstone3D and OHIF:
- Create your feature branch in the
cornerstonejs/cornerstone3Drepository and
push it. - Create a matching branch in OHIF.
- In the PR body, add:
CS3D_REF: <your-cs3d-branch>. - Playwright tests build CS3D from source, link it, and run the full suite. The
merge guard reports a red result for as long as the line names a branch, so
you can see the test results and the preview deploy while you iterate. - Once the CS3D side is merged and published, change the line to the retiring
form below.
Retiring a branch ref
Once the CS3D fix ships, change the line rather than deleting it:
CS3D_REF: feat/my-feature now 5.10.6The version after now is a record, not a request. It never moves the pin
backwards: on every run the workflow compares it against the version this repo
pins and keeps whichever is newer. So a line still saying now 5.10.6 in a repo
that has moved on to 5.11.0 tests 5.11.0, not 5.10.6.
That is what lets the line stay in place as history — the branch name remains
visible as the reason the pinned version moved, and the line stops changing what
the run does. Once the repo pins that version or something newer, no rewrite
happens, no reinstall happens, and no preview is built or deployed. The version
must be one concrete release, such as 5.10.6 or 5.11.0-beta.1, not a range.
A fork PR still asks for the cs3d-integration approval while the line is
present, even after the line is spent, because the gate has no checkout and
cannot tell which version the repo pins. Delete the line to stop the prompt.
Preview deploys
When a CS3D_REF line changes the tree under test, the Playwright workflow also
builds the OHIF viewer and deploys it to Netlify as a preview. This gives you a
live URL to manually test the combined CS3D + OHIF changes without running
anything locally. A spent retiring form tests the same tree as an ordinary run,
so it does not produce a preview.
For details on linking CS3D locally for development, see the
Cornerstone3D README.
Commands
These commands are available from the root directory. Each project directory
also supports a number of commands that can be found in their respectiveREADME.md and package.json files.
| Yarn Commands | Description |
|---|---|
| Develop | |
dev |
Default development experience for Viewer |
dev:fast |
Our experimental fast dev mode that uses rsbuild instead of webpack |
test:unit |
Jest multi-project test runner; overall coverage |
| Deploy | |
build* |
Builds production output for our PWA Viewer |
* - For more information on different builds, check out our Deploy
Docs
Which config each command uses
The dev server and the production build select a different default
configuration file when APP_CONFIG is not set explicitly:
| Command | Default config | Data sources | ?customization= |
|---|---|---|---|
dev, dev:fast, start |
config/dev.js |
Full set | Enabled |
build |
config/default.js |
One demo source | Disabled |
config/dev.jsis the full-featured local-development config: every data
source is enabled, the?customization=URL feature is turned on (viacustomizationUrlPrefixes), and it is kept at parity with the public demo
(config/netlify.js) so customizations behave locally the same way they do on
the demo.config/netlify.jsis the public demo / Netlify deploy config
(build:viewer:ci), with the same full data-source set and?customization=
enabled.config/default.jsis a locked-down baseline and is now only the
default for a plain production build (buildwith noAPP_CONFIG): a single
read-only demo data source and?customization=off.
Any explicit APP_CONFIG overrides the default, e.g.APP_CONFIG=config/default.js pnpm run dev orAPP_CONFIG=config/netlify.js pnpm run build.
Project
The OHIF Medical Image Viewing Platform is maintained as amonorepo. This means that this repository, instead of containing a
single project, contains many projects. If you explore our project structure,
you'll see the following:
/* Detailed source-code truncated for AI context efficiency. */Acknowledgments
To acknowledge the OHIF Viewer in an academic publication, please cite
Open Health Imaging Foundation Viewer: An Extensible Open-Source Framework
for Building Web-Based Imaging Applications to Support Cancer ResearchErik Ziegler, Trinity Urban, Danny Brown, James Petts, Steve D. Pieper, Rob
Lewis, Chris Hafey, and Gordon J. HarrisJCO Clinical Cancer Informatics, no. 4 (2020), 336-345, DOI:
10.1200/CCI.19.00131Open-Access on Pubmed Central:
https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7259879/
or, for v1, please cite:
LesionTracker: Extensible Open-Source Zero-Footprint Web Viewer for Cancer
Imaging Research and Clinical TrialsTrinity Urban, Erik Ziegler, Rob Lewis, Chris Hafey, Cheryl Sadow, Annick D.
Van den Abbeele and Gordon J. HarrisCancer Research, November 1 2017 (77) (21) e119-e122 DOI:
10.1158/0008-5472.CAN-17-0334
Note: If you use or find this repository helpful, please take the time to
star this repository on GitHub. This is an easy way for us to assess adoption
and it can help us obtain future funding for the project.
This work is supported primarily by the National Institutes of Health, National
Cancer Institute, Informatics Technology for Cancer Research (ITCR) program,
under a
grant to Dr. Gordon Harris at Massachusetts General Hospital (U24 CA199460).
NCI Imaging Data Commons (IDC) project supported the development of new features and bug fixes marked with "IDC:priority",
"IDC:candidate" or "IDC:collaboration". NCI Imaging Data Commons is supported by contract number 19X037Q from
Leidos Biomedical Research under Task Order HHSN26100071 from NCI. IDC Viewer is a customized version of the OHIF Viewer.
This project is tested with BrowserStack. Thank you for supporting open-source!
License
MIT © OHIF
Platform Docs README (`platform/docs/README.md`)
Website
This website is built using Docusaurus 2, a modern static website generator.
Installation
yarn install --frozen-lockfileLocal Development
yarn startThis command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
Build
yarn buildThis command generates static content into the build directory and can be served using any static contents hosting service.
Deployment
GIT_USER=<Your GitHub username> USE_SSH=true yarn deployIf you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the gh-pages branch.
Platform Docs Docs README (`platform/docs/docs/README.md`)
id: Introduction slug: / sidebar_position: 1
The Open Health Imaging Foundation (OHIF) Viewer is an open source,
web-based, medical imaging platform. It aims to provide a core framework for
building complex imaging applications.
Key features:
Designed to load large radiology studies as quickly as possible. Retrieves
metadata ahead of time and streams in imaging pixel data as needed.Leverages Cornerstone3D for decoding,
rendering, and annotating medical images.Works out-of-the-box with Image Archives that support DICOMWeb.
Offers a Data Source API for communicating with archives over proprietary API
formats.Provides a plugin framework for creating task-based workflow modes which can
reuse core functionality.Beautiful user interface (UI) designed with extensibility in mind. UI
components available in a reusable component library built with React.js and
Tailwind CSStext<a style={{ backgroundColor: '#4042af', color: 'white', padding: '0.5rem 1rem', borderRadius: '0.25rem', textDecoration: 'none', ':hover': { backgroundColor: '#2a2b74' } }} href="https://ohif.org/news/">Subscribe to our newsletter</a> <a style={{ backgroundColor: '#4042af', color: 'white', padding: '0.5rem 1rem', borderRadius: '0.25rem', textDecoration: 'none', ':hover': { backgroundColor: '#2a2b74' } }} href="./release-notes">Release Notes</a>
| Measurement Tracking | Demo | |
| Labelmap Segmentations | Demo | |
| Fusion and Custom Hanging protocols | Demo | |
| Volume Rendering | Demo | |
| Demo | ||
| RT STRUCT | Demo | |
| 4D | Demo | |
| Video | Demo | |
| Slide Microscopy | Demo |
Where to next?
The Open Health Imaging Foundation intends to provide an imaging viewer
framework which can be easily extended for specific uses. If you find yourself
unable to extend the viewer for your purposes, please reach out via our GitHub
issues. We are actively seeking feedback on ways to improve our
integration and extension points.
Check out these helpful links:
- Ready to dive into some code? Check out our
Getting Started Guide. - We're an active, vibrant community.
Learn how you can be more involved. - Feeling lost? Read our help page.
Citing OHIF
To cite the OHIF Viewer in an academic publication, please cite
Open Health Imaging Foundation Viewer: An Extensible Open-Source Framework
for Building Web-Based Imaging Applications to Support Cancer ResearchErik Ziegler, Trinity Urban, Danny Brown, James Petts, Steve D. Pieper, Rob
Lewis, Chris Hafey, and Gordon J. Harris JCO Clinical Cancer Informatics, no. 4 (2020), 336-345, DOI:
10.1200/CCI.19.00131
This article is freely available on Pubmed Central: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7259879/
or, for Lesion Tracker of OHIF v1, please cite:
LesionTracker: Extensible Open-Source Zero-Footprint Web Viewer for Cancer
Imaging Research and Clinical TrialsTrinity Urban, Erik Ziegler, Rob Lewis, Chris Hafey, Cheryl Sadow, Annick D.
Van den Abbeele and Gordon J. Harris Cancer Research, November 1 2017 (77) (21) e119-e122 DOI:
10.1158/0008-5472.CAN-17-0334
This article is freely available on Pubmed Central.
https://pubmed.ncbi.nlm.nih.gov/29092955/
Note: If you use or find this repository helpful, please take the time to
star this repository on Github. This is an easy way for us to assess adoption,
and it can help us obtain future funding for the project.
License
MIT © OHIF
Platform Docs Scripts README (`platform/docs/scripts/README.md`)
OHIF Viewer Documentation Scripts
This directory contains utility scripts for the OHIF Viewer documentation.
prepare-markdown-files.js
This script copies all markdown files from the docs directory (excluding api/ and assets/) to a /llm directory in the build output, making them available as static markdown files that can be accessed directly without the Docusaurus UI.
Purpose
These files are made available for easy access by LLMs and other tools that need to retrieve the raw markdown content without the surrounding Docusaurus UI elements.
Access URLs
After deployment, the markdown files can be accessed at URLs like:
https://docs.ohif.org/llm/platform/extensions/modules/commands.mdhttps://docs.ohif.org/llm/platform/services/ui/index.md
Implementation
The script is automatically run as part of the build:docs command and will:
- Find all markdown files in the
/platform/docs/docs/directory (excluding api/ and assets/) - Copy them to
/platform/docs/build/llm/preserving the directory structure - These files are then deployed to the website along with the rest of the built documentation
You can also run this script manually with:
cd platform/docs
yarn run prepare-markdown-filesgenerate-llms-txt.js
This script generates a llms.txt file that follows the llms.txt specification by creating an index of all the markdown files that have been copied to the /llm directory.
Purpose
The llms.txt file provides an overview of all available documentation in a format that's optimized for use with Large Language Models (LLMs). It creates a structured index that LLMs can use to efficiently navigate and find information in the documentation.
Access URL
After deployment, the llms.txt file can be accessed at:
https://docs.ohif.org/llms.txt
Implementation
The script is automatically run as part of the build:docs command (after prepare-markdown-files.js) and will:
- Scan all the markdown files that were copied to the
/llmdirectory - Extract titles and summaries from the frontmatter of each file
- Organize them into sections based on their directory structure
- Generate a single llms.txt file in the standard format with links to all the documentation files
- Save the file to the build directory root so it will be accessible at the root of the website
You can also run this script manually with (after running prepare-markdown-files.js):
cd platform/docs
yarn run generate-llms-txtgenerate-llms-full-txt.js
This script generates an llms-full.txt file by concatenating the content of all markdown files from the /llm directory into a single giant file, similar to the approach used by bun.sh.
Purpose
The llms-full.txt file provides the complete content of all documentation in a single file, which can be useful for LLMs that need to search or reference the entire documentation at once. This approach allows for contextual understanding across multiple documentation pages.
Access URL
After deployment, the llms-full.txt file can be accessed at:
https://docs.ohif.org/llms-full.txt
Implementation
The script is automatically run as part of the build:docs command (after generate-llms-txt.js) and will:
- Scan all the markdown files that were copied to the
/llmdirectory - Remove frontmatter from each file to clean up the content
- Add clear section headers and source URLs for each file
- Concatenate all the content into a single file with proper organization by section
- Save the file to the build directory root so it will be accessible at the root of the website
The output file has the following structure:
- Title and introduction for OHIF Viewer
- Files are organized by their directory structure (e.g., platform, extensions, services)
- Each file has a header with its title and source URL
- Separator lines between files for clarity
You can also run this script manually with (after running prepare-markdown-files.js):
cd platform/docs
yarn run generate-llms-full-txtPlatform Docs Docs Behaviours README (`platform/docs/docs/behaviours/README.md`)
id: README title: Behaviours sidebar_position: 0
Behaviours
This section documents how the system and UI actually behave — the
end-to-end behaviours that emerge from the interaction of services, extensions,
the data source, and Cornerstone3D, rather than the API of any single module.
It is the place for:
- Observed behaviours — how a feature works today across the stack (e.g. how
a DICOM SEG is fetched, decoded, and rendered; what the viewport does on study
change; how measurements round-trip to SR). - Design proposals — proposed or in-progress changes to a behaviour, captured
before/while they are implemented so the intent and trade-offs are recorded.
These are clearly marked as proposals until they land. - Edge cases and failure modes — what happens when something is missing,
slow, or malformed, and how the system is expected to degrade.
The goal is a durable, discoverable record of behaviour — the kind of
cross-cutting knowledge that is otherwise only in people's heads or scattered
across code comments. Prefer linking to the relevant source files (with line
references) so each behaviour doc stays anchored to the code it describes.
Index
Segmentation: loading a multiframe SEG as a single Part 10 instance
— implemented, enabled by default. Prefetch the whole instance in one request
and register it into the Cornerstone3D NATURALIZED frame registry so the
per-frame load path (WADO-RS and WADO-URI) is served locally, while keeping the
standard decode path unchanged. Per-frame loading is the exception — disable
vialoadMultiframeAsPart10: false(data source config or thecornerstone.segmentation.loadMultiframeAsPart10customization).Report dialog: where a save goes, and what the series is called
— implemented. The three destinations of a save, thepredecessorImageId
rule that decides which loaded series the dialog offers, the four names that a
new series starts from, and the descriptions that the viewer remembers.
Writing a new behaviour doc
- Add a
kebab-case.mdfile in this directory. - State whether it documents current behaviour or is a proposal.
- Link to the code (
path:line) that implements or will implement it. - Add it to the Index above.
Platform Docs Docs Deployment Index (`platform/docs/docs/deployment/index.md`)
sidebar_position: 1 sidebar_label: Overview title: Deployment Overview summary: Comprehensive guide to deploying the OHIF Viewer as a standalone web application or embedded iframe, covering data source configuration, security considerations, and various deployment options with examples for different hosting environments.
Deployment
The OHIF Viewer can be served as a stand-alone PWA (progressive web
application) by building and hosting a collection of static assets or be embedded in other web applications via an iframe if needed. In
either case, you will need to configure your instance of the Viewer so that it
can connect to your data source (the database or PACS that provides the data
your Viewer will display).
:::tip
Our goal is to make deployment as simple and painless as possible; however,
there is an inherent amount of complexity in configuring and deploying web
applications. If you find yourself a little lost, please don't hesitate to
reach out to for help.
:::
Deployment Scenarios
Stand-alone Viewer
Deploying the OHIF Viewer as a stand-alone web application provides many
benefits, but comes at the cost of time and complexity. Some benefits include:
Today:
- Leverage extensions and
modes to drop-in powerful new features - Add routes and customize the viewer's workflow
- Finer control over styling and whitelabeling
In the future:
- The ability to package the viewer for App Store distribution
Hosted Static Assets
At the end of the day, a production OHIF Viewer instance is a collection of
HTML, CSS, JS, Font Files, and Images. We "build" those files from oursource code with configuration specific to our project. We then make those
files publicly accessible by hosting them on a Web Server.
Part 1 - Build Production Assets
"Building", or creating, the files you will need is the same regardless of the
web host you choose. You can find detailed instructions on how to configure and
build the OHIF Viewer in our
"Build for Production" guide.
Part 2 - Host Your App
There are a lot of benefits to hosting static assets over
dynamic content. You can find instructions on how to host your build's output
via one of these guides:
Drag-n-drop
Easy
Advanced
Embedded Viewer (iframe)
OHIF-v3 has deprecated deploying the viewer as an embedded viewer via a script
tag as the number of underlying libraries that run web workers are increasing for OHIF. An example of these libraries is OHIF's 3D rendering functionality that is provided byvtk-js.
However, you can still embed the viewer using an iframe. You can utilize the iframe element to load the OHIF viewer and establish communication with it using the postMessage API if needed.
Read more about how to use the iframe here.
Data
The OHIF Viewer is able to connect to any data source that implements the DICOM
Web Standard. DICOM Web refers to RESTful
DICOM Services -- a recently standardized set of guidelines for exchanging
medical images and imaging metadata over the internet. Not all archives fully
support it yet, but it is gaining wider adoption.
Configure Connection
If you have an existing archive and intend to host the OHIF Viewer at the same
domain name as your archive, then connecting the two is as simple as following
the steps laid out in our
Configuration Essentials Guide.
What if I don't have an imaging archive?
We provide some guidance on configuring a local image archive in our
Data Source Essentials
guide. Hosting an archive remotely is a little trickier. You can check out some
of our advanced recipes for modeled setups that may work for you.
What if I intend to host the OHIF Viewer at a different domain?
There are two important steps to making sure this setup works:
- Your Image Archive needs to be exposed, in some way, to the open web. This
can be directly, or through areverse proxy, but the Viewer needs some
way to request its data. - * Your Image Archive needs to have appropriate CORS (Cross-Origin Resource
Sharing) Headers
* Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional
HTTP headers to tell a browser to let a web application running at one origin
(domain) have permission to access selected resources from a server at a
different origin. - MDN Web Docs: Web - Http - CORS
Most image archives do not provide either of these features "out of the box".
It's common to use IIS, Nginx, or Apache to route incoming requests and append
appropriate headers. You can find an example of this setup in our
Nginx + Image Archive Deployment Recipe.
What if my archive doesn't support DicomWeb?
It's possible to supply all Study data via JSON format, in the event you do not
have a DicomWeb endpoint. You can host all of the relevant files on any web
accessible server (Amazon S3, Azure Blob Storage, Local file server etc.)
This JSON is supplied via the '?url=' query parameter. It should reference an
endpoint that returns application/json formatted text.
If you do not have an API, you can simply return a text file containing the JSON
from any web server.
You tell the OHIF viewer to use JSON by using the dicomjson datasource and
appending '?url=' query to your mode's route:
e.g.https://my-test-ohif-server/myMode/dicomjson?url=https://my-json-server/study-uid.json
The returned JSON object must contain a single root object with a 'studies'
array.
You can read more about using different data sources for mode's routes
here
Sample JSON format:
/* Detailed source-code truncated for AI context efficiency. */More info on this JSON format can be found here
Issue #1500
Implementation Notes:
- For each instance url (dicom object) in the returned JSON, you must prefix
theurlwithdicomjson:in order for the cornerstone image loader to
retrieve it correctly. eg.https://image-server/my-image.dcm--->dicomjson:https://image-server/my-image.dcm - The JSON format above is compatible with >= v3.7.8 of the application in
V2
version. Older versions of the viewer used a different JSON format. As of
20/04/20 the public [https://viewer.ohif.org/] is a pre 3.0 version that does
not support this format yet. - The JSON format is case-sensitive. Please ensure you have matched casing with
the naturalised Dicom format referenced in
Issue #1500.
CORS Issues (Cross-Origin Resource Sharing)
If you host a JSON API or Images on a different domain from the app itself,
you will likely have CORS issues. This will also happen when testing from
Localhost and reaching out to remote servers. Even if the domain is the same,
different ports, subdomains or protocols (https vs http) will also cause CORS
errors. You will to need add a configuration on each server hosting these assets
to allow your App server origin.
For example:
Let's assume your application is hosted on https://my-ohif-server.com.
Your JSON API is hosted on https://my-json-api.aws.com
And your images are stored on Amazon S3 at https://my-s3-bucket.aws.com
When you first start your application, browsing tohttps://my-ohif-server.com/myMode/dicomjson?url=https://my-json-api.aws.com/api/my-json-study-info.json,
you will likely get a CORS error in the browser console as it tries to connect
to https://my-json-api.aws.com.
Adding a setting on the JSON server to allow the CORS origin =https://my-ohif-server.com should solve this.
Next, you will likely get a similar CORS error, as the browser tries to go tohttps://my-s3-bucket.aws.com. You will need to go to the S3 bucket
configuration, and add a CORS setting to allow origin =https://my-ohif-server.com.
Essentially, whenever the application connects to a remote resource, you will
need to add the applications url to the allowed CORS Origins on that resource.
Adding an origin similar to https://localhost:3000 will also allow for local
testing.
Securing Your Data
Coming soon
Recipes
We've included a few recipes for common deployment scenarios. There are many,
many possible configurations, so please don't feel limited to these setups.
Please feel free to suggest or contribute your own recipes.
Platform Docs Docs Development Getting Started (`platform/docs/docs/development/getting-started.md`)
sidebar_position: 1 sidebar_label: Getting Started title: Getting Started with OHIF Development summary: Quick start guide for OHIF development, covering repository setup options, branch organization, development environment requirements, project initialization, and steps for building production-ready assets.
Getting Started
Setup
Fork & Clone
If you intend to contribute back changes, or if you would like to pull updates
we make to the OHIF Viewer, then follow these steps:
- Fork the OHIF/Viewers repository
- Create a local clone of your fork
git clone https://github.com/YOUR-USERNAME/Viewers
- Add OHIF/Viewers as a remote repository labeled
upstream- Navigate to the cloned project's directory
git remote add upstream https://github.com/OHIF/Viewers.git
With this setup, you can now sync your fork to keep it
up-to-date with the upstream (original) repository. This is called a "Triangular
Workflow" and is common for Open Source projects. The GitHub blog has a good
graphic that illustrates this setup.
Private
Alternatively, if you intend to use the OHIF Viewer as a starting point, and you
aren't as concerned with syncing updates, then follow these steps:
- Navigate to the OHIF/Viewers repository
- Click
Clone or download, and thenDownload ZIP - Use the contents of the
.zipfile as a starting point for your viewer
NOTE: It is still possible to sync changes using this approach. However,
submitting pull requests for fixes and features are best done with the
separate, forked repository setup described in "Fork & Clone"
Developing
Branches
`master` branch - The latest dev (beta) release
master- The latest dev release
This is typically where the latest development happens. Code that is in the master branch has passed code reviews and automated tests, but it may not be deemed ready for production. This branch usually contains the most recent changes and features being worked on by the development team. It's often the starting point for creating feature branches (where new features are developed) and hotfix branches (for urgent fixes).
Each package is tagged with beta version numbers, and published to npm such as @ohif/[email protected]
`release/*` branches - The latest stable releases
Once the master branch code reaches a stable, release-ready state, we conduct a comprehensive code review and QA testing. Upon approval, we create a new release branch from master. These branches represent the latest stable version considered ready for production.
For example, release/3.5 is the branch for version 3.5.0, and release/3.6 is for version 3.6.0. After each release, we wait a few days to ensure no critical bugs. If any are found, we fix them in the release branch and create a new release with a minor version bump, e.g., 3.5.1 in the release/3.5 branch.
Each package is tagged with version numbers and published to npm, such as @ohif/[email protected]. Note that master is always ahead of the release branch. We publish docker builds for both beta and stable releases.
Here is a schematic representation of our development workflow:
Requirements
- Node.js & NPM
- Yarn
- Yarn workspaces should be enabled:
yarn config set workspaces-experimental true
Kick the tires
Navigate to the root of the project's directory in your terminal and run the
following commands:
# Restore dependencies
yarn install --frozen-lockfile
# Start local development server
yarn run dev:::danger
In general run yarn install with the --frozen-lockfile flag to help avoid
supply chain attacks by enforcing reproducible dependencies. That is, if theyarn.lock file is clean and does NOT reference compromised packages, then
no compromised packages should land on your machine by using this flag.
:::
You should see the following output:
@ohif/app: i 「wds」: Project is running at http://localhost:3000/
@ohif/app: i 「wds」: webpack output is served from /
@ohif/app: i 「wds」: Content not from webpack is served from D:\code\ohif\Viewers\platform\viewer
@ohif/app: i 「wds」: 404s will fallback to /index.html
# And a list of all generated files🎉 Celebrate 🎉
Building for Production
More comprehensive guides for building and publishing can be found in our
deployment docs
# Build static assets to host a PWA
yarn run buildUpdating Dependencies
In general you will typically not be updating the various package.json files.
But for the case when you do, you will have to also update the various OHIF lock files
and as such you will have to do both a yarn and bun install without
the --frozen-lockfile flag.
:::danger
Updating the package.json must be done with care so as to avoid incorporating
vulnerable, third-party packages and/or versions. Please research the added
packages and/or versions for vulnerabilities.
Here is what you should do when adding new packages and/or versions prior to
committing and pushing your code:
- Do your due diligence researching the added packages and/or versions for vulnerabilities.
- Update the
package.jsonfiles. - Execute
yarn run install:update-lockfile. This updates both theyarn.lockand
thebun.lockfiles. - Execute
yarn run auditfor a last security check. This runs bothyarn auditandbun audit. - Include both the
yarn.lockandbun.lockfiles as part of your commit.
If any of your research or auditing for vulnerabilities find HIGH risk vulnerabilities
do NOT commit or push your changes! Low and moderate risk vulnerabilities are acceptable.
:::
Troubleshooting
- If you receive a "No Studies Found" message and do not see your studies, try
changing the Study Date filters to a wider range. - If you see a 'Loading' message which never resolves, check your browser's
JavaScript console inside the Developer Tools to identify any errors.
Platform Docs Docs Faq Index (`platform/docs/docs/faq/index.md`)
id: index title: OHIF Viewer FAQ summary: Comprehensive list of frequently asked questions about the OHIF Viewer, covering common inquiries about reporting bugs, requesting features, academic collaborations, regulatory status, and obtaining demo studies.
General FAQ
How do I report a bug?
Navigate to our GitHub Repository, and submit a new bug report.
Follow the steps outlined in the Bug Report Template.
How can I request a new feature?
At the moment we are in the process of defining our roadmap and will do our best
to communicate this to the community. If your requested feature is on the
roadmap, then it will most likely be built at some point. If it is not, you are
welcome to build it yourself and contribute it.
If you have resources and would like to fund the development of a feature,
please contact us.
Who should I contact about Academic Collaborations?
Gordon J. Harris
at Massachusetts General Hospital is the primary contact for any academic
collaborators. We are always happy to hear about new groups interested in using
the OHIF framework, and may be able to provide development support if the
proposed collaboration has an impact on cancer research.
Does OHIF offer support?
yes, you can contact us for more information here
Does The OHIF Viewer have [510(k) Clearance][501k-clearance] from the U.S. F.D.A or [CE Marking][ce-marking] from the European Commission?
NO. The OHIF Viewer is NOT F.D.A. cleared or CE Marked. It is the users'
responsibility to ensure compliance with applicable rules and regulations. The
License for the OHIF
Platform does not prevent your company or group from seeking F.D.A. clearance
for a product built using the platform.
If you have gone this route (or are going there), please let us know because we
would be interested to hear about your experience.
Is there a DICOM Conformance Statement for the OHIF Viewer?
Yes, check it here DICOM Conformance Statement
Is The OHIF Viewer [HIPAA][hipaa-def] Compliant?
NO. The OHIF Viewer DOES NOT fulfill all of the criteria to become HIPAA
Compliant. It is the users' responsibility to ensure compliance with applicable
rules and regulations.
Could you provide me with a particular study from the OHIF Viewer Demo?
You can check out the studies that we have put in this Dropbox link
Platform Docs Docs Migration Guide Index (`platform/docs/docs/migration-guide/index.md`)
id: index title: Migration Guides Overview summary: Introduction to OHIF migration guides covering the upgrade paths between different versions of the platform, with links to version-specific guides for migrating from one OHIF version to another.
import DocCardList from '@theme/DocCardList';
Migration Guides
Based on the version you are migrating from, you can find the migration guide for the latest version of the platform.
Platform Docs Docs User Guide Index (`platform/docs/docs/user-guide/index.md`)
sidebar_position: 2 sidebar_label: Study List
Study List
Overview
The first page you will see when the viewer is loaded is the Study List. In
this page you can explore all the studies that are stored on the configured
server for the OHIF Viewer.
Study Limit
To accommodate the various data sources that support various query parameters for
paging and limiting results it was decided to handle paging in the OHIF client.
This nicely handles those data sources that do not support paging and query limits.
For those that support the limit query parameter, there is a data source
configuration parameter queryLimit that will be passed for study list searches
so as to cap the result. When not specified, this value defaults to 101.
Sorting
When the Study List is opened, the application queries the PACS for 101 studies
by default. If there are greater than 100 studies returned, the default sort for
the study list is dictated by the image archive that hosts these studies for the
viewer and study list sorting will be disabled. If there are less than or equal
to 100 studies returned, they will be sorted by study date (most recent to
oldest) and study list sorting will be enabled. Whenever a query returns greater
than 100 studies, use filters to narrow results below 100 studies to enable
Study List sorting.
Filters
There are certain filters that can be used to limit the study list to the
desired criteria.
- Patient Name: Searches between patients names
- MRN: Searches between patients Medical Record Number
- Study Date: Filters the date of the acquisition
- Description: Searches between study descriptions
- Modality: Filters the modalities
- Accession: Searches between patients accession number
An example of using study list filter is shown below:
Below the study list are pagination options for 25, 50, or 100 studies per page.
For static wado servers, you can enable fuzzy matching by setting the supportsFuzzyMatching property to true, after enabling it, fuzzy matching will be peformed on the patient name field, for example, if PatientName is "John^Doe", then "jo", "Do" and "John Doe" will all match. However "ohn" will not match.
Study Summary
Click on a study to expand the study summary panel.
A summary of series available in the study is shown, which contains the series
description, series number, modality of the series, instances in the series, and
buttons to launch viewer modes to display the study.
Study Specific Modes
All available modes are seen in the study expanded view. Modes can be enabled or
disabled for a study based on the modalities contained within the study.
In the screenshot below, there are two modes shown for the selected study
Basic Viewer: Default mode that enables rendering and measurement tracking
PET/CT Fusion: Mode for visualizing the PET CT study in a 3x3 format.
Based on the mode configurations (e.g., available modalities), PET/CT mode is
disabled for studies that do not contain PET AND CT images.
The previous screenshot shows a study containing PET and CT images and both
Basic Viewer and PET/CT Mode are available.
View Study
The Basic Viewer mode is available for all studies by default. Click on the
mode button to launch the viewer.
Platform Docs Versioned Docs Version 3.11 README (`platform/docs/versioned_docs/version-3.11/README.md`)
id: Introduction slug: / sidebar_position: 1
The Open Health Imaging Foundation (OHIF) Viewer is an open source,
web-based, medical imaging platform. It aims to provide a core framework for
building complex imaging applications.
Key features:
Designed to load large radiology studies as quickly as possible. Retrieves
metadata ahead of time and streams in imaging pixel data as needed.Leverages Cornerstone3D for decoding,
rendering, and annotating medical images.Works out-of-the-box with Image Archives that support DICOMWeb.
Offers a Data Source API for communicating with archives over proprietary API
formats.Provides a plugin framework for creating task-based workflow modes which can
reuse core functionality.Beautiful user interface (UI) designed with extensibility in mind. UI
components available in a reusable component library built with React.js and
Tailwind CSStext<a style={{ backgroundColor: '#4042af', color: 'white', padding: '0.5rem 1rem', borderRadius: '0.25rem', textDecoration: 'none', ':hover': { backgroundColor: '#2a2b74' } }} href="https://ohif.org/news/">Subscribe to our newsletter</a> <a style={{ backgroundColor: '#4042af', color: 'white', padding: '0.5rem 1rem', borderRadius: '0.25rem', textDecoration: 'none', ':hover': { backgroundColor: '#2a2b74' } }} href="./release-notes">Release Notes</a>
| Measurement Tracking | Demo | |
| Labelmap Segmentations | Demo | |
| Fusion and Custom Hanging protocols | Demo | |
| Volume Rendering | Demo | |
| Demo | ||
| RT STRUCT | Demo | |
| 4D | Demo | |
| Video | Demo | |
| Slide Microscopy | Demo |
Where to next?
The Open Health Imaging Foundation intends to provide an imaging viewer
framework which can be easily extended for specific uses. If you find yourself
unable to extend the viewer for your purposes, please reach out via our GitHub
issues. We are actively seeking feedback on ways to improve our
integration and extension points.
Check out these helpful links:
- Ready to dive into some code? Check out our
Getting Started Guide. - We're an active, vibrant community.
Learn how you can be more involved. - Feeling lost? Read our help page.
Citing OHIF
To cite the OHIF Viewer in an academic publication, please cite
Open Health Imaging Foundation Viewer: An Extensible Open-Source Framework
for Building Web-Based Imaging Applications to Support Cancer ResearchErik Ziegler, Trinity Urban, Danny Brown, James Petts, Steve D. Pieper, Rob
Lewis, Chris Hafey, and Gordon J. Harris JCO Clinical Cancer Informatics, no. 4 (2020), 336-345, DOI:
10.1200/CCI.19.00131
This article is freely available on Pubmed Central: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7259879/
or, for Lesion Tracker of OHIF v1, please cite:
LesionTracker: Extensible Open-Source Zero-Footprint Web Viewer for Cancer
Imaging Research and Clinical TrialsTrinity Urban, Erik Ziegler, Rob Lewis, Chris Hafey, Cheryl Sadow, Annick D.
Van den Abbeele and Gordon J. Harris Cancer Research, November 1 2017 (77) (21) e119-e122 DOI:
10.1158/0008-5472.CAN-17-0334
This article is freely available on Pubmed Central.
https://pubmed.ncbi.nlm.nih.gov/29092955/
Note: If you use or find this repository helpful, please take the time to
star this repository on Github. This is an easy way for us to assess adoption,
and it can help us obtain future funding for the project.
License
MIT © OHIF
Platform Docs Docs Migration Guide 3p10 To 3p11 Index (`platform/docs/docs/migration-guide/3p10-to-3p11/index.md`)
id: index sidebar_position: 1 sidebar_label: 3.10 -> 3.11 title: 3.10 to 3.11 Migration Guide
import DocCardList from '@theme/DocCardList';
3.10 to 3.11 Migration Guide
Here you can find the migration guides for upgrading from OHIF version 3.10 to version 3.11.
Platform Docs Docs Migration Guide 3p11 To 3p12 Index (`platform/docs/docs/migration-guide/3p11-to-3p12/index.md`)
sidebar_position: 1 sidebar_label: 3.11 -> 3.12
Migration Guide
This guide provides information about migrating from OHIF version 3.11 to version 3.12
Optional: Migrate modes to extend `modes/basic`
There is a lot of support for the basic mode definition contained in themodes/basic module. Using this framework will allow your mode to avoid
creating a lot of boilerplate code that may not upgrade very well.
This is an OPTIONAL change - your existing mode definitions will continue to work,
but using the new basic mode as a basis will reduce the amount of effort when
there are changes unrelated to your custom mode.
ui button with text size
Using the class text size with the ui-button is inconsistent as to whether
it will apply or not. Instead, create a new size value to assign the desired size.
To support this, a new size enum is created, smallTall, which is used in the worklist
for an over-ride.
`createReportDialogPrompt`
The create report dialog prompt (which is MOSTLY an internal component) has
change the API a bit. The input is now:
titleshown in the dialogmodalitybeing stored, used to query existing seriesminSeriesNumberis the start of new series of this modality type.
Will get set to 4000 if not determined by the modality- predecessorImageId is the image id that this series was currently loaded
from. That allows defaulting the dialog to show the specified series instead
of always creating a new series.
The minSeries and predecessor are both optional, so the input doesn't have to be
updated.
The output has been enhanced with:
series, is the series to store do, as referenced by a predecessorImageId value.
This allows exactly specifying which item to replace, which allows selecting it in the
menu by default instead of just guessing what value is being replaced.priorSeriesNumberis the previously lowest series number at least minSeriesNumber
of all the seris of the given modality type. This allows adding an instance to the
nextseries number by adding 1 to this value.
The priorSeriesNumber will default to 4000 for an unknown modality type, or
3000 for sr, 3100 for seg and 3200 for rtstruct.
metadataProvider and formatted metadata
The metadata provider has been formatting some fields, which causes inconsistency
between different metadata providers and use of the instance object. The
specific fields that have changed are:
patientNamestudyDate,studyTimeseriesDate,seriesTime
If these fields need formatted versions, it is recommended to add a secondary/computed
metadata provider which simply gets the base metadata module and adds the
formatting. That way different metadata providers are all handled identically.
Platform Docs Docs Migration Guide 3p12 To 3p13 Index (`platform/docs/docs/migration-guide/3p12-to-3p13/index.md`)
id: index sidebar_position: 1 sidebar_label: 3.12 -> 3.13 title: 3.12 to 3.13 Migration Guide
import DocCardList from '@theme/DocCardList';
3.12 to 3.13 Migration Guide
This guide covers changes when upgrading from OHIF version 3.12 to version 3.13.
The largest changes in 3.13 are infrastructure-level:
- Package Manager — the monorepo moves from
yarn + lerna to pnpm workspaces, with new install/run commands
and aworkspace:*syntax for cross-package dependencies. - Build Tooling — Webpack is replaced with
Rspack v2 across the app and every extension/mode, with new
plugin imports and faster build commands. - Node Version — the minimum Node.js runtime
is now 24. - SegmentationService — the
removeSegmentationRepresentationsmethod was renamed. - DICOM video viewport — the
@ohif/extension-dicom-video.viewportModule.dicom-videonamespace was
removed; route DICOM video display sets through the Cornerstone viewport. - Deployment recipes — the Keycloak recipes
now require a.envfile and a generated client secret beforedocker compose up, and the nginx recipes no longer send wildcard CORS
headers (cross-origin deployments must set an explicit origin).
Platform Docs Docs Migration Guide 3p13 To 3p14 Index (`platform/docs/docs/migration-guide/3p13-to-3p14/index.md`)
id: index sidebar_position: 1 sidebar_label: 3.13 -> 3.14 title: 3.13 to 3.14 Migration Guide
import DocCardList from '@theme/DocCardList';
3.13 to 3.14 Migration Guide
This guide covers changes when upgrading from OHIF version 3.13 to version 3.14.
React 19 — the monorepo moves to React 19.2.7.
@ohif/ui-nextnow declares react/react-dom aspeerDependencies, so
consuming applications must supply React 19, and extensions and modes require
it too.SmartScrollbar —
SmartScrollbarFillandSmartScrollbarEndpointsnow require themarkedarray to change identity when
its contents change. Theversionprop is deprecated and no longer invalidates.WorkList —
LegacyWorkListand theworkList.variant
customization still work in 3.14 and are deprecated. A future release removes
both; migrate to theworkList.*customizations on the ui-nextWorkList.DataTable / TanStack Table v9 —
@ohif/ui-nextupgrades@tanstack/react-tableto v9. Column definitions need theDataTableFeatures
generic and thesortFnrename; programmatic visibility toggles should go
throughuseToggleColumnVisibility.useSegmentationExpanded — the hook
returnsundefinedoutside aSegmentationExpandedProviderinstead of
throwing, and no longer takes a component-name argument. Callers that wrapped
it intry/catchshould check forundefined; callers that require the
provider should assert for themselves.Viewport element hooks —
useViewportRefanduseViewportRefsare replaced byuseViewportElementfor readers anduseViewportElementRegistrationfor the viewport that owns the element, andViewportRefsProvideris renamedViewportElementsProvider. The element is now
a subscribed value rather than a snapshot read during render.Save/report dialog — the dialog for storing
measurements, segmentations and contours replaces its series drop down with an
explicit choice of three destinations: Save to current, Save as new and
Replace existing. The series number of a new series is editable, and the
series descriptions used before are remembered per type of item and offered as
completions.createReportDialogPrompttakesdefaultSeriesDescription,itemTypeandrememberedDescriptionCount, and returns aseriesNumber. A
stored instance is now identified like a loaded one, so the object just saved
becomes the predecessor of the next save of the same data.Display set date/time ordering — derived
display sets are ordered by the creation date/time of the instance they show
rather than by their series date/time, comparators registered withaddSameSeriesComparenow actually run, instances tie-break by creation
date/time before the SOP instance UID, and saved reports and segmentations are
stamped with a creation date/time and an instance number.useCustomization —
@ohif/coreadds auseCustomizationhook. A component that callscustomizationService.getCustomizationduring render can now freeze at a stale
value, because the React Compiler caches the call on the service reference,
which never changes. Move such reads to the hook. Event handlers and non-React
code keep calling the service directly.InputNumber —
InputNumber.HorizontalControlsandInputNumber.VerticalControlsnow sharemin,max,stepanddisabled
through a nested provider rather than by writing onto the root context object.
That fixes constraints being discarded on every keystroke, but it means only
descendants of the controls receive them; anInputNumber.Inputrendered as
a sibling silently falls back tomin=0, max=100, step=1.createContext helper — the internal
ui-next/lib/createContexthelper is removed. It was never exported from@ohif/ui-next; if you imported it from source, use React's owncreateContextanduseContext— the compiler now provides the memoization it
was hand-rolling.
Platform Docs Docs Migration Guide 3p8 To 3p9 Index (`platform/docs/docs/migration-guide/3p8-to-3p9/index.md`)
id: 3p8-to-3p9 title: 3.8 -> 3.9 sidebar_position: 2 summary: Migration guide for upgrading from OHIF 3.8 to 3.9, covering segmentation architecture changes, renamings, data sources, measurements, viewport action corners, state sync service, RT structure improvements, UI changes, and other refactorings.
import DocCardList from '@theme/DocCardList';
Migration Guide Sections
Platform Docs Docs Migration Guide 3p9 To 3p10 Index (`platform/docs/docs/migration-guide/3p9-to-3p10/index.md`)
sidebar_position: 1 sidebar_label: 3.9 -> 3.10 title: Migration Guide from 3.9 to 3.10 beta summary: Migration guide for upgrading from OHIF 3.9 to 3.10 beta, covering general changes, customization service improvements, UI component upgrades, command handling, hotkey updates, routing changes, and testing strategies.
Migration Guide
General
Platform Docs Docs Platform Extensions Index (`platform/docs/docs/platform/extensions/index.md`)
sidebar_position: 1 sidebar_label: Introduction title: OHIF Extensions Introduction summary: Comprehensive introduction to the OHIF viewer extension system, explaining how extensions provide modular functionality through different module types, and how they're configured and accessed in modes to build customized viewer experiences.
Introduction
We have re-designed the architecture of the OHIF-v3 to enable building
applications that are easily extensible to various use cases (modes) that behind
the scene would utilize desired functionalities (extensions) to reach the goal
of the use case.
Previously, extensions were “additive” and could not easily be mixed and matched
within the same viewer for different use cases. Previous OHIF-v2 architecture
meant that any minor extension alteration usually would require the user to hard
fork. E.g. removing some tools from the toolbar of the cornerstone
extension meant you had to hard fork it, which was frustrating if the
implementation was otherwise the same as master.
- Developers should make packages of reusable functionality as extensions,
and can consume publicly available extensions.- Any conceivable radiological workflow or viewer setup will be able to be
built with the platform through modes.
Practical examples of extensions include:
- A set of segmentation tools that build on top of the
cornerstoneviewport - A set of rendering functionalities to volume render the data
- See our maintained extensions for more examples of what's possible
Diagram showing how extensions are configured and accessed.
Extension Skeleton
An extension is a plain JavaScript object that has id and version properties, and one or
more modules and/or lifecycle hooks.
// prettier-ignore
export default {
/**
* Required properties. Should be a unique value across all extensions.
*/
id,
// Lifecycle
preRegistration() { /* */ },
onModeEnter() { /* */ },
onModeExit() { /* */ },
// Modules
getLayoutTemplateModule() { /* */ },
getDataSourcesModule() { /* */ },
getSopClassHandlerModule() { /* */ },
getPanelModule() { /* */ },
getViewportModule() { /* */ },
getCommandsModule() { /* */ },
getContextModule() { /* */ },
getToolbarModule() { /* */ },
getHangingProtocolModule() { /* */ },
getUtilityModule() { /* */ },
}OHIF-Maintained Extensions
A small number of powerful extensions for popular use cases are maintained by
OHIF. They're co-located in the OHIF/Viewers repository, in
the top level extensions/ directory.
| Extension | Description | Modules |
|---|---|---|
| default | Default extension provides default viewer layout, a study/series |
browser, and a datasource that maps to a DICOMWeb compliant backend | commandsModule, ContextModule, DataSourceModule, HangingProtocolModule, LayoutTemplateModule, PanelModule, SOPClassHandlerModule, ToolbarModule || cornerstone | Provides 2d and 3d rendering functionalities | ViewportModule, CommandsModule, UtilityModule |
| dicom-pdf | Renders PDFs for a specific SopClassUID. | Viewport, SopClassHandler |
| dicom-video | Renders DICOM Video files. | Viewport, SopClassHandler |
| cornerstone-dicom-sr | Maintained extensions for cornerstone and visualization of DICOM Structured Reports | ViewportModule, CommandsModule, SOPClassHandlerModule |
| measurement-tracking | Tracking measurements in the measurement panel | ContextModule,PanelModule,ViewportModule,CommandsModule |
Registering of Extensions
viewer starts by registering all the extensions specified inside thepluginConfig.json, by default we register all extensions in the repo.
// Simplified version of the `pluginConfig.json` file
{
"extensions": [
{
"packageName": "@ohif/extension-cornerstone",
"version": "3.4.0"
},
{
"packageName": "@ohif/extension-measurement-tracking",
"version": "3.4.0"
},
// ...
],
"modes": [
{
"packageName": "@ohif/mode-longitudinal",
"version": "3.4.0"
}
]
}:::note
You can register extensions by editing the pluginConfig.json file directly.
The provided cli can also add/remove/install/uninstall extensions
(read more), but it is being phased out in
favour of generating extensions with an agent.
:::
For the full set of fields (packageName, version, default, directory,
the public section) and the three ways a plugin can be located (in-tree,
out-of-tree directory, or installed dependency), see the
pluginConfig.json reference.
The final registration and import of the extensions happen inside a non-tracked file pluginImport.js (this file is also for internal use only).
After an extension gets registered within the viewer,
each module defined by the extension becomes available to the modes
via the ExtensionManager by requesting it via its id.
Read more about Extension Manager
Lifecycle Hooks
Currently, there are three lifecycle hook for extensions:
preRegistration This hook is called once on
initialization of the entire viewer application, used to initialize the
extensions state, and consume user defined extension configuration. If an
extension defines the preRegistration
lifecycle hook, it is called before any modules are registered in theExtensionManager. It's most commonly used to wire up extensions to
services and commands, and to
bootstrap 3rd party libraries.
onModeEnter: This hook is called whenever a new
mode is entered, or a mode’s data or datasource is switched. This hook can be
used to initialize data.
onModeExit: Similarly to onModeEnter, this hook is
called when navigating away from a mode, or before a mode’s data or datasource
is changed. This can be used to cache data for reuse later, but since it
isn't known which mode will be entered next, the state after exiting should be
clean, that is, the same as the state on a clean start. This is called BEFORE
service clean up, and after mode specific onModeExit handling.
Modules
Modules are the meat of extensions, the blocks that we have been talking about
a lot. They provide "definitions", components, and filtering/mapping logic that
are then made available to modes and services.
Each module type has a special purpose, and is consumed by our viewer
differently.
| Types | Description |
|---|---|
| LayoutTemplate | Control Layout of a route |
| DataSource | Control the mapping from DICOM metadata to OHIF-metadata |
| SOPClassHandler | Determines how retrieved study data is split into "DisplaySets" |
| Panel | Adds left or right hand side panels |
| Viewport | Adds a component responsible for rendering a "DisplaySet" |
| Commands | Adds named commands, scoped to a context, to the CommandsManager |
| Toolbar | Adds buttons or custom components to the toolbar |
| Context | Shared state for a workflow or set of extension module definitions |
| HangingProtocol | Adds hanging protocol rules |
| Utility | Expose utility functions to the outside of extensions |
Tbl. Module types
with abridged descriptions and examples. Each module links to a dedicated
documentation page.
Contexts
The @ohif/app tracks "active contexts" that extensions can use to scope
their functionality. Some example contexts being:
- Route:
ROUTE:VIEWER,ROUTE:STUDY_LIST - Active Viewport:
ACTIVE_VIEWPORT:CORNERSTONE,ACTIVE_VIEWPORT:VTK
An extension module can use these to say "Only show this Toolbar Button if the
active viewport is a Cornerstone viewport." This helps us use the appropriate UI
and behaviors depending on the current contexts.
For example, if we have hotkey that "rotates the active viewport", each Viewport
module that supports this behavior can add a command with the same name, scoped
to the appropriate context. When the command is fired, the "active contexts"
are used to determine the appropriate implementation of the rotation behavior.
Platform Docs Docs Platform Hooks Index (`platform/docs/docs/platform/hooks/index.md`)
title: Hooks summary: List of React hooks available in the platform, these are custom hooks that are used to access the state of the platform
Hooks
[useMeasurements](./useMeasurements.md)
A React hook that provides mapped measurements from the measurement service with automatic updates when measurements change.
[useViewportSegmentations](./useViewportSegmentations.md)
A React hook that provides segmentation data and representations for the active viewport with automatic updates when segmentations change.
[useMeasurementTracking](./useMeasurementTracking.md)
A React hook that provides measurement tracking information for a specific viewport, including tracking state and tracked measurement UIDs.
[useViewportDisplaySets](./useViewportDisplaySets.md)
A React hook that provides access to display sets associated with a viewport, including background, foreground, overlay, and potential display sets.
[useViewportHover](./useViewportHover.md)
A React hook that tracks mouse hover state and active status for a specific viewport.
[usePatientInfo](./usePatientInfo.md)
A React hook that provides patient information from the active display sets and detects when multiple patients are loaded.
[useSearchParams](./useSearchParams.md)
A React hook that provides access to URL search parameters from both the query string and hash fragment.
[useDynamicMaxHeight](./useDynamicMaxHeight.md)
A React hook that calculates the maximum height for an element based on its position in the viewport, with automatic recalculation on window resize or data changes.
[useSessionStorage](./useSessionStorage.md)
A React hook that provides sessionStorage access with automatic JSON parsing/stringifying and an option to clear data when the page unloads.
Platform Docs Docs Platform Managers Index (`platform/docs/docs/platform/managers/index.md`)
sidebar_position: 1 sidebar_label: Introduction title: Managers Introduction summary: Overview of OHIF's manager system, which handles critical application infrastructure including extension registration, service management, command execution, and hotkey binding to coordinate functionality across the platform.
Managers
Overview
OHIF uses Managers to accomplish various purposes such as registering new
services, dependency injection, and aggregating and exposing extension
features.
OHIF-v3 provides the following managers which we will discuss in depth.
| Manager | Description |
|---|---|
| Extension Manager | Aggregating and exposing modules and features through out the app |
| Services Manager | Single point of registration for all internal and external services |
| Commands Manager | Register commands with specific context and run commands in the app |
| Hotkeys Manager | For keyboard keys assignment to commands |
Platform Docs Docs Platform Modes Index (`platform/docs/docs/platform/modes/index.md`)
sidebar_position: 1 sidebar_label: Introduction title: Modes Introduction summary: Overview of OHIF Modes, which are specialized viewer configurations for specific clinical workflows, allowing multiple purpose-specific applications to coexist within a single OHIF deployment.
Modes
Overview
A mode can be thought of as a viewer app configured to perform a specific task,
such as tracking measurements over time, 3D segmentation, a guided radiological
workflow, etc. Addition of modes enables application with many applications
as each mode become a mini app configuration behind the scene.
Upon initialization the viewer will consume extensions and modes and build up
the route desired, these can then be accessed via the study list, or directly
via url parameters.
OHIF-v3 architecture can be seen in the following:
Note: Templates are now a part of “extensions” Routes are configured by modes
and/or app
As mentioned, modes are tied to a specific route in the viewer, and multiple
modes/routes can be present within a single application. This allows for
tremendously more flexibility than before you can now:
- Simultaneously host multiple viewers with for different use cases from within
the same app deploy. - Make radiological viewers for specific purposes/workflows, e.g.:
- Tracking the size of lesions over time.
- PET/CT fusion workflows.
- Guided review workflows optimized for a specific clinical trial.
- Still host one single feature-rich viewer if you desire.
Anatomy
A mode configuration has a route name which is dynamically transformed into a
viewer route on initialization of the application. Modes that are available to a
study will appear in the study list.
The mode configuration specifies which extensions the mode requires, whichLayoutTemplate to use, and what props to pass to the template. For the default
template this defines which side panels will be available, as well as whatviewports and which displaySets they may hang.
Mode's config is composed of these elements:
id: the modeidmodeFactory: the function that returns the mode specific configurationmodeInstance: An optional configuration used by the default modeFactory
exported by the basic mode. This allows specifying or updating the
default mode values.extensionDependencies: the list of extensions that the mode requires
that return a config object with certain
properties, the high-level view of this config object is:
function modeFactory({modeConfiguration}) {
return { ...this.modeInstance, ...modeConfiguration };
}
const mode = {
id,
modeFactory,
modeInstance: {
id: '',
version: '',
hide: true,
displayName: '',
onModeEnter: () => {},
onModeExit: () => {},
validationTags: {},
isValidMode: () => {},
routes: [
{
path: '',
init: () => {},
layoutInstance: {
id,
props: {
leftPanels: [],
leftPanelResizable: true,
rightPanels: [],
rightPanelClosed: true,
rightPanelResizable: true,
viewports: [],
},
},
layoutTemplate: function() { return this.layoutInstance },
},
],
extensions: extensionDependencies,
hangingProtocol: [],
sopClassHandlers: [],
hotkeys: [],
nonModeModalities: [],
modeModalities: [],
},
extensionDependencies,
};
export default mode;| Property | Description |
|---|---|
| id | unique mode id used to refer to the mode |
| hide | Set to true to hide this mode on the worklist, but allow it in the path |
| displayName | actual name of the mode being displayed for each study in the study summary panel |
| onModeEnter | hook is called when the mode is entered by the specified route |
| onModeExit | hook is called when the mode exited |
| validationTags | validationTags |
| isValidMode | Checks if the mode is valid for a study |
| routes | route config which defines the route address, and the layout for it |
| extensionDependencies | extensions needed by the mode |
| hanging protocol | list of hanging protocols that the mode applies initially, choosing the highest scoring match |
| sopClassHandlers | list of SOPClass modules needed by the mode |
| hotkeys | hotkeys |
| modeModalities | If non-empty, then the default isValidMode will only return true when the modalities list has all of the elements of one of the mode modalities. Eg [ [CT,PT], [MR,PT] ]` would mean that the mode supports a CT AND a PT, OR an MR and a PT |
| nonModeModalities | Enable the mode if the modalities list contains a modality OTHER than those in the array |
| excludedModalities | The default isValidMode returns false when the modalities list contains ANY of these |
| excludedStudies | A list of study attribute objects; the default isValidMode returns false for a study matching every attribute of any entry, e.g. [{ mrn: 'M1' }] |
| toolbarSections | Toolbar section composition: a list of section-layout packs (as $reference markers) and/or literal section objects; seeded onto the Mode scope on enter |
| toolbarButtons | Toolbar button composition: a list of button packs (as $reference markers) and/or literal button definitions; seeded onto the Mode scope on enter |
| toolGroupAdditions | Per-tool-group composition: a map of tool-group id to a list of tool packs (as $reference markers) and/or literal tool blocks, layered onto the mode's tool groups after creation |
| initToolGroups | Tool group setup function called by the shared onModeEnter as initToolGroups({ extensionManager, toolGroupService, commandsManager, servicesManager }); extending modes can substitute their own |
| modeCustomizations | The mode's own customizations, applied by the mode route as the bottom layer of the mode scope on enter — before the app config / URL mode phase blocks, and below global-scope customizations, so final values are decided purely by scope precedence and application order. Usually the name of a block the extension registers at default scope (e.g. basicModeCustomizations, which sets panelSegmentation.disableEditing); may also be a literal object of immutability-helper commands or an array mixing those with customization module reference strings |
| activatePanelTriggers | Data-driven ActivatePanel event triggers: a list of { panelId, sourceServiceName, sourceEvents, forceActive? } entries wired up on mode enter (e.g. activating the segmentation panel when a segmentation is added). Empty by default; see defaultActivatePanelTriggers in the basic mode |
Extending Modes
The basic mode provides support for creating mode extensions without having
to redeclare the entire mode. See longitudinal/src/index.ts for an example
mode that builds on top of the basic mode. Also see basic/src/index.tsx for
some default functions which can be used to create your own modes. Doing a mode
this way makes the definition of new modes based on your existing mode much easier,
and the upgrade to new versions of modes tends to be more consistent.
The segmentation and tmtv modes now follow this same pattern. Likelongitudinal, each one exports a modeInstance object and reuses the basic
mode's modeFactory, so they are extensible in two complementary ways:
- Build a derived mode — create a new mode package (for example
mySegmentation) that imports the shipped mode and overrides only the parts
you need, exactly likelongitudinalbuilds onbasic. - Customize an existing mode at runtime — change a shipped mode's toolbar,
tools, or panels through per-mode customization keys, with no new package.
Building a derived mode
A derived mode imports the shipped mode's default export (which carries themodeFactory) and its modeInstance, then spreads and overrides. Because the
default modeFactory applies immutability-helper
commands from modeConfiguration onto modeInstance, you can also override
via modeConfiguration rather than editing the instance directly.
import segmentationMode, { modeInstance as segModeInstance } from '@ohif/mode-segmentation';
const id = 'mySegmentation';
export const modeInstance = {
...segModeInstance,
id,
routeName: 'mySegmentation',
displayName: 'My Segmentation',
// Override only what you need. Toolbar buttons/sections and tool group
// additions are plain composition arrays on the instance naming the
// capability packs the mode uses (see below); panel lists are literal
// arrays in the layout. Both are customized at runtime via the `mode` phase.
};
const mode = {
...segmentationMode, // carries modeFactory + extensionDependencies
id,
modeInstance,
};
export default mode;The tmtv mode is extended the same way — import @ohif/mode-tmtv and itsmodeInstance, then override.
Customizing a mode at runtime
The basic, longitudinal, segmentation, and tmtv modes declare their toolbar
buttons, toolbar sections, and tool-group additions as plain composition arrays on
the mode instance that name the capability packs the mode uses with { $reference }
markers (for exampletoolbarButtons: [{ $reference: 'cornerstone.toolbarButtons' }, { $reference: 'cornerstone.segmentationToolbarButtons' }]).
The mode route seeds these onto the Mode customization scope on enter, alongside theleftPanels / rightPanels panel lists. Because the values are lists whose{ $reference } entries the customization service expands at read time, a window.config
entry or a ?customization= JSON module can add a whole capability pack (such as the
segmentation editing tools), remove a default, or swap the panels — targeting the mode
through a mode phase block (mode.basic, mode.segmentation, ...) without building
a new mode. See Compose whole capability blocks into a mode in the
Customization Service docs for the full key table, the reusable capability
blocks, and worked examples (adding segmentation editing to the basic and
longitudinal modes, and enabling annotation tools inside the segmentation mode).
Consuming Extensions
As mentioned in the Extensions section, in OHIF-v3
developers write their extensions to create reusable functionalities that later
can be used by modes. Now, it is time to describe how the registered
extensions will get utilized for a workflow mode via its id.
Each mode has a list of its extensions dependencies which are the
the extension name and version number. In addition, to use a module element you can use the${extensionId}.${moduleType}.${element.name} schema. For instance, if a mode
requires the left panel with name of AIPanel that is added by themyAIExtension via the following getPanelModule code, it should address it asmyAIExtension.panelModule.AIPanel inside the mode configuration file. In the
background OHIF will handle grabbing the correct panel via ExtensionManager.
import PanelAI from './PanelAI.js';
function getPanelModule({
commandsManager,
extensionManager,
servicesManager,
}) {
const wrappedAIPanel = () => {
return (
<PanelAI
commandsManager={commandsManager}
servicesManager={servicesManager}
/>
);
};
return [
{
name: 'AIPanel',
iconName: 'list-bullets',
iconLabel: '',
label: 'AI Panel',
isDisabled: studies => {}, // optional
component: wrappedAIPanel,
},
];
}Now, let's look at a simplified code of the basic viewer mode which consumes various functionalities
from different extensions.
const extensionDependencies = {
'@ohif/extension-default': '^3.0.0',
'@ohif/extension-cornerstone': '^3.0.0',
'@ohif/extension-measurement-tracking': '^3.0.0',
};
const id = 'viewer';
const version = '3.0.0';
function modeFactory({ modeConfiguration }) {
return {
id,
// ...
routes: [
{
// ...
layoutTemplate: ({ location, servicesManager }) => {
return {
id: ohif.layout,
props: {
leftPanels: ['@ohif/extension-measurement-tracking.panelModule.seriesList'],
rightPanels: ['@ohif/extension-measurement-tracking.panelModule.trackedMeasurements'],
viewports: [
{
namespace: '@ohif/extension-measurement-tracking.viewportModule.cornerstone-tracked',
displaySetsToDisplay: ['@ohif/extension-default.sopClassHandlerModule.stack'],
},
],
},
};
},
},
],
extensions: extensionDependencies,
hangingProtocol: ['@ohif/extension-default.hangingProtocolModule.petCT'],
sopClassHandlers: ['@ohif/extension-default.sopClassHandlerModule.stack'],
// ...
};
}
const mode = {
id,
modeFactory,
extensionDependencies,
}
export default modeRoutes
routes config is an array of route settings, and the overall look and behavior
of the viewer at the designated route is defined by the layoutTemplate andinit functions for the route. We will learn more about each of the above
properties inside the route documentation
HangingProtocols
Currently, you can pass your defined hanging protocols inside thehangingProtocols property of the mode's config. If you specify the hanging protocol
explicitly by its name (only string and not array), it will be THE hanging protocol
that the mode runs with. However, if you specify an array of hanging protocols,
they will get ranked based on the displaySetSelector requirements and the winner
will be the hanging protocol that the mode runs with.
SopClassHandlers
Mode's configuration also accepts the sopClassHandler modules that have been
added by the extensions. This information will get used to initialize DisplaySetService with the provided SOPClass modules which
handles creation of the displaySets.
Hotkeys
hotkeys is another property in the configuration of a mode that can be defined
to add the specific hotkeys to the viewer on the mode route. Additionally, the
name under which the hotkeys are stored can be configured as hotkeyName.
This allows user customization of the mode specific hotkeys.
// default hotkeys
import { utils } from '@ohif/ui';
const { hotkeys } = utils;
const myHotkeys = [
{
commandName: 'setToolActive',
commandOptions: { toolName: 'Zoom' },
label: 'Zoom',
keys: ['z'],
isEditable: true,
},
{
commandName: 'scaleUpViewport',
label: 'Zoom In',
keys: ['+'],
isEditable: true,
},
]
function modeFactory() {
return {
id: '',
displayName: '',
/*
...
*/
hotkeys: {
// The name in preferences to use for this set of hotkeys
// Allows defining different sets for different modes
name: 'custom-hotkey-name',
// And the actual custom values here.
hotkeys:[..hotkeys.defaults.hotkeyBindings, ...myHotkeys]
},
}
}
// exportsRegistration
Similar to extension registration, viewer will look inside the pluginConfig.json to
find the modes to register.
// Simplified version of the `pluginConfig.json` file
{
"extensions": [
{
"packageName": "@ohif/extension-cornerstone",
"version": "3.4.0"
},
// ...
],
"modes": [
{
"packageName": "@ohif/mode-longitudinal",
"version": "3.4.0"
}
]
}:::note
You can register modes by editing the pluginConfig.json file directly.
The provided cli can also add/remove/install/uninstall modes
(read more), but it is being phased out in
favour of generating modes with an agent.
:::
For the full set of entry fields and the three ways a plugin can be located
(in-tree, out-of-tree directory, or installed dependency), see the
pluginConfig.json reference.
The final registration and import of the modes happen inside a non-tracked file pluginImport.js (this file is also for internal use only).
:::note
You can stack multiple panel components on top of each other by providing an array of panel components in the rightPanels or leftPanels properties.
For instance we can use
rightPanels: [[dicomSeg.panel, tracked.measurements], [dicomSeg.panel, tracked.measurements]]This will result in two panels, one with dicomSeg.panel and tracked.measurements and the other with dicomSeg.panel and tracked.measurements stacked on top of each other.
:::
APP Configuration of Modes
Modes based on the basic mode allow for customization using the immutability-helper
api within the app-config.js file as specified by the build process. For example,
to list the basic mode by default, and hide the longitudinal mode, the following
configuration from config/kheops.js can be used:
... app config file
modesConfiguration: {
'@ohif/mode-basic': {
hide: { $set: false },
displayName: { $set: 'Basic' },
},
'@ohif/mode-longitudinal': {
hide: { $set: true },
},
},Default Modes
There are a number of modes provided in a default OHIF installation. These
are described here, along with some amount of information about extending/configuration
of those modes.
Modes which are loaded by default, but which are hidden can be activated by
using a direct URL launch. For example, to show a study in the basic mode,
use the URL for the longitudinal mode, and replace the /viewer with /basic
Basic (NOT `Basic Viewer`, which got assigned to `longitudinal`)
The basic mode is a mode that demonstrates the base capabilities of the OHIF
system, without including features such as longitudinal tracking, segmentation editing
or other custom capabilities. The left hand panel uses the study browser thumbnails
without tracking, and the right hand panel uses the basic segmentation panel and the
measurements without tracking (longitudinal) layouts. This makes it a good overall
base for using when the tracking behaviour of longitudinal mode is not desired.
It can be used in a default install by direct URL launch to the /basic endpoint
instead of the /viewer endpoint.
Longitudinal (The `Basic Viewer` label in OHIF)
The longitudinal mode adds the tracking for measurements in the study browser
and in the measurements panel, and is otherwise identical to the basic mode.
Platform Docs Docs Platform Services Index (`platform/docs/docs/platform/services/index.md`)
sidebar_position: 1 sidebar_label: Introduction title: OHIF Services summary: Overview of OHIF's services architecture, which provides modular, concern-specific code components that manage state and operations throughout the application, including both data services and UI services that follow a pub/sub pattern to reduce coupling.
Services
Overview
Services are "concern-specific" code modules that can be consumed across layers.
Services provide a set of operations, often tied to some shared state, and are
made available to through out the app via the ServicesManager. Services are
particularly well suited to address cross-cutting
concerns.
Each service should be:
- self-contained
- able to fail and/or be removed without breaking the application
- completely interchangeable with another module implementing the same interface
In
OHIF-v3we have added multiple non-UI services and have introduced
pub/sub pattern to reduce coupling between layers.
Services
The following services is available in the OHIF-v3.
| Service | Type | Description |
|---|---|---|
| DicomMetadataStore | Data Service | DicomMetadataStore |
| DisplaySetService | Data Service | DisplaySetService |
| segmentationService | Segmentation Service | segmentationService |
| HangingProtocolService | Data Service | HangingProtocolService |
| MeasurementService (MODIFIED) | Data Service | MeasurementService |
| ToolBarService | Data Service | ToolBarService |
| ViewedDataService | Data Service | viewedDataService |
| ViewportGridService | UI Service | ViewportGridService |
| Cine Service | UI Service | cine |
| CustomizationService | UI Service | customizationService |
| UIDialogService | UI Service | UIDialogService |
| UIModalService | UI Service | UIModalService |
| UINotificationService | UI Service | UINotificationService |
| UIViewportDialogService | UI Service | UIViewportDialogService |
Platform Docs Docs User Guide Viewer Index (`platform/docs/docs/user-guide/viewer/index.md`)
sidebar_position: 1 sidebar_label: Overview
Overview
When you open a mode, viewport, toolbar and panels of the mode get shown.
It is important to note that each mode has a different UI, which serves its purpose.
Here we explain various components of Basic Viewer mode which includes measurement
tracking functionalities.
Basic viewer mode (longitudinal):
Let's break different aspects of the viewer to the main components:
- Left Panel (study panel): displays series thumbnails with series details
- Viewport: renders the image and displays annotations
- Right Panel (measurements): displays annotations details
- Toolbar: displays tools and logo
Now, we explain each component and its sub-elements in detail.
Platform Docs Versioned Docs Version 3.11 Deployment Index (`platform/docs/versioned_docs/version-3.11/deployment/index.md`)
sidebar_position: 1 sidebar_label: Overview title: Deployment Overview summary: Comprehensive guide to deploying the OHIF Viewer as a standalone web application or embedded iframe, covering data source configuration, security considerations, and various deployment options with examples for different hosting environments.
Deployment
The OHIF Viewer can be served as a stand-alone PWA (progressive web
application) by building and hosting a collection of static assets or be embedded in other web applications via an iframe if needed. In
either case, you will need to configure your instance of the Viewer so that it
can connect to your data source (the database or PACS that provides the data
your Viewer will display).
:::tip
Our goal is to make deployment as simple and painless as possible; however,
there is an inherent amount of complexity in configuring and deploying web
applications. If you find yourself a little lost, please don't hesitate to
reach out to for help.
:::
Deployment Scenarios
Stand-alone Viewer
Deploying the OHIF Viewer as a stand-alone web application provides many
benefits, but comes at the cost of time and complexity. Some benefits include:
Today:
- Leverage extensions and
modes to drop-in powerful new features - Add routes and customize the viewer's workflow
- Finer control over styling and whitelabeling
In the future:
- The ability to package the viewer for App Store distribution
Hosted Static Assets
At the end of the day, a production OHIF Viewer instance is a collection of
HTML, CSS, JS, Font Files, and Images. We "build" those files from oursource code with configuration specific to our project. We then make those
files publicly accessible by hosting them on a Web Server.
Part 1 - Build Production Assets
"Building", or creating, the files you will need is the same regardless of the
web host you choose. You can find detailed instructions on how to configure and
build the OHIF Viewer in our
"Build for Production" guide.
Part 2 - Host Your App
There are a lot of benefits to hosting static assets over
dynamic content. You can find instructions on how to host your build's output
via one of these guides:
Drag-n-drop
Easy
Advanced
Embedded Viewer (iframe)
OHIF-v3 has deprecated deploying the viewer as an embedded viewer via a script
tag as the number of underlying libraries that run web workers are increasing for OHIF. An example of these libraries is OHIF's 3D rendering functionality that is provided byvtk-js.
However, you can still embed the viewer using an iframe. You can utilize the iframe element to load the OHIF viewer and establish communication with it using the postMessage API if needed.
Read more about how to use the iframe here.
Data
The OHIF Viewer is able to connect to any data source that implements the DICOM
Web Standard. DICOM Web refers to RESTful
DICOM Services -- a recently standardized set of guidelines for exchanging
medical images and imaging metadata over the internet. Not all archives fully
support it yet, but it is gaining wider adoption.
Configure Connection
If you have an existing archive and intend to host the OHIF Viewer at the same
domain name as your archive, then connecting the two is as simple as following
the steps laid out in our
Configuration Essentials Guide.
What if I don't have an imaging archive?
We provide some guidance on configuring a local image archive in our
Data Source Essentials
guide. Hosting an archive remotely is a little trickier. You can check out some
of our advanced recipes for modeled setups that may work for you.
What if I intend to host the OHIF Viewer at a different domain?
There are two important steps to making sure this setup works:
- Your Image Archive needs to be exposed, in some way, to the open web. This
can be directly, or through areverse proxy, but the Viewer needs some
way to request its data. - * Your Image Archive needs to have appropriate CORS (Cross-Origin Resource
Sharing) Headers
* Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional
HTTP headers to tell a browser to let a web application running at one origin
(domain) have permission to access selected resources from a server at a
different origin. - MDN Web Docs: Web - Http - CORS
Most image archives do not provide either of these features "out of the box".
It's common to use IIS, Nginx, or Apache to route incoming requests and append
appropriate headers. You can find an example of this setup in our
Nginx + Image Archive Deployment Recipe.
What if my archive doesn't support DicomWeb?
It's possible to supply all Study data via JSON format, in the event you do not
have a DicomWeb endpoint. You can host all of the relevant files on any web
accessible server (Amazon S3, Azure Blob Storage, Local file server etc.)
This JSON is supplied via the '?url=' query parameter. It should reference an
endpoint that returns application/json formatted text.
If you do not have an API, you can simply return a text file containing the JSON
from any web server.
You tell the OHIF viewer to use JSON by using the dicomjson datasource and
appending '?url=' query to your mode's route:
e.g.https://my-test-ohif-server/myMode/dicomjson?url=https://my-json-server/study-uid.json
The returned JSON object must contain a single root object with a 'studies'
array.
You can read more about using different data sources for mode's routes
here
Sample JSON format:
/* Detailed source-code truncated for AI context efficiency. */More info on this JSON format can be found here
Issue #1500
Implementation Notes:
- For each instance url (dicom object) in the returned JSON, you must prefix
theurlwithdicomjson:in order for the cornerstone image loader to
retrieve it correctly. eg.https://image-server/my-image.dcm--->dicomjson:https://image-server/my-image.dcm - The JSON format above is compatible with >= v3.7.8 of the application in
V2
version. Older versions of the viewer used a different JSON format. As of
20/04/20 the public [https://viewer.ohif.org/] is a pre 3.0 version that does
not support this format yet. - The JSON format is case-sensitive. Please ensure you have matched casing with
the naturalised Dicom format referenced in
Issue #1500.
CORS Issues (Cross-Origin Resource Sharing)
If you host a JSON API or Images on a different domain from the app itself,
you will likely have CORS issues. This will also happen when testing from
Localhost and reaching out to remote servers. Even if the domain is the same,
different ports, subdomains or protocols (https vs http) will also cause CORS
errors. You will to need add a configuration on each server hosting these assets
to allow your App server origin.
For example:
Let's assume your application is hosted on https://my-ohif-server.com.
Your JSON API is hosted on https://my-json-api.aws.com
And your images are stored on Amazon S3 at https://my-s3-bucket.aws.com
When you first start your application, browsing tohttps://my-ohif-server.com/myMode/dicomjson?url=https://my-json-api.aws.com/api/my-json-study-info.json,
you will likely get a CORS error in the browser console as it tries to connect
to https://my-json-api.aws.com.
Adding a setting on the JSON server to allow the CORS origin =https://my-ohif-server.com should solve this.
Next, you will likely get a similar CORS error, as the browser tries to go tohttps://my-s3-bucket.aws.com. You will need to go to the S3 bucket
configuration, and add a CORS setting to allow origin =https://my-ohif-server.com.
Essentially, whenever the application connects to a remote resource, you will
need to add the applications url to the allowed CORS Origins on that resource.
Adding an origin similar to https://localhost:3000 will also allow for local
testing.
Securing Your Data
Coming soon
Recipes
We've included a few recipes for common deployment scenarios. There are many,
many possible configurations, so please don't feel limited to these setups.
Please feel free to suggest or contribute your own recipes.
Platform Docs Versioned Docs Version 3.11 Development Getting Started (`platform/docs/versioned_docs/version-3.11/development/getting-started.md`)
sidebar_position: 1 sidebar_label: Getting Started title: Getting Started with OHIF Development summary: Quick start guide for OHIF development, covering repository setup options, branch organization, development environment requirements, project initialization, and steps for building production-ready assets.
Getting Started
Setup
Fork & Clone
If you intend to contribute back changes, or if you would like to pull updates
we make to the OHIF Viewer, then follow these steps:
- Fork the OHIF/Viewers repository
- Create a local clone of your fork
git clone https://github.com/YOUR-USERNAME/Viewers
- Add OHIF/Viewers as a remote repository labeled
upstream- Navigate to the cloned project's directory
git remote add upstream https://github.com/OHIF/Viewers.git
With this setup, you can now sync your fork to keep it
up-to-date with the upstream (original) repository. This is called a "Triangular
Workflow" and is common for Open Source projects. The GitHub blog has a good
graphic that illustrates this setup.
Private
Alternatively, if you intend to use the OHIF Viewer as a starting point, and you
aren't as concerned with syncing updates, then follow these steps:
- Navigate to the OHIF/Viewers repository
- Click
Clone or download, and thenDownload ZIP - Use the contents of the
.zipfile as a starting point for your viewer
NOTE: It is still possible to sync changes using this approach. However,
submitting pull requests for fixes and features are best done with the
separate, forked repository setup described in "Fork & Clone"
Developing
Branches
`master` branch - The latest dev (beta) release
master- The latest dev release
This is typically where the latest development happens. Code that is in the master branch has passed code reviews and automated tests, but it may not be deemed ready for production. This branch usually contains the most recent changes and features being worked on by the development team. It's often the starting point for creating feature branches (where new features are developed) and hotfix branches (for urgent fixes).
Each package is tagged with beta version numbers, and published to npm such as @ohif/[email protected]
`release/*` branches - The latest stable releases
Once the master branch code reaches a stable, release-ready state, we conduct a comprehensive code review and QA testing. Upon approval, we create a new release branch from master. These branches represent the latest stable version considered ready for production.
For example, release/3.5 is the branch for version 3.5.0, and release/3.6 is for version 3.6.0. After each release, we wait a few days to ensure no critical bugs. If any are found, we fix them in the release branch and create a new release with a minor version bump, e.g., 3.5.1 in the release/3.5 branch.
Each package is tagged with version numbers and published to npm, such as @ohif/[email protected]. Note that master is always ahead of the release branch. We publish docker builds for both beta and stable releases.
Here is a schematic representation of our development workflow:
Requirements
- Node.js & NPM
- Yarn
- Yarn workspaces should be enabled:
yarn config set workspaces-experimental true
Kick the tires
Navigate to the root of the project's directory in your terminal and run the
following commands:
# Restore dependencies
yarn install
# Start local development server
yarn run devYou should see the following output:
@ohif/app: i 「wds」: Project is running at http://localhost:3000/
@ohif/app: i 「wds」: webpack output is served from /
@ohif/app: i 「wds」: Content not from webpack is served from D:\code\ohif\Viewers\platform\viewer
@ohif/app: i 「wds」: 404s will fallback to /index.html
# And a list of all generated files🎉 Celebrate 🎉
Building for Production
More comprehensive guides for building and publishing can be found in our
deployment docs
# Build static assets to host a PWA
yarn run buildTroubleshooting
- If you receive a "No Studies Found" message and do not see your studies, try
changing the Study Date filters to a wider range. - If you see a 'Loading' message which never resolves, check your browser's
JavaScript console inside the Developer Tools to identify any errors.
Platform Docs Versioned Docs Version 3.11 Faq Index (`platform/docs/versioned_docs/version-3.11/faq/index.md`)
id: index title: OHIF Viewer FAQ summary: Comprehensive list of frequently asked questions about the OHIF Viewer, covering common inquiries about reporting bugs, requesting features, academic collaborations, regulatory status, and obtaining demo studies.
General FAQ
How do I report a bug?
Navigate to our GitHub Repository, and submit a new bug report.
Follow the steps outlined in the Bug Report Template.
How can I request a new feature?
At the moment we are in the process of defining our roadmap and will do our best
to communicate this to the community. If your requested feature is on the
roadmap, then it will most likely be built at some point. If it is not, you are
welcome to build it yourself and contribute it.
If you have resources and would like to fund the development of a feature,
please contact us.
Who should I contact about Academic Collaborations?
Gordon J. Harris
at Massachusetts General Hospital is the primary contact for any academic
collaborators. We are always happy to hear about new groups interested in using
the OHIF framework, and may be able to provide development support if the
proposed collaboration has an impact on cancer research.
Does OHIF offer support?
yes, you can contact us for more information here
Does The OHIF Viewer have [510(k) Clearance][501k-clearance] from the U.S. F.D.A or [CE Marking][ce-marking] from the European Commission?
NO. The OHIF Viewer is NOT F.D.A. cleared or CE Marked. It is the users'
responsibility to ensure compliance with applicable rules and regulations. The
License for the OHIF
Platform does not prevent your company or group from seeking F.D.A. clearance
for a product built using the platform.
If you have gone this route (or are going there), please let us know because we
would be interested to hear about your experience.
Is there a DICOM Conformance Statement for the OHIF Viewer?
Yes, check it here DICOM Conformance Statement
Is The OHIF Viewer [HIPAA][hipaa-def] Compliant?
NO. The OHIF Viewer DOES NOT fulfill all of the criteria to become HIPAA
Compliant. It is the users' responsibility to ensure compliance with applicable
rules and regulations.
Could you provide me with a particular study from the OHIF Viewer Demo?
You can check out the studies that we have put in this Dropbox link
Platform Docs Versioned Docs Version 3.11 Migration Guide Index (`platform/docs/versioned_docs/version-3.11/migration-guide/index.md`)
id: index title: Migration Guides Overview summary: Introduction to OHIF migration guides covering the upgrade paths between different versions of the platform, with links to version-specific guides for migrating from one OHIF version to another.
import DocCardList from '@theme/DocCardList';
Migration Guides
Based on the version you are migrating from, you can find the migration guide for the latest version of the platform.
Platform Docs Versioned Docs Version 3.11 User Guide Index (`platform/docs/versioned_docs/version-3.11/user-guide/index.md`)
sidebar_position: 2 sidebar_label: Study List
Study List
Overview
The first page you will see when the viewer is loaded is the Study List. In
this page you can explore all the studies that are stored on the configured
server for the OHIF Viewer.
Sorting
When the Study List is opened, the application queries the PACS for 101 studies
by default. If there are greater than 100 studies returned, the default sort for
the study list is dictated by the image archive that hosts these studies for the
viewer and study list sorting will be disabled. If there are less than or equal
to 100 studies returned, they will be sorted by study date (most recent to
oldest) and study list sorting will be enabled. Whenever a query returns greater
than 100 studies, use filters to narrow results below 100 studies to enable
Study List sorting.
Filters
There are certain filters that can be used to limit the study list to the
desired criteria.
- Patient Name: Searches between patients names
- MRN: Searches between patients Medical Record Number
- Study Date: Filters the date of the acquisition
- Description: Searches between study descriptions
- Modality: Filters the modalities
- Accession: Searches between patients accession number
An example of using study list filter is shown below:
Below the study list are pagination options for 25, 50, or 100 studies per page.
For static wado servers, you can enable fuzzy matching by setting the supportsFuzzyMatching property to true, after enabling it, fuzzy matching will be peformed on the patient name field, for example, if PatientName is "John^Doe", then "jo", "Do" and "John Doe" will all match. However "ohn" will not match.
Study Summary
Click on a study to expand the study summary panel.
A summary of series available in the study is shown, which contains the series
description, series number, modality of the series, instances in the series, and
buttons to launch viewer modes to display the study.
Study Specific Modes
All available modes are seen in the study expanded view. Modes can be enabled or
disabled for a study based on the modalities contained within the study.
In the screenshot below, there are two modes shown for the selected study
Basic Viewer: Default mode that enables rendering and measurement tracking
PET/CT Fusion: Mode for visualizing the PET CT study in a 3x3 format.
Based on the mode configurations (e.g., available modalities), PET/CT mode is
disabled for studies that do not contain PET AND CT images.
The previous screenshot shows a study containing PET and CT images and both
Basic Viewer and PET/CT Mode are available.
View Study
The Basic Viewer mode is available for all studies by default. Click on the
mode button to launch the viewer.
Platform Docs Docs Migration Guide 3p8 To 3p9 1 Segmentation Index (`platform/docs/docs/migration-guide/3p8-to-3p9/1-segmentation/index.md`)
id: segmentation-index title: Segmentation sidebar_position: 1 summary: Migration guide for segmentation architecture changes in OHIF 3.9, covering the shift from tool group-centric to viewport-centric architecture to support advanced visualization capabilities and more flexible segmentation handling.
import DocCardList from '@theme/DocCardList';
:::info
This migration involves significant architectural changes to the segmentation system. While we typically aim for incremental updates, the shift from a tool group-centric to a viewport-centric architecture was necessary to support OHIF 3.9's advanced visualization capabilities, and more flexible segmentation handling.
Don't worry - we'll guide you through each change step by step!
:::
Platform Docs Docs Migration Guide 3p9 To 3p10 2 CustomizationService Index (`platform/docs/docs/migration-guide/3p9-to-3p10/2-CustomizationService/index.md`)
sidebar_position: 2 title: Customization Service summary: Migration guide for OHIF's Customization Service from 3.9 to 3.10, covering unified customization getters, simplified registration, new commands, renamed customizations, and updated patterns for modifying UI components.
CustomizationService
Key Changes:
Unified Customization Getter:
- The
getCustomizationmethod now uniformly retrieves customizations, prioritizingglobal, thenmode, and finallydefaultcustomizations. - The
defaultValueparameter ingetCustomizationis no longer used for setting defaults. It simply returns if no customization is found. - The methods
getModeCustomizationandgetGlobalCustomizationare deprecated.
- The
Simplified Customization Registration:
The
customizationTypeproperty in customization definitions is renamed toinheritsFrom.The
mergeproperty in customization definitions is removed. Instead, a customization is merged using the helper methods. The basic update commands are listed in the table below, and you can learn more about the helper methods here.Command Description Example $setReplace a value entirely Replace a list or object $pushAppend items to an array Add to the end of a list $unshiftPrepend items to an array Add to the start of a list $spliceInsert, remove, or replace at specific index Modify specific indices in a list $mergeUpdate specific fields in an object Change a subset of fields $applyCompute the new value dynamically Apply a function to transform values $filterFind and update specific items in arrays Target nested structures based on matching criteria
New
$transformcommand:- If you were using the
transformcommand, you should now use the$transformcommand. Just a simple rename to make it more consistent with the other commands.
- If you were using the
Renamed
CornerstoneOverlaycustomizations:- The
cornerstoneOverlaycustomizations (cornerstoneOverlayTopLeft,cornerstoneOverlayTopRight,cornerstoneOverlayBottomLeft,cornerstoneOverlayBottomRight) have been renamed toviewportOverlay.topLeft,viewportOverlay.topRight,viewportOverlay.bottomLeft, andviewportOverlay.bottomRight. See dedicated page for customizing viewport overlays here.
- The
Renamed
customRoutes:- The
customRoutescustomization is renamed toroutes.customRoutes.
- The
contextMenucustomization:- The
contextMenucustomization now uses theinheritsFromproperty to inherit from other context menus, previously it was calledcustomizationType
- The
New
immutability-helperdependency:
Theimmutability-helperlibrary is now used for merging customizations. If you encounter an error related to it, you'll need to install it - though OHIF should really handle the installation for you, so this is pretty much just a heads up.
Migration Steps:
Replace
getModeCustomizationandgetGlobalCustomizationwithgetCustomization:Before:
javascriptconst tools = customizationService.getModeCustomization( 'cornerstone.overlayViewportTools' )?.tools; const globalValue = customizationService.getGlobalCustomization('someGlobalKey');After:
javascriptconst tools = customizationService.getCustomization('cornerstone.overlayViewportTools'); const globalValue = customizationService.getCustomization('someGlobalKey');:::note
The returned value is the actual customization value, not an object that needs to be broken down.
:::
Update Customization Definitions:
- We've moved away from using random items in the customization definition, and now we use the
idproperty to identify the customization as a value. Previously, it was referred to asvalue,values, and so on, but now anidis used to reference the customization. This approach really simplifies things - when you need to grab the customization, you can just use theidto get it, and you don't have to bother with destructuring the value from the object.
- We've moved away from using random items in the customization definition, and now we use the
Example: Customizing a Panel
Before (v3.9):
// the default value was hardcoded inside the panel itself - bad idea!
// default was given in the panel itself
// PanelSegmentation.tsx
// Retrieve the onSegmentationAdd customization
const { onSegmentationAdd } = customizationService.getCustomization(
'PanelSegmentation.onSegmentationAdd',
{
id: 'segmentation.onSegmentationAdd',
onSegmentationAdd: handlers.onSegmentationAdd,
}
);
// Retrieve the disableEditing customization
const { disableEditing } = customizationService.getCustomization(
'PanelSegmentation.disableEditing',
{
id: 'default.disableEditing',
disableEditing: false,
}
);
// mode was customizing it via
customizationService.addModeCustomizations([
{
id: 'PanelSegmentation.tableMode',
mode: 'expanded',
},
{
id: 'PanelSegmentation.showAddSegment',
showAddSegment: false,
},
]);After (v3.10):
// cornerstone extension getCustomizationModule
// centralized customization location for all extensions - good!
function getCustomizationModule() {
return [
{
name: 'default',
value: {
'panelSegmentation.disableEditing': false,
'panelSegmentation.showAddSegment': true,
},
},
];
}
// inside panelSegmentation.tsx
const disableEditing = customizationService.getCustomization('panelSegmentation.disableEditing');
const showAddSegment = customizationService.getCustomization('panelSegmentation.showAddSegment');
// mode can customize it via $ operators for mode customizations
customizationService.setCustomizations({
'panelSegmentation.disableEditing': { $set: true },
'panelSegmentation.showAddSegment': { $set: false },
});
//or via configuration for global customizations
window.config = {
// rest of config
customizationService: [
{
'panelSegmentation.disableEditing': {
$set: true, // Disables editing of segmentations in the panel
},
},
],
// rest of config
};Example: Updating a Customization
Let's say you have a customization in v3.9 that adds a custom overlay item to the top-left corner:
Before (v3.9):
// In your mode's onModeEnter
customizationService.addModeCustomizations([
{
id: 'cornerstoneOverlayTopLeft',
items: [
{
id: 'myCustomOverlay',
customizationType: 'ohif.overlayItem',
attribute: 'PatientName',
label: 'Patient:',
},
],
},
]);After (v3.10):
// In your mode's onModeEnter or elsewhere
customizationService.setCustomizations({
'viewportOverlay.topLeft': {
$push: [
{
id: 'myCustomOverlay',
inheritsFrom: 'ohif.overlayItem',
attribute: 'PatientName',
label: 'Patient:',
},
],
},
});**Example: Customizing viewport action Menu**
**Before (v3.9):**
```javascript
// In your configuration for global customizations
window.config = {
// rest of config
addWindowLevelActionMenu: true,
};After (v3.10):
// you can now handle each action menu item (windowLevelActionMenu and segmentationOverlay) separately
// cornerstone extension getCustomizationModule
function getCustomizationModule() {
return [
{
name: 'default',
value: {
'viewportActionMenu.windowLevelActionMenu': {
enabled: true,
location: viewportActionCornersService.LOCATIONS.topRight,
},
'viewportActionMenu.segmentationOverlay': {
enabled: true,
location: viewportActionCornersService.LOCATIONS.topRight,
},
},
},
];
}
// Accessing customizations within your component (e.g., OHIFCornerstoneViewport.tsx)
const windowLevelActionMenu = customizationService.getCustomization('viewportActionMenu.windowLevelActionMenu');
const segmentationOverlay = customizationService.getCustomization('viewportActionMenu.segmentationOverlay');
// Modifying customizations at runtime, for example, in your mode's onModeEnter
customizationService.setCustomizations({
'viewportActionMenu.windowLevelActionMenu': {
$set: {
enabled: false,
location: viewportActionCornersService.LOCATIONS.bottomLeft,
},
},
'viewportActionMenu.segmentationOverlay': {
$set: {
enabled: true,
location: viewportActionCornersService.LOCATIONS.topLeft,
},
},
});
// Alternatively, setting global customizations via configuration
window.config = {
// rest of config
customizationService: [
{
'viewportActionMenu.windowLevelActionMenu': {
$set: {
enabled: false,
location: 1,
},
},
'viewportActionMenu.segmentationOverlay': {
$set: {
enabled: true,
location: 1,
},
},
},
],
// rest of config
};Note:
- The
customizationTypeis replaced withinheritsFrom.
Renaming
To keep our customization system consistent, you should be aware of a few key renaming conventions. We now follow a straightforward naming convention for customizations: scopeName.customizationItem.
| Customization Key (Old) | Customization Key (New) | Description |
|---|---|---|
PanelMeasurement.disableEditing |
panelMeasurement.disableEditing |
Disables editing measurements in the Measurement Panel and after SR hydration. |
PanelSegmentation.CustomDropdownMenuContent |
panelSegmentation.customDropdownMenuContent |
Custom content for the dropdown menu in the Segmentation Panel. |
PanelSegmentation.disableEditing |
panelSegmentation.disableEditing |
Disables editing segmentations in the Segmentation Panel. |
PanelSegmentation.showAddSegment |
panelSegmentation.showAddSegment |
Controls visibility of the "Add Segment" button in the Segmentation Panel. |
PanelSegmentation.onSegmentationAdd |
panelSegmentation.onSegmentationAdd |
Custom function to execute when a new segmentation is added. |
PanelSegmentation.tableMode |
panelSegmentation.tableMode |
Controls the table mode (collapsed/expanded) in the Segmentation Panel. |
PanelSegmentation.readableText |
panelSegmentation.readableText |
Custom readable text labels for the Segmentation Panel. |
PanelStudyBrowser.studyMode |
studyBrowser.studyMode |
Controls the study mode (all/primary/recent) in the Study Browser Panel. |
customRoutes |
routes.customRoutes |
Defines custom routes for the application. |
cornerstoneOverlayTopLeft |
viewportOverlay.topLeft |
Custom overlay items for the top-left corner of the viewport. |
cornerstoneOverlayTopRight |
viewportOverlay.topRight |
Custom overlay items for the top-right corner of the viewport. |
cornerstoneOverlayBottomLeft |
viewportOverlay.bottomLeft |
Custom overlay items for the bottom-left corner of the viewport. |
cornerstoneOverlayBottomRight |
viewportOverlay.bottomRight |
Custom overlay items for the bottom-right corner of the viewport. |
| (New) | viewportActionMenu.windowLevelActionMenu |
Controls the display and the location of the window level action menu in the viewport. |
| (New) | viewportActionMenu.segmentationOverlay |
Controls the display and the location of segmentation overlays in the viewport. |
Platform Docs Docs Platform Services Data Index (`platform/docs/docs/platform/services/data/index.md`)
sidebar_position: 1 sidebar_label: Overview title: Data Services Overview summary: Overview of OHIF's data services architecture, which replaced the Redux store with a more modular approach using service-specific state management and a pub/sub pattern for communication between components.
Overview
Data services are the first category of services which deal with handling non-ui
related state Each service have their own internal state which they handle.
We have replaced the redux store. Instead, we have introduced various
services and a pub/sub pattern to subscribe and run, which makes theOHIF-v3
architecture nice and clean.
We maintain the following non-ui Services:
- DicomMetadata Store
- DisplaySet Service
- Hanging Protocol Service
- Toolbar Service
- Measurement Service
- Customization Service
- Panel Service
- Viewed Data Service
Service Architecture
We have explained services and how to create a custom service in the
ServicesManagersection of the docs
To recap: The simplest service return a new object that has a name property,
and Create method which instantiate the service class. The "Factory Function"
that creates the service is provided with the implementation (this is slightly
different for UI Services).
// extensions/customExtension/src/services/backEndService/index.js
import backEndService from './backEndService';
export default function WrappedBackEndService(servicesManager) {
return {
name: 'myService',
create: ({ configuration = {} }) => {
return new backEndService(servicesManager);
},
};
}A service, once created, can be registered with the ServicesManager to make it
accessible to extensions. Similarly, the application code can access named
services from the ServicesManager.
Read more of how to design a new custom service and register it
Platform Docs Docs Platform Services Ui Index (`platform/docs/docs/platform/services/ui/index.md`)
sidebar_position: 1 sidebar_label: Overview title: UI Services Overview summary: Overview of OHIF's UI services architecture, which enables consistent UI interactions across the application through React context providers and service implementations, allowing extensions to leverage components like modals, notifications, and dialogs.
Overview
A typical web application will have components and state for common UI like
modals, notifications, dialogs, etc. A UI service makes it possible to leverage
these components from an extension.
We maintain the following UI Services:
- UI Notification Service
- UI Modal Service
- UI Dialog Service
- UI Viewport Dialog Service
- CINE Service
- Viewport Grid Service
Providers for UI services
There are several context providers that wraps the application routes. This
makes the context values exposed in the app, and service's setImplementation
can get run to override the implementation of the service.
function App({ config, defaultExtensions }) {
/**...**/
/**...**/
return (
/**...**/
<ViewportGridProvider service={ViewportGridService}>
<ViewportDialogProvider service={UIViewportDialogService}>
<CineProvider service={CineService}>
<SnackbarProvider service={UINotificationService}>
<DialogProvider service={UIDialogService}>
<ModalProvider modal={Modal} service={UIModalService}>
{appRoutes}
</ModalProvider>
</DialogProvider>
</SnackbarProvider>
</CineProvider>
</ViewportDialogProvider>
</ViewportGridProvider>
/**...**/
);
}Example
For instance UIModalService has the following Public API:
const publicAPI = {
name,
hide: _hide,
show: _show,
setServiceImplementation,
};
function setServiceImplementation({
hide: hideImplementation,
show: showImplementation,
}) {
/** ... **/
serviceImplementation._hide = hideImplementation;
serviceImplementation._show = showImplementation;
/** ... **/
}
export default {
name: 'UIModalService',
create: ({ configuration = {} }) => {
return publicAPI;
},
};UIModalService implementation can be set (override) in its context provider.
For instance in ModalProvider we have:
/* Detailed source-code truncated for AI context efficiency. */Therefore, anywhere in the app that we have access to react context we can use
it by calling the useModal from @ohif/ui-next. As a matter of fact, we are
utilizing the modal for the preference window which shows the hotkeys after
clicking on the gear button on the right side of the header.
A simplified code for our viewer header is:
import { Header, useModal } from '@ohif/ui-next';
import { useSystem } from '@ohif/core';
function ViewerHeader({ appConfig }) {
const { servicesManager } = useSystem();
const { customizationService } = servicesManager.services;
const { show } = useModal();
const AboutModal = customizationService.getCustomization('ohif.aboutModal');
const UserPreferencesModal = customizationService.getCustomization(
'ohif.userPreferencesModal'
);
const menuOptions = [
{
title: AboutModal?.menuTitle ?? t('Header:About'),
icon: 'info',
onClick: () =>
show({
content: AboutModal,
title: AboutModal?.title ?? t('AboutModal:About OHIF Viewer'),
containerClassName: AboutModal?.containerClassName ?? 'max-w-md',
}),
},
{
title: UserPreferencesModal.menuTitle ?? t('Header:Preferences'),
icon: 'settings',
onClick: () =>
show({
content: UserPreferencesModal,
title: UserPreferencesModal.title ?? t('UserPreferencesModal:User preferences'),
containerClassName:
UserPreferencesModal?.containerClassName ?? 'flex max-w-4xl p-6 flex-col',
}),
},
];
/** ... **/
return <Header menuOptions={menuOptions} /** ... **/ />;
}Tips & Tricks
It's important to remember that all we're doing is making it possible to control
bits of the application's UI from an extension. Here are a few non-obvious
takeaways worth mentioning:
- Your application code should continue to use React context
(consumers/providers) as it normally would - You can substitute our "out of the box" UI implementations with your own
- You can create and register your own UI services
- You can choose not to register a service or provide a service implementation
- In extensions, you can provide fallback/alternative behavior if an expected
service is not registered- No
UIModalService? Use theUINotificationServiceto notify users.
- No
- You can technically register a service in an extension and expose it to the
core application
Note: These are recommended patterns, not hard and fast rules. Following them
will help reduce confusion and interoperability with the larger OHIF
community, but they're not silver bullets. Please speak up, create an issue,
if you would like to discuss new services or improvements to this pattern.
Platform Docs Versioned Docs Version 3.11 Migration Guide 3p10 To 3p11 Index (`platform/docs/versioned_docs/version-3.11/migration-guide/3p10-to-3p11/index.md`)
sidebar_position: 1 sidebar_label: 3.10 -> 3.11
Migration Guide
This guide provides information about migrating from OHIF version 3.10 to version 3.11.
Platform Docs Versioned Docs Version 3.11 Migration Guide 3p11 To 3p12 Index (`platform/docs/versioned_docs/version-3.11/migration-guide/3p11-to-3p12/index.md`)
sidebar_position: 1 sidebar_label: 3.11 -> 3.12 beta
Migration Guide
This guide provides information about migrating from OHIF version 3.11 to version 3.12 beta
Platform Docs Versioned Docs Version 3.11 Migration Guide 3p8 To 3p9 Index (`platform/docs/versioned_docs/version-3.11/migration-guide/3p8-to-3p9/index.md`)
id: 3p8-to-3p9 title: 3.8 -> 3.9 sidebar_position: 2 summary: Migration guide for upgrading from OHIF 3.8 to 3.9, covering segmentation architecture changes, renamings, data sources, measurements, viewport action corners, state sync service, RT structure improvements, UI changes, and other refactorings.
import DocCardList from '@theme/DocCardList';
Migration Guide Sections
Platform Docs Versioned Docs Version 3.11 Migration Guide 3p9 To 3p10 Index (`platform/docs/versioned_docs/version-3.11/migration-guide/3p9-to-3p10/index.md`)
sidebar_position: 1 sidebar_label: 3.9 -> 3.10 title: Migration Guide from 3.9 to 3.10 beta summary: Migration guide for upgrading from OHIF 3.9 to 3.10 beta, covering general changes, customization service improvements, UI component upgrades, command handling, hotkey updates, routing changes, and testing strategies.
Migration Guide
General
Platform Docs Versioned Docs Version 3.11 Platform Extensions Index (`platform/docs/versioned_docs/version-3.11/platform/extensions/index.md`)
sidebar_position: 1 sidebar_label: Introduction title: OHIF Extensions Introduction summary: Comprehensive introduction to the OHIF viewer extension system, explaining how extensions provide modular functionality through different module types, and how they're configured and accessed in modes to build customized viewer experiences.
Introduction
We have re-designed the architecture of the OHIF-v3 to enable building
applications that are easily extensible to various use cases (modes) that behind
the scene would utilize desired functionalities (extensions) to reach the goal
of the use case.
Previously, extensions were “additive” and could not easily be mixed and matched
within the same viewer for different use cases. Previous OHIF-v2 architecture
meant that any minor extension alteration usually would require the user to hard
fork. E.g. removing some tools from the toolbar of the cornerstone
extension meant you had to hard fork it, which was frustrating if the
implementation was otherwise the same as master.
- Developers should make packages of reusable functionality as extensions,
and can consume publicly available extensions.- Any conceivable radiological workflow or viewer setup will be able to be
built with the platform through modes.
Practical examples of extensions include:
- A set of segmentation tools that build on top of the
cornerstoneviewport - A set of rendering functionalities to volume render the data
- See our maintained extensions for more examples of what's possible
Diagram showing how extensions are configured and accessed.
Extension Skeleton
An extension is a plain JavaScript object that has id and version properties, and one or
more modules and/or lifecycle hooks.
// prettier-ignore
export default {
/**
* Required properties. Should be a unique value across all extensions.
*/
id,
// Lifecycle
preRegistration() { /* */ },
onModeEnter() { /* */ },
onModeExit() { /* */ },
// Modules
getLayoutTemplateModule() { /* */ },
getDataSourcesModule() { /* */ },
getSopClassHandlerModule() { /* */ },
getPanelModule() { /* */ },
getViewportModule() { /* */ },
getCommandsModule() { /* */ },
getContextModule() { /* */ },
getToolbarModule() { /* */ },
getHangingProtocolModule() { /* */ },
getUtilityModule() { /* */ },
}OHIF-Maintained Extensions
A small number of powerful extensions for popular use cases are maintained by
OHIF. They're co-located in the OHIF/Viewers repository, in
the top level extensions/ directory.
| Extension | Description | Modules |
|---|---|---|
| default | Default extension provides default viewer layout, a study/series browser, and a datasource that maps to a DICOMWeb compliant backend | commandsModule, ContextModule, DataSourceModule, HangingProtocolModule, LayoutTemplateModule, PanelModule, SOPClassHandlerModule, ToolbarModule |
| cornerstone | Provides 2d and 3d rendering functionalities | ViewportModule, CommandsModule, UtilityModule |
| dicom-pdf | Renders PDFs for a specific SopClassUID. | Viewport, SopClassHandler |
| dicom-video | Renders DICOM Video files. | Viewport, SopClassHandler |
| cornerstone-dicom-sr | Maintained extensions for cornerstone and visualization of DICOM Structured Reports | ViewportModule, CommandsModule, SOPClassHandlerModule |
| measurement-tracking | Tracking measurements in the measurement panel | ContextModule,PanelModule,ViewportModule,CommandsModule |
Registering of Extensions
viewer starts by registering all the extensions specified inside thepluginConfig.json, by default we register all extensions in the repo.
// Simplified version of the `pluginConfig.json` file
{
"extensions": [
{
"packageName": "@ohif/extension-cornerstone",
"version": "3.4.0"
},
{
"packageName": "@ohif/extension-measurement-tracking",
"version": "3.4.0"
},
// ...
],
"modes": [
{
"packageName": "@ohif/mode-longitudinal",
"version": "3.4.0"
}
]
}:::note Important
You SHOULD NOT directly register extensions in the pluginConfig.json file.
Use the provided cli to add/remove/install/uninstall extensions. Read more here
:::
The final registration and import of the extensions happen inside a non-tracked file pluginImport.js (this file is also for internal use only).
After an extension gets registered within the viewer,
each module defined by the extension becomes available to the modes
via the ExtensionManager by requesting it via its id.
Read more about Extension Manager
Lifecycle Hooks
Currently, there are three lifecycle hook for extensions:
preRegistration This hook is called once on
initialization of the entire viewer application, used to initialize the
extensions state, and consume user defined extension configuration. If an
extension defines the preRegistration
lifecycle hook, it is called before any modules are registered in theExtensionManager. It's most commonly used to wire up extensions to
services and commands, and to
bootstrap 3rd party libraries.
onModeEnter: This hook is called whenever a new
mode is entered, or a mode’s data or datasource is switched. This hook can be
used to initialize data.
onModeExit: Similarly to onModeEnter, this hook is
called when navigating away from a mode, or before a mode’s data or datasource
is changed. This can be used to cache data for reuse later, but since it
isn't known which mode will be entered next, the state after exiting should be
clean, that is, the same as the state on a clean start. This is called BEFORE
service clean up, and after mode specific onModeExit handling.
Modules
Modules are the meat of extensions, the blocks that we have been talking about
a lot. They provide "definitions", components, and filtering/mapping logic that
are then made available to modes and services.
Each module type has a special purpose, and is consumed by our viewer
differently.
| Types | Description |
|---|---|
| LayoutTemplate | Control Layout of a route |
| DataSource | Control the mapping from DICOM metadata to OHIF-metadata |
| SOPClassHandler | Determines how retrieved study data is split into "DisplaySets" |
| Panel | Adds left or right hand side panels |
| Viewport | Adds a component responsible for rendering a "DisplaySet" |
| Commands | Adds named commands, scoped to a context, to the CommandsManager |
| Toolbar | Adds buttons or custom components to the toolbar |
| Context | Shared state for a workflow or set of extension module definitions |
| HangingProtocol | Adds hanging protocol rules |
| Utility | Expose utility functions to the outside of extensions |
<span style={{"textAlign": 'center', 'fontStyle': 'italic'}}>Tbl. Module types
with abridged descriptions and examples. Each module links to a dedicated
documentation page.
Contexts
The @ohif/app tracks "active contexts" that extensions can use to scope
their functionality. Some example contexts being:
- Route:
ROUTE:VIEWER,ROUTE:STUDY_LIST - Active Viewport:
ACTIVE_VIEWPORT:CORNERSTONE,ACTIVE_VIEWPORT:VTK
An extension module can use these to say "Only show this Toolbar Button if the
active viewport is a Cornerstone viewport." This helps us use the appropriate UI
and behaviors depending on the current contexts.
For example, if we have hotkey that "rotates the active viewport", each Viewport
module that supports this behavior can add a command with the same name, scoped
to the appropriate context. When the command is fired, the "active contexts"
are used to determine the appropriate implementation of the rotation behavior.
Platform Docs Versioned Docs Version 3.11 Platform Hooks Index (`platform/docs/versioned_docs/version-3.11/platform/hooks/index.md`)
title: Hooks summary: List of React hooks available in the platform, these are custom hooks that are used to access the state of the platform
Hooks
[useMeasurements](./useMeasurements.md)
A React hook that provides mapped measurements from the measurement service with automatic updates when measurements change.
[useViewportSegmentations](./useViewportSegmentations.md)
A React hook that provides segmentation data and representations for the active viewport with automatic updates when segmentations change.
[useMeasurementTracking](./useMeasurementTracking.md)
A React hook that provides measurement tracking information for a specific viewport, including tracking state and tracked measurement UIDs.
[useViewportDisplaySets](./useViewportDisplaySets.md)
A React hook that provides access to display sets associated with a viewport, including background, foreground, overlay, and potential display sets.
[useViewportHover](./useViewportHover.md)
A React hook that tracks mouse hover state and active status for a specific viewport.
[usePatientInfo](./usePatientInfo.md)
A React hook that provides patient information from the active display sets and detects when multiple patients are loaded.
[useSearchParams](./useSearchParams.md)
A React hook that provides access to URL search parameters from both the query string and hash fragment.
[useDynamicMaxHeight](./useDynamicMaxHeight.md)
A React hook that calculates the maximum height for an element based on its position in the viewport, with automatic recalculation on window resize or data changes.
[useSessionStorage](./useSessionStorage.md)
A React hook that provides sessionStorage access with automatic JSON parsing/stringifying and an option to clear data when the page unloads.
Platform Docs Versioned Docs Version 3.11 Platform Managers Index (`platform/docs/versioned_docs/version-3.11/platform/managers/index.md`)
sidebar_position: 1 sidebar_label: Introduction title: Managers Introduction summary: Overview of OHIF's manager system, which handles critical application infrastructure including extension registration, service management, command execution, and hotkey binding to coordinate functionality across the platform.
Managers
Overview
OHIF uses Managers to accomplish various purposes such as registering new
services, dependency injection, and aggregating and exposing extension
features.
OHIF-v3 provides the following managers which we will discuss in depth.
| Manager | Description |
|---|---|
| Extension Manager | Aggregating and exposing modules and features through out the app |
| Services Manager | Single point of registration for all internal and external services |
| Commands Manager | Register commands with specific context and run commands in the app |
| Hotkeys Manager | For keyboard keys assignment to commands |
Platform Docs Versioned Docs Version 3.11 Platform Modes Index (`platform/docs/versioned_docs/version-3.11/platform/modes/index.md`)
sidebar_position: 1 sidebar_label: Introduction title: Modes Introduction summary: Overview of OHIF Modes, which are specialized viewer configurations for specific clinical workflows, allowing multiple purpose-specific applications to coexist within a single OHIF deployment.
Modes
Overview
A mode can be thought of as a viewer app configured to perform a specific task,
such as tracking measurements over time, 3D segmentation, a guided radiological
workflow, etc. Addition of modes enables application with many applications
as each mode become a mini app configuration behind the scene.
Upon initialization the viewer will consume extensions and modes and build up
the route desired, these can then be accessed via the study list, or directly
via url parameters.
OHIF-v3 architecture can be seen in the following:
Note: Templates are now a part of “extensions” Routes are configured by modes
and/or app
As mentioned, modes are tied to a specific route in the viewer, and multiple
modes/routes can be present within a single application. This allows for
tremendously more flexibility than before you can now:
- Simultaneously host multiple viewers with for different use cases from within
the same app deploy. - Make radiological viewers for specific purposes/workflows, e.g.:
- Tracking the size of lesions over time.
- PET/CT fusion workflows.
- Guided review workflows optimized for a specific clinical trial.
- Still host one single feature-rich viewer if you desire.
Anatomy
A mode configuration has a route name which is dynamically transformed into a
viewer route on initialization of the application. Modes that are available to a
study will appear in the study list.
The mode configuration specifies which extensions the mode requires, whichLayoutTemplate to use, and what props to pass to the template. For the default
template this defines which side panels will be available, as well as whatviewports and which displaySets they may hang.
Mode's config is composed of three elements:
id: the modeidmodeFactory: the function that returns the mode specific configurationextensionDependencies: the list of extensions that the mode requires
that return a config object with certain
properties, the high-level view of this config object is:
function modeFactory() {
return {
id: '',
version: '',
displayName: '',
onModeEnter: () => {},
onModeExit: () => {},
validationTags: {},
isValidMode: () => {},
routes: [
{
path: '',
init: () => {},
layoutTemplate: () => {},
},
],
extensions: extensionDependencies,
hangingProtocol: [],
sopClassHandlers: [],
hotkeys: []
};
}
const mode = {
id,
modeFactory,
extensionDependencies,
};
export default mode;| Property | Description |
|---|---|
| id | unique mode id used to refer to the mode |
| displayName | actual name of the mode being displayed for each study in the study summary panel |
| onModeEnter | hook is called when the mode is entered by the specified route |
| onModeExit | hook is called when the mode exited |
| validationTags | validationTags |
| isValidMode | Checks if the mode is valid for a study |
| routes | route config which defines the route address, and the layout for it |
| extensionDependencies | extensions needed by the mode |
| hanging protocol | list of hanging protocols that the mode should have access to |
| sopClassHandlers | list of SOPClass modules needed by the mode |
| hotkeys | hotkeys |
Consuming Extensions
As mentioned in the Extensions section, in OHIF-v3
developers write their extensions to create reusable functionalities that later
can be used by modes. Now, it is time to describe how the registered
extensions will get utilized for a workflow mode via its id.
Each mode has a list of its extensions dependencies which are the
the extension name and version number. In addition, to use a module element you can use the${extensionId}.${moduleType}.${element.name} schema. For instance, if a mode
requires the left panel with name of AIPanel that is added by themyAIExtension via the following getPanelModule code, it should address it asmyAIExtension.panelModule.AIPanel inside the mode configuration file. In the
background OHIF will handle grabbing the correct panel via ExtensionManager.
import PanelAI from './PanelAI.js';
function getPanelModule({
commandsManager,
extensionManager,
servicesManager,
}) {
const wrappedAIPanel = () => {
return (
);
};
return [
{
name: 'AIPanel',
iconName: 'list-bullets',
iconLabel: '',
label: 'AI Panel',
isDisabled: studies => {}, // optional
component: wrappedAIPanel,
},
];
}Now, let's look at a simplified code of the basic viewer mode which consumes various functionalities
from different extensions.
const extensionDependencies = {
'@ohif/extension-default': '^3.0.0',
'@ohif/extension-cornerstone': '^3.0.0',
'@ohif/extension-measurement-tracking': '^3.0.0',
};
const id = 'viewer';
const version = '3.0.0';
function modeFactory({ modeConfiguration }) {
return {
id,
// ...
routes: [
{
// ...
layoutTemplate: ({ location, servicesManager }) => {
return {
id: ohif.layout,
props: {
leftPanels: ['@ohif/extension-measurement-tracking.panelModule.seriesList'],
rightPanels: ['@ohif/extension-measurement-tracking.panelModule.trackedMeasurements'],
viewports: [
{
namespace: '@ohif/extension-measurement-tracking.viewportModule.cornerstone-tracked',
displaySetsToDisplay: ['@ohif/extension-default.sopClassHandlerModule.stack'],
},
],
},
};
},
},
],
extensions: extensionDependencies,
hangingProtocol: ['@ohif/extension-default.hangingProtocolModule.petCT'],
sopClassHandlers: ['@ohif/extension-default.sopClassHandlerModule.stack'],
// ...
};
}
const mode = {
id,
modeFactory,
extensionDependencies,
}
export default modeRoutes
routes config is an array of route settings, and the overall look and behavior
of the viewer at the designated route is defined by the layoutTemplate andinit functions for the route. We will learn more about each of the above
properties inside the route documentation
HangingProtocols
Currently, you can pass your defined hanging protocols inside thehangingProtocols property of the mode's config. If you specify the hanging protocol
explicitly by its name (only string and not array), it will be THE hanging protocol
that the mode runs with. However, if you specify an array of hanging protocols,
they will get ranked based on the displaySetSelector requirements and the winner
will be the hanging protocol that the mode runs with.
SopClassHandlers
Mode's configuration also accepts the sopClassHandler modules that have been
added by the extensions. This information will get used to initialize DisplaySetService with the provided SOPClass modules which
handles creation of the displaySets.
Hotkeys
hotkeys is another property in the configuration of a mode that can be defined
to add the specific hotkeys to the viewer on the mode route. Additionally, the
name under which the hotkeys are stored can be configured as hotkeyName.
This allows user customization of the mode specific hotkeys.
// default hotkeys
import { utils } from '@ohif/ui';
const { hotkeys } = utils;
const myHotkeys = [
{
commandName: 'setToolActive',
commandOptions: { toolName: 'Zoom' },
label: 'Zoom',
keys: ['z'],
isEditable: true,
},
{
commandName: 'scaleUpViewport',
label: 'Zoom In',
keys: ['+'],
isEditable: true,
},
]
function modeFactory() {
return {
id: '',
id: '',
displayName: '',
/*
...
*/
hotkeys: {
// The name in preferences to use for this set of hotkeys
// Allows defining different sets for different modes
name: 'custom-hotkey-name',
// And the actual custom values here.
hotkeys:[..hotkeys.defaults.hotkeyBindings, ...myHotkeys]
},
}
}
// exportsRegistration
Similar to extension registration, viewer will look inside the pluginConfig.json to
find the modes to register.
// Simplified version of the `pluginConfig.json` file
{
"extensions": [
{
"packageName": "@ohif/extension-cornerstone",
"version": "3.4.0"
},
// ...
],
"modes": [
{
"packageName": "@ohif/mode-longitudinal",
"version": "3.4.0"
}
]
}:::note Important
You SHOULD NOT directly register modes in the pluginConfig.json file.
Use the provided cli to add/remove/install/uninstall modes. Read more here
:::
The final registration and import of the modes happen inside a non-tracked file pluginImport.js (this file is also for internal use only).
:::note
You can stack multiple panel components on top of each other by providing an array of panel components in the rightPanels or leftPanels properties.
For instance we can use
rightPanels: [[dicomSeg.panel, tracked.measurements], [dicomSeg.panel, tracked.measurements]]This will result in two panels, one with dicomSeg.panel and tracked.measurements and the other with dicomSeg.panel and tracked.measurements stacked on top of each other.
:::
Platform Docs Versioned Docs Version 3.11 Platform Services Index (`platform/docs/versioned_docs/version-3.11/platform/services/index.md`)
sidebar_position: 1 sidebar_label: Introduction title: OHIF Services summary: Overview of OHIF's services architecture, which provides modular, concern-specific code components that manage state and operations throughout the application, including both data services and UI services that follow a pub/sub pattern to reduce coupling.
Services
Overview
Services are "concern-specific" code modules that can be consumed across layers.
Services provide a set of operations, often tied to some shared state, and are
made available to through out the app via the ServicesManager. Services are
particularly well suited to address cross-cutting
concerns.
Each service should be:
- self-contained
- able to fail and/or be removed without breaking the application
- completely interchangeable with another module implementing the same interface
In
OHIF-v3we have added multiple non-UI services and have introduced
pub/sub pattern to reduce coupling between layers.
Services
The following services is available in the OHIF-v3.
| Service | Type | Description |
|---|---|---|
| DicomMetadataStore | Data Service | DicomMetadataStore |
| DisplaySetService | Data Service | DisplaySetService |
| segmentationService | Segmentation Service | segmentationService |
| HangingProtocolService | Data Service | HangingProtocolService |
| MeasurementService (MODIFIED) | Data Service | MeasurementService |
| ToolBarService | Data Service | ToolBarService |
| ViewportGridService | UI Service | ViewportGridService |
| Cine Service | UI Service | cine |
| CustomizationService | UI Service | customizationService |
| UIDialogService | UI Service | UIDialogService |
| UIModalService | UI Service | UIModalService |
| UINotificationService | UI Service | UINotificationService |
| UIViewportDialogService | UI Service | UIViewportDialogService |
Platform Docs Versioned Docs Version 3.11 User Guide Viewer Index (`platform/docs/versioned_docs/version-3.11/user-guide/viewer/index.md`)
sidebar_position: 1 sidebar_label: Overview
Overview
When you open a mode, viewport, toolbar and panels of the mode get shown.
It is important to note that each mode has a different UI, which serves its purpose.
Here we explain various components of Basic Viewer mode which includes measurement
tracking functionalities.
Basic viewer mode (longitudinal):
Let's break different aspects of the viewer to the main components:
- Left Panel (study panel): displays series thumbnails with series details
- Viewport: renders the image and displays annotations
- Right Panel (measurements): displays annotations details
- Toolbar: displays tools and logo
Now, we explain each component and its sub-elements in detail.
Platform Docs Versioned Docs Version 3.11 Migration Guide 3p8 To 3p9 1 Segmentation Index (`platform/docs/versioned_docs/version-3.11/migration-guide/3p8-to-3p9/1-segmentation/index.md`)
id: segmentation-index title: Segmentation sidebar_position: 1 summary: Migration guide for segmentation architecture changes in OHIF 3.9, covering the shift from tool group-centric to viewport-centric architecture to support advanced visualization capabilities and more flexible segmentation handling.
import DocCardList from '@theme/DocCardList';
:::info
This migration involves significant architectural changes to the segmentation system. While we typically aim for incremental updates, the shift from a tool group-centric to a viewport-centric architecture was necessary to support OHIF 3.9's advanced visualization capabilities, and more flexible segmentation handling.
Don't worry - we'll guide you through each change step by step!
:::
Platform Docs Versioned Docs Version 3.11 Migration Guide 3p9 To 3p10 2 CustomizationService Index (`platform/docs/versioned_docs/version-3.11/migration-guide/3p9-to-3p10/2-CustomizationService/index.md`)
sidebar_position: 2 title: Customization Service summary: Migration guide for OHIF's Customization Service from 3.9 to 3.10, covering unified customization getters, simplified registration, new commands, renamed customizations, and updated patterns for modifying UI components.
CustomizationService
Key Changes:
Unified Customization Getter:
- The
getCustomizationmethod now uniformly retrieves customizations, prioritizingglobal, thenmode, and finallydefaultcustomizations. - The
defaultValueparameter ingetCustomizationis no longer used for setting defaults. It simply returns if no customization is found. - The methods
getModeCustomizationandgetGlobalCustomizationare deprecated.
- The
Simplified Customization Registration:
The
customizationTypeproperty in customization definitions is renamed toinheritsFrom.The
mergeproperty in customization definitions is removed. Instead, a customization is merged using the helper methods. The basic update commands are listed in the table below, and you can learn more about the helper methods here.Command Description Example $setReplace a value entirely Replace a list or object $pushAppend items to an array Add to the end of a list $unshiftPrepend items to an array Add to the start of a list $spliceInsert, remove, or replace at specific index Modify specific indices in a list $mergeUpdate specific fields in an object Change a subset of fields $applyCompute the new value dynamically Apply a function to transform values $filterFind and update specific items in arrays Target nested structures based on matching criteria
New
$transformcommand:- If you were using the
transformcommand, you should now use the$transformcommand. Just a simple rename to make it more consistent with the other commands.
- If you were using the
Renamed
CornerstoneOverlaycustomizations:- The
cornerstoneOverlaycustomizations (cornerstoneOverlayTopLeft,cornerstoneOverlayTopRight,cornerstoneOverlayBottomLeft,cornerstoneOverlayBottomRight) have been renamed toviewportOverlay.topLeft,viewportOverlay.topRight,viewportOverlay.bottomLeft, andviewportOverlay.bottomRight. See dedicated page for customizing viewport overlays here.
- The
Renamed
customRoutes:- The
customRoutescustomization is renamed toroutes.customRoutes.
- The
contextMenucustomization:- The
contextMenucustomization now uses theinheritsFromproperty to inherit from other context menus, previously it was calledcustomizationType
- The
New
immutability-helperdependency:
Theimmutability-helperlibrary is now used for merging customizations. If you encounter an error related to it, you'll need to install it - though OHIF should really handle the installation for you, so this is pretty much just a heads up.
Migration Steps:
Replace
getModeCustomizationandgetGlobalCustomizationwithgetCustomization:Before:
javascriptconst tools = customizationService.getModeCustomization( 'cornerstone.overlayViewportTools' )?.tools; const globalValue = customizationService.getGlobalCustomization('someGlobalKey');After:
javascriptconst tools = customizationService.getCustomization('cornerstone.overlayViewportTools'); const globalValue = customizationService.getCustomization('someGlobalKey');:::note
The returned value is the actual customization value, not an object that needs to be broken down.
:::
Update Customization Definitions:
- We've moved away from using random items in the customization definition, and now we use the
idproperty to identify the customization as a value. Previously, it was referred to asvalue,values, and so on, but now anidis used to reference the customization. This approach really simplifies things - when you need to grab the customization, you can just use theidto get it, and you don't have to bother with destructuring the value from the object.
- We've moved away from using random items in the customization definition, and now we use the
Example: Customizing a Panel
Before (v3.9):
// the default value was hardcoded inside the panel itself - bad idea!
// default was given in the panel itself
// PanelSegmentation.tsx
// Retrieve the onSegmentationAdd customization
const { onSegmentationAdd } = customizationService.getCustomization(
'PanelSegmentation.onSegmentationAdd',
{
id: 'segmentation.onSegmentationAdd',
onSegmentationAdd: handlers.onSegmentationAdd,
}
);
// Retrieve the disableEditing customization
const { disableEditing } = customizationService.getCustomization(
'PanelSegmentation.disableEditing',
{
id: 'default.disableEditing',
disableEditing: false,
}
);
// mode was customizing it via
customizationService.addModeCustomizations([
{
id: 'PanelSegmentation.tableMode',
mode: 'expanded',
},
{
id: 'PanelSegmentation.showAddSegment',
showAddSegment: false,
},
]);After (v3.10):
// cornerstone extension getCustomizationModule
// centralized customization location for all extensions - good!
function getCustomizationModule() {
return [
{
name: 'default',
value: {
'panelSegmentation.disableEditing': false,
'panelSegmentation.showAddSegment': true,
},
},
];
}
// inside panelSegmentation.tsx
const disableEditing = customizationService.getCustomization('panelSegmentation.disableEditing');
const showAddSegment = customizationService.getCustomization('panelSegmentation.showAddSegment');
// mode can customize it via $ operators for mode customizations
customizationService.setCustomizations({
'panelSegmentation.disableEditing': { $set: true },
'panelSegmentation.showAddSegment': { $set: false },
});
//or via configuration for global customizations
window.config = {
// rest of config
customizationService: [
{
'panelSegmentation.disableEditing': {
$set: true, // Disables editing of segmentations in the panel
},
},
],
// rest of config
};Example: Updating a Customization
Let's say you have a customization in v3.9 that adds a custom overlay item to the top-left corner:
Before (v3.9):
// In your mode's onModeEnter
customizationService.addModeCustomizations([
{
id: 'cornerstoneOverlayTopLeft',
items: [
{
id: 'myCustomOverlay',
customizationType: 'ohif.overlayItem',
attribute: 'PatientName',
label: 'Patient:',
},
],
},
]);After (v3.10):
// In your mode's onModeEnter or elsewhere
customizationService.setCustomizations({
'viewportOverlay.topLeft': {
$push: [
{
id: 'myCustomOverlay',
inheritsFrom: 'ohif.overlayItem',
attribute: 'PatientName',
label: 'Patient:',
},
],
},
});**Example: Customizing viewport action Menu**
**Before (v3.9):**
```javascript
// In your configuration for global customizations
window.config = {
// rest of config
addWindowLevelActionMenu: true,
};After (v3.10):
// you can now handle each action menu item (windowLevelActionMenu and segmentationOverlay) separately
// cornerstone extension getCustomizationModule
function getCustomizationModule() {
return [
{
name: 'default',
value: {
'viewportActionMenu.windowLevelActionMenu': {
enabled: true,
location: viewportActionCornersService.LOCATIONS.topRight,
},
'viewportActionMenu.segmentationOverlay': {
enabled: true,
location: viewportActionCornersService.LOCATIONS.topRight,
},
},
},
];
}
// Accessing customizations within your component (e.g., OHIFCornerstoneViewport.tsx)
const windowLevelActionMenu = customizationService.getCustomization('viewportActionMenu.windowLevelActionMenu');
const segmentationOverlay = customizationService.getCustomization('viewportActionMenu.segmentationOverlay');
// Modifying customizations at runtime, for example, in your mode's onModeEnter
customizationService.setCustomizations({
'viewportActionMenu.windowLevelActionMenu': {
$set: {
enabled: false,
location: viewportActionCornersService.LOCATIONS.bottomLeft,
},
},
'viewportActionMenu.segmentationOverlay': {
$set: {
enabled: true,
location: viewportActionCornersService.LOCATIONS.topLeft,
},
},
});
// Alternatively, setting global customizations via configuration
window.config = {
// rest of config
customizationService: [
{
'viewportActionMenu.windowLevelActionMenu': {
$set: {
enabled: false,
location: 1,
},
},
'viewportActionMenu.segmentationOverlay': {
$set: {
enabled: true,
location: 1,
},
},
},
],
// rest of config
};Note:
- The
customizationTypeis replaced withinheritsFrom.
Renaming
To keep our customization system consistent, you should be aware of a few key renaming conventions. We now follow a straightforward naming convention for customizations: scopeName.customizationItem.
| Customization Key (Old) | Customization Key (New) | Description |
|---|---|---|
PanelMeasurement.disableEditing |
panelMeasurement.disableEditing |
Disables editing measurements in the Measurement Panel and after SR hydration. |
PanelSegmentation.CustomDropdownMenuContent |
panelSegmentation.customDropdownMenuContent |
Custom content for the dropdown menu in the Segmentation Panel. |
PanelSegmentation.disableEditing |
panelSegmentation.disableEditing |
Disables editing segmentations in the Segmentation Panel. |
PanelSegmentation.showAddSegment |
panelSegmentation.showAddSegment |
Controls visibility of the "Add Segment" button in the Segmentation Panel. |
PanelSegmentation.onSegmentationAdd |
panelSegmentation.onSegmentationAdd |
Custom function to execute when a new segmentation is added. |
PanelSegmentation.tableMode |
panelSegmentation.tableMode |
Controls the table mode (collapsed/expanded) in the Segmentation Panel. |
PanelSegmentation.readableText |
panelSegmentation.readableText |
Custom readable text labels for the Segmentation Panel. |
PanelStudyBrowser.studyMode |
studyBrowser.studyMode |
Controls the study mode (all/primary/recent) in the Study Browser Panel. |
customRoutes |
routes.customRoutes |
Defines custom routes for the application. |
cornerstoneOverlayTopLeft |
viewportOverlay.topLeft |
Custom overlay items for the top-left corner of the viewport. |
cornerstoneOverlayTopRight |
viewportOverlay.topRight |
Custom overlay items for the top-right corner of the viewport. |
cornerstoneOverlayBottomLeft |
viewportOverlay.bottomLeft |
Custom overlay items for the bottom-left corner of the viewport. |
cornerstoneOverlayBottomRight |
viewportOverlay.bottomRight |
Custom overlay items for the bottom-right corner of the viewport. |
| (New) | viewportActionMenu.windowLevelActionMenu |
Controls the display and the location of the window level action menu in the viewport. |
| (New) | viewportActionMenu.segmentationOverlay |
Controls the display and the location of segmentation overlays in the viewport. |
Platform Docs Versioned Docs Version 3.11 Platform Services Data Index (`platform/docs/versioned_docs/version-3.11/platform/services/data/index.md`)
sidebar_position: 1 sidebar_label: Overview title: Data Services Overview summary: Overview of OHIF's data services architecture, which replaced the Redux store with a more modular approach using service-specific state management and a pub/sub pattern for communication between components.
Overview
Data services are the first category of services which deal with handling non-ui
related state Each service have their own internal state which they handle.
We have replaced the redux store. Instead, we have introduced various
services and a pub/sub pattern to subscribe and run, which makes theOHIF-v3
architecture nice and clean.
We maintain the following non-ui Services:
- DicomMetadata Store
- DisplaySet Service
- Hanging Protocol Service
- Toolbar Service
- Measurement Service
- Customization Service
- Panel Service
Service Architecture
We have explained services and how to create a custom service in the
ServicesManagersection of the docs
To recap: The simplest service return a new object that has a name property,
and Create method which instantiate the service class. The "Factory Function"
that creates the service is provided with the implementation (this is slightly
different for UI Services).
// extensions/customExtension/src/services/backEndService/index.js
import backEndService from './backEndService';
export default function WrappedBackEndService(servicesManager) {
return {
name: 'myService',
create: ({ configuration = {} }) => {
return new backEndService(servicesManager);
},
};
}A service, once created, can be registered with the ServicesManager to make it
accessible to extensions. Similarly, the application code can access named
services from the ServicesManager.
Read more of how to design a new custom service and register it
Platform Docs Versioned Docs Version 3.11 Platform Services Ui Index (`platform/docs/versioned_docs/version-3.11/platform/services/ui/index.md`)
sidebar_position: 1 sidebar_label: Overview title: UI Services Overview summary: Overview of OHIF's UI services architecture, which enables consistent UI interactions across the application through React context providers and service implementations, allowing extensions to leverage components like modals, notifications, and dialogs.
Overview
A typical web application will have components and state for common UI like
modals, notifications, dialogs, etc. A UI service makes it possible to leverage
these components from an extension.
We maintain the following UI Services:
- UI Notification Service
- UI Modal Service
- UI Dialog Service
- UI Viewport Dialog Service
- CINE Service
- Viewport Grid Service
Providers for UI services
There are several context providers that wraps the application routes. This
makes the context values exposed in the app, and service's setImplementation
can get run to override the implementation of the service.
function App({ config, defaultExtensions }) {
/**...**/
/**...**/
return (
/**...**/
<ViewportGridProvider service={ViewportGridService}>
<ViewportDialogProvider service={UIViewportDialogService}>
<CineProvider service={CineService}>
<SnackbarProvider service={UINotificationService}>
<DialogProvider service={UIDialogService}>
<ModalProvider modal={Modal} service={UIModalService}>
{appRoutes}
</ModalProvider>
</DialogProvider>
</SnackbarProvider>
</CineProvider>
</ViewportDialogProvider>
</ViewportGridProvider>
/**...**/
);
}Example
For instance UIModalService has the following Public API:
const publicAPI = {
name,
hide: _hide,
show: _show,
setServiceImplementation,
};
function setServiceImplementation({
hide: hideImplementation,
show: showImplementation,
}) {
/** ... **/
serviceImplementation._hide = hideImplementation;
serviceImplementation._show = showImplementation;
/** ... **/
}
export default {
name: 'UIModalService',
create: ({ configuration = {} }) => {
return publicAPI;
},
};UIModalService implementation can be set (override) in its context provider.
For instance in ModalProvider we have:
/* Detailed source-code truncated for AI context efficiency. */Therefore, anywhere in the app that we have access to react context we can use
it by calling the useModal from @ohif/ui. As a matter of fact, we are
utilizing the modal for the preference window which shows the hotkeys after
clicking on the gear button on the right side of the header.
A simplified code for our worklist is:
import { useModal, Header } from '@ohif/ui';
function WorkList({
history,
data: studies,
dataTotal: studiesTotal,
isLoadingData,
dataSource,
hotkeysManager,
}) {
const { show, hide } = useModal();
/** ... **/
const menuOptions = [
{
title: t('Header:About'),
icon: 'info',
onClick: () => show({ content: AboutModal, title: 'About OHIF Viewer' }),
},
{
title: t('Header:Preferences'),
icon: 'settings',
onClick: () =>
show({
title: t('UserPreferencesModal:User Preferences'),
content: UserPreferences,
contentProps: {
hotkeyDefaults: hotkeysManager.getValidHotkeyDefinitions(
hotkeyDefaults
),
hotkeyDefinitions,
onCancel: hide,
currentLanguage: currentLanguage(),
availableLanguages,
defaultLanguage,
onSubmit: state => {
i18n.changeLanguage(state.language.value);
hotkeysManager.setHotkeys(state.hotkeyDefinitions);
hide();
},
onReset: () => hotkeysManager.restoreDefaultBindings(),
},
}),
},
];
/** ... **/
return (
<div>
/** ... **/
<Header isSticky menuOptions={menuOptions} isReturnEnabled={false} />
/** ... **/
</div>
);
}Tips & Tricks
It's important to remember that all we're doing is making it possible to control
bits of the application's UI from an extension. Here are a few non-obvious
takeaways worth mentioning:
- Your application code should continue to use React context
(consumers/providers) as it normally would - You can substitute our "out of the box" UI implementations with your own
- You can create and register your own UI services
- You can choose not to register a service or provide a service implementation
- In extensions, you can provide fallback/alternative behavior if an expected
service is not registered- No
UIModalService? Use theUINotificationServiceto notify users.
- No
- You can technically register a service in an extension and expose it to the
core application
Note: These are recommended patterns, not hard and fast rules. Following them
will help reduce confusion and interoperability with the larger OHIF
community, but they're not silver bullets. Please speak up, create an issue,
if you would like to discuss new services or improvements to this pattern.
Platform Docs CHANGELOG (`platform/docs/CHANGELOG.md`)
Change Log
All notable changes to this project will be documented in this file.
See Conventional Commits for commit guidelines.
[3.13.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.88...v3.13.0-beta.89) (2026-06-10)
Note: Version bump only for package ohif-docs
[3.13.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.87...v3.13.0-beta.88) (2026-06-05)
Note: Version bump only for package ohif-docs
[3.13.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.86...v3.13.0-beta.87) (2026-05-29)
Note: Version bump only for package ohif-docs
[3.13.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.85...v3.13.0-beta.86) (2026-05-28)
Note: Version bump only for package ohif-docs
[3.13.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.84...v3.13.0-beta.85) (2026-05-28)
Features
- WorkList: New Study List (WorkList based on ui-next); old study list renamed to LegacyWorklist (#6005) (daae4c1)
[3.13.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.83...v3.13.0-beta.84) (2026-05-27)
Note: Version bump only for package ohif-docs
[3.13.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.82...v3.13.0-beta.83) (2026-05-26)
Note: Version bump only for package ohif-docs
[3.13.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.81...v3.13.0-beta.82) (2026-05-22)
Note: Version bump only for package ohif-docs
[3.13.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.80...v3.13.0-beta.81) (2026-05-21)
Note: Version bump only for package ohif-docs
[3.13.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.79...v3.13.0-beta.80) (2026-05-20)
Note: Version bump only for package ohif-docs
[3.13.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.78...v3.13.0-beta.79) (2026-05-19)
Note: Version bump only for package ohif-docs
[3.13.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.77...v3.13.0-beta.78) (2026-05-19)
Note: Version bump only for package ohif-docs
[3.13.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.76...v3.13.0-beta.77) (2026-05-19)
Note: Version bump only for package ohif-docs
[3.13.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.75...v3.13.0-beta.76) (2026-05-19)
Note: Version bump only for package ohif-docs
[3.13.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.74...v3.13.0-beta.75) (2026-05-18)
Note: Version bump only for package ohif-docs
[3.13.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.73...v3.13.0-beta.74) (2026-05-15)
Note: Version bump only for package ohif-docs
[3.13.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.72...v3.13.0-beta.73) (2026-05-13)
Note: Version bump only for package ohif-docs
[3.13.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.71...v3.13.0-beta.72) (2026-05-12)
Note: Version bump only for package ohif-docs
[3.13.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.70...v3.13.0-beta.71) (2026-05-07)
Note: Version bump only for package ohif-docs
[3.13.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.69...v3.13.0-beta.70) (2026-05-07)
Note: Version bump only for package ohif-docs
[3.13.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.68...v3.13.0-beta.69) (2026-05-06)
Note: Version bump only for package ohif-docs
[3.13.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.67...v3.13.0-beta.68) (2026-05-05)
Bug Fixes
- ToolGroupService: Centralize tool binding persistence and provide API to add and remove persisted bindings. (#5989) (979d619)
[3.13.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.66...v3.13.0-beta.67) (2026-04-30)
Note: Version bump only for package ohif-docs
[3.13.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.65...v3.13.0-beta.66) (2026-04-29)
Note: Version bump only for package ohif-docs
[3.13.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.64...v3.13.0-beta.65) (2026-04-29)
Note: Version bump only for package ohif-docs
[3.13.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.63...v3.13.0-beta.64) (2026-04-27)
Note: Version bump only for package ohif-docs
[3.13.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.62...v3.13.0-beta.63) (2026-04-27)
Bug Fixes
- security: refine dynamic config URL trust policy and document trusted-origin behavior (#5973) (f3cca21)
[3.13.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.61...v3.13.0-beta.62) (2026-04-23)
Note: Version bump only for package ohif-docs
[3.13.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.60...v3.13.0-beta.61) (2026-04-23)
Features
- slice scrollbar: Integrate ViewportSliceProgressScrollbar with customizations and docs (#5960) (8fc0dc1)
[3.13.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.59...v3.13.0-beta.60) (2026-04-21)
Bug Fixes
- configuration: Harden dynamic datasource URL trust boundaries and credential handling. (#5963) (eede569)
[3.13.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.58...v3.13.0-beta.59) (2026-04-16)
Note: Version bump only for package ohif-docs
[3.13.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.57...v3.13.0-beta.58) (2026-04-14)
Note: Version bump only for package ohif-docs
[3.13.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.56...v3.13.0-beta.57) (2026-04-13)
Note: Version bump only for package ohif-docs
[3.13.0-beta.56](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.55...v3.13.0-beta.56) (2026-04-10)
Note: Version bump only for package ohif-docs
[3.13.0-beta.55](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.54...v3.13.0-beta.55) (2026-04-10)
Note: Version bump only for package ohif-docs
[3.13.0-beta.54](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.53...v3.13.0-beta.54) (2026-04-08)
Note: Version bump only for package ohif-docs
[3.13.0-beta.53](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.52...v3.13.0-beta.53) (2026-04-06)
Note: Version bump only for package ohif-docs
[3.13.0-beta.52](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.51...v3.13.0-beta.52) (2026-04-06)
Note: Version bump only for package ohif-docs
[3.13.0-beta.51](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.50...v3.13.0-beta.51) (2026-04-03)
Note: Version bump only for package ohif-docs
[3.13.0-beta.50](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.49...v3.13.0-beta.50) (2026-04-02)
Note: Version bump only for package ohif-docs
[3.13.0-beta.49](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.48...v3.13.0-beta.49) (2026-04-02)
Note: Version bump only for package ohif-docs
[3.13.0-beta.48](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.47...v3.13.0-beta.48) (2026-04-01)
Note: Version bump only for package ohif-docs
[3.13.0-beta.47](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.46...v3.13.0-beta.47) (2026-03-28)
Note: Version bump only for package ohif-docs
[3.13.0-beta.46](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.45...v3.13.0-beta.46) (2026-03-27)
Note: Version bump only for package ohif-docs
[3.13.0-beta.45](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.44...v3.13.0-beta.45) (2026-03-27)
Note: Version bump only for package ohif-docs
[3.13.0-beta.44](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.43...v3.13.0-beta.44) (2026-03-27)
Note: Version bump only for package ohif-docs
[3.13.0-beta.43](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.42...v3.13.0-beta.43) (2026-03-17)
Note: Version bump only for package ohif-docs
[3.13.0-beta.42](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.41...v3.13.0-beta.42) (2026-03-17)
Features
[3.13.0-beta.41](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.40...v3.13.0-beta.41) (2026-03-16)
Note: Version bump only for package ohif-docs
[3.13.0-beta.40](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.39...v3.13.0-beta.40) (2026-03-13)
Note: Version bump only for package ohif-docs
[3.13.0-beta.39](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.38...v3.13.0-beta.39) (2026-03-13)
Note: Version bump only for package ohif-docs
[3.13.0-beta.38](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.37...v3.13.0-beta.38) (2026-03-12)
Note: Version bump only for package ohif-docs
[3.13.0-beta.37](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.36...v3.13.0-beta.37) (2026-03-12)
Note: Version bump only for package ohif-docs
[3.13.0-beta.36](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.35...v3.13.0-beta.36) (2026-03-11)
Note: Version bump only for package ohif-docs
[3.13.0-beta.35](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.34...v3.13.0-beta.35) (2026-03-09)
Note: Version bump only for package ohif-docs
[3.13.0-beta.34](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.33...v3.13.0-beta.34) (2026-03-09)
Note: Version bump only for package ohif-docs
[3.13.0-beta.33](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.32...v3.13.0-beta.33) (2026-03-05)
Bug Fixes
[3.13.0-beta.32](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.31...v3.13.0-beta.32) (2026-03-05)
Note: Version bump only for package ohif-docs
[3.13.0-beta.31](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.30...v3.13.0-beta.31) (2026-03-04)
Note: Version bump only for package ohif-docs
[3.13.0-beta.30](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.29...v3.13.0-beta.30) (2026-03-04)
Note: Version bump only for package ohif-docs
[3.13.0-beta.29](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.28...v3.13.0-beta.29) (2026-03-04)
Bug Fixes
[3.13.0-beta.28](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.27...v3.13.0-beta.28) (2026-03-03)
Note: Version bump only for package ohif-docs
[3.13.0-beta.27](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.26...v3.13.0-beta.27) (2026-03-02)
Note: Version bump only for package ohif-docs
[3.13.0-beta.26](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.25...v3.13.0-beta.26) (2026-02-28)
Note: Version bump only for package ohif-docs
[3.13.0-beta.25](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.24...v3.13.0-beta.25) (2026-02-26)
Note: Version bump only for package ohif-docs
[3.13.0-beta.24](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.23...v3.13.0-beta.24) (2026-02-24)
Note: Version bump only for package ohif-docs
[3.13.0-beta.23](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.22...v3.13.0-beta.23) (2026-02-23)
Note: Version bump only for package ohif-docs
[3.13.0-beta.22](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.21...v3.13.0-beta.22) (2026-02-23)
Note: Version bump only for package ohif-docs
[3.13.0-beta.21](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.20...v3.13.0-beta.21) (2026-02-23)
Note: Version bump only for package ohif-docs
[3.13.0-beta.20](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.19...v3.13.0-beta.20) (2026-02-21)
Note: Version bump only for package ohif-docs
[3.13.0-beta.19](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.18...v3.13.0-beta.19) (2026-02-20)
Note: Version bump only for package ohif-docs
[3.13.0-beta.18](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.17...v3.13.0-beta.18) (2026-02-19)
Bug Fixes
[3.13.0-beta.17](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.16...v3.13.0-beta.17) (2026-02-19)
Note: Version bump only for package ohif-docs
[3.13.0-beta.16](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.15...v3.13.0-beta.16) (2026-02-18)
Bug Fixes
[3.13.0-beta.15](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.14...v3.13.0-beta.15) (2026-02-17)
Note: Version bump only for package ohif-docs
[3.13.0-beta.14](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.13...v3.13.0-beta.14) (2026-02-13)
Note: Version bump only for package ohif-docs
[3.13.0-beta.13](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.12...v3.13.0-beta.13) (2026-02-12)
Bug Fixes
[3.13.0-beta.12](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.11...v3.13.0-beta.12) (2026-02-12)
Note: Version bump only for package ohif-docs
[3.13.0-beta.11](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.10...v3.13.0-beta.11) (2026-02-12)
Note: Version bump only for package ohif-docs
[3.13.0-beta.10](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.9...v3.13.0-beta.10) (2026-02-11)
Note: Version bump only for package ohif-docs
[3.13.0-beta.9](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.6...v3.13.0-beta.9) (2026-02-11)
Note: Version bump only for package ohif-docs
[3.13.0-beta.8](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.6...v3.13.0-beta.8) (2026-02-11)
Note: Version bump only for package ohif-docs
[3.13.0-beta.7](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.6...v3.13.0-beta.7) (2026-02-10)
Note: Version bump only for package ohif-docs
[3.13.0-beta.6](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.5...v3.13.0-beta.6) (2026-02-10)
Note: Version bump only for package ohif-docs
[3.13.0-beta.5](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.4...v3.13.0-beta.5) (2026-02-10)
Note: Version bump only for package ohif-docs
[3.13.0-beta.4](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.3...v3.13.0-beta.4) (2026-02-10)
Bug Fixes
[3.13.0-beta.3](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.2...v3.13.0-beta.3) (2026-02-10)
Note: Version bump only for package ohif-docs
[3.13.0-beta.2](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.1...v3.13.0-beta.2) (2026-02-10)
Bug Fixes
[3.13.0-beta.1](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.0...v3.13.0-beta.1) (2026-02-09)
Note: Version bump only for package ohif-docs
[3.13.0-beta.0](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.135...v3.13.0-beta.0) (2026-02-07)
Note: Version bump only for package ohif-docs
[3.12.0-beta.135](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.134...v3.12.0-beta.135) (2026-02-05)
Note: Version bump only for package ohif-docs
[3.12.0-beta.134](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.133...v3.12.0-beta.134) (2026-02-05)
Note: Version bump only for package ohif-docs
[3.12.0-beta.133](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.132...v3.12.0-beta.133) (2026-02-04)
Note: Version bump only for package ohif-docs
[3.12.0-beta.132](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.131...v3.12.0-beta.132) (2026-01-30)
Note: Version bump only for package ohif-docs
[3.12.0-beta.131](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.130...v3.12.0-beta.131) (2026-01-30)
Note: Version bump only for package ohif-docs
[3.12.0-beta.130](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.129...v3.12.0-beta.130) (2026-01-28)
Note: Version bump only for package ohif-docs
[3.12.0-beta.129](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.128...v3.12.0-beta.129) (2026-01-27)
Note: Version bump only for package ohif-docs
[3.12.0-beta.128](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.127...v3.12.0-beta.128) (2026-01-27)
Note: Version bump only for package ohif-docs
[3.12.0-beta.127](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.126...v3.12.0-beta.127) (2026-01-22)
Bug Fixes
[3.12.0-beta.126](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.125...v3.12.0-beta.126) (2026-01-22)
Note: Version bump only for package ohif-docs
[3.12.0-beta.125](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.124...v3.12.0-beta.125) (2026-01-21)
Note: Version bump only for package ohif-docs
[3.12.0-beta.124](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.123...v3.12.0-beta.124) (2026-01-16)
Bug Fixes
[3.12.0-beta.123](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.122...v3.12.0-beta.123) (2026-01-14)
Note: Version bump only for package ohif-docs
[3.12.0-beta.122](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.121...v3.12.0-beta.122) (2026-01-13)
Note: Version bump only for package ohif-docs
[3.12.0-beta.121](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.120...v3.12.0-beta.121) (2026-01-12)
Note: Version bump only for package ohif-docs
[3.12.0-beta.120](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.119...v3.12.0-beta.120) (2026-01-09)
Note: Version bump only for package ohif-docs
[3.12.0-beta.119](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.118...v3.12.0-beta.119) (2026-01-08)
Note: Version bump only for package ohif-docs
[3.12.0-beta.118](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.117...v3.12.0-beta.118) (2026-01-07)
Note: Version bump only for package ohif-docs
[3.12.0-beta.117](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.116...v3.12.0-beta.117) (2026-01-06)
Note: Version bump only for package ohif-docs
[3.12.0-beta.116](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.115...v3.12.0-beta.116) (2026-01-06)
Note: Version bump only for package ohif-docs
[3.12.0-beta.115](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.114...v3.12.0-beta.115) (2026-01-05)
Note: Version bump only for package ohif-docs
[3.12.0-beta.114](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.113...v3.12.0-beta.114) (2026-01-05)
Bug Fixes
[3.12.0-beta.113](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.112...v3.12.0-beta.113) (2025-12-19)
Note: Version bump only for package ohif-docs
[3.12.0-beta.112](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.111...v3.12.0-beta.112) (2025-12-19)
Note: Version bump only for package ohif-docs
[3.12.0-beta.111](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.110...v3.12.0-beta.111) (2025-12-18)
Note: Version bump only for package ohif-docs
[3.12.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.109...v3.12.0-beta.110) (2025-12-18)
Note: Version bump only for package ohif-docs
[3.12.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.108...v3.12.0-beta.109) (2025-12-18)
Note: Version bump only for package ohif-docs
[3.12.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.107...v3.12.0-beta.108) (2025-12-17)
Note: Version bump only for package ohif-docs
[3.12.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.106...v3.12.0-beta.107) (2025-12-16)
Note: Version bump only for package ohif-docs
[3.12.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.105...v3.12.0-beta.106) (2025-12-16)
Note: Version bump only for package ohif-docs
[3.12.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.104...v3.12.0-beta.105) (2025-12-15)
Note: Version bump only for package ohif-docs
[3.12.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.103...v3.12.0-beta.104) (2025-12-12)
Note: Version bump only for package ohif-docs
[3.12.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.102...v3.12.0-beta.103) (2025-12-12)
Note: Version bump only for package ohif-docs
[3.12.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.101...v3.12.0-beta.102) (2025-12-10)
Note: Version bump only for package ohif-docs
[3.12.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.100...v3.12.0-beta.101) (2025-12-09)
Note: Version bump only for package ohif-docs
[3.12.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.99...v3.12.0-beta.100) (2025-12-05)
Features
[3.12.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.98...v3.12.0-beta.99) (2025-12-04)
Bug Fixes
[3.12.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.97...v3.12.0-beta.98) (2025-12-03)
Note: Version bump only for package ohif-docs
[3.12.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.96...v3.12.0-beta.97) (2025-12-03)
Note: Version bump only for package ohif-docs
[3.12.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.95...v3.12.0-beta.96) (2025-12-02)
Note: Version bump only for package ohif-docs
[3.12.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.94...v3.12.0-beta.95) (2025-12-02)
Note: Version bump only for package ohif-docs
[3.12.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.93...v3.12.0-beta.94) (2025-12-02)
Note: Version bump only for package ohif-docs
[3.12.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.92...v3.12.0-beta.93) (2025-11-25)
Note: Version bump only for package ohif-docs
[3.12.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.91...v3.12.0-beta.92) (2025-11-24)
Note: Version bump only for package ohif-docs
[3.12.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.90...v3.12.0-beta.91) (2025-11-21)
Note: Version bump only for package ohif-docs
[3.12.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.89...v3.12.0-beta.90) (2025-11-21)
Note: Version bump only for package ohif-docs
[3.12.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.88...v3.12.0-beta.89) (2025-11-20)
Note: Version bump only for package ohif-docs
[3.12.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.87...v3.12.0-beta.88) (2025-11-20)
Note: Version bump only for package ohif-docs
[3.12.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.86...v3.12.0-beta.87) (2025-11-19)
Bug Fixes
[3.12.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.85...v3.12.0-beta.86) (2025-11-13)
Note: Version bump only for package ohif-docs
[3.12.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.84...v3.12.0-beta.85) (2025-11-11)
Bug Fixes
- interpolation: Auto accept interpolation when the interpolation process is completed. (#5555) (834ae3c)
[3.12.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.83...v3.12.0-beta.84) (2025-11-10)
Note: Version bump only for package ohif-docs
[3.12.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.82...v3.12.0-beta.83) (2025-11-06)
Note: Version bump only for package ohif-docs
[3.12.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.81...v3.12.0-beta.82) (2025-11-05)
Note: Version bump only for package ohif-docs
[3.12.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.80...v3.12.0-beta.81) (2025-11-05)
Bug Fixes
- SegmentationTools: [Bug] Changes of brush/eraser radius with hotkey do not reflect on segmentation tool (#5535) (29bd87c)
[3.12.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.79...v3.12.0-beta.80) (2025-11-05)
Note: Version bump only for package ohif-docs
[3.12.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.78...v3.12.0-beta.79) (2025-10-30)
Bug Fixes
[3.12.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.77...v3.12.0-beta.78) (2025-10-29)
Note: Version bump only for package ohif-docs
[3.12.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.76...v3.12.0-beta.77) (2025-10-28)
Note: Version bump only for package ohif-docs
[3.12.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.75...v3.12.0-beta.76) (2025-10-27)
Note: Version bump only for package ohif-docs
[3.12.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.74...v3.12.0-beta.75) (2025-10-24)
Bug Fixes
- security: For bun, enforce frozen lockfile. For yarn, strongly suggest using frozen lockfile. (#5508) (1009c60)
[3.12.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.73...v3.12.0-beta.74) (2025-10-23)
Note: Version bump only for package ohif-docs
[3.12.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.72...v3.12.0-beta.73) (2025-10-22)
Note: Version bump only for package ohif-docs
[3.12.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.71...v3.12.0-beta.72) (2025-10-22)
Note: Version bump only for package ohif-docs
[3.12.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.70...v3.12.0-beta.71) (2025-10-21)
Note: Version bump only for package ohif-docs
[3.12.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.69...v3.12.0-beta.70) (2025-10-20)
Note: Version bump only for package ohif-docs
[3.12.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.68...v3.12.0-beta.69) (2025-10-20)
Note: Version bump only for package ohif-docs
[3.12.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.67...v3.12.0-beta.68) (2025-10-18)
Note: Version bump only for package ohif-docs
[3.12.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.66...v3.12.0-beta.67) (2025-10-17)
Bug Fixes
[3.12.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.65...v3.12.0-beta.66) (2025-10-17)
Note: Version bump only for package ohif-docs
[3.12.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.64...v3.12.0-beta.65) (2025-10-17)
Note: Version bump only for package ohif-docs
[3.12.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.63...v3.12.0-beta.64) (2025-10-15)
Note: Version bump only for package ohif-docs
[3.12.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.62...v3.12.0-beta.63) (2025-10-15)
Note: Version bump only for package ohif-docs
[3.12.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.61...v3.12.0-beta.62) (2025-10-15)
Note: Version bump only for package ohif-docs
[3.12.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.60...v3.12.0-beta.61) (2025-10-15)
Bug Fixes
[3.12.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.59...v3.12.0-beta.60) (2025-10-15)
Note: Version bump only for package ohif-docs
[3.12.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.58...v3.12.0-beta.59) (2025-10-14)
Bug Fixes
[3.12.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.57...v3.12.0-beta.58) (2025-10-14)
Note: Version bump only for package ohif-docs
[3.12.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.56...v3.12.0-beta.57) (2025-10-14)
Note: Version bump only for package ohif-docs
[3.12.0-beta.56](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.55...v3.12.0-beta.56) (2025-10-10)
Note: Version bump only for package ohif-docs
[3.12.0-beta.55](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.54...v3.12.0-beta.55) (2025-10-09)
Note: Version bump only for package ohif-docs
[3.12.0-beta.54](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.53...v3.12.0-beta.54) (2025-10-08)
Note: Version bump only for package ohif-docs
[3.12.0-beta.53](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.52...v3.12.0-beta.53) (2025-10-07)
Note: Version bump only for package ohif-docs
[3.12.0-beta.52](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.51...v3.12.0-beta.52) (2025-10-07)
Note: Version bump only for package ohif-docs
[3.12.0-beta.51](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.50...v3.12.0-beta.51) (2025-10-07)
Note: Version bump only for package ohif-docs
[3.12.0-beta.50](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.49...v3.12.0-beta.50) (2025-10-07)
Note: Version bump only for package ohif-docs
[3.12.0-beta.49](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.48...v3.12.0-beta.49) (2025-10-07)
Note: Version bump only for package ohif-docs
[3.12.0-beta.48](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.47...v3.12.0-beta.48) (2025-10-07)
Note: Version bump only for package ohif-docs
[3.12.0-beta.47](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.46...v3.12.0-beta.47) (2025-10-07)
Note: Version bump only for package ohif-docs
[3.12.0-beta.46](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.45...v3.12.0-beta.46) (2025-10-06)
Note: Version bump only for package ohif-docs
[3.12.0-beta.45](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.44...v3.12.0-beta.45) (2025-10-06)
Note: Version bump only for package ohif-docs
[3.12.0-beta.44](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.43...v3.12.0-beta.44) (2025-10-06)
Note: Version bump only for package ohif-docs
[3.12.0-beta.43](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.42...v3.12.0-beta.43) (2025-10-06)
Note: Version bump only for package ohif-docs
[3.12.0-beta.42](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.41...v3.12.0-beta.42) (2025-10-03)
Note: Version bump only for package ohif-docs
[3.12.0-beta.41](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.40...v3.12.0-beta.41) (2025-10-03)
Note: Version bump only for package ohif-docs
[3.12.0-beta.40](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.39...v3.12.0-beta.40) (2025-10-02)
Note: Version bump only for package ohif-docs
[3.12.0-beta.39](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.38...v3.12.0-beta.39) (2025-10-01)
Features
[3.12.0-beta.38](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.37...v3.12.0-beta.38) (2025-09-30)
Note: Version bump only for package ohif-docs
[3.12.0-beta.37](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.36...v3.12.0-beta.37) (2025-09-30)
Note: Version bump only for package ohif-docs
[3.12.0-beta.36](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.35...v3.12.0-beta.36) (2025-09-30)
Note: Version bump only for package ohif-docs
[3.12.0-beta.35](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.34...v3.12.0-beta.35) (2025-09-29)
Note: Version bump only for package ohif-docs
[3.12.0-beta.34](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.33...v3.12.0-beta.34) (2025-09-29)
Note: Version bump only for package ohif-docs
[3.12.0-beta.33](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.32...v3.12.0-beta.33) (2025-09-29)
Note: Version bump only for package ohif-docs
[3.12.0-beta.32](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.31...v3.12.0-beta.32) (2025-09-26)
Note: Version bump only for package ohif-docs
[3.12.0-beta.31](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.30...v3.12.0-beta.31) (2025-09-25)
Note: Version bump only for package ohif-docs
[3.12.0-beta.30](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.29...v3.12.0-beta.30) (2025-09-25)
Note: Version bump only for package ohif-docs
[3.12.0-beta.29](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.28...v3.12.0-beta.29) (2025-09-22)
Features
[3.12.0-beta.28](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.27...v3.12.0-beta.28) (2025-09-19)
Note: Version bump only for package ohif-docs
[3.12.0-beta.27](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.26...v3.12.0-beta.27) (2025-09-17)
Note: Version bump only for package ohif-docs
[3.12.0-beta.26](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.25...v3.12.0-beta.26) (2025-09-17)
Note: Version bump only for package ohif-docs
[3.12.0-beta.25](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.24...v3.12.0-beta.25) (2025-09-16)
Note: Version bump only for package ohif-docs
[3.12.0-beta.24](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.23...v3.12.0-beta.24) (2025-09-10)
Note: Version bump only for package ohif-docs
[3.12.0-beta.23](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.22...v3.12.0-beta.23) (2025-09-05)
Note: Version bump only for package ohif-docs
[3.12.0-beta.22](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.21...v3.12.0-beta.22) (2025-08-29)
Note: Version bump only for package ohif-docs
[3.12.0-beta.21](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.20...v3.12.0-beta.21) (2025-08-29)
Note: Version bump only for package ohif-docs
[3.12.0-beta.20](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.19...v3.12.0-beta.20) (2025-08-28)
Note: Version bump only for package ohif-docs
[3.12.0-beta.19](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.18...v3.12.0-beta.19) (2025-08-28)
Note: Version bump only for package ohif-docs
[3.12.0-beta.18](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.17...v3.12.0-beta.18) (2025-08-28)
Note: Version bump only for package ohif-docs
[3.12.0-beta.17](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.16...v3.12.0-beta.17) (2025-08-28)
Note: Version bump only for package ohif-docs
[3.12.0-beta.16](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.15...v3.12.0-beta.16) (2025-08-25)
Note: Version bump only for package ohif-docs
[3.12.0-beta.15](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.14...v3.12.0-beta.15) (2025-08-25)
Note: Version bump only for package ohif-docs
[3.12.0-beta.14](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.13...v3.12.0-beta.14) (2025-08-25)
Note: Version bump only for package ohif-docs
[3.12.0-beta.13](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.12...v3.12.0-beta.13) (2025-08-25)
Note: Version bump only for package ohif-docs
[3.12.0-beta.12](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.11...v3.12.0-beta.12) (2025-08-25)
Bug Fixes
[3.12.0-beta.11](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.10...v3.12.0-beta.11) (2025-08-25)
Note: Version bump only for package ohif-docs
[3.12.0-beta.10](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.9...v3.12.0-beta.10) (2025-08-22)
Note: Version bump only for package ohif-docs
[3.12.0-beta.9](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.8...v3.12.0-beta.9) (2025-08-22)
Note: Version bump only for package ohif-docs
[3.12.0-beta.8](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.7...v3.12.0-beta.8) (2025-08-20)
Note: Version bump only for package ohif-docs
[3.12.0-beta.7](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.6...v3.12.0-beta.7) (2025-08-15)
Note: Version bump only for package ohif-docs
[3.12.0-beta.6](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.5...v3.12.0-beta.6) (2025-08-13)
Note: Version bump only for package ohif-docs
[3.12.0-beta.5](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.4...v3.12.0-beta.5) (2025-08-11)
Note: Version bump only for package ohif-docs
[3.12.0-beta.4](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.3...v3.12.0-beta.4) (2025-08-11)
Note: Version bump only for package ohif-docs
[3.12.0-beta.3](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.2...v3.12.0-beta.3) (2025-08-11)
Note: Version bump only for package ohif-docs
[3.12.0-beta.2](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.1...v3.12.0-beta.2) (2025-08-08)
Note: Version bump only for package ohif-docs
[3.12.0-beta.1](https://github.com/OHIF/Viewers/compare/v3.12.0-beta.0...v3.12.0-beta.1) (2025-08-05)
Note: Version bump only for package ohif-docs
[3.12.0-beta.0](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.116...v3.12.0-beta.0) (2025-08-05)
Note: Version bump only for package ohif-docs
[3.11.0-beta.116](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.115...v3.11.0-beta.116) (2025-08-05)
Note: Version bump only for package ohif-docs
[3.11.0-beta.115](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.114...v3.11.0-beta.115) (2025-07-31)
Features
[3.11.0-beta.114](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.113...v3.11.0-beta.114) (2025-07-30)
Note: Version bump only for package ohif-docs
[3.11.0-beta.113](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.112...v3.11.0-beta.113) (2025-07-30)
Note: Version bump only for package ohif-docs
[3.11.0-beta.112](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.111...v3.11.0-beta.112) (2025-07-28)
Note: Version bump only for package ohif-docs
[3.11.0-beta.111](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.110...v3.11.0-beta.111) (2025-07-28)
Note: Version bump only for package ohif-docs
[3.11.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.109...v3.11.0-beta.110) (2025-07-28)
Note: Version bump only for package ohif-docs
[3.11.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.108...v3.11.0-beta.109) (2025-07-28)
Note: Version bump only for package ohif-docs
[3.11.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.107...v3.11.0-beta.108) (2025-07-25)
Note: Version bump only for package ohif-docs
[3.11.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.106...v3.11.0-beta.107) (2025-07-25)
Note: Version bump only for package ohif-docs
[3.11.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.105...v3.11.0-beta.106) (2025-07-24)
Note: Version bump only for package ohif-docs
[3.11.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.104...v3.11.0-beta.105) (2025-07-23)
Note: Version bump only for package ohif-docs
[3.11.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.103...v3.11.0-beta.104) (2025-07-23)
Note: Version bump only for package ohif-docs
[3.11.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.102...v3.11.0-beta.103) (2025-07-23)
Note: Version bump only for package ohif-docs
[3.11.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.101...v3.11.0-beta.102) (2025-07-23)
Note: Version bump only for package ohif-docs
[3.11.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.100...v3.11.0-beta.101) (2025-07-23)
Note: Version bump only for package ohif-docs
[3.11.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.99...v3.11.0-beta.100) (2025-07-23)
Note: Version bump only for package ohif-docs
[3.11.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.98...v3.11.0-beta.99) (2025-07-23)
Note: Version bump only for package ohif-docs
[3.11.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.97...v3.11.0-beta.98) (2025-07-23)
Bug Fixes
[3.11.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.96...v3.11.0-beta.97) (2025-07-22)
Note: Version bump only for package ohif-docs
[3.11.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.95...v3.11.0-beta.96) (2025-07-22)
Note: Version bump only for package ohif-docs
[3.11.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.94...v3.11.0-beta.95) (2025-07-21)
Bug Fixes
[3.11.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.93...v3.11.0-beta.94) (2025-07-21)
Note: Version bump only for package ohif-docs
[3.11.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.92...v3.11.0-beta.93) (2025-07-21)
Note: Version bump only for package ohif-docs
[3.11.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.91...v3.11.0-beta.92) (2025-07-18)
Note: Version bump only for package ohif-docs
[3.11.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.90...v3.11.0-beta.91) (2025-07-17)
Bug Fixes
- image slices are displayed in reverse order, if we switch from common layout to 2D MPR (#5022) (6a4ca70)
[3.11.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.89...v3.11.0-beta.90) (2025-07-16)
Note: Version bump only for package ohif-docs
[3.11.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.88...v3.11.0-beta.89) (2025-07-16)
Note: Version bump only for package ohif-docs
[3.11.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.87...v3.11.0-beta.88) (2025-07-16)
Note: Version bump only for package ohif-docs
[3.11.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.86...v3.11.0-beta.87) (2025-07-15)
Note: Version bump only for package ohif-docs
[3.11.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.85...v3.11.0-beta.86) (2025-07-14)
Note: Version bump only for package ohif-docs
[3.11.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.84...v3.11.0-beta.85) (2025-07-14)
Note: Version bump only for package ohif-docs
[3.11.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.83...v3.11.0-beta.84) (2025-07-14)
Note: Version bump only for package ohif-docs
[3.11.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.82...v3.11.0-beta.83) (2025-07-11)
Note: Version bump only for package ohif-docs
[3.11.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.81...v3.11.0-beta.82) (2025-07-11)
Note: Version bump only for package ohif-docs
[3.11.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.80...v3.11.0-beta.81) (2025-07-11)
Note: Version bump only for package ohif-docs
[3.11.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.79...v3.11.0-beta.80) (2025-07-11)
Note: Version bump only for package ohif-docs
[3.11.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.78...v3.11.0-beta.79) (2025-07-11)
Note: Version bump only for package ohif-docs
[3.11.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.77...v3.11.0-beta.78) (2025-07-11)
Note: Version bump only for package ohif-docs
[3.11.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.76...v3.11.0-beta.77) (2025-07-10)
Note: Version bump only for package ohif-docs
[3.11.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.75...v3.11.0-beta.76) (2025-07-10)
Note: Version bump only for package ohif-docs
[3.11.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.74...v3.11.0-beta.75) (2025-07-09)
Note: Version bump only for package ohif-docs
[3.11.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.73...v3.11.0-beta.74) (2025-07-08)
Note: Version bump only for package ohif-docs
[3.11.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.72...v3.11.0-beta.73) (2025-07-07)
Note: Version bump only for package ohif-docs
[3.11.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.71...v3.11.0-beta.72) (2025-07-03)
Note: Version bump only for package ohif-docs
[3.11.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.70...v3.11.0-beta.71) (2025-07-03)
Note: Version bump only for package ohif-docs
[3.11.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.69...v3.11.0-beta.70) (2025-07-03)
Note: Version bump only for package ohif-docs
[3.11.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.68...v3.11.0-beta.69) (2025-07-02)
Note: Version bump only for package ohif-docs
[3.11.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.67...v3.11.0-beta.68) (2025-06-27)
Note: Version bump only for package ohif-docs
[3.11.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.66...v3.11.0-beta.67) (2025-06-27)
Note: Version bump only for package ohif-docs
[3.11.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.65...v3.11.0-beta.66) (2025-06-27)
Note: Version bump only for package ohif-docs
[3.11.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.64...v3.11.0-beta.65) (2025-06-26)
Note: Version bump only for package ohif-docs
[3.11.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.63...v3.11.0-beta.64) (2025-06-26)
Note: Version bump only for package ohif-docs
[3.11.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.62...v3.11.0-beta.63) (2025-06-26)
Note: Version bump only for package ohif-docs
[3.11.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.61...v3.11.0-beta.62) (2025-06-25)
Note: Version bump only for package ohif-docs
[3.11.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.60...v3.11.0-beta.61) (2025-06-25)
Note: Version bump only for package ohif-docs
[3.11.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.59...v3.11.0-beta.60) (2025-06-24)
Note: Version bump only for package ohif-docs
[3.11.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.58...v3.11.0-beta.59) (2025-06-20)
Note: Version bump only for package ohif-docs
[3.11.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.57...v3.11.0-beta.58) (2025-06-18)
Note: Version bump only for package ohif-docs
[3.11.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.56...v3.11.0-beta.57) (2025-06-18)
Note: Version bump only for package ohif-docs
[3.11.0-beta.56](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.55...v3.11.0-beta.56) (2025-06-13)
Note: Version bump only for package ohif-docs
[3.11.0-beta.55](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.54...v3.11.0-beta.55) (2025-06-11)
Note: Version bump only for package ohif-docs
[3.11.0-beta.54](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.53...v3.11.0-beta.54) (2025-06-11)
Note: Version bump only for package ohif-docs
[3.11.0-beta.53](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.52...v3.11.0-beta.53) (2025-06-11)
Bug Fixes
[3.11.0-beta.52](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.51...v3.11.0-beta.52) (2025-06-10)
Note: Version bump only for package ohif-docs
[3.11.0-beta.51](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.50...v3.11.0-beta.51) (2025-06-09)
Note: Version bump only for package ohif-docs
[3.11.0-beta.50](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.49...v3.11.0-beta.50) (2025-06-09)
Note: Version bump only for package ohif-docs
[3.11.0-beta.49](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.48...v3.11.0-beta.49) (2025-06-07)
Note: Version bump only for package ohif-docs
[3.11.0-beta.48](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.47...v3.11.0-beta.48) (2025-06-05)
Note: Version bump only for package ohif-docs
[3.11.0-beta.47](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.46...v3.11.0-beta.47) (2025-06-02)
Note: Version bump only for package ohif-docs
[3.11.0-beta.46](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.45...v3.11.0-beta.46) (2025-06-02)
Note: Version bump only for package ohif-docs
[3.11.0-beta.45](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.44...v3.11.0-beta.45) (2025-05-30)
Note: Version bump only for package ohif-docs
[3.11.0-beta.44](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.43...v3.11.0-beta.44) (2025-05-29)
Features
[3.11.0-beta.43](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.42...v3.11.0-beta.43) (2025-05-29)
Note: Version bump only for package ohif-docs
[3.11.0-beta.42](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.41...v3.11.0-beta.42) (2025-05-28)
Note: Version bump only for package ohif-docs
[3.11.0-beta.41](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.40...v3.11.0-beta.41) (2025-05-26)
Note: Version bump only for package ohif-docs
[3.11.0-beta.40](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.39...v3.11.0-beta.40) (2025-05-26)
Note: Version bump only for package ohif-docs
[3.11.0-beta.39](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.38...v3.11.0-beta.39) (2025-05-26)
Note: Version bump only for package ohif-docs
[3.11.0-beta.38](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.37...v3.11.0-beta.38) (2025-05-24)
Note: Version bump only for package ohif-docs
[3.11.0-beta.37](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.36...v3.11.0-beta.37) (2025-05-16)
Note: Version bump only for package ohif-docs
[3.11.0-beta.36](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.35...v3.11.0-beta.36) (2025-05-16)
Bug Fixes
[3.11.0-beta.35](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.34...v3.11.0-beta.35) (2025-05-16)
Note: Version bump only for package ohif-docs
[3.11.0-beta.34](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.33...v3.11.0-beta.34) (2025-05-15)
Note: Version bump only for package ohif-docs
[3.11.0-beta.33](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.32...v3.11.0-beta.33) (2025-05-15)
Features
[3.11.0-beta.32](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.31...v3.11.0-beta.32) (2025-05-13)
Note: Version bump only for package ohif-docs
[3.11.0-beta.31](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.30...v3.11.0-beta.31) (2025-05-12)
Note: Version bump only for package ohif-docs
[3.11.0-beta.30](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.29...v3.11.0-beta.30) (2025-05-09)
Note: Version bump only for package ohif-docs
[3.11.0-beta.29](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.28...v3.11.0-beta.29) (2025-05-08)
Features
[3.11.0-beta.28](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.27...v3.11.0-beta.28) (2025-05-08)
Features
[3.11.0-beta.27](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.26...v3.11.0-beta.27) (2025-05-07)
Note: Version bump only for package ohif-docs
[3.11.0-beta.26](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.25...v3.11.0-beta.26) (2025-05-07)
Note: Version bump only for package ohif-docs
[3.11.0-beta.25](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.24...v3.11.0-beta.25) (2025-05-06)
Note: Version bump only for package ohif-docs
[3.11.0-beta.24](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.23...v3.11.0-beta.24) (2025-05-05)
Features
- data overlay: add foreground background control plus orientation change in the UI and add RTDOSE support (#5007) (cd4e640)
[3.11.0-beta.23](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.22...v3.11.0-beta.23) (2025-05-05)
Note: Version bump only for package ohif-docs
[3.11.0-beta.22](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.21...v3.11.0-beta.22) (2025-05-02)
Note: Version bump only for package ohif-docs
[3.11.0-beta.21](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.20...v3.11.0-beta.21) (2025-05-02)
Note: Version bump only for package ohif-docs
[3.11.0-beta.20](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.19...v3.11.0-beta.20) (2025-05-01)
Note: Version bump only for package ohif-docs
[3.11.0-beta.19](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.18...v3.11.0-beta.19) (2025-05-01)
Note: Version bump only for package ohif-docs
[3.11.0-beta.18](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.17...v3.11.0-beta.18) (2025-04-30)
Note: Version bump only for package ohif-docs
[3.11.0-beta.17](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.16...v3.11.0-beta.17) (2025-04-29)
Note: Version bump only for package ohif-docs
[3.11.0-beta.16](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.15...v3.11.0-beta.16) (2025-04-29)
Note: Version bump only for package ohif-docs
[3.11.0-beta.15](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.14...v3.11.0-beta.15) (2025-04-22)
Bug Fixes
- docs: Fix SSR build errors by dynamically importing UI components and resolving other issues (#4991) (09ac43f)
[3.11.0-beta.14](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.13...v3.11.0-beta.14) (2025-04-22)
Note: Version bump only for package ohif-docs
[3.11.0-beta.13](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.12...v3.11.0-beta.13) (2025-04-22)
Note: Version bump only for package ohif-docs
[3.11.0-beta.12](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.11...v3.11.0-beta.12) (2025-04-22)
Note: Version bump only for package ohif-docs
[3.11.0-beta.11](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.10...v3.11.0-beta.11) (2025-04-18)
Note: Version bump only for package ohif-docs
[3.11.0-beta.10](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.9...v3.11.0-beta.10) (2025-04-17)
Note: Version bump only for package ohif-docs
[3.11.0-beta.9](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.8...v3.11.0-beta.9) (2025-04-17)
Note: Version bump only for package ohif-docs
[3.11.0-beta.8](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.7...v3.11.0-beta.8) (2025-04-16)
Note: Version bump only for package ohif-docs
[3.11.0-beta.7](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.6...v3.11.0-beta.7) (2025-04-16)
Note: Version bump only for package ohif-docs
[3.11.0-beta.6](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.5...v3.11.0-beta.6) (2025-04-16)
Note: Version bump only for package ohif-docs
[3.11.0-beta.5](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.4...v3.11.0-beta.5) (2025-04-14)
Note: Version bump only for package ohif-docs
[3.11.0-beta.4](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.3...v3.11.0-beta.4) (2025-04-11)
Note: Version bump only for package ohif-docs
[3.11.0-beta.3](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.2...v3.11.0-beta.3) (2025-04-11)
Note: Version bump only for package ohif-docs
[3.11.0-beta.2](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.1...v3.11.0-beta.2) (2025-04-11)
Note: Version bump only for package ohif-docs
[3.11.0-beta.1](https://github.com/OHIF/Viewers/compare/v3.11.0-beta.0...v3.11.0-beta.1) (2025-04-10)
Note: Version bump only for package ohif-docs
[3.11.0-beta.0](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.159...v3.11.0-beta.0) (2025-04-10)
Note: Version bump only for package ohif-docs
[3.10.0-beta.159](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.158...v3.10.0-beta.159) (2025-04-09)
Bug Fixes
- ui: Enhance UI Components and Update CornerstoneJS Dependencies and resizable panels (#4938) (43bc142)
[3.10.0-beta.158](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.157...v3.10.0-beta.158) (2025-04-09)
Note: Version bump only for package ohif-docs
[3.10.0-beta.157](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.156...v3.10.0-beta.157) (2025-04-09)
Note: Version bump only for package ohif-docs
[3.10.0-beta.156](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.155...v3.10.0-beta.156) (2025-04-08)
Note: Version bump only for package ohif-docs
[3.10.0-beta.155](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.154...v3.10.0-beta.155) (2025-04-08)
Note: Version bump only for package ohif-docs
[3.10.0-beta.154](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.153...v3.10.0-beta.154) (2025-04-08)
Note: Version bump only for package ohif-docs
[3.10.0-beta.153](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.152...v3.10.0-beta.153) (2025-04-08)
Note: Version bump only for package ohif-docs
[3.10.0-beta.152](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.151...v3.10.0-beta.152) (2025-04-07)
Note: Version bump only for package ohif-docs
[3.10.0-beta.151](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.150...v3.10.0-beta.151) (2025-04-07)
Note: Version bump only for package ohif-docs
[3.10.0-beta.150](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.149...v3.10.0-beta.150) (2025-04-04)
Bug Fixes
[3.10.0-beta.149](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.148...v3.10.0-beta.149) (2025-04-04)
Features
[3.10.0-beta.148](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.147...v3.10.0-beta.148) (2025-04-04)
Features
[3.10.0-beta.147](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.146...v3.10.0-beta.147) (2025-04-03)
Note: Version bump only for package ohif-docs
[3.10.0-beta.146](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.145...v3.10.0-beta.146) (2025-04-02)
Note: Version bump only for package ohif-docs
[3.10.0-beta.145](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.144...v3.10.0-beta.145) (2025-04-02)
Note: Version bump only for package ohif-docs
[3.10.0-beta.144](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.143...v3.10.0-beta.144) (2025-04-01)
Note: Version bump only for package ohif-docs
[3.10.0-beta.143](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.142...v3.10.0-beta.143) (2025-04-01)
Note: Version bump only for package ohif-docs
[3.10.0-beta.142](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.141...v3.10.0-beta.142) (2025-03-31)
Note: Version bump only for package ohif-docs
[3.10.0-beta.141](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.140...v3.10.0-beta.141) (2025-03-28)
Note: Version bump only for package ohif-docs
[3.10.0-beta.140](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.139...v3.10.0-beta.140) (2025-03-27)
Bug Fixes
[3.10.0-beta.139](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.138...v3.10.0-beta.139) (2025-03-27)
Note: Version bump only for package ohif-docs
[3.10.0-beta.138](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.137...v3.10.0-beta.138) (2025-03-26)
Bug Fixes
[3.10.0-beta.137](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.136...v3.10.0-beta.137) (2025-03-26)
Note: Version bump only for package ohif-docs
[3.10.0-beta.136](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.135...v3.10.0-beta.136) (2025-03-25)
Note: Version bump only for package ohif-docs
[3.10.0-beta.135](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.134...v3.10.0-beta.135) (2025-03-25)
Note: Version bump only for package ohif-docs
[3.10.0-beta.134](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.133...v3.10.0-beta.134) (2025-03-20)
Note: Version bump only for package ohif-docs
[3.10.0-beta.133](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.132...v3.10.0-beta.133) (2025-03-20)
Features
[3.10.0-beta.132](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.131...v3.10.0-beta.132) (2025-03-20)
Features
[3.10.0-beta.131](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.130...v3.10.0-beta.131) (2025-03-19)
Note: Version bump only for package ohif-docs
[3.10.0-beta.130](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.129...v3.10.0-beta.130) (2025-03-19)
Note: Version bump only for package ohif-docs
[3.10.0-beta.129](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.128...v3.10.0-beta.129) (2025-03-18)
Note: Version bump only for package ohif-docs
[3.10.0-beta.128](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.127...v3.10.0-beta.128) (2025-03-18)
Note: Version bump only for package ohif-docs
[3.10.0-beta.127](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.126...v3.10.0-beta.127) (2025-03-18)
Note: Version bump only for package ohif-docs
[3.10.0-beta.126](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.125...v3.10.0-beta.126) (2025-03-18)
Features
- segmentation: segment statistics, labelmap interpolation and segment bidirectional (#4865) (ec79b55)
[3.10.0-beta.125](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.124...v3.10.0-beta.125) (2025-03-17)
Note: Version bump only for package ohif-docs
[3.10.0-beta.124](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.123...v3.10.0-beta.124) (2025-03-17)
Note: Version bump only for package ohif-docs
[3.10.0-beta.123](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.122...v3.10.0-beta.123) (2025-03-17)
Note: Version bump only for package ohif-docs
[3.10.0-beta.122](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.121...v3.10.0-beta.122) (2025-03-17)
Note: Version bump only for package ohif-docs
[3.10.0-beta.121](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.120...v3.10.0-beta.121) (2025-03-11)
Note: Version bump only for package ohif-docs
[3.10.0-beta.120](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.119...v3.10.0-beta.120) (2025-03-11)
Note: Version bump only for package ohif-docs
[3.10.0-beta.119](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.118...v3.10.0-beta.119) (2025-03-10)
Note: Version bump only for package ohif-docs
[3.10.0-beta.118](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.117...v3.10.0-beta.118) (2025-03-07)
Note: Version bump only for package ohif-docs
[3.10.0-beta.117](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.116...v3.10.0-beta.117) (2025-03-07)
Features
[3.10.0-beta.116](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.115...v3.10.0-beta.116) (2025-03-06)
Note: Version bump only for package ohif-docs
[3.10.0-beta.115](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.114...v3.10.0-beta.115) (2025-02-28)
Note: Version bump only for package ohif-docs
[3.10.0-beta.114](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.113...v3.10.0-beta.114) (2025-02-28)
Note: Version bump only for package ohif-docs
[3.10.0-beta.113](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.112...v3.10.0-beta.113) (2025-02-28)
Note: Version bump only for package ohif-docs
[3.10.0-beta.112](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.111...v3.10.0-beta.112) (2025-02-28)
Features
[3.10.0-beta.111](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.110...v3.10.0-beta.111) (2025-02-26)
Note: Version bump only for package ohif-docs
[3.10.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.109...v3.10.0-beta.110) (2025-02-26)
Note: Version bump only for package ohif-docs
[3.10.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.108...v3.10.0-beta.109) (2025-02-25)
Note: Version bump only for package ohif-docs
[3.10.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.107...v3.10.0-beta.108) (2025-02-25)
Note: Version bump only for package ohif-docs
[3.10.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.106...v3.10.0-beta.107) (2025-02-25)
Note: Version bump only for package ohif-docs
[3.10.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.105...v3.10.0-beta.106) (2025-02-25)
Features
[3.10.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.104...v3.10.0-beta.105) (2025-02-25)
Note: Version bump only for package ohif-docs
[3.10.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.103...v3.10.0-beta.104) (2025-02-25)
Note: Version bump only for package ohif-docs
[3.10.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.102...v3.10.0-beta.103) (2025-02-23)
Note: Version bump only for package ohif-docs
[3.10.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.101...v3.10.0-beta.102) (2025-02-20)
Note: Version bump only for package ohif-docs
[3.10.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.100...v3.10.0-beta.101) (2025-02-20)
Note: Version bump only for package ohif-docs
[3.10.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.99...v3.10.0-beta.100) (2025-02-19)
Note: Version bump only for package ohif-docs
[3.10.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.98...v3.10.0-beta.99) (2025-02-18)
Note: Version bump only for package ohif-docs
[3.10.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.97...v3.10.0-beta.98) (2025-02-18)
Note: Version bump only for package ohif-docs
[3.10.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.96...v3.10.0-beta.97) (2025-02-18)
Note: Version bump only for package ohif-docs
[3.10.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.95...v3.10.0-beta.96) (2025-02-18)
Note: Version bump only for package ohif-docs
[3.10.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.94...v3.10.0-beta.95) (2025-02-13)
Note: Version bump only for package ohif-docs
[3.10.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.93...v3.10.0-beta.94) (2025-02-11)
Note: Version bump only for package ohif-docs
[3.10.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.92...v3.10.0-beta.93) (2025-02-04)
Note: Version bump only for package ohif-docs
[3.10.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.91...v3.10.0-beta.92) (2025-02-04)
Bug Fixes
- core: Address 3D reconstruction and Android compatibility issues and clean up 4D data mode (#4762) (149d6d0)
[3.10.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.90...v3.10.0-beta.91) (2025-02-04)
Note: Version bump only for package ohif-docs
[3.10.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.89...v3.10.0-beta.90) (2025-02-04)
Features
[3.10.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.88...v3.10.0-beta.89) (2025-02-04)
Features
[3.10.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.87...v3.10.0-beta.88) (2025-02-04)
Note: Version bump only for package ohif-docs
[3.10.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.86...v3.10.0-beta.87) (2025-02-03)
Note: Version bump only for package ohif-docs
[3.10.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.85...v3.10.0-beta.86) (2025-02-03)
Note: Version bump only for package ohif-docs
[3.10.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.84...v3.10.0-beta.85) (2025-02-03)
Features
[3.10.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.83...v3.10.0-beta.84) (2025-01-31)
Note: Version bump only for package ohif-docs
[3.10.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.82...v3.10.0-beta.83) (2025-01-31)
Note: Version bump only for package ohif-docs
[3.10.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.81...v3.10.0-beta.82) (2025-01-31)
Note: Version bump only for package ohif-docs
[3.10.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.80...v3.10.0-beta.81) (2025-01-29)
Note: Version bump only for package ohif-docs
[3.10.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.79...v3.10.0-beta.80) (2025-01-29)
Features
[3.10.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.78...v3.10.0-beta.79) (2025-01-28)
Bug Fixes
[3.10.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.77...v3.10.0-beta.78) (2025-01-28)
Note: Version bump only for package ohif-docs
[3.10.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.76...v3.10.0-beta.77) (2025-01-28)
Note: Version bump only for package ohif-docs
[3.10.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.75...v3.10.0-beta.76) (2025-01-27)
Note: Version bump only for package ohif-docs
[3.10.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.74...v3.10.0-beta.75) (2025-01-27)
Features
[3.10.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.73...v3.10.0-beta.74) (2025-01-27)
Note: Version bump only for package ohif-docs
[3.10.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.72...v3.10.0-beta.73) (2025-01-24)
Bug Fixes
[3.10.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.71...v3.10.0-beta.72) (2025-01-24)
Note: Version bump only for package ohif-docs
[3.10.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.70...v3.10.0-beta.71) (2025-01-23)
Features
[3.10.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.69...v3.10.0-beta.70) (2025-01-23)
Note: Version bump only for package ohif-docs
[3.10.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.68...v3.10.0-beta.69) (2025-01-22)
Bug Fixes
[3.10.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.67...v3.10.0-beta.68) (2025-01-21)
Note: Version bump only for package ohif-docs
[3.10.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.66...v3.10.0-beta.67) (2025-01-21)
Bug Fixes
[3.10.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.65...v3.10.0-beta.66) (2025-01-21)
Note: Version bump only for package ohif-docs
[3.10.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.64...v3.10.0-beta.65) (2025-01-20)
Note: Version bump only for package ohif-docs
[3.10.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.63...v3.10.0-beta.64) (2025-01-20)
Note: Version bump only for package ohif-docs
[3.10.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.62...v3.10.0-beta.63) (2025-01-17)
Note: Version bump only for package ohif-docs
[3.10.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.61...v3.10.0-beta.62) (2025-01-16)
Note: Version bump only for package ohif-docs
[3.10.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.60...v3.10.0-beta.61) (2025-01-16)
Note: Version bump only for package ohif-docs
[3.10.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.59...v3.10.0-beta.60) (2025-01-15)
Note: Version bump only for package ohif-docs
[3.10.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.58...v3.10.0-beta.59) (2025-01-14)
Note: Version bump only for package ohif-docs
[3.10.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.57...v3.10.0-beta.58) (2025-01-13)
Features
[3.10.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.56...v3.10.0-beta.57) (2025-01-13)
Note: Version bump only for package ohif-docs
[3.10.0-beta.56](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.55...v3.10.0-beta.56) (2025-01-13)
Note: Version bump only for package ohif-docs
[3.10.0-beta.55](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.54...v3.10.0-beta.55) (2025-01-10)
Features
[3.10.0-beta.54](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.53...v3.10.0-beta.54) (2025-01-10)
Note: Version bump only for package ohif-docs
[3.10.0-beta.53](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.52...v3.10.0-beta.53) (2025-01-10)
Note: Version bump only for package ohif-docs
[3.10.0-beta.52](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.51...v3.10.0-beta.52) (2025-01-10)
Note: Version bump only for package ohif-docs
[3.10.0-beta.51](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.50...v3.10.0-beta.51) (2025-01-10)
Note: Version bump only for package ohif-docs
[3.10.0-beta.50](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.49...v3.10.0-beta.50) (2025-01-10)
Note: Version bump only for package ohif-docs
[3.10.0-beta.49](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.48...v3.10.0-beta.49) (2025-01-09)
Note: Version bump only for package ohif-docs
[3.10.0-beta.48](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.47...v3.10.0-beta.48) (2025-01-09)
Note: Version bump only for package ohif-docs
[3.10.0-beta.47](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.46...v3.10.0-beta.47) (2025-01-09)
Note: Version bump only for package ohif-docs
[3.10.0-beta.46](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.45...v3.10.0-beta.46) (2025-01-08)
Note: Version bump only for package ohif-docs
[3.10.0-beta.45](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.44...v3.10.0-beta.45) (2025-01-08)
Note: Version bump only for package ohif-docs
[3.10.0-beta.44](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.43...v3.10.0-beta.44) (2025-01-08)
Note: Version bump only for package ohif-docs
[3.10.0-beta.43](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.42...v3.10.0-beta.43) (2025-01-08)
Note: Version bump only for package ohif-docs
[3.10.0-beta.42](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.41...v3.10.0-beta.42) (2025-01-08)
Note: Version bump only for package ohif-docs
[3.10.0-beta.41](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.40...v3.10.0-beta.41) (2025-01-08)
Note: Version bump only for package ohif-docs
[3.10.0-beta.40](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.39...v3.10.0-beta.40) (2025-01-08)
Note: Version bump only for package ohif-docs
[3.10.0-beta.39](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.38...v3.10.0-beta.39) (2025-01-08)
Note: Version bump only for package ohif-docs
[3.10.0-beta.38](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.37...v3.10.0-beta.38) (2025-01-07)
Note: Version bump only for package ohif-docs
[3.10.0-beta.37](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.36...v3.10.0-beta.37) (2025-01-06)
Note: Version bump only for package ohif-docs
[3.10.0-beta.36](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.35...v3.10.0-beta.36) (2025-01-03)
Note: Version bump only for package ohif-docs
[3.10.0-beta.35](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.34...v3.10.0-beta.35) (2025-01-03)
Note: Version bump only for package ohif-docs
[3.10.0-beta.34](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.33...v3.10.0-beta.34) (2025-01-02)
Bug Fixes
[3.10.0-beta.33](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.32...v3.10.0-beta.33) (2024-12-20)
Note: Version bump only for package ohif-docs
[3.10.0-beta.32](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.31...v3.10.0-beta.32) (2024-12-20)
Note: Version bump only for package ohif-docs
[3.10.0-beta.31](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.30...v3.10.0-beta.31) (2024-12-20)
Note: Version bump only for package ohif-docs
[3.10.0-beta.30](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.29...v3.10.0-beta.30) (2024-12-18)
Note: Version bump only for package ohif-docs
[3.10.0-beta.29](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.28...v3.10.0-beta.29) (2024-12-18)
Note: Version bump only for package ohif-docs
[3.10.0-beta.28](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.27...v3.10.0-beta.28) (2024-12-18)
Note: Version bump only for package ohif-docs
[3.10.0-beta.27](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.26...v3.10.0-beta.27) (2024-12-18)
Note: Version bump only for package ohif-docs
[3.10.0-beta.26](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.25...v3.10.0-beta.26) (2024-12-18)
Note: Version bump only for package ohif-docs
[3.10.0-beta.25](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.24...v3.10.0-beta.25) (2024-12-17)
Bug Fixes
[3.10.0-beta.24](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.23...v3.10.0-beta.24) (2024-12-17)
Features
[3.10.0-beta.23](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.22...v3.10.0-beta.23) (2024-12-17)
Note: Version bump only for package ohif-docs
[3.10.0-beta.22](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.21...v3.10.0-beta.22) (2024-12-13)
Note: Version bump only for package ohif-docs
[3.10.0-beta.21](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.20...v3.10.0-beta.21) (2024-12-11)
Features
[3.10.0-beta.20](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.19...v3.10.0-beta.20) (2024-12-11)
Note: Version bump only for package ohif-docs
[3.10.0-beta.19](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.18...v3.10.0-beta.19) (2024-12-11)
Note: Version bump only for package ohif-docs
[3.10.0-beta.18](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.17...v3.10.0-beta.18) (2024-12-06)
Note: Version bump only for package ohif-docs
[3.10.0-beta.17](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.16...v3.10.0-beta.17) (2024-12-06)
Note: Version bump only for package ohif-docs
[3.10.0-beta.16](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.15...v3.10.0-beta.16) (2024-12-05)
Note: Version bump only for package ohif-docs
[3.10.0-beta.15](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.14...v3.10.0-beta.15) (2024-12-05)
Note: Version bump only for package ohif-docs
[3.10.0-beta.14](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.13...v3.10.0-beta.14) (2024-12-03)
Note: Version bump only for package ohif-docs
[3.10.0-beta.13](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.12...v3.10.0-beta.13) (2024-12-02)
Note: Version bump only for package ohif-docs
[3.10.0-beta.12](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.11...v3.10.0-beta.12) (2024-11-29)
Note: Version bump only for package ohif-docs
[3.10.0-beta.11](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.10...v3.10.0-beta.11) (2024-11-28)
Bug Fixes
[3.10.0-beta.10](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.9...v3.10.0-beta.10) (2024-11-28)
Note: Version bump only for package ohif-docs
[3.10.0-beta.9](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.8...v3.10.0-beta.9) (2024-11-22)
Note: Version bump only for package ohif-docs
[3.10.0-beta.8](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.7...v3.10.0-beta.8) (2024-11-22)
Note: Version bump only for package ohif-docs
[3.10.0-beta.7](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.6...v3.10.0-beta.7) (2024-11-22)
Bug Fixes
[3.10.0-beta.6](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.5...v3.10.0-beta.6) (2024-11-22)
Note: Version bump only for package ohif-docs
[3.10.0-beta.5](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.4...v3.10.0-beta.5) (2024-11-15)
Note: Version bump only for package ohif-docs
[3.10.0-beta.4](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.3...v3.10.0-beta.4) (2024-11-15)
Note: Version bump only for package ohif-docs
[3.10.0-beta.3](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.2...v3.10.0-beta.3) (2024-11-14)
Note: Version bump only for package ohif-docs
[3.10.0-beta.2](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.1...v3.10.0-beta.2) (2024-11-13)
Note: Version bump only for package ohif-docs
[3.10.0-beta.1](https://github.com/OHIF/Viewers/compare/v3.10.0-beta.0...v3.10.0-beta.1) (2024-11-12)
Note: Version bump only for package ohif-docs
[3.10.0-beta.0](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.111...v3.10.0-beta.0) (2024-11-12)
Note: Version bump only for package ohif-docs
[3.9.0-beta.111](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.110...v3.9.0-beta.111) (2024-11-12)
Bug Fixes
- Have an addIcon that adds to both ui and ui-next (#4490) (4a12523)
- Measurement Tracking: Various UI and functionality improvements (#4481) (62b2748)
[3.9.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.109...v3.9.0-beta.110) (2024-11-11)
Bug Fixes
[3.9.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.108...v3.9.0-beta.109) (2024-11-08)
Note: Version bump only for package ohif-docs
[3.9.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.107...v3.9.0-beta.108) (2024-11-07)
Bug Fixes
[3.9.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.106...v3.9.0-beta.107) (2024-11-06)
Note: Version bump only for package ohif-docs
[3.9.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.105...v3.9.0-beta.106) (2024-11-06)
Note: Version bump only for package ohif-docs
[3.9.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.104...v3.9.0-beta.105) (2024-11-05)
Note: Version bump only for package ohif-docs
[3.9.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.103...v3.9.0-beta.104) (2024-10-30)
Note: Version bump only for package ohif-docs
[3.9.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.102...v3.9.0-beta.103) (2024-10-29)
Note: Version bump only for package ohif-docs
[3.9.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.101...v3.9.0-beta.102) (2024-10-29)
Note: Version bump only for package ohif-docs
[3.9.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.100...v3.9.0-beta.101) (2024-10-18)
Note: Version bump only for package ohif-docs
[3.9.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.99...v3.9.0-beta.100) (2024-10-17)
Note: Version bump only for package ohif-docs
[3.9.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.98...v3.9.0-beta.99) (2024-10-17)
Note: Version bump only for package ohif-docs
[3.9.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.97...v3.9.0-beta.98) (2024-10-15)
Note: Version bump only for package ohif-docs
[3.9.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.96...v3.9.0-beta.97) (2024-10-11)
Note: Version bump only for package ohif-docs
[3.9.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.95...v3.9.0-beta.96) (2024-10-10)
Note: Version bump only for package ohif-docs
[3.9.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.94...v3.9.0-beta.95) (2024-10-08)
Note: Version bump only for package ohif-docs
[3.9.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.93...v3.9.0-beta.94) (2024-10-04)
Features
[3.9.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.92...v3.9.0-beta.93) (2024-10-04)
Note: Version bump only for package ohif-docs
[3.9.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.91...v3.9.0-beta.92) (2024-10-01)
Note: Version bump only for package ohif-docs
[3.9.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.90...v3.9.0-beta.91) (2024-10-01)
Note: Version bump only for package ohif-docs
[3.9.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.89...v3.9.0-beta.90) (2024-09-30)
Note: Version bump only for package ohif-docs
[3.9.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.88...v3.9.0-beta.89) (2024-09-27)
Note: Version bump only for package ohif-docs
[3.9.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.87...v3.9.0-beta.88) (2024-09-24)
Note: Version bump only for package ohif-docs
[3.9.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.86...v3.9.0-beta.87) (2024-09-19)
Note: Version bump only for package ohif-docs
[3.9.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.85...v3.9.0-beta.86) (2024-09-19)
Note: Version bump only for package ohif-docs
[3.9.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.84...v3.9.0-beta.85) (2024-09-17)
Note: Version bump only for package ohif-docs
[3.9.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.83...v3.9.0-beta.84) (2024-09-12)
Note: Version bump only for package ohif-docs
[3.9.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.82...v3.9.0-beta.83) (2024-09-11)
Note: Version bump only for package ohif-docs
[3.9.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.81...v3.9.0-beta.82) (2024-09-05)
Note: Version bump only for package ohif-docs
[3.9.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.80...v3.9.0-beta.81) (2024-08-27)
Note: Version bump only for package ohif-docs
[3.9.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.79...v3.9.0-beta.80) (2024-08-16)
Note: Version bump only for package ohif-docs
[3.9.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.78...v3.9.0-beta.79) (2024-08-16)
Note: Version bump only for package ohif-docs
[3.9.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.77...v3.9.0-beta.78) (2024-08-15)
Features
[3.9.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.76...v3.9.0-beta.77) (2024-08-15)
Note: Version bump only for package ohif-docs
[3.9.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.75...v3.9.0-beta.76) (2024-08-08)
Note: Version bump only for package ohif-docs
[3.9.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.74...v3.9.0-beta.75) (2024-08-07)
Note: Version bump only for package ohif-docs
[3.9.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.73...v3.9.0-beta.74) (2024-08-06)
Note: Version bump only for package ohif-docs
[3.9.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.72...v3.9.0-beta.73) (2024-08-02)
Note: Version bump only for package ohif-docs
[3.9.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.71...v3.9.0-beta.72) (2024-07-31)
Note: Version bump only for package ohif-docs
[3.9.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.70...v3.9.0-beta.71) (2024-07-30)
Note: Version bump only for package ohif-docs
[3.9.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.69...v3.9.0-beta.70) (2024-07-30)
Note: Version bump only for package ohif-docs
[3.9.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.68...v3.9.0-beta.69) (2024-07-27)
Note: Version bump only for package ohif-docs
[3.9.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.67...v3.9.0-beta.68) (2024-07-26)
Note: Version bump only for package ohif-docs
[3.9.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.66...v3.9.0-beta.67) (2024-07-26)
Note: Version bump only for package ohif-docs
[3.9.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.65...v3.9.0-beta.66) (2024-07-24)
Note: Version bump only for package ohif-docs
[3.9.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.64...v3.9.0-beta.65) (2024-07-23)
Note: Version bump only for package ohif-docs
[3.9.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.63...v3.9.0-beta.64) (2024-07-19)
Note: Version bump only for package ohif-docs
[3.9.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.62...v3.9.0-beta.63) (2024-07-10)
Note: Version bump only for package ohif-docs
[3.9.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.61...v3.9.0-beta.62) (2024-07-09)
Note: Version bump only for package ohif-docs
[3.9.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.60...v3.9.0-beta.61) (2024-07-09)
Features
- auth: Add Authorization Code Flow and new Keycloak recipes with new video tutorials (#4234) (aefa6d9)
[3.9.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.59...v3.9.0-beta.60) (2024-07-09)
Note: Version bump only for package ohif-docs
[3.9.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.58...v3.9.0-beta.59) (2024-07-05)
Bug Fixes
Features
[3.9.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.57...v3.9.0-beta.58) (2024-07-04)
Note: Version bump only for package ohif-docs
[3.9.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.56...v3.9.0-beta.57) (2024-07-02)
Note: Version bump only for package ohif-docs
[3.9.0-beta.56](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.55...v3.9.0-beta.56) (2024-07-02)
Note: Version bump only for package ohif-docs
[3.9.0-beta.55](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.54...v3.9.0-beta.55) (2024-06-28)
Note: Version bump only for package ohif-docs
[3.9.0-beta.54](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.53...v3.9.0-beta.54) (2024-06-28)
Features
[3.9.0-beta.53](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.52...v3.9.0-beta.53) (2024-06-28)
Note: Version bump only for package ohif-docs
[3.9.0-beta.52](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.51...v3.9.0-beta.52) (2024-06-27)
Note: Version bump only for package ohif-docs
[3.9.0-beta.51](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.50...v3.9.0-beta.51) (2024-06-27)
Bug Fixes
[3.9.0-beta.50](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.49...v3.9.0-beta.50) (2024-06-26)
Note: Version bump only for package ohif-docs
[3.9.0-beta.49](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.48...v3.9.0-beta.49) (2024-06-26)
Note: Version bump only for package ohif-docs
[3.9.0-beta.48](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.47...v3.9.0-beta.48) (2024-06-25)
Note: Version bump only for package ohif-docs
[3.9.0-beta.47](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.46...v3.9.0-beta.47) (2024-06-21)
Bug Fixes
- Allow the mode setup/creation to be async, and provide a few more values to extension/app config/mode setup. (#4016) (88575c6)
- CustomViewportOverlay: pass accurate data to Custom Viewport Functions (#4224) (aef00e9)
Features
- customization service append and customize functionality should run once (#4238) (e462fd3)
- sort: custom series sort in study panel (#4214) (a433d40)
[3.9.0-beta.46](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.45...v3.9.0-beta.46) (2024-06-18)
Note: Version bump only for package ohif-docs
[3.9.0-beta.45](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.44...v3.9.0-beta.45) (2024-06-18)
Note: Version bump only for package ohif-docs
[3.9.0-beta.44](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.43...v3.9.0-beta.44) (2024-06-17)
Bug Fixes
[3.9.0-beta.43](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.42...v3.9.0-beta.43) (2024-06-12)
Note: Version bump only for package ohif-docs
[3.9.0-beta.42](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.41...v3.9.0-beta.42) (2024-06-12)
Note: Version bump only for package ohif-docs
[3.9.0-beta.41](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.40...v3.9.0-beta.41) (2024-06-12)
Note: Version bump only for package ohif-docs
[3.9.0-beta.40](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.39...v3.9.0-beta.40) (2024-06-12)
Note: Version bump only for package ohif-docs
[3.9.0-beta.39](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.38...v3.9.0-beta.39) (2024-06-08)
Note: Version bump only for package ohif-docs
[3.9.0-beta.38](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.37...v3.9.0-beta.38) (2024-06-07)
Note: Version bump only for package ohif-docs
[3.9.0-beta.37](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.36...v3.9.0-beta.37) (2024-06-05)
Note: Version bump only for package ohif-docs
[3.9.0-beta.36](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.35...v3.9.0-beta.36) (2024-06-05)
Note: Version bump only for package ohif-docs
[3.9.0-beta.35](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.34...v3.9.0-beta.35) (2024-06-05)
Note: Version bump only for package ohif-docs
[3.9.0-beta.34](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.33...v3.9.0-beta.34) (2024-06-05)
Note: Version bump only for package ohif-docs
[3.9.0-beta.33](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.32...v3.9.0-beta.33) (2024-06-05)
Note: Version bump only for package ohif-docs
[3.9.0-beta.32](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.31...v3.9.0-beta.32) (2024-05-31)
Note: Version bump only for package ohif-docs
[3.9.0-beta.31](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.30...v3.9.0-beta.31) (2024-05-30)
Note: Version bump only for package ohif-docs
[3.9.0-beta.30](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.29...v3.9.0-beta.30) (2024-05-30)
Note: Version bump only for package ohif-docs
[3.9.0-beta.29](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.28...v3.9.0-beta.29) (2024-05-30)
Note: Version bump only for package ohif-docs
[3.9.0-beta.28](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.27...v3.9.0-beta.28) (2024-05-30)
Note: Version bump only for package ohif-docs
[3.9.0-beta.27](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.26...v3.9.0-beta.27) (2024-05-29)
Note: Version bump only for package ohif-docs
[3.9.0-beta.26](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.25...v3.9.0-beta.26) (2024-05-29)
Features
[3.9.0-beta.25](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.24...v3.9.0-beta.25) (2024-05-29)
Note: Version bump only for package ohif-docs
[3.9.0-beta.24](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.23...v3.9.0-beta.24) (2024-05-29)
Note: Version bump only for package ohif-docs
[3.9.0-beta.23](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.22...v3.9.0-beta.23) (2024-05-28)
Note: Version bump only for package ohif-docs
[3.9.0-beta.22](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.21...v3.9.0-beta.22) (2024-05-27)
Features
[3.9.0-beta.21](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.20...v3.9.0-beta.21) (2024-05-24)
Note: Version bump only for package ohif-docs
[3.9.0-beta.20](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.19...v3.9.0-beta.20) (2024-05-24)
Note: Version bump only for package ohif-docs
[3.9.0-beta.19](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.18...v3.9.0-beta.19) (2024-05-24)
Note: Version bump only for package ohif-docs
[3.9.0-beta.18](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.17...v3.9.0-beta.18) (2024-05-24)
Note: Version bump only for package ohif-docs
[3.9.0-beta.17](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.16...v3.9.0-beta.17) (2024-05-23)
Note: Version bump only for package ohif-docs
[3.9.0-beta.16](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.15...v3.9.0-beta.16) (2024-05-23)
Note: Version bump only for package ohif-docs
[3.9.0-beta.15](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.14...v3.9.0-beta.15) (2024-05-22)
Note: Version bump only for package ohif-docs
[3.9.0-beta.14](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.13...v3.9.0-beta.14) (2024-05-21)
Note: Version bump only for package ohif-docs
[3.9.0-beta.13](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.12...v3.9.0-beta.13) (2024-05-21)
Note: Version bump only for package ohif-docs
[3.9.0-beta.12](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.11...v3.9.0-beta.12) (2024-05-21)
Note: Version bump only for package ohif-docs
[3.9.0-beta.11](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.10...v3.9.0-beta.11) (2024-05-21)
Features
[3.9.0-beta.10](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.9...v3.9.0-beta.10) (2024-05-21)
Note: Version bump only for package ohif-docs
[3.9.0-beta.9](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.8...v3.9.0-beta.9) (2024-05-17)
Note: Version bump only for package ohif-docs
[3.9.0-beta.8](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.7...v3.9.0-beta.8) (2024-05-16)
Note: Version bump only for package ohif-docs
[3.9.0-beta.7](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.6...v3.9.0-beta.7) (2024-05-15)
Note: Version bump only for package ohif-docs
[3.9.0-beta.6](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.5...v3.9.0-beta.6) (2024-05-15)
Note: Version bump only for package ohif-docs
[3.9.0-beta.5](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.4...v3.9.0-beta.5) (2024-05-14)
Note: Version bump only for package ohif-docs
[3.9.0-beta.4](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.3...v3.9.0-beta.4) (2024-05-14)
Note: Version bump only for package ohif-docs
[3.9.0-beta.3](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.2...v3.9.0-beta.3) (2024-05-08)
Features
- typings: Enhance typing support with withAppTypes and custom services throughout OHIF (#4090) (374065b)
[3.9.0-beta.2](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.1...v3.9.0-beta.2) (2024-05-06)
Bug Fixes
[3.9.0-beta.1](https://github.com/OHIF/Viewers/compare/v3.9.0-beta.0...v3.9.0-beta.1) (2024-05-06)
Note: Version bump only for package ohif-docs
[3.9.0-beta.0](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.94...v3.9.0-beta.0) (2024-04-29)
Note: Version bump only for package ohif-docs
[3.8.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.93...v3.8.0-beta.94) (2024-04-29)
Note: Version bump only for package ohif-docs
[3.8.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.92...v3.8.0-beta.93) (2024-04-29)
Bug Fixes
[3.8.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.91...v3.8.0-beta.92) (2024-04-28)
Note: Version bump only for package ohif-docs
[3.8.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.90...v3.8.0-beta.91) (2024-04-25)
Note: Version bump only for package ohif-docs
[3.8.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.89...v3.8.0-beta.90) (2024-04-22)
Note: Version bump only for package ohif-docs
[3.8.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.88...v3.8.0-beta.89) (2024-04-22)
Note: Version bump only for package ohif-docs
[3.8.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.87...v3.8.0-beta.88) (2024-04-22)
Note: Version bump only for package ohif-docs
[3.8.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.86...v3.8.0-beta.87) (2024-04-19)
Features
[3.8.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.85...v3.8.0-beta.86) (2024-04-19)
Bug Fixes
[3.8.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.84...v3.8.0-beta.85) (2024-04-18)
Note: Version bump only for package ohif-docs
[3.8.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.83...v3.8.0-beta.84) (2024-04-18)
Bug Fixes
- bugs: and replace seriesInstanceUID and seriesInstanceUIDs URL with seriesInstanceUIDs (#4049) (da7c1a5)
[3.8.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.82...v3.8.0-beta.83) (2024-04-18)
Note: Version bump only for package ohif-docs
[3.8.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.81...v3.8.0-beta.82) (2024-04-17)
Note: Version bump only for package ohif-docs
[3.8.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.80...v3.8.0-beta.81) (2024-04-16)
Bug Fixes
- viewport: Reset viewport state and fix CINE looping, thumbnail resolution, and dynamic tool settings (#4037) (f99a0bf)
[3.8.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.79...v3.8.0-beta.80) (2024-04-16)
Bug Fixes
[3.8.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.78...v3.8.0-beta.79) (2024-04-10)
Note: Version bump only for package ohif-docs
[3.8.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.77...v3.8.0-beta.78) (2024-04-10)
Note: Version bump only for package ohif-docs
[3.8.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.76...v3.8.0-beta.77) (2024-04-10)
Note: Version bump only for package ohif-docs
[3.8.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.75...v3.8.0-beta.76) (2024-04-10)
Note: Version bump only for package ohif-docs
[3.8.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.74...v3.8.0-beta.75) (2024-04-10)
Note: Version bump only for package ohif-docs
[3.8.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.73...v3.8.0-beta.74) (2024-04-10)
Features
[3.8.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.72...v3.8.0-beta.73) (2024-04-08)
Note: Version bump only for package ohif-docs
[3.8.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.71...v3.8.0-beta.72) (2024-04-05)
Note: Version bump only for package ohif-docs
[3.8.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.70...v3.8.0-beta.71) (2024-04-05)
Note: Version bump only for package ohif-docs
[3.8.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.69...v3.8.0-beta.70) (2024-04-05)
Features
[3.8.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.68...v3.8.0-beta.69) (2024-04-03)
Note: Version bump only for package ohif-docs
[3.8.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.67...v3.8.0-beta.68) (2024-04-03)
Features
[3.8.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.66...v3.8.0-beta.67) (2024-04-02)
Features
- ViewportActionMenu: window level per viewport / new patient info / colorbars/ 3D presets and 3D volume rendering (#3963) (b7f90e3)
[3.8.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.65...v3.8.0-beta.66) (2024-03-28)
Note: Version bump only for package ohif-docs
[3.8.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.64...v3.8.0-beta.65) (2024-03-28)
Features
[3.8.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.63...v3.8.0-beta.64) (2024-03-27)
Features
[3.8.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.62...v3.8.0-beta.63) (2024-03-25)
Features
[3.8.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.61...v3.8.0-beta.62) (2024-03-19)
Note: Version bump only for package ohif-docs
[3.8.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.60...v3.8.0-beta.61) (2024-03-18)
Note: Version bump only for package ohif-docs
[3.8.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.59...v3.8.0-beta.60) (2024-03-15)
Note: Version bump only for package ohif-docs
[3.8.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.58...v3.8.0-beta.59) (2024-03-08)
Note: Version bump only for package ohif-docs
[3.8.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.57...v3.8.0-beta.58) (2024-03-05)
Note: Version bump only for package ohif-docs
[3.8.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.56...v3.8.0-beta.57) (2024-02-28)
Bug Fixes
[3.8.0-beta.56](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.55...v3.8.0-beta.56) (2024-02-22)
Note: Version bump only for package ohif-docs
[3.8.0-beta.55](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.54...v3.8.0-beta.55) (2024-02-21)
Features
[3.8.0-beta.54](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.53...v3.8.0-beta.54) (2024-02-14)
Note: Version bump only for package ohif-docs
[3.8.0-beta.53](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.52...v3.8.0-beta.53) (2024-02-05)
Note: Version bump only for package ohif-docs
[3.8.0-beta.52](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.51...v3.8.0-beta.52) (2024-01-22)
Note: Version bump only for package ohif-docs
[3.8.0-beta.51](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.50...v3.8.0-beta.51) (2024-01-22)
Note: Version bump only for package ohif-docs
[3.8.0-beta.50](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.49...v3.8.0-beta.50) (2024-01-22)
Note: Version bump only for package ohif-docs
[3.8.0-beta.49](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.48...v3.8.0-beta.49) (2024-01-19)
Note: Version bump only for package ohif-docs
[3.8.0-beta.48](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.47...v3.8.0-beta.48) (2024-01-17)
Note: Version bump only for package ohif-docs
[3.8.0-beta.47](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.46...v3.8.0-beta.47) (2024-01-12)
Note: Version bump only for package ohif-docs
[3.8.0-beta.46](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.45...v3.8.0-beta.46) (2024-01-12)
Note: Version bump only for package ohif-docs
[3.8.0-beta.45](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.44...v3.8.0-beta.45) (2024-01-09)
Note: Version bump only for package ohif-docs
[3.8.0-beta.44](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.43...v3.8.0-beta.44) (2024-01-09)
Features
[3.8.0-beta.43](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.42...v3.8.0-beta.43) (2024-01-09)
Bug Fixes
[3.8.0-beta.42](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.41...v3.8.0-beta.42) (2024-01-08)
Note: Version bump only for package ohif-docs
[3.8.0-beta.41](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.40...v3.8.0-beta.41) (2024-01-08)
Features
[3.8.0-beta.40](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.39...v3.8.0-beta.40) (2024-01-08)
Note: Version bump only for package ohif-docs
[3.8.0-beta.39](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.38...v3.8.0-beta.39) (2024-01-08)
Note: Version bump only for package ohif-docs
[3.8.0-beta.38](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.37...v3.8.0-beta.38) (2024-01-08)
Note: Version bump only for package ohif-docs
[3.8.0-beta.37](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.36...v3.8.0-beta.37) (2024-01-08)
Note: Version bump only for package ohif-docs
[3.8.0-beta.36](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.35...v3.8.0-beta.36) (2023-12-15)
Note: Version bump only for package ohif-docs
[3.8.0-beta.35](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.34...v3.8.0-beta.35) (2023-12-14)
Note: Version bump only for package ohif-docs
[3.8.0-beta.34](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.33...v3.8.0-beta.34) (2023-12-13)
Note: Version bump only for package ohif-docs
[3.8.0-beta.33](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.32...v3.8.0-beta.33) (2023-12-13)
Note: Version bump only for package ohif-docs
[3.8.0-beta.32](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.31...v3.8.0-beta.32) (2023-12-13)
Note: Version bump only for package ohif-docs
[3.8.0-beta.31](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.30...v3.8.0-beta.31) (2023-12-13)
Note: Version bump only for package ohif-docs
[3.8.0-beta.30](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.29...v3.8.0-beta.30) (2023-12-13)
Note: Version bump only for package ohif-docs
[3.8.0-beta.29](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.28...v3.8.0-beta.29) (2023-12-13)
Features
- config: Add activateViewportBeforeInteraction parameter for viewport interaction customization (#3847) (f707b4e)
[3.8.0-beta.28](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.27...v3.8.0-beta.28) (2023-12-08)
Note: Version bump only for package ohif-docs
[3.8.0-beta.27](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.26...v3.8.0-beta.27) (2023-12-06)
Bug Fixes
[3.8.0-beta.26](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.25...v3.8.0-beta.26) (2023-11-28)
Note: Version bump only for package ohif-docs
[3.8.0-beta.25](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.24...v3.8.0-beta.25) (2023-11-27)
Note: Version bump only for package ohif-docs
[3.8.0-beta.24](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.23...v3.8.0-beta.24) (2023-11-24)
Note: Version bump only for package ohif-docs
[3.8.0-beta.23](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.22...v3.8.0-beta.23) (2023-11-24)
Features
[3.8.0-beta.22](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.21...v3.8.0-beta.22) (2023-11-21)
Note: Version bump only for package ohif-docs
[3.8.0-beta.21](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.20...v3.8.0-beta.21) (2023-11-21)
Note: Version bump only for package ohif-docs
[3.8.0-beta.20](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.19...v3.8.0-beta.20) (2023-11-21)
Note: Version bump only for package ohif-docs
[3.8.0-beta.19](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.18...v3.8.0-beta.19) (2023-11-18)
Features
[3.8.0-beta.18](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.17...v3.8.0-beta.18) (2023-11-15)
Features
[3.8.0-beta.17](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.16...v3.8.0-beta.17) (2023-11-13)
Note: Version bump only for package ohif-docs
[3.8.0-beta.16](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.15...v3.8.0-beta.16) (2023-11-13)
Note: Version bump only for package ohif-docs
[3.8.0-beta.15](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.14...v3.8.0-beta.15) (2023-11-10)
Features
[3.8.0-beta.14](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.13...v3.8.0-beta.14) (2023-11-10)
Bug Fixes
[3.8.0-beta.13](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.12...v3.8.0-beta.13) (2023-11-09)
Note: Version bump only for package ohif-docs
[3.8.0-beta.12](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.11...v3.8.0-beta.12) (2023-11-08)
Note: Version bump only for package ohif-docs
[3.8.0-beta.11](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.10...v3.8.0-beta.11) (2023-11-08)
Features
[3.8.0-beta.10](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.9...v3.8.0-beta.10) (2023-11-03)
Note: Version bump only for package ohif-docs
[3.8.0-beta.9](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.8...v3.8.0-beta.9) (2023-11-02)
Note: Version bump only for package ohif-docs
[3.8.0-beta.8](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.7...v3.8.0-beta.8) (2023-10-31)
Note: Version bump only for package ohif-docs
[3.8.0-beta.7](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.6...v3.8.0-beta.7) (2023-10-30)
Note: Version bump only for package ohif-docs
[3.8.0-beta.6](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.5...v3.8.0-beta.6) (2023-10-25)
Bug Fixes
- toolbar: allow customizable toolbar for active viewport and allow active tool to be deactivated via a click (#3608) (dd6d976)
[3.8.0-beta.5](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.4...v3.8.0-beta.5) (2023-10-24)
Bug Fixes
- sr: dcm4chee requires the patient name for an SR to match what is in the original study (#3739) (d98439f)
[3.8.0-beta.4](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.3...v3.8.0-beta.4) (2023-10-23)
Note: Version bump only for package ohif-docs
[3.8.0-beta.3](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.2...v3.8.0-beta.3) (2023-10-23)
Note: Version bump only for package ohif-docs
[3.8.0-beta.2](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.1...v3.8.0-beta.2) (2023-10-19)
Bug Fixes
[3.8.0-beta.1](https://github.com/OHIF/Viewers/compare/v3.8.0-beta.0...v3.8.0-beta.1) (2023-10-19)
Note: Version bump only for package ohif-docs
[3.8.0-beta.0](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.110...v3.8.0-beta.0) (2023-10-12)
Note: Version bump only for package ohif-docs
[3.7.0-beta.110](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.109...v3.7.0-beta.110) (2023-10-11)
Note: Version bump only for package ohif-docs
[3.7.0-beta.109](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.108...v3.7.0-beta.109) (2023-10-11)
Bug Fixes
[3.7.0-beta.108](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.107...v3.7.0-beta.108) (2023-10-10)
Note: Version bump only for package ohif-docs
[3.7.0-beta.107](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.106...v3.7.0-beta.107) (2023-10-10)
Note: Version bump only for package ohif-docs
[3.7.0-beta.106](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.105...v3.7.0-beta.106) (2023-10-10)
Bug Fixes
[3.7.0-beta.105](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.104...v3.7.0-beta.105) (2023-10-10)
Note: Version bump only for package ohif-docs
[3.7.0-beta.104](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.103...v3.7.0-beta.104) (2023-10-09)
Note: Version bump only for package ohif-docs
[3.7.0-beta.103](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.102...v3.7.0-beta.103) (2023-10-09)
Note: Version bump only for package ohif-docs
[3.7.0-beta.102](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.101...v3.7.0-beta.102) (2023-10-06)
Note: Version bump only for package ohif-docs
[3.7.0-beta.101](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.100...v3.7.0-beta.101) (2023-10-06)
Bug Fixes
[3.7.0-beta.100](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.99...v3.7.0-beta.100) (2023-10-06)
Note: Version bump only for package ohif-docs
[3.7.0-beta.99](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.98...v3.7.0-beta.99) (2023-10-04)
Note: Version bump only for package ohif-docs
[3.7.0-beta.98](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.97...v3.7.0-beta.98) (2023-10-04)
Note: Version bump only for package ohif-docs
[3.7.0-beta.97](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.96...v3.7.0-beta.97) (2023-10-04)
Note: Version bump only for package ohif-docs
[3.7.0-beta.96](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.95...v3.7.0-beta.96) (2023-10-04)
Note: Version bump only for package ohif-docs
[3.7.0-beta.95](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.94...v3.7.0-beta.95) (2023-10-04)
Note: Version bump only for package ohif-docs
[3.7.0-beta.94](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.93...v3.7.0-beta.94) (2023-10-03)
Note: Version bump only for package ohif-docs
[3.7.0-beta.93](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.92...v3.7.0-beta.93) (2023-10-03)
Features
[3.7.0-beta.92](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.91...v3.7.0-beta.92) (2023-10-03)
Note: Version bump only for package ohif-docs
[3.7.0-beta.91](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.90...v3.7.0-beta.91) (2023-10-03)
Note: Version bump only for package ohif-docs
[3.7.0-beta.90](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.89...v3.7.0-beta.90) (2023-10-03)
Note: Version bump only for package ohif-docs
[3.7.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.88...v3.7.0-beta.89) (2023-10-03)
Note: Version bump only for package ohif-docs
[3.7.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.87...v3.7.0-beta.88) (2023-10-03)
Bug Fixes
[3.7.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.86...v3.7.0-beta.87) (2023-09-29)
Bug Fixes
[3.7.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.85...v3.7.0-beta.86) (2023-09-29)
Bug Fixes
[3.7.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.84...v3.7.0-beta.85) (2023-09-26)
Note: Version bump only for package ohif-docs
[3.7.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.83...v3.7.0-beta.84) (2023-09-26)
Note: Version bump only for package ohif-docs
[3.7.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.82...v3.7.0-beta.83) (2023-09-26)
Note: Version bump only for package ohif-docs
[3.7.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.81...v3.7.0-beta.82) (2023-09-26)
Note: Version bump only for package ohif-docs
[3.7.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.80...v3.7.0-beta.81) (2023-09-26)
Note: Version bump only for package ohif-docs
[3.7.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.79...v3.7.0-beta.80) (2023-09-22)
Features
[3.7.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.78...v3.7.0-beta.79) (2023-09-22)
Performance Improvements
[3.7.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.77...v3.7.0-beta.78) (2023-09-21)
Note: Version bump only for package ohif-docs
[3.7.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.76...v3.7.0-beta.77) (2023-09-21)
Note: Version bump only for package ohif-docs
[3.7.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.75...v3.7.0-beta.76) (2023-09-19)
Bug Fixes
[3.7.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.74...v3.7.0-beta.75) (2023-09-18)
Note: Version bump only for package ohif-docs
[3.7.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.73...v3.7.0-beta.74) (2023-09-15)
Note: Version bump only for package ohif-docs
[3.7.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.72...v3.7.0-beta.73) (2023-09-12)
Note: Version bump only for package ohif-docs
[3.7.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.71...v3.7.0-beta.72) (2023-09-12)
Note: Version bump only for package ohif-docs
[3.7.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.70...v3.7.0-beta.71) (2023-09-12)
Note: Version bump only for package ohif-docs
[3.7.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.69...v3.7.0-beta.70) (2023-09-12)
Note: Version bump only for package ohif-docs
[3.7.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.68...v3.7.0-beta.69) (2023-09-11)
Note: Version bump only for package ohif-docs
[3.7.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.67...v3.7.0-beta.68) (2023-09-11)
Note: Version bump only for package ohif-docs
[3.7.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.66...v3.7.0-beta.67) (2023-09-06)
Note: Version bump only for package ohif-docs
[3.7.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.65...v3.7.0-beta.66) (2023-09-06)
Note: Version bump only for package ohif-docs
[3.7.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.64...v3.7.0-beta.65) (2023-09-06)
Note: Version bump only for package ohif-docs
[3.7.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.63...v3.7.0-beta.64) (2023-09-05)
Bug Fixes
[3.7.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.62...v3.7.0-beta.63) (2023-09-01)
Features
[3.7.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.61...v3.7.0-beta.62) (2023-08-30)
Note: Version bump only for package ohif-docs
[3.7.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.60...v3.7.0-beta.61) (2023-08-29)
Note: Version bump only for package ohif-docs
[3.7.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.59...v3.7.0-beta.60) (2023-08-29)
Note: Version bump only for package ohif-docs
[3.7.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.58...v3.7.0-beta.59) (2023-08-29)
Note: Version bump only for package ohif-docs
[3.7.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.57...v3.7.0-beta.58) (2023-08-25)
Features
- cloud data source config: GUI and API for configuring a cloud data source with Google cloud healthcare implementation (#3589) (a336992)
[3.7.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.7.0-beta.56...v3.7.0-beta.57) (2023-08-23)
Note: Version bump only for package ohif-docs
Platform Docs Docs Conformance (`platform/docs/docs/conformance.md`)
sidebar_position: 12 sidebar_label: DICOM Conformance Statement title: DICOM Conformance Statement summary: Access information about the OHIF Viewer's compliance with DICOM standards through an open-sourced document provided by Radical Imaging, which details the application's implementation of DICOM protocols and services.
You can find a version that has been open sourced by Radical Imaging in this link
Platform Docs Docs Release Notes (`platform/docs/docs/release-notes.md`)
sidebar_position: 2 sidebar_label: Release Notes title: OHIF Viewer Release Notes summary: Information about OHIF Viewer version releases, including new features, improvements, and bug fixes, which can be found in detail on the official OHIF website.
Release Notes
You can find the detailed release notes on the OHIF website. Please visit https://ohif.org/release-notes
Platform Docs Docs Resources (`platform/docs/docs/resources.md`)
sidebar_position: 13 sidebar_label: Resources title: OHIF Viewer Educational Resources summary: A comprehensive collection of presentations, slides, posters, and videos from conferences, hackathons, and community meetings where the OHIF team has shared knowledge about the viewer's development, features, and capabilities, organized chronologically from 2016 to present.
Resources
Throughout the development of the OHIF Viewer, we have participated in various
conferences and "hackathons". In this page, we will provide the presentations
and other resources that we have provided to the community in the past:
2025
Machine Learning in Medical Imaging Consortium (MaLMIC) | January 2025
We presented two talks at the Machine Learning in Medical Imaging Consortium (MaLMIC) 2025 conference.
- Advanced Medical Imaging Visualization Slides
- Introducing Advanced Segmentation Tools in the OHIF Viewer and Cornerstone3D Slides
2024
ITCR Sustainment Session 2024
Dr. Gordon Harris presented at ITCR sustainment session about the future of OHIF.
- OHIF Sustainability Slides
ITCR Sustainment Panel 2024
- Advanced Medical Imaging Visualization Slides
IMNO 2024 - March 19-20, 2024
We participated in the Imaging Network Ontario (ImNO) 2024 symposium, presenting three posters. One of our presentations received the best talk award during the session.
- Advancing Medical Imaging on the Web: Implementation of Hanging Protocols for Automated Image Display Configuration in OHIF V3 Poster
- Advancing Medical Imaging on the Web: Optimizing the Dicomweb Server Architecture with Static Dicomweb Poster
- (🏆🏆 BEST PRESENTATION AWARD in the Session 7 Pitches: Devices, HW, SW Development 🏆🏆) Advancing Medical Imaging on the Web: Integrating High Throughput JPEG 2000 (HTJ2K) in Cornerstone3D for Streamlined Progressive Loading and Visualization Poster
2023
ITCR 2023 Conference | September 11-13, 2023
Dr. Gordon Harris presented an update on OHIF in NCI Informatics Technology for Cancer Research Annual Meeting. You can find the slides and poster here:
[Slides][Poster]
SIIM 2023 Tech Tools Webinar | April 12th, 2023
Free, Open Source Tools for Research: MONAI and OHIF Viewer
[Slides][Video]
NA-MIC Project Week 38th 2023 - Remote
We participated in the 38th Project Week with three projects around OHIF. [Website]
- PolySeg representations for OHIF Viewer (link)
- Cross study synchronizer for OHIF Crosshair (link)
- DATSCAN Viewer implementation in OHIF (link)
2022
OHIF Demo to Interns
SIIM 2022 - Updates from the Imaging Informatics Community
We participated in the SIIM 2022 conference to give update for the imaging
informatics community.
[Slides]
[Video]
The Imaging Network Ontario - Remote
The Imaging Network Ontario (ImNO) is an annual symposium that brings together
medical imaging researchers and scientists from across Canada to share
knowledge, ideas, and experiences.
[Slides]
[Video]
[NA-MIC Project Week 36th 2022 - Remote](https://github.com/NA-MIC/ProjectWeek/blob/master/PW36_2022_Virtual/README.md)
The Project Week is a week-long hackathon of hands-on activity in which medical
image computing researchers. OHIF team participated and gave a talk on OHIF and
Cornerstone in the 36th Project Week:
[Slides]
[Video]
2021
[NA-MIC Project Week 35th 2021 - Remote](https://github.com/NA-MIC/ProjectWeek/tree/master/PW35_2021_Virtual)
The Project Week is a week-long hackathon of hands-on activity in which medical
image computing researchers. OHIF team participated in the 35th Project Week
in 2021.
[Slides]
Chan Zuckerberg Initiative (CZI)
Project presentations and demonstrations of Essential Open Source Software for
Science (EOSS) grantees
[Slides]
[Video]
Google Cloud Tech
Healthcare Imaging with Cloud Healthcare API
[Video]
2020
OHIF ITCR Pitch
OHIF pitch for Informatics Technology for Cancer Research (ITCR)
[Slides]
[Video]
2019
OHIF and VTK.js Training Course
OHIF and Kitware collaboration to create a training course for OHIF and VTK.js
developers. Funding for this work was provided by Kitware (NIH NINDS
R44NS081792, NIH NINDS R42NS086295, NIH NIBIB and NIGMS R01EB021396, NIH NIBIB
R01EB014955), Isomics (NIH P41 EB015902), and Massachusetts General Hospital
(NIH U24 CA199460).
- Introduction to VTK.js and OHIF
[Slides]
[Video] - Developing with VTK.js
[Slides]
[Video] - VTK.js Architecture and Tooling
[Slides]
[Video] - OHIF + VTK.js Integration
[Slides]
[Video]
2017
Lesion Tracker
LesionTracker: Extensible Open-Source Zero-Footprint Web Viewer for Cancer
Imaging Research and Clinical Trials. This project was supported in part by
grant U24 CA199460 from the National Cancer Institute (NCI) Informatics
Technology for Cancer Research (ITCR) Program.
[Video]
OHIF Community Meeting - June
2016
Imaging Community Call
Open Source Oncology Web Viewer; Presentation by Gordon J. Harris
[Slides]
OHIF Community Meeting - June
OHIF Community Meeting - September
Platform Docs Docs Test Coverage (`platform/docs/docs/test-coverage.md`)
sidebar_position: 14 sidebar_label: Test Coverage title: OHIF Viewer Test Coverage summary: Information about the automated testing infrastructure for the OHIF Viewer, with a focus on Playwright tests and access to the latest test coverage reports, which help ensure reliability and quality of the codebase.
Test Coverage
Playwright
Here's the test coverage report for our Playwright tests. Keep in mind that this doesn't include our Cypress tests, so our actual test coverage is likely higher than what's shown. We're focusing on Playwright for future OHIF testing, and we're really pushing to improve that coverage number.
You can view our latest test coverage report here:
Platform Docs Docs Behaviours Report Dialog Save Destinations (`platform/docs/docs/behaviours/report-dialog-save-destinations.md`)
Report dialog: where a save goes, and what the series is called
Status: Implemented — current behaviour
The report dialog stores a segmentation, a contour set, or a measurement report.
The dialog asks the user two things: which series the object goes into, and what
that series is called.
Implemented across:
extensions/default/src/customizations/reportDialogCustomization.tsx— the
dialog, and theohif.createReportDialogcustomization.extensions/default/src/Panels/createReportDialogPrompt.tsx— the prompt that
shows the dialog, and the input and the output of the prompt.extensions/default/src/utils/seriesDescriptionHistory.ts— the descriptions
that the viewer remembers.extensions/cornerstone-dicom-seg/src/commandsModule.ts—storeSegmentation,
the SEG caller and the RTSTRUCT caller.extensions/default/src/utils/promptSaveReport.tsx— the measurement report
caller.libs/@cornerstonejs/packages/adapters/src/utilities/referencedMetadataProvider.ts
— thePredecessorSequenceprovider, which reads the predecessor instance.
One save stores one object
Each destination stores all of the current data as one object, and the dialog
merges nothing. A save into a series that already holds data does not read that
data, and the save leaves no part of the current data out. The destination
decides which series holds the new object, and therefore which instance the new
object supersedes. The earlier instances stay in the series, and the new
instance becomes the one that the viewer loads by default.
The three destinations
| Destination | Where the object goes | When the dialog offers the destination |
|---|---|---|
Save to current |
The series that the viewer loaded the data from | The predecessorImageId of the data names a loaded series |
Save as new |
A new series, with an editable number and description | Always |
Replace existing |
Another loaded series of this modality, which the user selects | The viewer holds at least one other such series |
Save to current is the default choice when the dialog offers it, andSave as new is the default choice otherwise. Save to current andReplace existing keep the number and the description of the target series, so
the dialog does not let the user edit either one.
Which series the dialog offers
The dialog offers a loaded series as a destination only when both of these hold:
- The series holds the same type of object, which is the modality of the save.
- The series has a
predecessorImageIdvalue.
The predecessorImageId value names the immediate prior object that someone
saved into the series. The save supersedes that one instance. The adapter reads
the series and the instance number through the value, from thePredecessorSequence provider.
The dialog does not fall back to the SeriesInstanceUID value of the display
set. A UID names a series and not an instance, so a UID names no prior object,
and a UID is not an image id. The provider finds no instance for a UID, and the
save then starts a new series rather than extending the chosen one.
A local id, such as dicomfile:3, is a valid value. The viewer registers an
uploaded instance under a local id, and the provider resolves a local id, so a
user can save against an uploaded instance more than once.
A display set that the viewer downloaded and never stored has nopredecessorImageId value, and the dialog does not offer that display set. The
number of a new series still counts such a series, because the number comes from
every loaded series of the modality and not from the offered ones alone.
What the new series is called
Save as new offers four names, and the field starts from the first name that is
not blank:
itemName, the name that the user chose for the item. A rename before the
save therefore reaches the field.storeSegmentationpassessegmentation.label, but only when the user chose that label: the service
invents a name such asSegmentation 3for a new segmentation, and marks the
segmentation withlabelIsGenerated. A label that is still marked this way
goes todefaultSeriesDescriptioninstead, so a generated name does not
outrank the remembered descriptions. A rename clears the mark, and the save
compares no two strings, so a user who types the invented name still gets the
name initemName.- The description of the series that the viewer loaded the data from, which is
the name of the last save of this data. - The descriptions that the user used before for this type of item, most recent
first. See remembered descriptions. defaultSeriesDescription, the name for an item that has no other name. The
in-tree callers passSegmentation,ContoursandMeasurements.
The pull-down holds the four names in that order. A blank name, and a name of
spaces, drops out of the list, so such a name cannot hide a later name. The
dialog compares the names without case, and the list holds each name once. An
emptied field falls back to the first name of the list.
A caller with no editable name passes no itemName: the measurement report has
no such name, and the report therefore starts from the description of the loaded
series, or from the last used name.
Remembered descriptions
The viewer remembers a description when the user creates a new series with the
description, and a download counts as a save. A save into a series that already
exists remembers nothing, because that series keeps its own description.
The history holds a name that the user chose. A save that usesdefaultSeriesDescription remembers nothing, because the caller supplies that
name at every save, and the dialog offers the name in any case. A generated
segmentation label reaches defaultSeriesDescription, so Segmentation 1 stays
out of the history and the dialog cannot offer Segmentation 1 as the name of a
later, unrelated segmentation.
itemTypeis the key that the viewer remembers the descriptions under, anditemTypedefaults to the modality.rememberedDescriptionCountis how many descriptions the viewer remembers, and
the count defaults to 5.- A count of 0 turns the history off. The list then holds one name, and the
dialog does not render the pull-down.
The user reaches the list in three ways: the pull-down button shows every name;
typing narrows the list to the names that the typing can complete; Tab
completes to the first of those names, and the arrow keys plus Enter select
one.
The series number of a new series
The dialog offers one past the highest series number of the loaded series of this
modality, and at least minSeriesNumber. The user can edit the number. An empty
number, and a number that is not valid, falls back to the offered number.
createReportDialogPrompt returns seriesNumber, and alsopriorSeriesNumber, which is one less. A caller that computes the number as1 + priorSeriesNumber gets the number that the dialog shows.
Platform Docs Docs Behaviours Segmentation Multiframe Part10 Prefetch (`platform/docs/docs/behaviours/segmentation-multiframe-part10-prefetch.md`)
Full-instance prefetch for segmentation (and multiframe) loading
Status: Implemented — enabled and awaited to completion by default;
per-frame loading is the explicit opt-out
The boolean loadMultiframeAsPart10 resolves, in order: the data sourceconfiguration, the global customizationcornerstone.segmentation.loadMultiframeAsPart10, then the built-in default oftrue — i.e. by default the SEG load waits for the whole-instance
fetch+parse to complete or fail (deliberately no timeout) and serves every
frame from the registry. Set loadMultiframeAsPart10: false explicitly to
force per-frame loading — the exception, for back ends that need to fetch the
individual images instead (e.g. servers that cannot serve a whole-instance
retrieve, or deployments where holding the full Part 10 object in memory is
undesirable). A failed or unsupported instance fetch resolves quickly and
falls back to per-frame regardless of the setting, so it never wedges the load.
Note the per-frame endpoint itself is not inefficient — each frame request is
cheap — but SEG frames are so small and numerous that one bulk Part 10 fetch
beats hundreds of tiny requests (see Problem below). This holds even for very
large SEG objects (hundreds of MB): any finite race cap would simply expire on
those and storm per-frame anyway while abandoning the bulk fetch's benefit,
which is why there is no timeout.
Implemented across:
@cornerstonejs/dicom-image-loaderimageLoader/prefetchPart10Instance.ts— registers a Part 10 instance into
the frame registry (thin wrapper overaddDicomPart10Instance).imageLoader/wadors/loadImageFromRegistry.ts+wadors/loadImage.ts— WADO-RS loads now consult the registry first.
@ohif/extension-defaultDicomWebDataSource—retrieve.prefetchInstanceFrames.@ohif/extension-cornerstone-dicom-seggetSopClassHandlerModule.ts— call
site (resolves the config and awaits the prefetch).
Related: @cornerstonejs/adapters labelmapImagesFromBuffer.ts
(decodeSegPixelDataFromFrameIds, bounded by concurrency, default 16).
Problem
The SEG load path now fetches/decodes frames through the cornerstone image
loader, one loadable imageId per frame, parallelized up to N=16
(concurrency). For a SEG (or any multiframe instance) with 800+ small
frames, this means 800+ independent HTTP requests, each with its own
request/response overhead. Even at 16-wide concurrency the per-request latency
floor dominates: each frame is < 1 KB of payload but pays a full round trip.
Streaming one large object (the entire Part 10 / multiframe instance) is far
cheaper than streaming hundreds of tiny ones — a single connection, a single set
of headers, no per-frame TTFB. The whole instance for an 800-frame binary SEG is
typically a few hundred KB to a few MB.
Goal
Add a generic data-source capability that, just before the segmentation
loader runs, optionally fetches the entire original instance in one request
and registers it into the Cornerstone3D frame registry (the@cornerstonejs/metadata NATURALIZED + COMPRESSED_FRAME_DATA framework, parsed
by the dcmjs async reader) — so the existing per-frame imageId fetch path
transparently hits local data instead of the network, while the cornerstone
decode path stays byte-for-byte identical (same decompressor, same workers).
Crucially this is best-effort:
- By default (
loadMultiframeAsPart10unset →true) the load waits for the
full-instance fetch+parse to complete or fail — no timeout — then every
frame is served from the registry. - If
loadMultiframeAsPart10resolves tofalse(explicitly configured), the
capability is disabled — no full-instance fetch is attempted. Per-frame
loading is the exception, opted into per deployment. - If the full-instance fetch or parse fails for any reason, it must never
fail the segmentation decode. We log and fall back to per-frame fetches.
Why this is safe / transparent
There is one uniform frame registry: the Cornerstone3D @cornerstonejs/metadata
NATURALIZED framework, populated by addDicomPart10Instance (which parses the
Part 10 with the dcmjs AsyncDicomReader) and read per-frame via theCOMPRESSED_FRAME_DATA typed provider. Frame imageIds are normalized to the base
instance by baseImageIdQueryFilter (strips /frames/N, ?frame=N, &frame=N),
so one registration under the instance serves every frame.
This is the same registry the WADO-URI / dicomweb loader already uses:wadouri/loadImage.ts's loadImageFromNaturalizedMetadata resolves each frame
from COMPRESSED_FRAME_DATA and decodes it with createImage. The gap was that
WADO-RS (wadors/loadImage.ts) always issued a per-frame /frames/N request
and never consulted the registry. The adapter closes that gap:
wadors/loadImageFromRegistry.ts—loadImageFromCompressedFrameRegistry(imageId)
looks upCOMPRESSED_FRAME_DATAfor the frame; if present it decodes via the
samecreateImagepath and returns the image; if absent it returnsundefined.wadors/loadImage.tscalls it first and short-circuits when the registry has
the frame, otherwise falls through to the existing network path.
So once prefetchPart10Instance has registered the instance, both WADO-URI and
WADO-RS serve every frame from the single registry, with the same decode
pipeline (createImage → worker decoder). From cornerstone's perspective
nothing changed except the compressed bytes came from the registry instead of the
wire.
Rejected alternatives: (1) a bespoke
Mapregistry plusgetPixelDatashims — duplicates a registry that already exists; (2) seeding
the core image cache (cache.putImageLoadObject) per frame — works, but the
per-frame compressed data already lives in the NATURALIZED registry, so basing
the design on that registry (and teaching WADO-RS to read it) keeps a single
source of truth instead of copying frames into a second cache.
API (as implemented)
A generic capability on the data source's retrieve namespace (so it works for
any multiframe instance, not just SEG, and alternate data sources can override
it), plus the SEG handler call site that awaits it.
IWebApiDataSource.create passes retrieve through verbatim, so the capability
is added there (no @ohif/core change):
// On the data source (DicomWebDataSource):
dataSource.retrieve.prefetchInstanceFrames({
instance, // study/series/sop UIDs for retrieveInstance
imageId, // SEG instance imageId (frame qualifiers normalized away)
}): {
done: Promise<boolean>; // resolves true if fetched+registered, false if skipped/failed
cancel: () => void;
};The implementation fetches the instance with wadoDicomWebClient.retrieveInstance
(which returns the Part 10 as an ArrayBuffer, unwrapping multipart/related
transparently) and passes a lazy resolver todicomImageLoader.prefetchPart10Instance(imageId, resolver). All work is wrapped
so any failure resolves done to false — it never throws into the loader.
Call site (just before the loader)
In getSopClassHandlerModule.ts, immediately beforecreateFromDicomSegImageId(...) (abridged from the actual code):
const loadMultiframeAsPart10 =
(dataSource?.getConfig?.()?.loadMultiframeAsPart10 as boolean | undefined) ??
(customizationService?.getCustomization?.(
'cornerstone.segmentation.loadMultiframeAsPart10'
) as boolean | undefined) ??
true;
let prefetch;
if (loadMultiframeAsPart10) {
prefetch = dataSource.retrieve?.prefetchInstanceFrames?.({
instance,
imageId: segImageIdForMetadata,
});
if (prefetch?.done) {
// Wait for the bulk fetch to complete or fail — no timeout.
await prefetch.done;
}
}
try {
results = await adaptersSEG.Cornerstone3D.Segmentation.createFromDicomSegImageId(
imageIds,
segImageIdForMetadata,
{ metadataProvider: metaData, tolerance, parserType, frameImageIds,
concurrency: SEG_FRAME_DECODE_CONCURRENCY }
);
} finally {
eventTarget.removeEventListener(Enums.Events.SEGMENTATION_LOAD_PROGRESS, onProgress);
prefetch?.cancel?.();
}The SEG loader and adapter are unchanged — the loader still asks the image
loader for each frame. Registered frames resolve from the registry; the rest
fetch normally.
Mechanism (the 4 requested points)
1. Async DICOM reader (dcmjs) to parse the instance
Parsing is done by @cornerstonejs/metadata's addDicomPart10Instance, which
uses the dcmjs AsyncDicomReader (naturalizePart10Buffer innaturalizedHandlers.ts) and understands encapsulated PixelData fragmentation,
so the NATURALIZED instance exposes pixel data as an array of per-frame
ArrayBuffer fragments. COMPRESSED_FRAME_DATA then slices out the requested
frame. We did not re-implement any parsing — the prefetch just feeds the fetched
Part 10 buffer to this existing reader.
Implemented as full-buffer v1: the whole instance is fetched, then parsed.addDicomPart10Instance accepts a lazy resolver, so the fetch is what the race
waits on. Progressive/streaming registration (registering frames as bytes arrive)
is a future optimization — see rollout step 4.
Response envelope: `multipart/related` vs raw DICOM
The full-instance fetch can come back in two shapes, and the parser must
handle both before any DICOM parsing happens:
multipart/related— a WADO-RS instance retrieve
(GET …/instances/{sop}withAccept: multipart/related; type="application/dicom")
wraps the Part 10 object(s) in a MIME multipart envelope: leading part headers,
a--boundarymarker, the DICOM bytes, then a terminal--boundary--. The
inner DICOM byte offsets are shifted by the MIME header length, so dcmjs
must be fed the unwrapped inner part, never the raw response.- raw DICOM — WADO-URI, a direct file/object URL, or a
bulkDataURIthat
returns a singleapplication/dicombody: the response is the Part 10
bytes, no envelope.
As implemented, the full-buffer path delegates this to dicomweb-client'sretrieveInstance, which performs the WADO-RS instance retrieve and returns the
Part 10 as an ArrayBuffer with the multipart/related envelope already
unwrapped (and returns the single-part body as-is). prefetchInstanceFrames
additionally tolerates an [ArrayBuffer] or ArrayBufferView shape defensively.
So the implemented path is:
retrieveInstance() → ArrayBuffer (multipart unwrapped by dicomweb-client)
→ prefetchPart10Instance → addDicomPart10Instance → dcmjs AsyncDicomReaderDetection by Content-Type and manual unwrapping (the approach wadors/extractMultipart.ts
uses: contentType.indexOf('multipart') === -1 → bytes as-is; else strip the
boundary/part headers) becomes relevant only for the future streaming path
(rollout step 4), where these wrinkles must be handled directly:
- The multipart preamble/boundary stripped at the start of the stream and the
terminal boundary detected at the end; a boundary token can straddle chunk
boundaries, so the unwrapper must buffer across chunks (the existingfindIndexOfString+tokenIndexcarry-over inextractMultipartis built for
incremental calls). multipart/relatedmay contain multiple parts; a single-instance retrieve
yields one — guard for >1.- A truncated/partial body (no terminal boundary yet) must not be mis-parsed.
2. Register the compressed data into the frame registry
The fetched Part 10 buffer is registered once per instance via theprefetchPart10Instance adapter (a thin wrapper over addDicomPart10Instance):
// @cornerstonejs/dicom-image-loader: imageLoader/prefetchPart10Instance.ts
import { utilities } from '@cornerstonejs/metadata';
const { addDicomPart10Instance } = utilities;
export function prefetchPart10Instance(baseImageId, part10 /* buffer | resolver */) {
return addDicomPart10Instance(baseImageId, part10);
}That populates NATURALIZED for the instance; COMPRESSED_FRAME_DATA then yields
each frame's compressed bytes + transfer syntax on demand. Frame imageIds
normalize to the instance key automatically (baseImageIdQueryFilter), so there
is no per-frame registration loop and no second cache to keep coherent — the
registry is the existing NATURALIZED framework.
The "few new adapters" the task calls for:
prefetchPart10Instance(baseImageId, part10)— entry point to register a
fetched instance into the registry (exported from@cornerstonejs/dicom-image-loader).loadImageFromCompressedFrameRegistry(imageId, options)inwadors/loadImageFromRegistry.ts— teaches the WADO-RS loader to read the
registry. It looks upCOMPRESSED_FRAME_DATAfor the frame and, if present,
decodes via the samecreateImagethe network path uses;wadors/loadImage.ts
calls it first and short-circuits on a hit. (WADO-URI already reads the
registry vialoadImageFromNaturalizedMetadata.)
Metadata the decoder needs (imagePixelModule, transfer syntax) comes from the
same NATURALIZED instance, plus the SEG handler's existing_ensureSegInstanceMetadataAvailable per frame imageId.
3. Cornerstone uses its existing decompressor — identical downstream
Both the WADO-URI path and the new WADO-RS registry path decode viacreateImage (→ the same web-worker decoder used for every network frame), so
encapsulated transfer syntaxes are decompressed exactly as if fetched per-frame
and native/uncompressed frames pass through unchanged. No new decode path, no
codec changes, no divergence in pixel output — the only difference is that the
compressed bytes came from the registry instead of the wire.
4. Failure is non-fatal — fall back to per-frame fetches
prefetchInstanceFrames wraps the fetch + parse so that any failure (network
error, cancel, parse error, unexpected retrieveInstance shape) resolvesdone to false and logs a warning — it never throws into the SEG load. When
the registry has no data for a frame, loadImageFromCompressedFrameRegistry
returns undefined and the WADO-RS loader falls through to its normal/frames/N request. So if the prefetch is slow, disabled, or fails, loading is
exactly today's per-frame behaviour.
Edge cases that degrade gracefully:
cancel()(viewport closed / segmentation removed mid-load) → the resolver
throws on its cancelled flag;doneresolvesfalse; any already-registered
data stays usable.- A misbehaving metadata provider → the registry lookup is wrapped in try/catch
and returnsundefined, so per-frame loading is never broken.
Semantics (the `loadMultiframeAsPart10` knob)
- Unset (default) or
true→ start the full-instance fetch+parse and await
it to completion or failure (await prefetch.done) — deliberately no
timeout; every frame is then served from the registry. Fetch failure resolvesdonequickly, so unsupported servers fall straight through to per-frame. false(explicitly configured) → disabled; per-frame loading is the
exception, opted into per deployment.
addDicomPart10Instanceregisters the instance atomically (one parse), so
registration is all-or-nothing rather than progressive. Progressive
registration (rollout step 4) would let frames be served as they arrive.
There is no timeout because a bounded wait loses on exactly the objects where
the prefetch matters most: a large SEG (hundreds of MB) cannot finish inside
any small cap, so a capped race expires and storms per-frame anyway while
abandoning the bulk fetch's benefit. The only failure mode a timeout would
bound — a fetch that never settles — is already covered by the browser's
network-level failure surfacing through done.
Where the generic capability lives
- The registry is the existing
@cornerstonejs/metadataNATURALIZED framework
— no new cache. New code in@cornerstonejs/dicom-image-loaderis the thin
adapterprefetchPart10Instance()plus the WADO-RS read path
(wadors/loadImageFromRegistry.ts, wired intowadors/loadImage.ts). - The fetch + register orchestration lives in the data source
(extensions/default/.../DicomWebDataSource→retrieve.prefetchInstanceFrames),
because it knows how to retrieve a full instance (auth headers,wadoRoot,
WADO-RS instance retrieve viadicomweb-client, CORS), and so alternate data
sources can implement/override it. - The SEG handler only reads the configuration and awaits the prefetch.
This keeps the layering clean: data source = "how to get bytes", image loader =
"how to register/decode bytes", SEG handler = "when to ask".
Open questions / risks
- NATURALIZED registry key alignment. Both registration
(addDicomPart10Instance) and the WADO-RS read normalize frame imageIds to the
base instance viabaseImageIdQueryFilter, so they agree. Worth a sanity check
per data source that the SEGimageIdpassed toprefetchInstanceFramesand
the frame imageIds the SEG loader requests share the same instance base. - Memory. Holding the full instance plus the still-compressed frames in the
registry raises memory for that instance until it is evicted. Compressed frames
are small and decode is on-demand. Registry/cache eviction lifecycle for
prefetched instances should be verified (especially repeated SEG loads). - Streaming availability. v1 uses a single full-buffer
retrieveInstance. A
future streaming path (step 4) would register frames as bytes arrive. - Auth / headers. Handled — the resolver sets
wadoDicomWebClient.headers = getAuthorizationHeader()before retrieve, reusing
the data source's existing decoration. - Per-frame overhead. Every WADO-RS load now does one cheap
COMPRESSED_FRAME_DATAlookup (a Map get after base normalization) before
falling through. Negligible, and only short-circuits when an instance was
actually prefetched.
Incremental rollout
- ✅
prefetchPart10Instanceadapter + WADO-RS registry read
(wadors/loadImageFromRegistry.ts) in dicom-image-loader. No behaviour change
until something registers an instance. - ✅
retrieve.prefetchInstanceFramesin DicomWebDataSource (full-buffer v1 viaretrieveInstance); whether to call it is the caller's policy. - ✅ SEG handler call site. Now enabled and awaited to completion by
default (no timeout); per-frame loading requires an explicitloadMultiframeAsPart10: false. - ⏳ Progressive (streaming) parse to register frames as they arrive (handle the
multipart/relatedunwrap + boundary-straddle directly). - ⏳ Extend to other multiframe loaders (the registry path is generic).
Platform Docs Docs Configuration ConfigurationFiles (`platform/docs/docs/configuration/configurationFiles.md`)
sidebar_position: 1 sidebar_label: Configuration Files title: Configuration Files summary: Comprehensive guide to configuring OHIF Viewer, including data sources, environment variables, advanced options like study prefetching, and detailed explanations of configuration parameters for performance optimization and feature customization.
Config files
After following the steps outlined in
Getting Started, you'll notice that the
OHIF Viewer has data for several studies and their images. You didn't add this
data, so where is it coming from?
By default, the viewer is configured to connect to a Amazon S3 bucket that is hosting
a Static WADO server (see Static WADO DICOMWeb).
By default we use default.js for the configuration file. You can change this by setting the APP_CONFIG environment variable
and select other options such as config/local_orthanc.js or config/google.js.
Configuration Files
The configuration for our viewer is in the <root>platform/app/public/config
directory. Our build process knows which configuration file to use based on theAPP_CONFIG environment variable. By default, its value isconfig/default.js. The majority of the viewer's features,
and registered extension's features, are configured using this file.
The simplest way is to update the existing default config:
window.config = {
routerBasename: null,
extensions: [],
modes: [],
showStudyList: true,
dataSources: [
{
namespace: '@ohif/extension-default.dataSourcesModule.dicomweb',
sourceName: 'dicomweb',
configuration: {
friendlyName: 'dcmjs DICOMWeb Server',
name: 'DCM4CHEE',
wadoUriRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado',
qidoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
wadoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
qidoSupportsIncludeField: true,
supportsReject: true,
imageRendering: 'wadors',
thumbnailRendering: 'wadors',
enableStudyLazyLoad: true,
supportsFuzzyMatching: true,
supportsWildcard: true,
omitQuotationForMultipartRequest: true,
},
},
],
defaultDataSourceName: 'dicomweb',
};As you can see a new change in
OHIF-v3is the addition ofdataSources. You
can build your own datasource and map it to the internal data structure of
OHIF’s > metadata and enjoy using other peoples developed mode on your own
data!You can read more about data sources at
Data Source section in Modes
The configuration can also be written as a JS Function in case you need to
inject dependencies like external services:
window.config = ({ servicesManager } = {}) => {
const { UIDialogService } = servicesManager.services;
return {
cornerstoneExtensionConfig: {
tools: {
ArrowAnnotate: {
configuration: {
getTextCallback: (callback, eventDetails) => UIDialogService.create({...
}
}
},
},
routerBasename: null,
dataSources: [
{
namespace: '@ohif/extension-default.dataSourcesModule.dicomweb',
sourceName: 'dicomweb',
configuration: {
friendlyName: 'dcmjs DICOMWeb Server',
name: 'DCM4CHEE',
wadoUriRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado',
qidoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
wadoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
qidoSupportsIncludeField: true,
supportsReject: true,
imageRendering: 'wadors',
thumbnailRendering: 'wadors',
enableStudyLazyLoad: true,
supportsFuzzyMatching: true,
supportsWildcard: true,
omitQuotationForMultipartRequest: true,
},
},
],
defaultDataSourceName: 'dicomweb',
};
};Configuration Options
Here are a list of some options available:
customizationService: An array of customization module references and inline overrides applied at the global scope. This is how deployers enable optional features like the Appearance & Theming system and configure UI components without modifying core code. See Customization Service for the full syntax reference.disableEditing: If true, it disables editing in OHIF, hiding edit buttons in segmentation
panel and locking already stored measurements.maxNumberOfWebWorkers: The maximum number of web workers to use for
decoding. Defaults to minimum ofnavigator.hardwareConcurrencyand
what is specified bymaxNumberOfWebWorkers. Some windows machines require smaller values.acceptHeader: accept header to request specific dicom transfer syntax ex : [ 'multipart/related; type=image/jls; q=1', 'multipart/related; type=application/octet-stream; q=0.1' ]investigationalUseDialog: This should contain an object withoptionvalue, it can be eitheralwayswhich always shows the dialog once per session,neverwhich never shows the dialog, orconfigurewhich shows the dialog once and won't show it again until a set number of days defined by the user, if it's set to configure, you are required to add an additional propertydayswhich is the number of days to wait before showing the dialog again.groupEnabledModesFirst: boolean, if set to true, all valid modes for the study get grouped together first, then the rest of the modes. If false, all modes are shown in the order they are defined in the configuration.experimentalStudyBrowserSort: boolean, if set to true, you will get the experimental StudyBrowserSort component in the UI, which displays a list of sort functions that the displaySets can be sorted by, the sort reflects in all part of the app including the thumbnail/study panel. These sort functions are defined in the customizationModule and can be expanded by users.disableConfirmationPrompts: boolean, if set to true, it skips confirmation prompts for segmentation related prompts.showPatientInfo: string, if set to 'visible', the patient info header will be shown and its initial state is expanded. If set to 'visibleCollapsed', the patient info header will be shown but it's initial state is collapsed. If set to 'disabled', the patient info header will never be shown, and if set to 'visibleReadOnly', the patient info header will be shown and always expanded.requestTransferSyntaxUID: Request a specific Transfer syntax from dicom web server ex: 1.2.840.10008.1.2.4.80 (applied only if acceptHeader is not set)omitQuotationForMultipartRequest: Some servers (e.g., .NET) require themultipart/relatedrequest to be sent without quotation marks. Defaults tofalse. If your server doesn't require this, then setting this flag totruemight improve performance (by removing the need for preflight requests). Also note that
if auth headers are used, a preflight request is required.maxNumRequests: The maximum number of requests to allow in parallel. It is an object with keys ofinteraction,thumbnail, andprefetch. You can specify a specific number for each type. Forthumbnail, a small pool (around5) is recommended: the study list preview panel fetches a thumbnail per series in parallel, and a larger pool yields little throughput benefit while risking server overload and contention withinteraction/prefetchrequests.modesConfiguration: Allows overriding modes configuration.- Example config:
jsmodesConfiguration: { '@ohif/mode-longitudinal': { displayName: 'Custom Name', routeName: 'customRouteName', routes: [ { path: 'customPath', layoutTemplate: () => { /** Custom Layout */ return { id: ohif.layout, props: { leftPanels: [tracked.thumbnailList], rightPanels: [dicomSeg.panel, tracked.measurements], rightPanelClosed: true, viewports: [ { namespace: tracked.viewport, displaySetsToDisplay: [ohif.sopClassHandler], }, ], }, }; }, }, ], } },Note: Although the mode configuration is passed to the mode factory function, it is up to the particular mode itself if its going to use it to allow overwriting its original configuration e.g.
jsfunction modeFactory({ modeConfiguration }) { return { id, routeName: 'viewer', displayName: 'Basic Viewer', ... onModeEnter: ({ servicesManager, extensionManager, commandsManager }) => { ... }, /** * This mode allows its configuration to be overwritten by * destructuring the modeConfiguration value from the mode fatory function * at the end of the mode configuration definition. */ ...modeConfiguration, }; }showLoadingIndicator: (default to true), if set to false, the loading indicator will not be shown when navigating between studies.showStudyList: (default to false), if set to false, the OHIF search (or work list) page will not be shown nor will there be a back button (chevron) in the viewer to navigate to ituseNorm16Texture: (default to false), if set to true, it will use 16 bit data type for the image data wherever possible which has
significant impact on reducing the memory usage. However, the 16Bit textures require EXT_texture_norm16 extension in webGL 2.0 (you can check if you have it here https://webglreport.com/?v=2). In addition to the extension, there are reported problems for Intel Macs that might cause the viewer to crash. In summary, it is great a configuration if you have support for it.useSharedArrayBuffer(default to 'TRUE', options: 'AUTO', 'FALSE', 'TRUE', note that these are strings), for volume loading we use sharedArrayBuffer to be able to
load the volume progressively as the data arrives (each webworker has the shared buffer and can write to it). However, there might be certain environments that do not support sharedArrayBuffer. In that case, you can set this flag to false and the viewer will use the regular arrayBuffer which might be slower for large volume loading.supportsWildcard: (default to false), if set to true, the datasource will support wildcard matching for patient name and patient id.allowMultiSelectExport: (default to false), if set to true, the user will be able to select the datasource to export the report to.activateViewportBeforeInteraction: (default to true), if set to false, tools can be used directly without the need to click and activate the viewport.autoPlayCine: (default to false), if set to true, data sets with the DICOM frame time tag (i.e. (0018,1063)) will auto play when displayedaddWindowLevelActionMenu: (default to true), if set to false, the window level action menu item is NOT added to the viewport action cornersshowErrorDetails: determines which runtime environments can display exception and error details caught at theErrorBoundary; acceptable values include:always,dev, andproductiondangerouslyUseDynamicConfig: Dynamic config allows user to passconfigUrlquery string. This allows to load config without recompiling application. If theconfigUrlquery string is passed, the worklist and modes will load from the referenced json rather than the default .env config. If there is noconfigUrlpath provided, the default behaviour is used and there should not be any deviation from current user experience.
Points to consider while usingdangerouslyUseDynamicConfig:- User have to enable this feature by setting
dangerouslyUseDynamicConfig.enabled:true. By default it isfalse. - Regex helps to avoid easy exploit. Default is
/.*/. Setup your own regex to choose a specific source of configuration only. - System administrators can return
cross-origin: same-originwith OHIF files to disallow any loading from other origin. It will block read access to resources loaded from a different origin to avoid potential attack vector. - Example config:js
dangerouslyUseDynamicConfig: { enabled: false, regex: /.*/ }
Example 1, to allow numbers and letters in an absolute or sub-path only.
regex: /(0-9A-Za-z.]+)(\/[0-9A-Za-z.]+)*/
Example 2, to restricts to either hosptial.com or othersite.com.regex: /(https:\/\/hospital.com(\/[0-9A-Za-z.]+)*)|(https:\/\/othersite.com(\/[0-9A-Za-z.]+)*)/
Example usage:http://localhost:3000/?configUrl=http://localhost:3000/config/example.json- User have to enable this feature by setting
onConfiguration: Currently only available for DicomWebDataSource, this option allows the interception of the data source configuration for dynamic values e.g. values coming from url params or query params. Here is an example of building the dicomweb datasource configuration object with values that are based on the route url params:text{ namespace: '@ohif/extension-default.dataSourcesModule.dicomweb', sourceName: 'gcpdicomweb', configuration: { friendlyName: 'GCP DICOMWeb Server', name: 'gcpdicomweb', qidoSupportsIncludeField: false, imageRendering: 'wadors', thumbnailRendering: 'wadors', enableStudyLazyLoad: true, supportsFuzzyMatching: false, supportsWildcard: false, singlepart: 'bulkdata,video,pdf', onConfiguration: (dicomWebConfig, options) => { const { params } = options; const { project, location, dataset, dicomStore } = params; const pathUrl = `https://healthcare.googleapis.com/v1/projects/${project}/locations/${location}/datasets/${dataset}/dicomStores/${dicomStore}/dicomWeb`; return { ...dicomWebConfig, wadoRoot: pathUrl, qidoRoot: pathUrl, wadoUri: pathUrl, wadoUriRoot: pathUrl, }; }, }, },
This configuration would allow the user to build a dicomweb configuration from a GCP healthcare api path e.g. http://localhost:3000/projects/your-gcp-project/locations/us-central1/datasets/your-dataset/dicomStores/your-dicom-store/study/1.3.6.1.4.1.1234.5.2.1.1234.1234.123123123123123123123123123123
:::note
You can stack multiple panel components on top of each other by providing an array of panel components in the rightPanels or leftPanels properties.
For instance we can use
rightPanels: [[dicomSeg.panel, tracked.measurements], [dicomSeg.panel, tracked.measurements]]This will result in two panels, one with dicomSeg.panel and tracked.measurements and the other with dicomSeg.panel and tracked.measurements stacked on top of each other.
:::
Study Prefetcher
You can enable the study prefetcher so that OHIF loads the next/previous series/display sets
based on the proximity to the current series/display set. This can be useful to improve the user experience
studyPrefetcher: {
/* Enable/disable study prefetching service (default: false) */
enabled: true,
/* Number of displaysets to be prefetched (default: 2)*/
displaySetsCount: 2,
/**
* Max number of concurrent prefetch requests (default: 10)
* High numbers may impact on the time to load a new dropped series because
* the browser will be busy with all prefetching requests. As soon as the
* prefetch requests get fulfilled the new ones from the new dropped series
* are sent to the server.
*
* TODO: abort all prefetch requests when a new series is loaded on a viewport.
* (need to add support for `AbortController` on Cornerstone)
* */
maxNumPrefetchRequests: 10,
/* Display sets loading order (closest (deafult), downward or upward) */
order: 'closest',
},More on Accept Header Configuration
In the previous section we showed that you can modify the acceptHeader
configuration to request specific dicom transfer syntax. By default
we use acceptHeader: ['multipart/related; type=application/octet-stream; transfer-syntax=*'] for the following
reasons:
Ensures Optimal Transfer Syntax: By allowing the server to select the transfer syntax,
the client is more likely to receive the image in a syntax that's well-suited for fast transmission
and rendering. This might be the original syntax the image was stored in or another syntax that the server deems efficient.Avoids Transcoding: Transcoding (converting from one transfer syntax to another) can be a resource-intensive process.
Since the OHIF Viewer supports all transfer syntaxes, it is fine to accept any transfer syntax (transfer-syntax=*).
This allows the server to send the images in their stored syntax, avoiding the need for costly on-the-fly conversions.
This approach not only saves server resources but also reduces response times by leveraging the viewer's capability to handle various syntaxes directly.Faster Data Transfer: Compressed transfer syntaxes generally result in smaller file sizes compared
to uncompressed ones. Smaller files transmit faster over the network, leading to quicker load
times for the end-user. By accepting any syntax, the client can take advantage of compression when available.
However, if you would like to get compressed data in a specific transfer syntax, you can modify the acceptHeader configuration orrequestTransferSyntaxUID configuration.
Data Source: stackRetrieveOptions
At the data source configuration level, you can set stackRetrieveOptions to customize Cornerstone stack image retrieval. Merged with defaults; only specify overrides. For example, set streaming: false when the data source returns uncompressed DICOM (e.g. application/octet-stream only) to avoid black image on load:
configuration: {
acceptHeader: ['application/octet-stream'],
stackRetrieveOptions: {
retrieveOptions: { single: { streaming: false } },
},
}Environment Variables
We use environment variables at build and dev time to change the Viewer's
behavior. We can update the HTML_TEMPLATE to easily change which extensions
are registered, and specify a different APP_CONFIG to connect to an
alternative data source (or even specify different default hotkeys).
| Environment Variable | Description | Default |
|---|---|---|
HTML_TEMPLATE |
Which HTML template to use as our web app's entry point. Specific to PWA builds. | index.html |
PUBLIC_URL |
The route relative to the host that the app will be served from. Specific to PWA builds. | / |
APP_CONFIG |
Which configuration file to copy to output as app-config.js |
config/default.js |
PROXY_TARGET |
When developing, proxy requests that match this pattern to PROXY_DOMAIN |
undefined |
PROXY_DOMAIN |
When developing, proxy requests from PROXY_TARGET to PROXY_DOMAIN |
undefined |
OHIF_PORT |
The port to run the webpack server on for PWA builds. | 3000 |
You can also create a new config file and specify its path relative to the build
output's root by setting the APP_CONFIG environment variable. You can set the
value of this environment variable a few different ways:
Add a temporary environment variable in your shell- Previous
react-scriptsfunctionality that we need to duplicate withdotenv-webpack
- Previous
Add environment specific variables in.envfile(s)- Previous
react-scriptsfunctionality that we need to duplicate withdotenv-webpack
- Previous
- Using the
cross-envpackage in a npm script:"build": "cross-env APP_CONFIG=config/my-config.js react-scripts build"
After updating the configuration, yarn run build to generate updated build
output.
Platform Docs Docs Configuration Tours (`platform/docs/docs/configuration/tours.md`)
sidebar_position: 3 sidebar_label: Tours title: Configuring Tours in OHIF summary: Guide to implementing interactive guided tours in OHIF using Shepherd.js, including detailed configuration options, step definitions, customization parameters, and examples for creating effective user onboarding experiences.
Configuring Tours in OHIF with Shepherd.js
In OHIF, you can configure guided tours for users by leveraging Shepherd.js, a JavaScript library for building feature tours. This page explains how you can define and customize these tours within your app configuration file.
Overview
Tours allow you to provide step-by-step guidance to users, explaining different features of your mode/extension or the viewer. Each tour is associated with a route and consists of several steps, each guiding the user through specific interactions in the viewer.
Adding a Tour to your Configuration
Here's how you can add a tour to your configuration file:
window.config = {
customizationService: {
'ohif.tours': {
$set: [
{
id: 'basicViewerTour',
route: '/viewer',
steps: [
{
id: 'zoom',
title: 'Zooming In and Out',
text: 'You can zoom the images using the right click.',
attachTo: {
element: '.viewport-element',
on: 'left',
},
advanceOn: {
selector: '.cornerstone-viewport-element',
event: 'CORNERSTONE_TOOLS_MOUSE_UP',
},
},
],
},
],
},
},
};Explanation of Parameters
`tours` Array
Each item in the tours array defines a specific tour for a particular route. The object contains the following properties:
id: A unique identifier for the tour. This helps in tracking whether the tour has been shown.route: The route in the application where the tour is applicable. When the user navigates to this route, the tour can automatically trigger if it hasn't been shown before.steps: An array of steps that define the individual guide elements in the tour. Each step corresponds to a UI element and guides the user through interactions.tourOptions: An object that allows you to configure the overall behavior of the tour, such as using a modal overlay or defining default step options.
`steps` Array
Each step defines a part of the tour. Here's a breakdown of the properties you can define:
id: A unique identifier for the step within the tour.title: The title of the step, which appears at the top of the tooltip for the step.text: The content or description of the step, explaining what the user needs to do or understand.attachTo: Specifies where the step should be attached in the DOM. It includes:element: A string selector or a DOM element that the step should attach to.on: Specifies the position of the tooltip relative to the element (e.g., 'top', 'left', 'bottom', 'right').
advanceOn: Defines an event that will automatically advance the tour to the next step. This is useful for actions like clicking a button or scrolling.selector: The CSS selector for the element that triggers the advance.event: The event name that advances the step, this can be a OHIF service event, or a cornerstone event, or any native JS event (e.g., 'click', 'CORNERSTONE_TOOLS_MOUSE_WHEEL').
beforeShowPromise: A function that returns a promise. When the promise resolves, the rest of the show logic for the step will execute. You can use this to ensure that the target element is ready before the step shows.
`tourOptions`
The tourOptions object allows you to configure the overall behavior of the tour. Here's a breakdown of the available properties:
useModalOverlay: A boolean that, if set totrue, places the tour steps above a darkened modal overlay. The overlay creates an opening around the target element so it can remain interactive.defaultStepOptions: Default options that apply to all steps in the tour. You can override these in individual steps. The following are some options available:buttons: An array of button objects that appear in the footer of each step. Each button can trigger actions like advancing the tour or skipping it. For example:text: The label text on the button.action: A function to execute when the button is clicked. You can advance the tour usingthis.next(), or complete it usingthis.complete().secondary: A boolean that, when set totrue, styles the button as secondary (often for actions like skipping).
`floatingUIOptions`
You can define positioning options for the steps using Floating UI middleware. This helps control how the steps are positioned, especially near the browser edges.
For example, you can ensure that the steps maintain a margin of 24px from the viewport edges by configuring preventOverflow middleware:
floatingUIOptions: {
middleware: [
preventOverflow({ padding: 24 }),
flip(), // Allows the step to flip if it is overflowing
]
}Shepherd.js Lifecycle Events
Each step and tour can have lifecycle events like show, hide, complete, or cancel. These events allow you to hook into the tour’s lifecycle to perform actions when certain events are triggered.
For example:
when: {
show() {
console.log('Step shown!');
},
hide() {
console.log('Step hidden.');
}
}Customizing Your Tour
Once you have a basic tour in place, you can extend it with more advanced features like custom scrolling behavior, dynamic elements, and event-based step advancement. For more details, check out the Shepherd.js documentation.
Licensing
All versions below 14.0 for Shepherd.JS is under the MIT license, if you wish to use any version above 14.0, you can visit the ShepherdJS website to learn about their pricing and plans Shepherd.js
Demo
Conclusion
By leveraging Shepherd.js, you can provide users with interactive and informative guided tours of the viewer. This can greatly improve the user experience and help users understand how to use key features.
Platform Docs Docs Configuration Ui (`platform/docs/docs/configuration/ui.md`)
sidebar_position: 5 sidebar_label: UI & Appearance title: UI & Appearance summary: Overview of OHIF's UI system — the component library, theming and appearance customization, iconography, and the services that drive modals, dialogs, notifications, and viewport layout.
UI & Appearance
OHIF's user interface is built on ui-next, a component library purpose-built
for medical imaging workflows. It provides a consistent set of React components,
a token-based theming system, a curated icon set, and a collection of UI services
that manage runtime behavior like modals, notifications, and viewport layout.
This page gives a high-level map of how these pieces fit together and where to
find detailed documentation for each.
Component Library
The component library is the foundation of every panel, toolbar, dialog, and
control in the viewer. Components are organized into three tiers:
Simple components — atomic building blocks like Button, Checkbox, Input,
Label, Slider, and Switch. These are styled with the design system's tokens and
are the smallest interactive units.Compound components — composed from simple components to handle more
complex interactions: Select, Dialog, DropdownMenu, Tabs, Table, Popover,
Tooltip, Toast, and others. These manage their own state (open/close, selection,
focus) via headless patterns.OHIF-specific components — built for medical imaging workflows and not
found in general-purpose libraries: AllInOneMenu, CinePlayer, DataRow,
DataTable, Numeric, PanelSection, SmartScrollbar, ToolButton, and
ToolButtonList. These integrate directly with OHIF's services and extension
system.
Every component renders live in the interactive
Components section of this documentation site, where you
can see props, variants, and copy usage examples.
Appearance Dialog
The Appearance dialog is an optional UI that lets end users switch presets,
apply custom CSS overrides, and share themes via URL. It is not enabled by
default, but deployers can
opt in via configuration.
See Appearance & Theming
for the full setup and developer guide.
Colors & Theming
OHIF uses a token-based color system built on CSS custom properties with HSL
values. The base theme (dark mode) is defined in :root via Tailwind CSS, and
theme presets override specific tokens by applying a CSS class to document.body.
The theming system covers:
Design tokens — a set of semantic color variables (
--background,--primary,--card,--border, etc.) that every component references. Tokens
are defined as HSL triplets and consumed via Tailwind'shsl(var(...))pattern.Theme presets — six built-in themes (three tonal, three neutral) that shift
the entire interface's color palette. Presets are defined as JSON files and
applied via CSS classes. Also see:
Creating Themes and
Adding a Theme Preset.Accessibility — foreground tokens are paired with every surface token to
maintain contrast ratios across themes. When adding custom themes,
test colors to match accessibility standards.
Explore the live token swatches and theme picker in the interactive
Colors & Theming page, and see
Appearance & Theming
for the full configuration and developer guide.
Iconography
OHIF ships a curated set of icons designed specifically for medical imaging interfaces.
Icons are SVG-based, registered via addIcon(), and rendered through the Icons
component. They follow the same token system as the rest of the UI, so icon colors
respond to the active theme.
Browse the full set with search and click-to-copy in the
Iconography page.
White Labeling
OHIF supports replacing the header logo with custom branding via thewhiteLabeling configuration key. This lets you rebrand the viewer without
modifying source code.
Add a whiteLabeling entry to your configuration file with acreateLogoComponentFn that returns a React element:
window.config = {
/** .. **/
whiteLabeling: {
createLogoComponentFn: function(React) {
return React.createElement(
'a',
{
target: '_self',
rel: 'noopener noreferrer',
className: 'text-purple-600 line-through',
href: '/',
},
React.createElement('img', {
src: './customLogo.svg',
})
);
},
},
/** .. **/
};You can use Tailwind CSS utility classes in the className property to style
your custom logo component.
UI Services
While the component library handles what gets rendered, UI services handle
the runtime behavior: opening modals, showing notifications, managing viewport
layout, and coordinating dialogs. These services use a pub/sub architecture and
are accessed through the servicesManager:
| Service | What it manages |
|---|---|
| Modal Service | Full-screen and contained modals (including the Appearance dialog) |
| Dialog Service | Lightweight dialogs with form inputs and confirmations |
| Notification Service | Toast notifications (success, warning, error, info) |
| Viewport Grid Service | Viewport layout, grid arrangement, and active viewport tracking |
| Viewport Dialog Service | Dialogs anchored to specific viewports |
| Viewport Action Menu | Context menus and action buttons on viewport corners |
| Cine Service | Cine playback controls and frame rate |
UI services are documented in the Services > UI
section.
Customization Service
The Customization Service
is the mechanism that ties everything together. It allows deployers and
extension authors to override, extend, or replace UI components and behaviors
without modifying core code. Customizations can be scoped to a specific mode, set
globally via configuration, or provided as defaults by extensions.
The Appearance dialog itself is delivered as a customization module. Deployers
enable it by adding a single reference to their config's customizationService
array. This pattern means that any part of the UI that supports customization
can be configured the same way.
See the full customization guide at
Customization Service,
including the syntax reference for $set, $push, $merge, $filter, and
other operations.
Platform Docs Docs Configuration Url (`platform/docs/docs/configuration/url.md`)
sidebar_position: 4 sidebar_label: URL title: URL Parameters summary: Reference for OHIF Viewer URL parameters that control WorkList filtering, study/series loading, and viewer behavior, including parameters for filtering by patient name, modality, data sources, specifying initial series/instances, and selecting hanging protocols.
URL
You can modify the URL at any state of the app to get the desired result. Here
are different part of the APP that you can modify:
WorkList
The WorkList can be modified by adding the following query parameters:
PatientName
The patient name can be modified by adding the PatientName query parameter.
/?patientName=myQueryMRN
The MRN can be modified by adding the MRN query parameter.
/?mrn=myQueryDescription
The description can be modified by adding the Description query parameter.
/?description=myQueryModality
The modality can be modified by adding the modalities query parameter.
/?modalities=MGAccession Number
The accession number can be modified by adding the accession query parameter.
/?accession=myQueryDataSources
If you happen to have multiple data sources configured, you can filter the
WorkList by adding the dataSources query parameter.
/?dataSources=orthancNote1: You should pass the sourceName of the data source in the configuration file (not the friendly name nor the name)
Note2: Make sure that the configuration file you are using actually includes that data source. You cannot use a data source from another configuration file.
:::tip
You can add sortBy and sortDirection query parameters to sort the WorkList
/?patientName=myquery&sortBy=studyDate&sortDirection=ascending:::
Viewer
The Viewer can be modified by adding the following query parameters:
Mode
As you have seen before, the Viewer can be configured to be in different modes.
Each mode registers their id in the URL.
For instance
/viewer?StudyInstanceUIDs=1.3.6.1.4.1.14519.5.2.1.7009.2403.871108593056125491804754960339will open the viewer in the basic (longitudinal) mode with the StudyInstanceUID
1.3.6.1.4.1.14519.5.2.1.7009.2403.871108593056125491804754960339.
And if configured, the same study can be opened in the tmtv mode
/tmtv?StudyInstanceUIDs=1.3.6.1.4.1.14519.5.2.1.7009.2403.871108593056125491804754960339StudyInstanceUIDs
You can open more than one study in the Viewer by adding the StudyInstanceUIDs
/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095722.1&StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095258.1:::tip
You can use this feature to open a current and prior study in the Viewer.
Read more in the Hanging Protocol Module section. You can also use commas to separate
values.
:::
SeriesInstanceUIDs
Sometimes you need to only retrieve a specific series in a study, you can do
that by providing series level QIDO query parameters in the URL such as
SeriesInstanceUIDs. This does NOT work with instance or study
level parameters. For example:
http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8This will only open the viewer with one series (one displaySet) loaded, and no
queries made for any other series.
Sometimes you need to only retrieve a subset of series in a study, you can do
that by providing more than one series, separated by commas. For example:
http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8,1.3.6.1.4.1.25403.345050719074.3824.20170125095506.10This will only open the viewer with two series (two displaySets) loaded, and no
queries made for any other series.
initialSeriesInstanceUID
Alternatively, sometimes you want to just open the study on a specified series, but allowing other
series to be present too. This is the same behavior can be
achieved by using the initialSeriesInstanceUID parameter. For example:
http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&initialSeriesInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8This will open all the series in the study, but the viewer will start with the
series specified by the initialSeriesInstanceUID parameter.
Note that you can combine these, if you want to load a specific set of series
plus show an initial one as the first one selected, for example:
http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8,1.3.6.1.4.1.25403.345050719074.3824.20170125095506.10&initialSeriesInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095506.10initialSopInstanceUID
You can also specify the initial SOP Instance to be displayed by using theinitialSopInstanceUID parameter. For example:
http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8&initialSopInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095501.9This will open the study with the filtered series, and navigate to the slice 101
which happens to be the SOP Instance specified by the initialSopInstanceUID
Note: again you can mix and match
http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&SeriesInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095449.8,1.3.6.1.4.1.25403.345050719074.3824.20170125095506.10&initialSeriesInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095506.10&initialSopInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095510.8You can even load the whole study and only specify the initial SOP Instance to be displayed. Although
it will take more time to match, but it works as expected.
http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&initialSopInstanceUID=1.3.6.1.4.1.25403.345050719074.3824.20170125095510.8hangingProtocolId
You can select the initial hanging protocol to apply by using the
hangingProtocolId parameter. The selected parameter must be available in a
hangingProtocolModule registration, but does not have to be active.
For instance for loading a specific study in mpr mode from start you can use:
http://localhost:3000/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&hangingProtocolId=@ohif/mnGridtoken
Although not recommended, you can use the token param in the URL which will inject
the token into the Authorization header of the request.
Platform Docs Docs Deployment Authorization (`platform/docs/docs/deployment/authorization.md`)
sidebar_position: 6 sidebar_label: Auth title: Authorization and Authentication summary: Guide to configuring OpenID-Connect authentication in OHIF Viewer, including setup of authorization flows, token handling, and implementation details for securing access to medical imaging data.
Authorization and Authentication
The OHIF Viewer can be configured to work with authorization servers that support one or more of the OpenID-Connect authorization flows. The Viewer finds it's OpenID-Connect settings on the oidc configuration key. You can set these values in your configuration files. For instance you can take a look at ourgoogle.js configuration file.
oidc: [
{
// ~ REQUIRED
authority: 'https://accounts.google.com',
client_id: '723928408739-k9k9r3i44j32rhu69vlnibipmmk9i57p.apps.googleusercontent.com',
redirect_uri: '/callback',
response_type: 'id_token token',
scope: 'email profile openid https://www.googleapis.com/auth/cloudplatformprojects.readonly https://www.googleapis.com/auth/cloud-healthcare', // email profile openid
// ~ OPTIONAL
post_logout_redirect_uri: '/logout-redirect.html',
revoke_uri: 'https://accounts.google.com/o/oauth2/revoke?token=',
automaticSilentRenew: true,
revokeAccessTokenOnSignout: true,
},
],You need to provide the following information:
- authority: The URL of the authorization server.
- client_id: The client id of your application (provided by the authorization server).
- redirect_uri: The callback URL of your application.
- response_type: The response type of the authorization flow (e.g. id_token token, learn more about different flows).
- scope: The scopes that your application needs to access
- post_logout_redirect_uri: The URL that the user will be redirected to after logout.
- revoke_uri: The URL that the user will be redirected to after logout.
- automaticSilentRenew: If true, the user will be automatically logged in after the token expires.
- revokeAccessTokenOnSignout: If true, the access token will be revoked on logout.
How it works
The Viewer uses the userAuthenticationService to set the OpenID-Connect settings. The userAuthenticationService is a singleton service that is responsible for authentication and authorization. It is initialized by the app and you can grab it
from the servicesManager
const userAuthenticationService = servicesManager.services.userAuthenticationService;Then the userAuthenticationService will inject the token as Authorization header in the requests that are sent to the server (both metadata
and pixelData).
Token based authentication in URL
Sometimes (although not recommended), some servers like to send the token
in the query string. In this case, the viewer will automatically grab the token from the query string
and add it to the userAuthenticationService and remove it from the query string (to prevent it from being logged in the console
in future requests).
and example would be
http://localhost:3000/viewer?StudyInstanceUIDs=1.2.3.4.5.6.6.7&token=e123125jsdfahsdfSecuring dynamic datasource URLs
When using dicomwebproxy or dicomjson data sources with a runtime ?url=... query parameter,
configure explicit trust boundaries to prevent credential exfiltration.
Use these datasource configuration options:
dangerouslyAllowedOriginsForAuthenticatedEnvironments: Origin allowlist used only when the viewer is running in an authenticated environment. Entries may usehttp://orhttps://and can include localhost origins.
Allowed entry format for dangerouslyAllowedOriginsForAuthenticatedEnvironments:
- Must be a bare origin only:
scheme://host[:port] http://andhttps://are both allowed- Localhost is allowed when explicitly listed (for example,
http://localhost:5000) - Must not include username/password, path, query string, or hash
- Invalid entries are ignored and logged as misconfigured
Policy summary:
- In unauthenticated environments, any HTTP(S)
?url=origin is allowed. - In authenticated environments, same-origin
?url=values are allowed by default. - In authenticated environments, cross-origin
?url=values must be present indangerouslyAllowedOriginsForAuthenticatedEnvironments, otherwise loading fails closed. - In unauthenticated environments, cross-origin config URLs are fetched with:
method: 'GET'mode: 'cors'credentials: 'omit'redirect: 'error'referrerPolicy: 'no-referrer'
- In unauthenticated environments, same-origin config URLs use a plain
fetch()call (browser defaultcredentials: 'same-origin'). - Same-origin config URLs are fetched using simple fetch behavior (so same-origin session/cookie auth is preserved).
- In authenticated environments, allowlisted cross-origin config URLs are fetched using simple fetch behavior.
- Returned datasource configuration payloads are consumed as-is (no additional URL/config scrubbing).
Example:
dataSources: [
{
namespace: '@ohif/extension-default.dataSourcesModule.dicomwebproxy',
sourceName: 'dicomwebproxy',
configuration: {
name: 'dicomwebproxy',
dangerouslyAllowedOriginsForAuthenticatedEnvironments: [
'https://config.example.com',
'http://localhost:5000',
],
},
},
]Implicit Flow vs Authorization Code Flow
The Viewer supports both the Implicit Flow and the Authorization Code Flow. The Implicit Flow is the default currently, as it is easier to set up and use. However, you can opt for better security by using the Authorization Code Flow. To do so, add useAuthorizationCodeFlow to the configuration and change the response_type from id_token token to code.
Read more about Implicit Flow vs Authorization Code Flow here and here
oidc: [
{
authority: 'https://accounts.google.com',
client_id: '723928408739-k9k9r3i44j32rhu69vlnibipmmk9i57p.apps.googleusercontent.com',
redirect_uri: '/callback',
scope: 'email profile openid',
post_logout_redirect_uri: '/logout-redirect.html',
revoke_uri: 'https://accounts.google.com/o/oauth2/revoke?token=',
revokeAccessTokenOnSignout: true,
automaticSilentRenew: true,
// CHANGE THESE *****************************
response_type: 'code',
useAuthorizationCodeFlow: true,
},
],In fact, since browsers are blocking third-party cookies, the Implicit Flow will cease functioning in the future (not specific to OHIF). Read more here. It is recommended to use the Authorization Code Flow and begin migrating to it.
:::note
For the Authorization Code Flow, when authenticating against Google, you must add the client_secret to the configuration as well. Unfortunately, this seems to occur only with Google.
:::
Platform Docs Docs Deployment Azure (`platform/docs/docs/deployment/azure.md`)
sidebar_position: 12 title: Microsoft Azure Integration summary: Comprehensive guide for configuring OHIF with Microsoft Azure Healthcare APIs, including step-by-step instructions for Azure AD registration, DICOM service setup, CORS configuration, and OAuth authentication implementation.
Microsoft Azure
This guide explains how to configure a DICOM datasource in OHIF using Azure Healthcare APIs. It focuses on the configuration details and parameters necessary for integration.
Configuring Azure Healthcare APIs as a DICOMweb Data Source
Follow these steps to set up Azure as a DICOM datasource for the OHIF Viewer.
Azure AD Registration:
- Navigate to the Azure Portal.
- Select "Azure Active Directory" > "App registrations" > "New registration".
- Name your application.
- Under "Supported account types", select "Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)".
- Enter the following values in your redirect URI tab:
API Permissions:
- Under your registered application, go to "API permissions".
- Click "Add a permission".
- Choose the Azure API for DICOM (Dicom.ReadWrite). If you can't find it, refer to the "Configure Azure DICOMWEB Service" section and then return to this step.
Authentication:
- Under "Authentication", check the "ID tokens" box since we are using OpenID Connect.
App Client ID and Tenant ID:
- Copy your app client ID and tenant ID to prepare for use in configuring an OHIF datasource.
Consent:
- The first time a user logs in, they will be prompted to consent to the permissions your application has requested.
- Once they grant consent, your application can use the obtained access token to call the specific Microsoft API on behalf of the user.
Configure Azure DICOMWEB Service:
Create a Health Data Services workspace:
Visit the newly created workspace and press "Deploy DICOM Service":
After the DICOM service is deployed, visit the "CORS headers" section:
Set the headers and origins to
*and specify the HTTP methods you'd like to use:Save the changes.
Add the Microsoft emails of the users you'd like to grant access to your DICOM service in the "Access control" section and assign them the "DICOM Data Owner" role (or other roles depending on your requirements):
Copy your DICOM service URL to prepare it for usage in OHIF as a datasource:
Upload your DICOM files to your service.
1. Configure OIDC Authentication
Azure uses OpenID Connect (OIDC) for authentication. Update the OIDC section in your configuration file with the following parameters:
"oidc": [
{
"redirect_uri": "/callback",
"response_type": "id_token token",
"scope": "openid https://dicom.healthcareapis.azure.com/Dicom.ReadWrite",
"post_logout_redirect_uri": "/logout-redirect.html",
"automaticSilentRenew": false,
"revokeAccessTokenOnSignout": true,
"loadUserInfo": false,
"authority": "https://login.microsoftonline.com/{tenant-id}/v2.0/",
"client_id": "{client-id}"
}
]Parameters:
- redirect_uri: The URL where users are redirected after successful authentication.
- response_type: Specifies the authentication response type (id_token and token).
- scope: Defines the level of access. Use
Dicom.ReadWriteto allow read and write access to DICOM data. - post_logout_redirect_uri: The URL users are redirected to after logout.
- automaticSilentRenew: Automatically renews tokens without user interaction. Set to
falsefor manual renewal. - revokeAccessTokenOnSignout: Revokes access tokens upon logout for added security.
- loadUserInfo: Disables loading additional user information; set to
falsefor Azure as it is not supported. - authority: The Azure AD tenant URL for OIDC authorization.
- client_id: The application’s client ID from Azure AD.
2. Add the Data Source Configuration
Update the data source configuration file with your Azure Healthcare APIs details:
{
"namespace": "@ohif/extension-default.dataSourcesModule.dicomweb",
"sourceName": "ohif_azure",
"friendlyName": "ohif_azure",
"configuration": {
"singlepart": "bulkdata,pdf,video",
"imageRendering": "wadors",
"thumbnailRendering": "wadors",
"supportsWildcard": true,
"enableStudyLazyLoad": true,
"supportsFuzzyMatching": false,
"supportsStow": true,
"qidoRoot": "https://{your-dicom-instance}.dicom.azurehealthcareapis.com/v2",
"wadoUriRoot": "https://{your-dicom-instance}.dicom.azurehealthcareapis.com/v2",
"wadoRoot": "https://{your-dicom-instance}.dicom.azurehealthcareapis.com/v2"
}
}Parameters:
- qidoRoot: Base URL for QIDO-RS queries.
- wadoUriRoot: Base URL for WADO-URI requests.
- wadoRoot: Base URL for WADO-RS requests.
3. Running the Viewer with Azure Configuration
Save the above configurations in your OHIF Viewer configuration file.
Run the viewer:
bashcd OHIFViewer yarn install --frozen-lockfile APP_CONFIG=config/azure.js yarn run devReplace
config/azure.jswith the path to your configuration file.
Additional Notes
- Ensure that the Azure Healthcare API is enabled for your subscription and that the necessary permissions (e.g.,
Dicom.ReadWrite) are assigned to the OIDC client. - The
qidoRoot,wadoUriRoot, andwadoRootshould point to your Azure DICOM service URL. Replace{your-dicom-instance}with your actual instance name.
This setup allows OHIF to interact seamlessly with Azure's Healthcare APIs, enabling robust DICOM management and visualization.
Platform Docs Docs Deployment Build For Production (`platform/docs/docs/deployment/build-for-production.md`)
sidebar_position: 2 title: Build for Production summary: Step-by-step guide to building a production-ready version of the OHIF Viewer, including environment setup, code acquisition, dependency restoration, production build creation, and configuration options for deployment.
Build for Production
Build Machine Requirements
Getting the Code
With Git:
# Clone the remote repository to your local machine
git clone https://github.com/OHIF/Viewers.gitMore on: git clone,git checkout
From .zip:
Restore Dependencies & Build
Open your terminal, and navigate to the directory containing the source files.
Next run these commands:
# If you haven't already, enable yarn workspaces
yarn config set workspaces-experimental true
# Restore dependencies
yarn install --frozen-lockfile
# Build source code for production
yarn run buildIf everything worked as expected, you should have a new dist/ directory in theplatform/app/dist folder. It should roughly resemble the following:
platform/app/dist/"">├── app-config.js
├── app.bundle.js
├── app.css
├── index.html
├── manifest.json
├── service-worker.js
└── ...By default, the build output will connect to OHIF's publicly accessible PACS. If
this is your first time setting up the OHIF Viewer, it is recommended that you
test with these default settings. After testing, you can find instructions on
how to configure the project for your own imaging archive below.
Configuration
The configuration for our viewer is in the <root>platform/app/public/config
directory. Our build process knows which configuration file to use based on theAPP_CONFIG environment variable. By default, its value isconfig/default.js. The majority of the viewer's features,
and registered extension's features, are configured using this file.
The easiest way to apply your own configuration is to modify the default.js
file. For more advanced configuration options, check out our
configuration essentials guide.
Next Steps
Deploying Build Output
Drag-n-drop
Easy
Advanced
Testing Build Output Locally
A quick way to test your build output locally is to spin up a small webserver.
You can do this by running the following commands in the dist/ output
directory:
# Install http-server as a globally available package
yarn global add http-server
# Change the directory to the platform/app
cd platform/app
# Serve the files in our current directory
npx serve ./dist -c ../public/serve.jsonAutomating Builds and Deployments
If you found setting up your environment and running all of these steps to be a
bit tedious, then you are in good company. Thankfully, there are a large number
of tools available to assist with automating tasks like building and deploying
web application. For a starting point, check out this repository's own use of:
Platform Docs Docs Deployment Cors (`platform/docs/docs/deployment/cors.md`)
sidebar_position: 8 title: Cross-Origin Resource Sharing summary: Detailed explanation of cross-origin security configurations for OHIF Viewer, covering CORS requirements for data source access, iframe embedding, secure contexts, and troubleshooting techniques for proper implementation.
Cross-Origin Information for OHIF
This document describes various security configurations, settings and environments/contexts needed to fully leverage OHIF’s capabilities. One may need some configurations while others might need ALL of them - it all depends on the environment OHIF is expected to run in.
In particular, three of OHIF’s features depend on these configurations:
Embedding OHIF in an iframe
As described here, there are cases where OHIF will be embedded in an iframe. The following links provide more information for setting up and configuring OHIF to work in an iframe:
Secure Context
MDN defines a secure context as “a Window or Worker for which certain minimum standards of authentication and confidentiality are met.“
Any local URL is considered secure. The following are some examples of local URLs that are considered secure…
URLs that are NOT local must be delivered over https:// or wss:// (i.e. TLS) to be considered secure. See When is a context considered secure in MDN for more information.
iframes
A page embedded in an iframe is considered secure if it itself and every one of its embedding ancestors are delivered securely. Otherwise it is deemed insecure.
Configuring/setting up a secure context
Local URLs are considered secure, and as such whenever OHIF is accessed via a local URL (e.g. http://localhost:3000) it is running in a secure context. For example, in a development environment using the default webpack setup, OHIF can be deployed and accessed in a secure context at http://localhost:3000.
The best alternative is to host OHIF over HTTPS.
:::tip
OHIF can be served over HTTPS in a variety of ways (these are just some examples).
- Website hosting services that offer HTTPS deployment (e.g,. Netlify) or offer HTTPS load balancers (AWS, Google Cloud etc.)
- Setting up a reverse proxy (e.g.
nginx) with a self-signed certificate that forwards requests to the OHIF server
Origin Definition
According to MDN, a Web content’s origin is defined by the scheme (protocol), hostname (domain), and port of the URL used to access it. Two objects have the same origin only when the scheme, hostname, and port all match.
CORS - Cross-Origin Resource Sharing
A cross-origin resource is a resource (e.g. image, JSON, etc) that is served by one origin and used/referenced by a different origin.
CORS is the protocol utilized by web servers and browsers whereby a server of one origin identifies and/or restricts which of its resources that other origins (i.e. other than its own) a browser should allow access to. By default a browser does not permit cross-origin resource sharing.
The CORS mechanism relies on the HTTP response headers from the server to indicate if a resource can be shared with a different origin.
See the MDN CORS article for more information.
CORS HTTP Headers
The header that mostly concerns OHIF is listed below and should be configured accordingly on the DICOMweb server or any data source that OHIF would make XMLHttpRequests to for its data.
Access-Control-Allow-Origin: `<origin>` | *:::tip
The Access-Control-Allow-Origin header specifies which origins can access the served resource embedded in the response.
Either a single, specific origin (i.e. <origin>) can be specified or ALL origins (i.e. *)
See MDN for more information.
:::
CORS in OHIF
OHIF fetches and displays data and images from data sources. It invokes XMLHttpRequests to some data sources such as DICOMweb data sources to fetch the information to render. Typically, a DICOMweb server is hosted on a completely different origin than the one serving OHIF. As such, those XMLHttpRequests use CORS.
Troubleshooting CORS in OHIF
The following is an example screenshot of the browser console when one of OHIF’s DICOMweb data source servers is not configured for CORS.
And the following is what is in the accompanying network tab.
:::info
Setting the appropriate CORS header varies per server or service that is hosting the data source. What follows below is just one example to remedy the problem.
:::
:::tip
If Orthanc is the data source running in a Docker container composed with/behind nginx. And OHIF is being served at localhost:3000. The issue can be remedied by adding either of the following to Orthanc’s Docker container nginx.conf file.
add_header 'Access-Control-Allow-Origin' 'http://localhost:3000' always;Or
add_header 'Access-Control-Allow-Origin' '*' always;:::
Header Values (see [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cross-Origin_Resource_Policy#usage) for more information)
| Value | Description |
|---|---|
| same-site | Only requests from the same site can read the resource. |
| same-origin | Only requests from the same origin can read the resource. |
| cross-origin | Requests from any origin can read the resource. The value is useful and exists primarily for letting documents with the COEP require-corp value know that the resource is ok to be embedded |
OHIF and CORP
PDF from a Cross Origin DICOMweb Data Source
There are some DICOMweb data sources (e.g. dcm4chee) whereby OHIF uses the data source’s /rendered endpoint to embed a DICOM PDF document in the OHIF DOM using an <object> tag.
As specified for the COEP require-corp value, a page like OHIF with COEP header require-corp can embed cross-origin resources in DOM elements that have the crossorigin attribute OR the resource is delivered with an appropriate CORP header. The <object> tag does NOT support the crossorigin attribute. As such, the PDF must be delivered with a CORP header.
:::tip
Setting the CORP header varies per server or service that is hosting the data source. The following is just one example.
For a dcm4chee DICOMweb data source composed in Docker behind nginx, the CORP header can be configured in the nginx.conf file as such:
add_header 'Cross-Origin-Resource-Policy' 'cross-origin' always;If the dcm4chee server and the OHIF server are hosted on the same site, then the following would also work:
add_header 'Cross-Origin-Resource-Policy' 'same-site' always;:::
Platform Docs Docs Deployment Custom Url Access (`platform/docs/docs/deployment/custom-url-access.md`)
sidebar_position: 4 title: Custom URL Access/Build summary: "Instructions for hosting the OHIF Viewer on custom URL paths, with two deployment approaches: simple setup for serving the viewer from a subpath with assets at the root, and advanced setup for custom asset paths with detailed configuration steps."
Hosting the Web Viewer on a Custom URL Path
You can host the viewer on a subpath like /abc instead of the root /. There are two levels of customization depending on how you want to serve your static assets.
Simple Setup (Recommended for Most Use Cases)
If you want to make the viewer accessible from a custom path (e.g. /abc) and don’t care where the assets are loaded from (they’ll be fetched from the root /), this setup is for you.
What You Get
- Viewer available at
https://yourdomain.com/abc - All assets (JS, WASM, etc.) still loaded from the root (
/app.js,/viewer.wasm, etc.)
How To Set It Up
- Set
routerBasenamein your config file (e.g.,config/myConfig.js) to/abc - Build the viewer with:
APP_CONFIG=config/myConfig.js yarn buildLocal Development
APP_CONFIG=config/myConfig.js yarn devAdvanced Setup (Custom Asset Path)
If you want to host the viewer at /abc and serve static assets from a different location (e.g. /my-private-assets), this is a more advanced scenario.
What You Get
- Viewer accessible from
https://yourdomain.com/abc - All assets loaded from
https://yourdomain.com/my-private-assets/
Why This is Tricky
Some libraries (especially ones using WASM) load assets using relative paths, which can break if not handled carefully. To solve this:
- Set
routerBasenameto/abc - Set
PUBLIC_URLto/my-private-assets/ - Webpack will load assets from the specified public URL.
Local Development Notes
In development, use proxy rewrites to handle relative asset paths. Example for dicom-microscopy-viewer:
proxy: {
'/dicom-microscopy-viewer': {
target: 'http://localhost:3000',
pathRewrite: {
'^/dicom-microscopy-viewer': `/${PUBLIC_URL}/dicom-microscopy-viewer`,
},
},
}This ensures local development can find assets even when libraries expect them at certain paths.
Building and Serving in Production
To build the viewer for production:
PUBLIC_URL=/my-private-assets/ APP_CONFIG=config/myConfig.js yarn buildIf you're using npx serve, make sure to update serve.json:
{
"rewrites": [{ "source": "*", "destination": "/abc/index.html" }]
}Serve the viewer like this:
cd platform/app
mv dist abc # Rename dist folder to match your viewer route
npx serve -c ./public/serve.json🐳 Using Docker? You're Covered
If you’re using our Dockerfile, you’re all set — it already handles copying specific asset folders (like dicom-microscopy-viewer) to the root:
COPY --from=builder /usr/src/app/platform/app/dist/dicom-microscopy-viewer /usr/share/nginx/html/dicom-microscopy-viewerKeep an eye on the browser network tab for any assets that might fail to load — if any other libraries require similar treatment, you’ll need to handle those as well.
Summary
| Goal | routerBasename | PUBLIC_URL | Assets Load From |
|---|---|---|---|
Viewer at /abc, assets from / |
/abc |
default | Root / |
Viewer at /abc, assets from /my-private-assets |
/abc |
/my-private-assets/ |
/my-private-assets/ |
Platform Docs Docs Deployment Google Cloud Healthcare (`platform/docs/docs/deployment/google-cloud-healthcare.md`)
sidebar_position: 9 title: Google Cloud Healthcare Integration summary: Guide to setting up Google Cloud Healthcare API as a DICOM data source for OHIF, including project creation, API configuration, OAuth authentication setup, and implementation details for connecting the viewer to Google-hosted medical imaging data.
Google Cloud Healthcare
The Google Cloud Healthcare API is a
powerful option for storing medical imaging data in the cloud.
An alternative to deploying your own PACS is to use a software-as-a-service
provider such as Google Cloud. The Cloud Healthcare API promises to be a
scalable, secure, cost effective image storage solution for those willing to
store their data in the cloud. It offers an
almost-entirely complete DICOMWeb API
which requires tokens generated via the
OAuth 2.0 Sign In flow.
Images can even be transcoded on the fly if this is desired.
Setup a Google Cloud Healthcare Project
Create a Google Cloud account
Create a project in Google Cloud
A project in Google Cloud can be created by clicking the projects drop down box.
And then clicking the
NEW PROJECTbutton in the top-right corner of the
dialogue that is displayed.Enable the Cloud Healthcare API for your project
:::tip
An API can be enabled through theAPIs & Services > Enabled APIs & Services
console and clicking the+ ENABLE APIS AND SERVICESbutton.:::
:::tip
The principal (i.e. account) that is enabling the Cloud Healthcare API will require
the following roles that can be set in theIAM & Admin > IAMconsole for the
desired project.- Service Usage Viewer
- Service Usage Admin
:::
:::tip
Roles can be added to a principal in theIAM & Admin > IAMconsole by clicking
theEdit principal(i.e. pencil) icon to the right of a principal or by clicking theGRANT ACCESSbutton at the top of the list of principals. TheGRANT ACCESS
button is particularly useful if theEdit principalicon is disabled.
:::(Optional): Create a Dataset and DICOM Data Store for storing your DICOM data
:::tip
To both list existing datasets as well as create a new dataset for your project,
the principal (i.e. account) must have the following roles enabled
in theIAM & Admin > IAMconsole.- Editor
:::
Enable the Cloud Resource Manager API for your project.
Note: If you are having trouble finding the APIs, use the search box at
the top of the Cloud console.Go to APIs & Services > OAuth Consent Screen to create an OAuth Consent screen and fill in your application details.
Run through the three step process of adding an OAuth Consent Screen, clicking
SAVE AND CONTINUEat the end of each step.For the Scopes step, for Google APIs, click the
ADD OR REMOVE SCOPESbutton.In the
Update selected scopesdialogue that flies in from the right, add the
following scopes to theManually add scopestext box.https://www.googleapis.com/auth/cloudplatformprojects.readonlyhttps://www.googleapis.com/auth/cloud-healthcare
Click
ADD TO TABLEand then clickUPDATE
Go to APIs & Services > Credentials to create a new set of credentials:
Click
+ CREATE CREDENTIALSand from the drop down selectOAuth Client ID.
See OAuth 2.0 Client ID for more information.Choose the "Web Application" type
Add your domain (e.g.
http://localhost:3000) to the Authorized JavaScript
origins.Add your domain, plus
callback(e.g.http://localhost:3000/callback) to the Authorized Redirect URIs.Save your Client ID for later.
(Optional): Create a bucket containing DICOM files and import it into a Data Store
When importing a bucket into a Data Store, the following warning might be
displayed indicating that the Cloud Healthcare Service Agent service account associated with the
project does not have theStorage Object Viewerrole.The Cloud Healthcare Service Agent service account can be displayed in the
IAM & Admin > IAMconsole by checking theInclude Google-provided role grantscheckbox.
TheStorage Object Viewerrole can then be granted to the Cloud Healthcare Service Agent service account.More information regarding the Cloud Healthcare Service Agent service account can
be found at https://cloud.google.com/healthcare-api/docs/permissions-healthcare-api-gcp-products
(Optional): Enable Public Datasets that are being hosted by Google:
https://cloud.google.com/healthcare/docs/resources/public-datasets/
Run the viewer with your OAuth Client ID
- Open the
config/google.jsfile and changeYOURCLIENTIDto your Client ID
value. - Run the OHIF Viewer using the config/google.js configuration file
cd OHIFViewer
yarn install --frozen-lockfile
APP_CONFIG=config/google.js yarn run devConfiguring Google Cloud Healthcare as a datasource in OHIF
A Google Cloud Healthcare DICOM store can be configured as a DICOMweb datasource
in OHIF. A full or partial path is permitted in the configuration file. For
partial paths, the data source configuration UI
will assist in filling in the missing pieces. For example, a configuration with
empty wadoUriRoot, qidoRoot and wadoRoot will prompt for the entire path
step-by-step starting with the project.
Platform Docs Docs Deployment Iframe (`platform/docs/docs/deployment/iframe.md`)
sidebar_position: 7 sidebar_label: iframe title: Embedding OHIF in an iframe summary: Guidelines for embedding OHIF Viewer within other applications using iframe integration, explaining configuration requirements for path settings, static builds, and proper setup to ensure WebWorkers, WASM, and WebGL features function correctly.
iframe
With the transition to more advanced visualization, loading, and rendering techniques using WebWorkers, WASM, and WebGL, the script tag usage of the OHIF viewer v3 has been deprecated.
An alternative option for script tag usage is to employ an iframe. You can utilize the iframe element to load the OHIF viewer and establish communication with it using the postMessage API if needed.
We recommend utilizing modern development practices and incorporating OHIF viewer within your application using a more modular and integrated approach, such as leveraging bundlers, other UI
components, and frameworks.
Static Build
You can use the iframe element to load the OHIF viewer as a child element of your application if you need the
viewer to be embedded within your application. The iframe element can be used as follows (use your own custom styles)
<iframe src="./path-to-ohif-build" style="width: 100%; height: 500px; border: none"/>The important thing to note here is that the iframe element is loading the OHIF viewer from the ./path-to-ohif-build. This path can be
named anything you want, but it should be the path to the OHIF viewer build directory. The build directory is the directory that
contains the index.html file (See build for production for more information).
It is also required that the PUBLIC_URL environment variable is set to the same path. For example, if the iframe is
`` (which means there is a ohif folder containing the build in your main app), then you need to:
- use a config (e.g. config/myConfig.js) file that is using the
routerBasenameof/ohif(note the one / - it is not /ohif/). - build the viewer with
PUBLIC_URL=/ohif/ APP_CONFIG=config/myConfig.js yarn build(note the two / - it is not /ohif).
:::tip
Check to make sure the app-config.js in the build is reflecting the correct routerBasename.
:::
:::tip
The PUBLIC_URL tells the application where to find the static assets and the routerBasename will tell the application how to handle the rouets
:::
Try it locally
Download the index.html and the build (against the /ohif/ path) from here
Then run the
npx http-server unzipped-folder
# you can use npx serve ./dist -c ../public/serve.json as an alternative to http-serverYou should be able to see
Platform Docs Docs Deployment Nginx Image Archive (`platform/docs/docs/deployment/nginx--image-archive.md`)
sidebar_position: 10 title: Nginx + Image Archive Setup summary: Tutorial for setting up OHIF Viewer with Nginx and PACS (Orthanc or DCM4CHEE), using Docker for a production-ready system with reverse proxy configuration to securely handle medical imaging data, including installation steps and troubleshooting tips.
Nginx + Image Archive
At a certain point, you may want others to have access to your instance of the
OHIF Viewer and its medical imaging data. This post covers one of many potential
setups that accomplish that. Please note, noticeably absent is user account
control.
Do not use this recipe to host sensitive medical data on the open web. Depending
on your company's policies, this may be an appropriate setup on an internal
network when protected with a server's basic authentication.
Handling Web Requests
We mitigate our first issue by allowing [Nginx][nginx] to handle incoming web
requests. Nginx is open source software for web serving, reverse proxying,
caching, and more. It's designed for maximum performance and stability --
allowing us to more reliably serve content.
More specifically, we accomplish this by using areverse proxy to retrieve
resources from our image archive (Orthanc), and when accessing its web admin.
A reverse proxy is a type of proxy server that retrieves resources on behalf
of a client from one or more servers. These resources are then returned to the
client, appearing as if they originated from the proxy server itself.
This setup allows us to create a setup similar to the one pictured below:
- All web requests are routed through
nginximage /pacs/dicom-webis a reverse proxy fororthanc'sDICOM Webendpoints, which handles DICOM requests/pacsis a reverse proxy fororthanc's Web Admin, which is the UI for managing studies- All static resources for OHIF Viewer are served up by
nginxwhen a matching
route for that resource is requested
Getting Started
Requirements
- Docker
Not sure if you have docker installed already? Try running docker --version
in command prompt or terminal
Setup
cd platform/app/.recipes/Nginx-Orthanc- run:
docker-compose up --build - Navigate to
127.0.0.1for the viewer (at first there is no study) - Navigate to
127.0.0.1/pacsfor uploading studies via the UI, or send studies via DIMSE C-STORE to[email protected]:4242(hint: you can use utilizes like dcm4che'sstorescuto send studies in bulk via the command line)
:::note
For subsequent runs, use docker-compose up -d to start the services without rebuilding the images. However, ensure you rebuild the images if you make changes to the Dockerfile. If you modify the configurations in the nginx.conf or orthanc.json files, you can restart the services by running docker-compose up, as these files are mounted as volumes.
Inside docker compose file you see the following volumes mounted:
volumes:
# Nginx config
- ./config/nginx.conf:/etc/nginx/nginx.conf
# Logs
- ./logs/nginx:/var/logs/nginx:::
You can see the overview of the mentioned steps:
:::info
The following video demonstrates an outdated capture using the deprecated OpenResty-Orthanc recipe. However, it still provides insight into the steps for running the viewer with Orthanc. Use the new Nginx-Orthanc recipe for the most up-to-date instructions.
:::
Troubleshooting
Exit code 137
This means Docker ran out of memory. Open Docker Desktop, go to the advanced
tab, and increase the amount of Memory available.
Cannot create container for service X
Use this one with caution: docker system prune
X is already running
Stop running all containers:
- Win:
docker ps -a -q | ForEach { docker stop $_ } - Linux:
docker stop $(docker ps -a -q)
Traceback (most recent call last):
File "urllib3/connectionpool.py", line 670, in urlopen
....
Are you sure your docker is running? see explanation here
Configuration
After verifying that everything runs with default configuration values, you will
likely want to update:
- The domain:
http://127.0.0.1
OHIF Viewer
The OHIF Viewer's configuration is imported from a static .js file. The
configuration we use is set to a specific file when we build the viewer, and
determined by the env variable: APP_CONFIG. You can see where we set its value
in the dockerfile for this solution:
ENV APP_CONFIG=config/docker-nginx-orthanc.js
You can find the configuration we're using here:/public/config/docker-nginx-orthanc.js
To rebuild the webapp image created by our dockerfile after updating the
Viewer's configuration, you can run:
docker-compose buildORdocker-compose up --build
Other
All other files are found in: /docker/Nginx-Orthanc/
| Service | Configuration | Docs |
|---|---|---|
| OHIF Viewer | [dockerfile][dockerfile] | You're reading them now! |
| Nginx | [/nginx.conf][config-nginx] |
|
| Orthanc | [/orthanc.json][config-orthanc] |
[Here][orthanc-docs] |
Next Steps
OHIF + Dcm4chee
You can follow the similar steps above to run OHIF Viewer with Dcm4chee PACS.
The recipe for this setup can be found at `platform/app/.recipes/Nginx-Dcm4chee