Skip to content

CLI quickstart

dcmclient is one static binary. Every subcommand is self-describing, and the whole roster is agent-discoverable over manifest and mcp.

$ dcmclient --help            # the full command list
$ dcmclient dcmdump --help    # per-tool flags

Networking

# DICOMweb  convenience verbs, or the raw RS verbs (qido / wado / stow)
$ dcmclient search https://pacs.example.com --patient-id 42 --json
$ dcmclient pull   https://pacs.example.com --study 1.2.3 -o ./out
$ dcmclient push   https://pacs.example.com ./series/*.dcm --study 1.2.3

# DIMSE  verification / storage / query-retrieve
$ dcmclient echo-scu  PACS 4242 --aec PACS
$ dcmclient store-scu PACS 11112 ./*.dcm --aec PACS
$ dcmclient find-scu  PACS 11112 -S -k QueryRetrieveLevel=SERIES --json
$ dcmclient get-scu   PACS 11112 -S -k StudyInstanceUID=1.2.3 --out-dir out/   # C-GET pull
$ dcmclient move-scu  PACS 11112 --move-dest STORESCP -S -k StudyInstanceUID=1.2.3  # C-MOVE to a third party
$ dcmclient term-scu  PACS 4242 --aec PACS                                     # connectivity probe (open + release)

# DIMSE-N workflow services  MPPS, print, storage commitment, UPS, IAN
$ dcmclient mpps-scu  PACS 11112 --action create --dataset-file step.json
$ dcmclient stgcmt-scu PACS 11112 --dataset-file commit.json

DICOMweb has both the convenience verbs above and the raw RS verbs as their own tools (qido / wado / wado-uri / stow / ups, plus delete to remove a study / series / instance); DIMSE covers the full classic set (echo / store / find / get / move SCU + store-scp, plus the term-scu connectivity probe) and the DIMSE-N services (mpps-scu, printscu, stgcmt-scu, upsscu, ian-scu). Every networked subcommand accepts --profile <name> to fill --server / --base-path / --auth from a saved registry (dcmclient config add …), plus AWS SigV4 (--aws-* / $AWS_*) and OAuth2 (--oauth2-* / $DCMCLIENT_OAUTH2_*).

Local file tools

The 55-tool roster groups into ten kinds of operation — at least one example of each below. The generated tool reference has every flag of every tool.

Inspect — read a file as text / JSON / XML / semantic content

$ dcmclient dcmdump    scan.dcm                 # one element per line
$ dcmclient dcm2json   scan.dcm > scan.json     # DICOM JSON (PS3.18 §F)
$ dcmclient dcm2xml    scan.dcm > scan.xml      # Native DICOM XML (PS3.19)
$ dcmclient dcm2content seg.dcm --json          # semantic JSON of SEG/RT/PS/Waveform
$ dcmclient dsrdump    report.dcm               # SR content tree as text

Vendor character sets decode where strict readers fail

Text values come out as correct UTF-8 regardless of how the source declared its SpecificCharacterSet — the native text engine handles the full DICOM range (Latin / Cyrillic / Greek / Arabic / Hebrew / Thai, Japanese Shift-JIS + ISO 2022 IR 87 / 159, Korean EUC-KR, Chinese GB18030 / GBK, UTF-8) and decodes it adaptively — lenient charset-alias matching, tolerant of malformed ISO 2022 escapes, with a fault-tolerant fallback. The messy real-world vendor exports that a strict iconv-based reader rejects, dcmdump / dcm2json / dcm2xml read correctly.

Render & extract pixels / signals

$ dcmclient dcm2raw   ct.dcm out.raw --json     # decode ANY transfer syntax → raw pixels + numpy sidecar
$ dcmclient dcm2img   ct.dcm out.png            # 8-bit PNG/PNM for display
$ dcmclient dcm2mpg   video.dcm out.mp4         # extract an embedded video stream
$ dcmclient dcm2waveform ecg.dcm out.csv        # ECG/EEG samples → CSV / WAV

Convert & transcode

$ dcmclient dcmconv   --to j2k ct.dcm out.dcm   # transcode (also: rle / jls / htj2k / jxl / …)
$ dcmclient dcm2nii   ct_series/ ct.nii.gz      # validated NIfTI
$ dcmclient img2dcm   photo.jpg out.dcm         # JPEG → Secondary Capture
$ dcmclient pdf2dcm   report.pdf out.dcm        # wrap a PDF  ↔  dcm2pdf extracts it back
$ dcmclient dcm2pdf   report.dcm report.pdf     #   …the reverse: pull the embedded document out
$ dcmclient dcmencap  model.stl out.dcm         # wrap PDF/CDA/STL/OBJ/MTL  ↔  dcmdecap unwraps
$ dcmclient dcmdecap  report.dcm out.pdf        #   …the reverse: extract any encapsulated payload
$ dcmclient json2dcm  scan.json out.dcm         # DICOM JSON / XML / dcmdump text → Part-10
$ dcmclient dump2dcm  edited.txt out.dcm        # an (edited) dcmdump text listing → Part-10
$ dcmclient dsr2xml   report.dcm report.xml     # SR content tree → XML  ↔  xml2dsr rebuilds the SR

Every codec built in — including JPEG-XL and HTJ2K

dcmconv encodes and decodes every DICOM transfer syntax out of the box, with no plugins or external codec packages — JPEG-2000 (.4.90/.91), JPEG-LS (.4.80/.81), RLE, baseline / lossless JPEG, and the newest JPEG-XL (.4.110/.111) and HTJ2K / High-Throughput JPEG 2000 (.4.201–.203). JPEG-XL and HTJ2K in particular are syntaxes most DICOM toolchains still don't ship, so dcmclient is often the only tool that can read or produce them:

# encode to the modern codecs
$ dcmclient dcmconv --to jxl    ct.dcm ct_jxl.dcm        # JPEG-XL (lossless)
$ dcmclient dcmconv --to htj2k  ct.dcm ct_htj2k.dcm      # HTJ2K / jph

# decode them anywhere  dcm2raw / dcm2img read ANY transfer syntax
$ dcmclient dcm2raw ct_jxl.dcm   pixels.raw --json
$ dcmclient dcm2img ct_htj2k.dcm preview.png

Author derived objects

$ dcmclient mkseg     ct.dcm --mask labelmap.dcm --meta seg.json -o out-seg.dcm   # coded SEG
$ dcmclient mkparamap series/ --values adc.f32 --meta adc.json -o adc_map.dcm     # Parametric Map
$ dcmclient mkreport  findings.json report.dcm --series-from study.dcm            # TID 1500 SR
$ dcmclient mksr      report.json -o report-sr.dcm                                # arbitrary SR content tree
$ dcmclient mkkos     keyimages.json kos.dcm --series-from study.dcm              # Key Object Selection

Edit, de-identify & validate

$ dcmclient dcmodify    scan.dcm -i '(0010,0010)=Anon^Patient'   # byte-verbatim edit
$ dcmclient dcmdeident  study/*.dcm --out-dir deid/            # PS3.15 de-identification
$ dcmclient dsign       in.dcm signed.dcm --key key.pem --cert cert.pem   # PS3.15 digital signature
$ dcmclient dcmradiomics ct.dcm --mask roi.dcm --json         # IBSI radiomic features
$ dcmclient dcmprobe    scan.dcm                              # is it valid Part-10?
$ dcmclient dcmvalidate scan.dcm                             # IOD conformance
$ dcmclient dcmicmp     original.dcm compressed.dcm           # pixel-difference metrics

A directory of instances → a DICOMDIR-indexed file-set (PS3.10 media):

$ dcmclient dcmmkdir study/ --output /media/dicom

De-identification — the full PS3.15 Annex E profile, configurable

dcmdeident implements the PS3.15 Annex E Basic Profile with every retain / clean option column as a flag — keep exactly what your use case allows and remove the rest. A batch shares one session, so UIDs are remapped consistently across the whole study, and it never edits in place:

# de-identify a study but keep dates and patient characteristics for research,
# shift nothing, drop private tags, consistent UID remap across the batch:
$ dcmclient dcmdeident study/*.dcm --out-dir deid/ \
      --retain-dates --retain-patient-chars

# or shift every date by a fixed offset (consistent across the batch):
$ dcmclient dcmdeident study/*.dcm --out-dir deid/ --shift-dates -3650 --json

Options include --retain-uids / --retain-device-id / --retain-institution-id / --retain-private / --clean-descriptors / --clean-graphics — see the tool reference.

Validation — IOD conformance, agent-readable

dcmvalidate goes past VR / value-length / dictionary checks to full IOD conformance: per-SOP-Class mandatory modules, Type 1/2 presence, value multiplicity, enumerated values — top-level and nested per sequence item. --json emits a structured findings document an agent can branch on:

$ dcmclient dcmvalidate ct.dcm --json            # findings as JSON
$ dcmclient dcmvalidate study/*.dcm --errors-only # only error-severity

Worked recipes

Real chains — each step is one tool call, so an agent can run them too.

PACS → de-identified NIfTI for a model

$ dcmclient search https://pacs.example.com --patient-id 42 --modality CT --json
$ dcmclient pull   https://pacs.example.com --study 1.2.840... -o ./study
$ dcmclient dcmdeident ./study/*.dcm --out-dir ./deid     # PS3.15 de-identification
$ dcmclient dcm2nii ./deid ct.nii.gz                       # 3-D volume, validated affine

Migrate a study between two PACSes (streaming, constant memory)

$ dcmclient forward --source https://old-pacs.example.com \
                    --dest   https://new-pacs.example.com \
                    --study 1.2.840...

Bridge a legacy DIMSE sender to a DICOMweb archive

$ dcmclient listen --port 11112 --ae-title BRIDGE \
                   --sink https://archive.example.com    # C-STORE in → STOW out

Inspect, fix a wrong tag, and re-validate — the LLM edit loop

$ dcmclient dcmdump ct.dcm | grep PatientID                # see the current value
$ dcmclient dcmodify ct.dcm -i '(0010,0020)=ANON-001'      # byte-verbatim edit
$ dcmclient dcmvalidate ct.dcm                             # confirm still conformant

Author a structured report from measurements

$ dcmclient mkreport findings.json -o report.dcm           # TID 1500 SR
$ dcmclient dsr2html report.dcm > report.html              # human-readable render

Agent / MCP

The same ToolSpec registry that backs the CLI is the agent surface:

$ dcmclient manifest          # JSON self-description of every tool (inputSchema + outputSchema)
$ dcmclient mcp               # live MCP server over stdio — an agent drives the whole roster

Because the tool reference is generated from manifest, the docs, the agent surface, and the binary can never disagree.

Exit codes

Code Meaning
0 success
1 runtime error (bad input, or a per-file failure)
104 argument conversion error (bad numeric / enum)
105 validation error (rejected or mutually-exclusive option)
106 required option or argument missing