Skip to content

dcm (mri image) parsing support#20

Merged
ethanrous merged 5 commits into
mainfrom
dcm-parsing-support
Jun 7, 2026
Merged

dcm (mri image) parsing support#20
ethanrous merged 5 commits into
mainfrom
dcm-parsing-support

Conversation

@ethanrous

Copy link
Copy Markdown
Owner

No description provided.

Copilot AI review requested due to automatic review settings June 6, 2026 23:44

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds native DICOM (.dcm) Part-10 decoding support to agno, including byte-level parsing, window/level rendering to RGB8, and integration into the auto-detecting loader pipeline.

Changes:

  • Introduces a new codec::dicom module (parser + VOI math + renderer) behind a dicom feature (enabled by default).
  • Routes .dcm files through agno_image’s type detection + loader bridge, and adds integration/unit tests plus fixture-generation tooling.
  • Updates internal docs/rules to document the new codec and architecture, plus small unrelated tweaks (Just test invocation, PDF lexer test constant).

Reviewed changes

Copilot reviewed 17 out of 19 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
scripts/make_dicom_fixture.py Adds a fixture generator for PHI-stripped DICOM + reference RGB render.
justfile Adjusts cargo test invocation argument expansion.
CLAUDE.md Documents the new dicom feature/codec support.
agno/tests/dicom_decode_tests.rs Adds integration tests against a real DICOM fixture + loader routing + error-path test.
agno/src/exif/mod.rs Treats DICOM as “no EXIF” (returns empty context).
agno/src/codec/pdf/lexer.rs Updates a float parsing test constant.
agno/src/codec/mod.rs Feature-gates and exposes the new codec::dicom module.
agno/src/codec/dicom/voi.rs Adds modality LUT + linear window/level math with unit tests.
agno/src/codec/dicom/parse.rs Adds a Part-10 parser with sequence skipping + metadata extraction and tests.
agno/src/codec/dicom/mod.rs Adds public DICOM module entry point and documentation.
agno/src/codec/dicom/decode.rs Adds pixel extraction + grayscale/RGB rendering to RGB8 with tests.
agno/src/agno_image/load/mod.rs Adds and re-exports the DICOM loader bridge module.
agno/src/agno_image/load/load.rs Extends format detection to recognize DICOM Part-10 and dispatch to loader.
agno/src/agno_image/load/dicom.rs Implements load_dicom_from_bytes bridge (feature-gated) + tests.
agno/Cargo.toml Adds dicom feature and enables it in default features.
.claude/rules/codec-guide.md Documents DICOM decode API in the codec guide.
.claude/rules/architecture.md Updates module map to include the new DICOM loader/codec.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/make_dicom_fixture.py Outdated
Comment thread scripts/make_dicom_fixture.py Outdated
Comment thread agno/src/codec/dicom/mod.rs
Comment thread agno/src/codec/dicom/mod.rs Outdated
Comment thread agno/src/codec/dicom/mod.rs Outdated
Comment thread agno/src/codec/dicom/decode.rs Outdated
Address findings from a max-effort code review of the DICOM decoder:

Correctness / robustness
- Bound sequence nesting depth to prevent stack overflow on crafted
  deeply-nested undefined-length sequences (untrusted input).
- Reject PALETTE COLOR / non-mono photometrics instead of silently
  rendering palette indices as grayscale.
- Support multi-frame access: add decode_dicom_frame +
  load_dicom_frame_from_bytes and a DICOM arm in load_image_page so the
  page_count it reports is actually reachable.
- Detect the DICM marker before leading-magic checks so a DICOM with a
  non-zero preamble (e.g. an embedded JPEG/TIFF preview) is not misrouted.
- Support 16-bit RGB (mask to BitsStored, scale to 8-bit).
- Reject non-finite WindowCenter/Width/Rescale (NaN/Inf) so a malformed
  value falls back to auto-window rather than producing an all-black frame.
- Trim NUL padding (not just whitespace) when parsing DS/IS values.
- Bound file-meta element lengths to the meta group so an overshooting
  element errors clearly instead of skipping the transfer syntax.
- Fix make_dicom_fixture.py to mask/sign-extend from BitsStored and to
  auto-window when no VOI is present, matching the Rust decoder.

Cleanup
- Render MONOCHROME frames in a single streaming pass (no Vec<f64>
  intermediate; auto-window derived from raw sample extremes).
- Share Part-10 test builders via codec/dicom/test_fixtures.rs and the
  PSNR helper via tests/common/mod.rs.
- Remove the duplicated disabled-feature error stub; drop the dead
  window clamp and redundant default guards; add non-square coverage.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 21 out of 23 changed files in this pull request and generated 5 comments.

Comment thread agno/src/codec/dicom/decode.rs
Comment thread agno/src/codec/dicom/voi.rs Outdated
Comment thread agno/src/lib_interface.rs Outdated
Comment thread scripts/make_dicom_fixture.py Outdated
Comment thread scripts/make_dicom_fixture.py Outdated
ethanrous added 2 commits June 6, 2026 21:04
- lib_interface: check is_dicom() before the PDF/GIF magic dispatch in
  load_image_page; a Part-10 preamble is arbitrary and may begin with
  another format's magic, so the DICM marker must be authoritative
  (mirrors detect_image_type()).
- decode: reject PlanarConfiguration values outside {0,1} instead of
  silently treating any non-zero value as planar.
- decode: 8-bit RGB now masks to BitsStored and scales up to 8 bits,
  matching the 16-bit and grayscale paths. Added tests for both.
- mod: replace intra-doc links into private modules with plain code
  spans to avoid rustdoc private-link warnings.
- scripts/make_dicom_fixture.py: drop unused math import, require an
  explicit source path with a usage message, and reword the misleading
  "raw pixels are not identifying" comment.
Copilot AI review requested due to automatic review settings June 7, 2026 01:23

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 22 out of 24 changed files in this pull request and generated 3 comments.

Comment thread agno/src/agno_image/load/load.rs
Comment thread agno/src/codec/dicom/decode.rs Outdated
Comment thread scripts/make_dicom_fixture.py
- voi: clamp window output to [0,255] before the u8 cast so float
  roundoff at window endpoints can never land outside the byte range
- load: rewind the file cursor after a failed DICOM probe so
  detect_image_type stays side-effect-free for non-DICOM inputs
- decode: use checked arithmetic for frame size/offset math to reject
  crafted dimensions/frame counts instead of overflowing usize
- scripts: drop the unused bits_allocated var from the fixture generator
@ethanrous ethanrous merged commit 9086bc2 into main Jun 7, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants