Technical Notes
DICOM Multipart Extraction / MRI Modality Regression
Problem
Some PACS-loaded MRI studies lost usable DICOM metadata during multipart extraction.
When modality information was lost:
- Modality became unknown/blank
- The application selected the generic rendering profile
- MRI could appear CT-like
- Patient/study metadata could also be missing
Cause
The issue was traced to extractDicomFromMultipart() in dicomWebAdapter.js.
The multipart response was being decoded into a string with:
TextDecoder('latin1')
Treating the binary DICOM payload as text could alter the original DICOM bytes before metadata extraction.
Fix
Multipart boundaries are now parsed directly on the Uint8Array, preserving the DICOM payload as binary data.
After the change on a previously failing MRI:
DICMremained at byte 128extractMetadataFromDicomBuffer()succeeded- Modality returned
MR - Patient metadata returned
- The MRI rendering profile was selected correctly
The fix appeared successful on the known failing case.
Broader regression testing across additional PACS-loaded studies is still useful.
ITK → VTK Scalar Precision
The rendering pipeline was checked to determine whether DICOM/NIfTI intensity data was being reduced to 8-bit grayscale.
Tested Datasets
- Head/Neck CT
- CTA Head and Neck
- BRATS NIfTI MRI
For the tested datasets, scalar data remained Int16Array / 2 bytes per scalar through the ITK → VTK pipeline.
CTA Head and Neck
- ITK:
Int16Array - VTK:
Int16Array - Scalar range: approximately
-1024to3071
BRATS MRI
- ITK:
Int16Array - VTK:
Int16Array - Scalar range: approximately
0to995
Conclusion
There was no observed 16-bit → 8-bit conversion in the tested ITK → VTK pipeline.
A visible grayscale/window range such as 0–255 does not imply that the underlying volume data itself is stored as 8-bit.
View vs. Plan Transfer Functions
View and Plan intentionally use different transfer-function behavior.
View
View uses the standard visualization transfer function.
For CT, values above the selected iso threshold remain highly opaque/white, prioritizing conventional volume visualization.
Plan
Plan uses a Plan-specific CT transfer function intended to make cuts and internal geometry easier to inspect.
It preserves an opacity ramp below the selected iso threshold but reduces opacity toward the high end rather than keeping all higher values fully opaque.
The CT ramp width is currently fixed at approximately 40.
MRI
MRI does not use CT/HU threshold assumptions.
MRI rendering is intensity-based and adapts to the dataset's scalar range.
Important
The different Plan behavior is intentional.
Changes to Plan rendering should not automatically be applied to View.
Future rendering work may introduce additional CT/MRI transfer functions optimized for particular tissue types or surgical tasks.
Adaptive Rendering / Performance Presets
OperSight adjusts volume-rendering settings based on:
- The user-selected performance preset
- The current rendering/interaction state
User Presets
- High Quality
- Balanced
- Performance
Volume States
normalIdlecropIdlecropInteractive
cropInteractive maps internally to interactionLow.
Relevant parameters include:
sampleDistanceimageSampleDistancemaximumSamplesPerRay
The selected performance preset is stored in local storage and defaults to Balanced if no valid stored setting is found.
The distinction between the user-selected preset and adaptive interaction state should be preserved if the renderer is refactored.
Vite / Build Configuration
The current Vite configuration contains several deliberate implementation details:
@itk-wasm/dicom,@itk-wasm/image-io, anditk-wasmare excluded from Vite dependency pre-bundling because of their worker behavior..dcm,.nii,.vti, and.wasmare explicitly treated as assets.- The development server uses port
3000. - Rollup's
maxParallelFileOpsis set to1to reduce peak memory usage, particularly for CI/build environments.
These settings should not be removed as generic cleanup without checking why they were introduced.
App Typography / Font Testing
Font Configuration
Global OperSight app fonts are controlled in:
src/theme/fonts.js
The font defined there is applied through:
src/theme/typography.jsxsrc/theme/globalStyles.jsx
For quick visual testing, directly change APP_FONT in:
src/theme/fonts.js
Current Font Candidates
The current candidates for app-wide testing are:
- Public Sans
- Source Sans 3
- Inter
- Noto Sans
No final font decision has been made yet.
The current system font stack should be used as the baseline when comparing candidates.
Important
Fonts must be loaded/imported before testing.
Simply adding a font name to the font stack does not guarantee that the browser is actually using that font. If the font is unavailable, the browser may silently fall back to a system font.
Recommended Testing Setup
- Install the relevant
@fontsourcepackages. - Import font weights:
400500600700
- Set the candidate as
APP_FONTinsrc/theme/fonts.js. - Open OperSight.
- Use browser DevTools to confirm that the selected font is actually rendering.
- Compare the same application screens using each candidate.
Screens to Compare
Use the following screens when evaluating fonts:
- PACS / DICOMweb studies table
- Viewer with the left sidebar open
- Tool options panel
- Dense metadata or overlay labels
- Current Scan / saved scan cards
Compare each candidate against the existing system font stack.
Current Status
No final application font has been selected.
Active candidates:
- Public Sans
- Source Sans 3
- Inter
- Noto Sans
Font testing should continue from these candidates when development resumes.