Skip to content

Runtime architecture

The self-contained Rust binary is the center of every dcmview workflow. The Python package wraps or bundles that binary, the VS Code extension launches it or accepts bridged launches, and release builds embed the compiled Svelte frontend in it.

CLI / Python wrapper / VS Code
→ process dispatch
→ active VS Code workspace bridge, when available
→ otherwise local startup
→ bind loopback listener
→ start progressive DICOM discovery
→ serve embedded viewer and /api routes
→ file and logical-series catalog
→ display/raw pixel service and caches
→ tags, references, semantic and WSI context
→ in-memory annotation store
→ stop, cancel discovery, and release resources

The CLI parses paths and startup options. Before starting a local server, v0.2.12 looks for a trusted dcmview bridge registered by an active VS Code workspace. If the bridge accepts the launch, VS Code owns the viewer session. If no matching bridge exists or it is unavailable, the CLI starts the normal local viewer.

dcmview_py.view() follows the same rule unless vscode_bridge=False or DCMVIEW_VSCODE_BYPASS=1. Its non-blocking local and VS Code handles expose the same .url and .stop() surface even though session ownership differs.

Local startup binds the requested host and port before starting DICOM discovery. Port 0 asks the operating system for an available port, and the startup message reports the actual bound address.

Discovery runs outside the asynchronous HTTP executor and publishes valid files progressively. This lets the browser render an early file while a larger directory scan continues. A cancellation-aware coordinator owns the blocking scan, final counters, optional annotation import, and task join through shutdown.

Zero valid DICOM files is a non-zero startup outcome. Individual unreadable, filtered, metadata-only, or unsupported objects do not terminate a mixed scan.

The HTTP contract joins backend and frontend

Section titled “The HTTP contract joins backend and frontend”

The Rust contract declares every API operation, method, path, query and body type, success status, media type, required headers, and JSON error shape. Generated TypeScript types and endpoint metadata drive the frontend fetch boundary.

The browser never needs direct filesystem access. It receives file summaries, tags, decoded frame data, references, semantic context, and annotations from the loopback server. The internal API is versioned with the application rather than supported as a stable third-party SDK.

The server groups objects only when Study and Series Instance UIDs provide a complete identity. Geometry-aware ordering can combine related single-frame objects, multiframe objects, and enhanced concatenations into a logical sequence.

Each logical position remains a (file index, source frame) reference. Crossing a file boundary therefore preserves the correct tags, cache key, annotation scope, and DICOM-reference target. Files with incomplete study/series identity stay independent instead of being merged speculatively.

Display and raw caches use byte budgets, and cache locks are held only for lookup or insertion—not while opening files, decoding codecs, windowing pixels, encoding PNGs, or serializing tags. The frontend also retains active encoded frames, decoded bitmaps, and raw buffers within separate byte-budgeted caches.

The server can render a supported frame to PNG for correctness. The browser uses raw decoded samples for responsive window/level only when metadata says it can reproduce the presentation pipeline safely; otherwise it uses the server PNG path.

See DICOM and pixel support for the release-specific decode boundary and the internal HTTP API for exact routes.