# OHIF Documentation > OHIF (Open Health Imaging Foundation) Viewer is an open-source, web-based, zero-footprint DICOM viewer platform designed for medical imaging. It provides a highly configurable and extensible framework for building diagnostic quality medical imaging applications. OHIF Viewer supports various imaging formats (primarily DICOM), offers advanced visualization tools, customizable workflows, and integration capabilities with different data sources. This file contains the complete documentation for OHIF Viewer, concatenated for easy reference and searching. Each section is clearly marked with its source URL. # Root Documentation ## Where to next? Source: https://docs.ohif.org/llm/README The [Open Health Imaging Foundation][ohif-org] (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](https://github.com/cornerstonejs/cornerstone3D-beta) for decoding, rendering, and annotating medical images. - Works out-of-the-box with Image Archives that support [DICOMWeb][dicom-web]. 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 CSS
| Measurement Tracking | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5) |
|
| Labelmap Segmentations | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.12.2.1107.5.2.32.35162.30000015050317233592200000046) |
|
| Fusion and Custom Hanging protocols | [Demo](https://viewer.ohif.org/tmtv?StudyInstanceUIDs=1.3.6.1.4.1.14519.5.2.1.7009.2403.334240657131972136850343327463) |
|
| Volume Rendering | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&hangingprotocolId=mprAnd3DVolumeViewport) |
|
| PDF | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=2.25.317377619501274872606137091638706705333) |
|
| RT STRUCT | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.6.1.4.1.5962.99.1.2968617883.1314880426.1493322302363.3.0) |
|
| 4D | [Demo](https://viewer.ohif.org/dynamic-volume?StudyInstanceUIDs=2.25.232704420736447710317909004159492840763) |
|
| Video | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=2.25.96975534054447904995905761963464388233) |
|
| Slide Microscopy | [Demo](https://viewer.ohif.org/microscopy?StudyInstanceUIDs=2.25.141277760791347900862109212450152067508) |
#### 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][gh-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](./development/getting-started.md).
- We're an active, vibrant community.
[Learn how you can be more involved.](./development/contributing.md)
- Feeling lost? Read our [help page](/help).
#### 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 Research_
>
> Erik 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](https://www.doi.org/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 Trials_
>
> Trinity 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](https://www.doi.org/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](https://github.com/OHIF)
[ohif-org]: https://www.ohif.org
[ohif-demo]: http://viewer.ohif.org/
[dicom-web]: https://en.wikipedia.org/wiki/DICOMweb
[gh-issues]: https://github.com/OHIF/Viewers/issues
---
## DICOM Conformance Statement
Source: https://docs.ohif.org/llm/conformance
You can find a version that has been open sourced by Radical Imaging [in this link](https://docs.google.com/document/d/1hbDlUApX4svX33gAUGxGfD7fXXZNaBsX0hSePbc-hNA/edit?usp=sharing)
---
## OHIF Viewer Release Notes
Source: https://docs.ohif.org/llm/release-notes
#### Release Notes
You can find the detailed release notes on the OHIF website. Please visit [https://ohif.org/release-notes](https://ohif.org/release-notes)
---
## OHIF Viewer Educational Resources
Source: https://docs.ohif.org/llm/resources
#### 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](https://docs.google.com/presentation/d/1HZDL-72nNe4BPawDxR3XnSFLB3oLo72RjExc-KHDZfo/edit?usp=sharing)
- Introducing Advanced Segmentation Tools in the OHIF Viewer and Cornerstone3D [Slides](https://docs.google.com/presentation/d/146oJ24PPsFZaDPHeFudRF1dmbL42K9yHzQdXXAXdWxk/edit?usp=sharing)
#### 2024
#### ITCR Sustainment Session 2024
Dr. Gordon Harris presented at ITCR sustainment session about the future of OHIF.
- OHIF Sustainability [Slides](https://docs.google.com/presentation/d/15380mjCzBKBj9PuysCW1Q9ODnyoypJrCDpj3atTtK6I/edit?usp=sharing)
#### ITCR Sustainment Panel 2024
- Advanced Medical Imaging Visualization [Slides](https://docs.google.com/presentation/d/1alUp9uJpoJs3aAUE0KqrufGo6e6HHvXYmOAdJp-Rlkc/edit?usp=sharing)
#### 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](https://www.dropbox.com/scl/fi/z4h86bmsxi0c62e1n6h9l/P7-9-Alireza-Sedghi-Final.pdf?rlkey=v5pm0p5ygkbq41x9bz3hr5yi8&dl=0)
- Advancing Medical Imaging on the Web: Optimizing the Dicomweb Server Architecture with Static Dicomweb [Poster](https://www.dropbox.com/scl/fi/ep0lxjp90kbxhjoffe4kh/P7-10-Bill-Wallace-Final.pdf?rlkey=xl2u6tdnh9j9hgvkajxv3b02o&dl=0)
- (**ππ 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](https://www.dropbox.com/scl/fi/srs2rxgtv2r69ver9ub1j/P7-8-Bill-Wallace-Final.pdf?rlkey=k9mmraw76r9q2s3b9w9s0793w&dl=0)
#### 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](https://www.itcr2023.org/). You can find the slides and poster here:
[[Slides]](https://docs.google.com/presentation/d/1R38s95db_yZj0WoYdlUbaWGZsWVb3H-3u_hXBZXiTaE/edit?usp=sharing)[[Poster]](https://ohif-assets.s3.us-east-2.amazonaws.com/presentations/OHIF-ITCR-2023-FINAL-PRINT.pdf)
#### SIIM 2023 Tech Tools Webinar | April 12th, 2023
Free, Open Source Tools for Research: MONAI and OHIF Viewer
[[Slides](https://docs.google.com/presentation/d/1afJ5Y9Tzukgn7eAbaO1oiCtN7XvIimFdmZP-HcOUofA/edit?usp=sharing)][[Video](https://www.youtube.com/watch?v=lo8J5w5jUJI)]
#### NA-MIC Project Week 38th 2023 - Remote
We participated in the 38th Project Week with three projects around OHIF. [[Website](https://projectweek.na-mic.org/PW38_2023_GranCanaria/)]
- PolySeg representations for OHIF Viewer ([link](https://projectweek.na-mic.org/PW38_2023_GranCanaria/Projects/OHIF_PolySeg/))
- Cross study synchronizer for OHIF Crosshair ([link](https://projectweek.na-mic.org/PW38_2023_GranCanaria/Projects/OHIF_SyncCrosshair/))
- DATSCAN Viewer implementation in OHIF ([link](https://projectweek.na-mic.org/PW38_2023_GranCanaria/Projects/OHIF_DATSCAN/))
#### 2022
#### OHIF Demo to Interns
[[Slides]](https://docs.google.com/presentation/d/1a2PkUnqkVMaXaBsuFn7-PPlBJULU3dBwzI_44gKFeYI/edit?usp=sharing)
#### SIIM 2022 - Updates from the Imaging Informatics Community
We participated in the SIIM 2022 conference to give update for the imaging
informatics community.
[[Slides]](https://docs.google.com/presentation/d/1EUGaUzQtGhZbZWpGLe6ONqChpVMw9Qr9l3KHODevMow/edit?usp=sharing)
[[Video]](https://vimeo.com/734463662/dbd5a88371)
#### 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]](https://docs.google.com/presentation/d/18XZDon4-Sitc2a70V5sFyhyUVZI_mIgfXHGtdxhZMjE/edit?usp=sharing)
[[Video]](https://vimeo.com/843234581/ad7d308a44)
#### [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]](https://docs.google.com/presentation/d/1-GtOKmr2cQi-r3OFyseSmgLeurtB3KXUkGMx2pVLh1I/edit?usp=sharing)
[[Video]](https://vimeo.com/668339696/63a2c48de8)
#### 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]](https://docs.google.com/presentation/d/1KYNjuiI8lT1foQ4P9TGNV0lBhM6H-5KBs0wkYj4JJbk/edit?usp=sharing)
#### Chan Zuckerberg Initiative (CZI)
Project presentations and demonstrations of Essential Open Source Software for
Science (EOSS) grantees
[[Slides]](https://docs.google.com/presentation/d/1_CLtG2hsL3ZxOtV2olVnzBOzq-TMLrHLomOy3FiU4NE/edit?usp=sharing)
[[Video]](https://youtu.be/0FjKkTJO0Rc?t=3737)
#### Google Cloud Tech
Healthcare Imaging with Cloud Healthcare API
[[Video]](https://www.youtube.com/watch?v=2MiX9ScHFhY)
#### 2020
#### OHIF ITCR Pitch
OHIF pitch for Informatics Technology for Cancer Research (ITCR)
[[Slides]](https://docs.google.com/presentation/d/1MZXnZrVAnjmhVIWqC-aRSvJOoMMRLhLddACdCa1TybM/edit?usp=sharing)
[[Video]](https://vimeo.com/843234613/625bdb8793)
#### 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).
1. Introduction to VTK.js and OHIF
[[Slides]](https://docs.google.com/presentation/d/1NCJxpfx_qUGJI_2DhbECzaOg0k-Z6b65QlUptCofN-A/edit#slide=id.p)
[[Video]](https://vimeo.com/375520781)
2. Developing with VTK.js
[[Slides]](https://docs.google.com/presentation/d/17TCS6EhFi6SWFIrcAJ-DFdFzFFL-WD9BBTv-owmMdDU/edit#slide=id.p)
[[Video]](https://vimeo.com/375521036)
3. VTK.js Architecture and Tooling
[[Slides]](https://docs.google.com/presentation/d/1Sr1OGxMSw0oCt46koKQbmwSIE11Kqq8MGtyW3W0ASpk/edit?usp=gmail_thread)
[[Video]](https://vimeo.com/375521810)
4. OHIF + VTK.js Integration
[[Slides]](https://docs.google.com/presentation/d/1Iwg-u01HGVf1CgC6NbcBD3gm3uHN9WhjU59FSz55TN8/edit?ts=5d9c9ce4#slide=id.g59aa99cda4_0_131)
[[Video]](https://vimeo.com/375521206)
#### 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]](https://www.youtube.com/watch?v=gUIPtoSBL-Q)
#### OHIF Community Meeting - June
[[Slides]](https://docs.google.com/presentation/d/1K9Y6eP5DYTXoDlfwCZE6GkCUp83AK4_40YQS0dlzVBo/edit?usp=sharing)
#### 2016
#### Imaging Community Call
Open Source Oncology Web Viewer; Presentation by Gordon J. Harris
[[Slides]](https://www.slideshare.net/imgcommcall/lesiontracker)
#### OHIF Community Meeting - June
[[Slides]](https://docs.google.com/presentation/d/1Ai25mBG0ZWUPhaadp3VnbCVmkYs9K51sQ8osMixrvJ0/edit?usp=sharing)
#### OHIF Community Meeting - September
[[Slides]](https://docs.google.com/presentation/d/1iYZoU7v7KHSLHiKwH1_9_wweAkG7RGnyxrWeeHva4zQ/edit?usp=sharing)
---
## OHIF Viewer Test Coverage
Source: https://docs.ohif.org/llm/test-coverage
#### 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:
- [OHIF Playwright Test Coverage Report](https://docs.ohif.org/coverage)
---
# Behaviours
## Behaviours
Source: https://docs.ohif.org/llm/behaviours/README.md
#### 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](./segmentation-multiframe-part10-prefetch.md)
β _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
via `loadMultiframeAsPart10: false` (data source config or the
`cornerstone.segmentation.loadMultiframeAsPart10` customization).
- [Report dialog: where a save goes, and what the series is called](./report-dialog-save-destinations.md)
β _implemented_. The three destinations of a save, the `predecessorImageId`
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
1. Add a `kebab-case.md` file in this directory.
2. State whether it documents **current behaviour** or is a **proposal**.
3. Link to the code (`path:line`) that implements or will implement it.
4. Add it to the **Index** above.
---
## Report dialog: where a save goes, and what the series is called
Source: https://docs.ohif.org/llm/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 the `ohif.createReportDialog` customization.
- `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`
β the `PredecessorSequence` provider, 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, and
`Save as new` is the default choice otherwise. `Save to current` and
`Replace 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:
1. The series holds the same type of object, which is the modality of the save.
2. The series has a `predecessorImageId` value.
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 the
`PredecessorSequence` 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 no
`predecessorImageId` 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:
1. `itemName`, the name that the user chose for the item. A rename before the
save therefore reaches the field. `storeSegmentation` passes
`segmentation.label`, but only when the user chose that label: the service
invents a name such as `Segmentation 3` for a new segmentation, and marks the
segmentation with `labelIsGenerated`. A label that is still marked this way
goes to `defaultSeriesDescription` instead, 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 in `itemName`.
2. The description of the series that the viewer loaded the data from, which is
the name of the last save of this data.
3. The descriptions that the user used before for this type of item, most recent
first. See [remembered descriptions](#remembered-descriptions).
4. `defaultSeriesDescription`, the name for an item that has no other name. The
in-tree callers pass `Segmentation`, `Contours` and `Measurements`.
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 uses
`defaultSeriesDescription` 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.
- `itemType` is the key that the viewer remembers the descriptions under, and
`itemType` defaults to the modality.
- `rememberedDescriptionCount` is 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 also
`priorSeriesNumber`, which is one less. A caller that computes the number as
`1 + priorSeriesNumber` gets the number that the dialog shows.
---
## Full-instance prefetch for segmentation (and multiframe) loading
Source: https://docs.ohif.org/llm/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 source
`configuration`, the global customization
`cornerstone.segmentation.loadMultiframeAsPart10`, then the built-in default of
`true` β 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-loader`
- `imageLoader/prefetchPart10Instance.ts` β registers a Part 10 instance into
the frame registry (thin wrapper over `addDicomPart10Instance`).
- `imageLoader/wadors/loadImageFromRegistry.ts` +
`wadors/loadImage.ts` β WADO-RS loads now consult the registry first.
- `@ohif/extension-default` `DicomWebDataSource` β `retrieve.prefetchInstanceFrames`.
- `@ohif/extension-cornerstone-dicom-seg` `getSopClassHandlerModule.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 (`loadMultiframeAsPart10` unset β `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 `loadMultiframeAsPart10` resolves to `false` (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 the
`COMPRESSED_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 up `COMPRESSED_FRAME_DATA` for the frame; if present it decodes via the
**same `createImage`** path and returns the image; if absent it returns
`undefined`.
- `wadors/loadImage.ts` calls 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 `Map