Skip to main content

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:

  • DICM remained at byte 128
  • extractMetadataFromDicomBuffer() 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 -1024 to 3071

BRATS MRI​

  • ITK: Int16Array
  • VTK: Int16Array
  • Scalar range: approximately 0 to 995

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:

  1. The user-selected performance preset
  2. The current rendering/interaction state

User Presets​

  • High Quality
  • Balanced
  • Performance

Volume States​

  • normalIdle
  • cropIdle
  • cropInteractive

cropInteractive maps internally to interactionLow.

Relevant parameters include:

  • sampleDistance
  • imageSampleDistance
  • maximumSamplesPerRay

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, and itk-wasm are excluded from Vite dependency pre-bundling because of their worker behavior.
  • .dcm, .nii, .vti, and .wasm are explicitly treated as assets.
  • The development server uses port 3000.
  • Rollup's maxParallelFileOps is set to 1 to 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.jsx
  • src/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.

  1. Install the relevant @fontsource packages.
  2. Import font weights:
    • 400
    • 500
    • 600
    • 700
  3. Set the candidate as APP_FONT in src/theme/fonts.js.
  4. Open OperSight.
  5. Use browser DevTools to confirm that the selected font is actually rendering.
  6. 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.