Python wrapper for launching the dcmview Rust binary
Project description
dcmview
dcmview is an ephemeral DICOM inspection tool for developers and data scientists. It scans one or more DICOM files or directories, starts a local browser viewer, exposes a small HTTP API for frames, tags, and annotations, and exits cleanly when stopped.
The main use case is fast multi-frame inspection, such as DBT and cine MR, from a single Rust binary with the Svelte frontend embedded at build time.
Install
Recommended install paths:
- Ubuntu and other managed Linux systems:
python -m pip install --user dcmview-py
dcmview --help
This wheel bundles the dcmview binary on supported platforms, so users do not need Rust or Node.js installed.
- macOS: use the published Homebrew tap or download a prebuilt archive from GitHub Releases
Source builds remain available for contributors and unsupported platforms.
Build prerequisites:
- Rust stable 1.75+
- Node.js 18+ and npm at build time
sshonPATHonly when using--tunnel
Install from a checkout of this repository:
cargo install --path .
Build without installing:
cargo build --release
./target/release/dcmview --help
build.rs runs npm ci when frontend/package-lock.json changes and then builds the frontend. If node or npm are not on PATH, set DCMVIEW_NODE_PATH or DCMVIEW_NPM_PATH to absolute executable paths.
Quick Start
# Open one file in the browser
dcmview ./scan.dcm
# Scan a directory recursively
dcmview ./study_dir
# Run headless on a fixed port and stop after 5 idle minutes
dcmview --host 127.0.0.1 --port 8888 --no-browser --timeout 300 ./study_dir
When ready, dcmview prints:
dcmview: server running at http://127.0.0.1:<port>
Press Ctrl+C to stop the server.
CLI
dcmview [OPTIONS] <PATH> [PATH ...]
| Option | Default | Description |
|---|---|---|
<PATH>... |
required | DICOM files or directories to inspect |
-p, --port <u16> |
0 |
Bind port; 0 auto-assigns an available port |
--host <addr> |
127.0.0.1 |
Bind address |
--no-browser |
false | Do not open the browser automatically |
--timeout <seconds> |
none | Exit after this many seconds without API/browser requests |
--no-recursive |
false | Scan only the top level of input directories |
--tunnel |
false | Start an SSH local port-forward helper |
--tunnel-host <host> |
none | SSH target used with --tunnel |
--tunnel-port <u16> |
0 |
Forwarded local port; 0 uses the server port |
--annotations <csv> |
none | Load EMBED-style ROI annotations for overlay and editing |
Examples:
dcmview ./scan.dcm
dcmview --no-recursive ./study_dir
dcmview --host 0.0.0.0 --port 8888 ./study_dir
dcmview --tunnel --tunnel-host user@host --tunnel-port 9000 ./study_dir
dcmview --annotations ./embed_annotations.csv ./study_dir
The server is unauthenticated. It binds to loopback by default; if you bind to a public interface, use your own network access controls.
Viewer
The embedded Svelte viewer includes:
- File tabs labeled from
PatientID · Modality · StudyDatewhen available, otherwise by filename - Canvas-based frame viewing with pan, zoom, scroll, window/level, reset, flips, and 90-degree rotation
- Window presets: Default, Full Dynamic, and common CT presets
- Multi-frame controls with previous/next, cine playback, FPS selection, loop, and sweep
- Lazy DICOM tag browsing with filter, sequence expansion, binary length display, resizable columns, and click-to-copy
- Rectangular ROI annotation display and editing, including draw, select, move, resize, delete, frame scoping, and CSV export
Input shortcuts:
| Action | Shortcut |
|---|---|
| Frame previous/next | Left/Right arrows or [ / ] |
| Play/pause cine | Space |
| Window/level tool | W |
| Pan tool | P |
| Zoom tool | Z |
| Scroll tool | S |
| ROI tool | R |
| Reset viewport | Double-click |
Mouse behavior depends on the active tool. Right-drag always zooms, middle-drag always pans, the wheel scrolls frames, and Ctrl/Cmd+wheel zooms.
Annotations
--annotations loads an EMBED-style CSV into memory. dcmview never modifies the input CSV or DICOM files. Viewer edits are kept in memory and can be downloaded with Export ROIs.
Required columns:
anon_dicom_pathROI_coords
Optional columns:
num_ROI; when present, it must equallen(ROI_coords)ROI_frames; when omitted or[], ROIs apply to all frames
ROI_coords is a JSON array of [ymin, xmin, ymax, xmax] boxes. ROI_frames is a JSON array of frame-index lists. JSON-valued fields must be CSV-quoted.
anon_dicom_path,num_ROI,ROI_coords,ROI_frames
/path/to/dbt_case.dcm,2,"[[120,340,220,430],[400,510,480,590]]","[[0,1,2],[5,6]]"
/path/to/ffdm_case.dcm,1,"[[80,150,190,260]]","[]"
Behavior:
- Matching uses normalized path equality against loaded DICOM paths
- Rows without a matching loaded file are ignored
- Loaded files without matching rows start with no ROIs
- Duplicate
anon_dicom_pathrows are rejected - Frame indices are zero-based and must be less than
NumberOfFrames - Coordinates are canonicalized to
[ymin, xmin, ymax, xmax]when edited through the API
Python Wrapper
The dcmview-py package is a subprocess wrapper around the Rust binary.
On supported release platforms, published wheels bundle dcmview inside the Python package, so a user-level install is enough:
python -m pip install --user dcmview-py
dcmview --help
The package installs both dcmview and dcmview-py; dcmview is the primary CLI, and dcmview-py remains as a compatibility alias.
From a source checkout, the wrapper still works with a locally installed dcmview on PATH.
cargo install --path .
python -m pip install -e .
python -m dcmview_py --help
Script usage:
from dcmview_py import view
# Blocking call; returns when dcmview exits.
view(["./scan.dcm"], browser=False, timeout=300)
# Non-blocking call.
handle = view(["./study_dir"], browser=False, annotations="./embed_annotations.csv", block=False)
print(handle.url)
handle.stop()
Context manager:
from dcmview_py import view
with view(["./study_dir"], browser=False, block=False) as handle:
print(handle.url)
Module CLI:
python -m dcmview_py --no-browser --timeout 120 ./study_dir
python -m dcmview_py --annotations ./embed_annotations.csv ./study_dir
The module CLI mirrors the Rust options: --host, --port, --tunnel, --no-recursive, --annotations, and related flags.
HTTP API
Static frontend assets are served at / and /assets/*.
| Method | Path | Description |
|---|---|---|
| GET | /api/files |
File registry and server metadata |
| GET | /api/file/:index/info |
Frame metadata for one file |
| GET | /api/file/:index/frame/:frame |
Display frame; supported image transfer syntaxes return PNG |
| GET | /api/file/:index/frame/:frame/raw |
Decoded frame sample bytes for client-side rendering |
| GET | /api/file/:index/tags |
Lazy DICOM tag tree |
| GET | /api/file/:index/annotations |
Current in-memory ROI annotations |
| PUT | /api/file/:index/annotations |
Replace in-memory ROI annotations for one file |
| GET | /api/annotations/export.csv |
Download current annotations as EMBED CSV |
Files
GET /api/files returns:
{
"files": [
{
"index": 0,
"path": "/path/to/scan.dcm",
"label": "PATIENT · MG · 20240101",
"has_pixels": true,
"frame_count": 60,
"rows": 3000,
"columns": 2500,
"transfer_syntax_uid": "1.2.840.10008.1.2.4.50",
"default_window": { "center": 200.0, "width": 4000.0 }
}
],
"tunnelled": false,
"tunnel_host": null,
"server_start_ms": 1714300000000
}
GET /api/file/:index/info returns frame_count, rows, columns, transfer_syntax, has_pixels, and default_window for one file.
Display Frames
GET /api/file/:index/frame/:frame returns image/png for supported display paths.
Query parameters:
| Param | Description |
|---|---|
wc |
Window center; used with ww in default mode |
ww |
Window width; used with wc in default mode |
mode |
default or full_dynamic |
Window selection:
default: explicitwcandww, then DICOM Window Center/Width, then 1st/99th percentile fallbackfull_dynamic: true min/max of the current frame; ignores DICOM defaults and query window values
Transfer syntax behavior:
| Transfer syntax | Display behavior |
|---|---|
| JPEG Baseline / Extended | Decoded server-side and PNG-encoded |
| JPEG Lossless / Lossless SV1 | Decoded server-side and PNG-encoded |
| JPEG 2000 lossless/lossy | Decoded server-side and PNG-encoded |
| Implicit LE / Explicit LE / Explicit BE | Windowed server-side and PNG-encoded |
| JPEG-LS / RLE / other | 422 {"error": "unsupported transfer syntax: ..."} |
Response headers include X-Cache: HIT or X-Cache: MISS.
Raw Frames
GET /api/file/:index/frame/:frame/raw returns application/octet-stream plus metadata headers. This is a decoded sample transport for the frontend, not a copy of the original DICOM Pixel Data element for compressed syntaxes.
Supported raw paths:
- Uncompressed frames: native sample bytes, normalized to little-endian by
dicom-object - JPEG Baseline / Extended: decoded to 8-bit grayscale samples
- JPEG Lossless: decoded to 8-bit or 16-bit grayscale samples when supported by the codec stack
- Grayscale JPEG 2000: decoded to 8-bit or 16-bit samples
JPEG-LS, RLE, unsupported syntaxes, and multi-component JP2 raw decoding return 422 or a decode error.
Headers:
X-CacheX-Frame-Rows,X-Frame-ColumnsX-Frame-Bits-Allocated,X-Frame-Pixel-RepresentationX-Frame-Samples-Per-Pixel,X-Frame-Photometric-InterpretationX-Frame-Rescale-Slope,X-Frame-Rescale-InterceptX-Frame-Default-Wc,X-Frame-Default-Wwwhen DICOM window tags are available
Tags
GET /api/file/:index/tags returns an array of tag nodes:
[
{
"tag": "(0008,0060)",
"vr": "CS",
"keyword": "Modality",
"value": { "type": "string", "value": "MG" }
}
]
Value types are string, number, numbers, binary, sequence, and error. Pixel data and other binary VRs are represented by byte length, not by full values. Long numeric arrays and sequences may be truncated with truncated and total fields.
Annotations
GET /api/file/:index/annotations returns:
{
"num_roi": 2,
"roi_coords": [[120, 340, 220, 430], [400, 510, 480, 590]],
"roi_frames": [[0, 1, 2], [5, 6]]
}
Files without annotations return:
{ "num_roi": 0, "roi_coords": [], "roi_frames": [] }
PUT /api/file/:index/annotations replaces one file's in-memory annotations and returns the canonicalized payload. Invalid coordinates or frame mappings return 400 {"error": "..."}.
GET /api/annotations/export.csv downloads the current in-memory annotations as anon_dicom_path,num_ROI,ROI_coords,ROI_frames.
Development
Frontend:
npm --prefix frontend ci
npm --prefix frontend run dev
npm --prefix frontend run build
Backend:
cargo check
cargo build
cargo build --release
Tests:
cargo test
Integration tests use real DICOM fixtures and cover discovery, display-frame decoding, raw-frame transport, cache headers, tag serialization, annotations, and tunnel fallback.
Architecture summary:
- Backend: Rust, Axum, Tokio
- DICOM:
dicom-rs,dicom-pixeldata,jpeg2k - Pixel pipeline: server-side display PNGs, raw sample transport for interactive rendering, LRU caches
- Frontend: Svelte 5, Vite, TypeScript, embedded via
rust-embed - Distribution: one executable with no runtime frontend assets
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dcmview_py-0.1.0-py3-none-manylinux_2_28_x86_64.whl.
File metadata
- Download URL: dcmview_py-0.1.0-py3-none-manylinux_2_28_x86_64.whl
- Upload date:
- Size: 5.2 MB
- Tags: Python 3, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cc7cd28d3e8fabc7c51c9e739ed35a956aad97f43bed04d81c62eb7a478a4c27
|
|
| MD5 |
84b7932f53ba69f7c39a92383830e54f
|
|
| BLAKE2b-256 |
b4c9b6b8cc85fbf927173d430de89181f2911bbebb6b0d301caa9e79ff6d19ec
|
Provenance
The following attestation bundles were made for dcmview_py-0.1.0-py3-none-manylinux_2_28_x86_64.whl:
Publisher:
release.yml on beatrice-b-m/dcmview
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dcmview_py-0.1.0-py3-none-manylinux_2_28_x86_64.whl -
Subject digest:
cc7cd28d3e8fabc7c51c9e739ed35a956aad97f43bed04d81c62eb7a478a4c27 - Sigstore transparency entry: 1760917487
- Sigstore integration time:
-
Permalink:
beatrice-b-m/dcmview@9d61aa6e55407803a3f09dd965964666abb1b2b7 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/beatrice-b-m
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9d61aa6e55407803a3f09dd965964666abb1b2b7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file dcmview_py-0.1.0-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: dcmview_py-0.1.0-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 4.7 MB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2ddf9aae8ff43a7f99faf83b9fad788c327d81552f7985561270881a3baf5166
|
|
| MD5 |
4606c7eb8b3ba3c37e552da78b23c5e6
|
|
| BLAKE2b-256 |
5b57bc6236baf4eed608a6526b5787bf7be607057e5696e7f68b86e88eba13fd
|
Provenance
The following attestation bundles were made for dcmview_py-0.1.0-py3-none-macosx_11_0_arm64.whl:
Publisher:
release.yml on beatrice-b-m/dcmview
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dcmview_py-0.1.0-py3-none-macosx_11_0_arm64.whl -
Subject digest:
2ddf9aae8ff43a7f99faf83b9fad788c327d81552f7985561270881a3baf5166 - Sigstore transparency entry: 1760917262
- Sigstore integration time:
-
Permalink:
beatrice-b-m/dcmview@9d61aa6e55407803a3f09dd965964666abb1b2b7 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/beatrice-b-m
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9d61aa6e55407803a3f09dd965964666abb1b2b7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file dcmview_py-0.1.0-py3-none-macosx_10_13_x86_64.whl.
File metadata
- Download URL: dcmview_py-0.1.0-py3-none-macosx_10_13_x86_64.whl
- Upload date:
- Size: 4.9 MB
- Tags: Python 3, macOS 10.13+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0bef71737e6b4251ac1604fc2a3404191911c2ba3e762e0a0e5179f23443e512
|
|
| MD5 |
a70da4dcf2a196ba1de8db74106c0a8b
|
|
| BLAKE2b-256 |
18248ddf182513eecd22370b221f242289b8f4451f80773387d57cc1d5801bc6
|
Provenance
The following attestation bundles were made for dcmview_py-0.1.0-py3-none-macosx_10_13_x86_64.whl:
Publisher:
release.yml on beatrice-b-m/dcmview
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dcmview_py-0.1.0-py3-none-macosx_10_13_x86_64.whl -
Subject digest:
0bef71737e6b4251ac1604fc2a3404191911c2ba3e762e0a0e5179f23443e512 - Sigstore transparency entry: 1760917393
- Sigstore integration time:
-
Permalink:
beatrice-b-m/dcmview@9d61aa6e55407803a3f09dd965964666abb1b2b7 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/beatrice-b-m
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9d61aa6e55407803a3f09dd965964666abb1b2b7 -
Trigger Event:
push
-
Statement type: