go-dicom

command module
v1.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 14, 2026 License: MIT Imports: 3 Imported by: 0

README

go-dicom

Go Reference Tests Release Go Version

A comprehensive, high-performance Go library for reading, writing, manipulating, and networking DICOM (Digital Imaging and Communications in Medicine) data. The Go equivalent of Python's pydicom + pynetdicom.

Overview

go-dicom is designed for healthcare IT systems, medical imaging applications, PACS systems, and clinical data management. It provides:

  • Complete DICOM file I/O with support for all transfer syntaxes (.dcm, .ima, DICOMDIR, raw)
  • DICOM networking — SCU/SCP with C-ECHO, C-STORE, C-FIND, C-MOVE, C-GET, and all N-DIMSE services
  • Thread-safe dataset operations for concurrent processing
  • 5,000+ standard DICOM tags with O(1) lookup
  • 10,500+ private vendor tags (GE, Siemens, Philips, Toshiba, and more)
  • De-identification / anonymization per DICOM PS3.15 Annex E
  • Pixel data extraction with multi-frame and multi-bit-depth support
  • 30+ international character encodings (Japanese, Chinese, Korean, Arabic, etc.)
  • TLS support for encrypted DICOM communication (HIPAA compliance)
  • CLI tools for file inspection, conversion, and network operations (echoscu, storescu, storescp, findscu, movescu)

Quick Start

Installation
go get github.com/amrshadid/go-dicom
DICOM Networking (SCU Client)
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/amrshadid/go-dicom/network"
)

func main() {
    ctx := context.Background()

    // Create SCU (client) — equivalent to pynetdicom's AE().associate()
    scu := network.NewSCU(network.SCUConfig{
        CallingAE: "MY_APP",
        CalledAE:  "PACS",
        Address:   "pacs.hospital.com:11112",
    })

    // Associate with the server
    if err := scu.Associate(ctx, nil); err != nil {
        log.Fatal(err)
    }
    defer scu.Release(ctx)

    // C-ECHO (verification/ping)
    if err := scu.Echo(ctx); err != nil {
        log.Fatal(err)
    }
    fmt.Println("Server is reachable!")

    // C-STORE (send a dataset)
    // err = scu.Store(ctx, dataset)

    // C-FIND (query) — results stream on a Go channel
    // results, _ := scu.Find(ctx, queryDataset)
    // for result := range results {
    //     fmt.Println(result.DataSet)
    // }

    // C-MOVE (retrieve to another AE)
    // err = scu.Move(ctx, queryDataset, "DEST_AE")
}
DICOM Networking (SCP Server)
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/amrshadid/go-dicom/dataset"
    "github.com/amrshadid/go-dicom/network"
)

func main() {
    ctx := context.Background()

    // Create SCP (server) — equivalent to pynetdicom's AE().start_server()
    scp := network.NewSCP(network.SCPConfig{
        AETitle: "MY_SCP",
        Port:    11112,
    })

    // Set handler for incoming requests
    scp.SetHandler(&network.StorageHandler{
        OnStore: func(ctx context.Context, sopClass, sopInstance string, ds *dataset.Dataset) uint16 {
            fmt.Printf("Received: %s\n", sopInstance)
            // Save to disk, database, forward to another PACS, etc.
            return network.StatusSuccess
        },
    })

    // Listen and serve (blocks, handles associations in goroutines)
    log.Fatal(scp.ListenAndServe(ctx))
}
Read a DICOM File
package main

import (
    "fmt"
    "log"
    "os"

    "github.com/amrshadid/go-dicom/filebase"
    "github.com/amrshadid/go-dicom/filereader"
    "github.com/amrshadid/go-dicom/tag"
)

func main() {
    file, err := os.Open("patient.dcm")
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()

    // Wrap the file in a byte-order-aware reader
    reader := filebase.NewFileReader(file)

    dicomFile, err := filereader.ReadDICOMFile(reader)
    if err != nil {
        log.Fatal(err)
    }

    // Non-fatal parse issues (unknown tags, retired tags, VR mismatches)
    for _, w := range dicomFile.Warnings {
        log.Println("warning:", w)
    }

    // Convert to a Dataset — nested sequences become child Datasets
    ds := dicomFile.GetDataset()

    // Access elements by tag
    if elem, ok := ds.Get(tag.New(0x0010, 0x0010)); ok { // Patient Name
        fmt.Printf("Patient: %s\n", elem.GetValue())
    }

    fmt.Println("Transfer Syntax:", dicomFile.FileMetaInfo.TransferSyntaxUID)
}
Read a file and write it back
df, _ := filereader.ReadDICOMFile(filebase.NewFileReader(in))

w := filewriter.NewDICOMFileWriter(filebase.NewFileWriter(out))
w.SetFileMetaInfo(&filewriter.FileMetaInfo{ /* ... */ })
for _, e := range filewriter.ElementsFromDataset(df.GetDataset()) {
    _ = w.AddDataElement(e)
}
_ = w.Write()

ElementsFromDataset descends into sequences. Copying Value and ignoring Items writes a file that looks complete with every nested item missing — the element is present, its length is zero, and nothing reports it.

Work with Sequences

Nested sequences (SQ) are parsed recursively into child Dataset values:

ds := dicomFile.GetDataset()

// (0040,A730) ContentSequence
if seq, err := ds.GetSequence(tag.New(0x0040, 0xA730)); err == nil {
    for i := 0; i < seq.Length(); i++ {
        item, _ := seq.Get(i)
        child := item.(*dataset.Dataset)

        // Child datasets know their parent
        if code, ok := child.Get(tag.New(0x0008, 0x0100)); ok {
            fmt.Printf("item %d code value: %s\n", i, code.GetValue())
        }
    }
}
Command-Line Tools
# Build the CLI
go build -o dicom .

# === File Operations ===
./dicom show patient.dcm          # Display DICOM file contents
./dicom info patient.dcm           # Display file metadata
./dicom convert patient.dcm out.json  # Convert to JSON

# === Network Operations (like pynetdicom CLI) ===
# Verification (ping a PACS)
./dicom echoscu pacs.hospital.com:11112

# Send DICOM files (.dcm, .ima, any DICOM format)
./dicom storescu -aec PACS pacs:11112 study/*.dcm

# Start a storage server (receive files)
./dicom storescp -port 11112 -output ./received/

# Query for patients/studies
./dicom findscu -patient-name "Smith*" -level STUDY pacs:11112

# Retrieve studies to a destination
./dicom movescu -dest MY_SCP -study 1.2.3.4 pacs:11112

# Ask an archive to take responsibility for instances you have sent
./dicom commitscu -aec PACS -instance 1.2.840.10008.5.1.4.1.1.2:1.2.3.4 -wait pacs:11112

# Get help
./dicom -h

Architecture

Module Organization

The library is organized into focused packages, each handling a specific DICOM aspect:

Core I/O
Package Description
filebase Low-level binary I/O with byte order handling
filereader DICOM file reading (preamble, meta info, dataset)
filewriter DICOM file writing with validation
fileutil Byte order detection, padding, caching, codec integration
fileset File-set management and DICOMDIR: reads the record tree from its byte offsets, and generates a conformant index
Data Model
Package Description
dataset Thread-safe in-memory dataset with rich query API
dataelem Data element representation with all 28+ VRs
tag Tag definitions, dictionary (5,000+ standard + 10,500+ private)
element Value encoding, decoding, and conversion
sequence Thread-safe ordered sequence container
uid UID management, validation, and classification
valuerep Value representation validation and parsing
values Value conversion and encoding
multival Type-safe multi-value lists
Networking (DICOM Upper Layer Protocol)
Package Description
network DICOM networking — SCU/SCP, DIMSE services, PDU encoding, TLS
Encoding and Compression
Package Description
charset 30+ encodings (ISO 2022, Unicode, CJK), applied automatically on read
compress Compression/decompression (DEFLATE, RLE, JPEG)
encaps Encapsulated pixel data parsing and frame extraction
Imaging and Clinical
Package Description
pixels Pixel data access and statistical analysis
overlays Overlay groups, ROI analysis, graphics
waveforms Physiological signals (ECG, EEG) with QRS detection
sr Structured reports: the PS3.3 C.17 content tree, read and written, including by-reference relationships. StructuredReport alongside it is a simpler bespoke model, not the DICOM tree
anonymize De-identification per DICOM PS3.15 Annex E — the whole of Table E.1-1, sequences and repeating groups included
Serialization and Utilities
Package Description
jsonrep A flat summary struct of common attributes, for feeding a web API. Not the DICOM JSON Model — see dataset.ToDICOMJSON for that
config Thread-safe global configuration
errors DICOM-specific error types
hooks Extensible callback/plugin system
util General utilities (hex dump, dataset info)
cli Command-line interface framework

Networking Features

pynetdicom Feature Parity

go-dicom's network package provides feature parity with pynetdicom, reimplemented in Go with goroutines, channels, and context.Context.

Feature pynetdicom go-dicom Notes
C-ECHO (Verification) Yes Yes scu.Echo(ctx)
C-STORE (Storage) Yes Yes scu.Store(ctx, ds)
C-FIND (Query) Yes Yes scu.Find(ctx, ds) — streams via Go channel
C-MOVE (Retrieve) Yes Yes scu.Move(ctx, ds, dest); SCP opens an association to the destination AE and transfers via C-STORE sub-operations
C-GET (Get) Yes Yes scu.Get(ctx, ds) with SCUConfig.OnCStore; SCP transfers instances via C-STORE sub-operations
N-EVENT-REPORT Yes Yes Full N-DIMSE service support
N-GET Yes Yes
N-SET Yes Yes
N-ACTION Yes Yes
N-CREATE Yes Yes
N-DELETE Yes Yes
SCU (Client) Yes Yes network.NewSCU()
SCP (Server) Yes Yes network.NewSCP() with goroutine-per-association
TLS Encryption Yes Yes network.DialTLS() / network.ListenTLS()
Association Negotiation Yes Yes Full A-ASSOCIATE-RQ/AC/RJ state machine
Presentation Context Negotiation Yes Yes Abstract + Transfer Syntax negotiation
Extended Negotiation Yes Yes Async ops, SCP/SCU role selection, user identity — negotiated on the wire
Storage SOP Classes 165 169 Every one pynetdicom lists, plus 4 recent standard additions
SOP Class UIDs named 256 256 Full parity, checked against pynetdicom's own table
Transfer Syntax Support 37 37 4 negotiated by default, all via AllTransferSyntaxes()
Storage Commitment Yes Yes N-ACTION request, N-EVENT-REPORT result
Query/Retrieve Models 2 4 Patient Root, Study Root, Patient/Study Only, Modality Worklist
Modality Worklist Yes Yes MWL SOP Class with WorklistHandler
MPPS Yes Yes N-CREATE/N-SET both directions, verified against pynetdicom
Print Management Yes Yes Film session, film box, image box, print action
Unified Procedure Step Yes Yes Push and Watch: state machine and Transaction UID enforced by UPSHandler, subscriptions and N-EVENT-REPORT fan-out by UPSSubscriptionStore
Handler Interface evt_handlers Handler interface Go-idiomatic with BaseHandler embedding
CLI Tools 8 9 All 8 of pynetdicom's, plus commitscu
Async Operations Thread pool Goroutines Native Go concurrency
Context/Cancellation N/A context.Context Timeouts, graceful shutdown
Limitations

Known gaps, stated plainly so you can judge fit before adopting:

Area Status
Move destination resolution A C-MOVE names its destination only by AE title, so the SCP must be told how to reach it via SCPConfig.MoveDestinations or SCPConfig.ResolveMoveDestination. An unresolvable title is answered with StatusMoveDestUnknown rather than guessed at.
Asynchronous operations Enforced as an SCU: a negotiated window bounds how many operations are outstanding, each matched to its response by Message ID. C-MOVE and C-GET take the association exclusively. As an SCP, dispatch is still one message at a timeMaxOperationsPerformed does not yet bound concurrent dispatch, which is the other half.
Cancelling a slice handler A C-FIND, C-GET or C-MOVE handler that returns a slice cannot be interrupted while it builds one. Implement CFindStreamer, CGetStreamer or CMoveStreamer to stop on C-CANCEL; sub-operations are abandoned on cancel either way.
Compressing pixel data Two syntaxes are compressed to: RLE Lossless and JPEG-LS Lossless. Every other compressed target fails rather than sending bytes described as something they are not. JPEG-LS Near-Lossless is refused deliberately — it is lossy, and the error budget is the caller's decision. There is no JPEG or JPEG 2000 encoder here.
Concurrent use of one SCU Safe to share: operations on one SCU are serialized, so several goroutines may use it and each waits its turn. Serialized is not pipelined — sharing bounds the number of associations rather than raising throughput.
Interoperability

Every release is tested against pynetdicom and dcmtk in CI — C-ECHO and C-STORE in both directions, C-GET and C-MOVE sub-operations, storage commitment, MPPS and print management — with the transferred data verified by pydicom rather than by this library's own reader.

This matters more than the unit suite: every serious defect this project has had was code agreeing with itself. Reintroducing one of them, the N-SET that named its target with Affected instead of Requested SOP Instance UID, leaves the unit tests green and fails the interoperability tests.

go build -o dicom .
PYNETDICOM_BIN=/path/to/venv/bin DCMTK_BIN=/usr/bin ./scripts/interop-test.sh

The fixture is pydicom's CT_small.dcm, not a file this project generates, so it exercises encodings the library would not think to produce itself.

Supported File Formats

The network module works with any DICOM data regardless of source format:

Format Extension Support
Standard DICOM .dcm Full
Siemens IMA .ima Full
DICOMDIR DICOMDIR Read and write. The record tree is built from the byte offsets, so a file whose records are stored out of tree order reads correctly; generated files are verified against pydicom and dcmtk
Raw DICOM (none) Full
DICOM Part 10 .dicom Full
Handler Patterns
// 1. Echo-only (verification server)
scp.SetHandler(&network.EchoHandler{})

// 2. Storage with callback
scp.SetHandler(&network.StorageHandler{
    OnStore: func(ctx context.Context, sopClass, sopInstance string, ds *dataset.Dataset) uint16 {
        // Save to disk, database, cloud storage, etc.
        return network.StatusSuccess
    },
})

// 3. Query/Retrieve with callbacks
scp.SetHandler(&network.QueryRetrieveHandler{
    OnFind: func(ctx context.Context, sopClass string, query *dataset.Dataset) ([]*dataset.Dataset, error) {
        // Search database, return matching results
        return results, nil
    },
})

// 4. Modality Worklist
scp.SetHandler(&network.WorklistHandler{
    OnWorklist: func(ctx context.Context, query *dataset.Dataset) ([]*dataset.Dataset, error) {
        // Return scheduled procedures
        return procedures, nil
    },
})

// 5. Composite handler (mix & match)
h := network.NewCompositeHandler()
h.SetStoreHandler(myStoreHandler)
h.SetFindHandler(myFindHandler)
scp.SetHandler(h)

// 6. Custom handler (implement the interface)
type MyHandler struct { network.BaseHandler }
func (h *MyHandler) HandleCStore(ctx context.Context, req *network.CStoreRequest) (*network.CStoreResponse, error) {
    // Full control over request processing
}
Extended Negotiation

Extended negotiation items are carried in the A-ASSOCIATE-RQ/AC User Information item. SCP/SCU role selection is what allows an SCU to also act as an SCP for a SOP Class on an association it initiated — required for C-GET, where the peer sends C-STORE sub-operations back over the same association.

scu := network.NewSCU(network.SCUConfig{
    CallingAE: "MY_APP",
    CalledAE:  "PACS",
    Address:   "pacs.hospital.com:11112",
    ExtendedNegotiation: &network.ExtendedNegotiation{
        // Allow the peer to send C-STORE back to us for C-GET
        RoleSelections: []network.SCPSCURoleSelection{
            {SOPClassUID: network.CTImageStorageUID, SCURole: true, SCPRole: true},
        },
        // Permit up to 4 outstanding operations in each direction
        AsyncOperations: &network.AsynchronousOperationsWindow{
            MaxOperationsInvoked:   4,
            MaxOperationsPerformed: 4,
        },
        // Authenticate with the remote AE
        UserIdentity: &network.UserIdentityNegotiation{
            Type:           network.UserIdentityUsernamePassword,
            PrimaryField:   []byte("operator"),
            SecondaryField: []byte("password"),
        },
    },
})

// After associating, inspect what the peer agreed to
if role, ok := scu.Association().RoleSelectionFor(network.CTImageStorageUID); ok {
    fmt.Println("peer accepted SCP role:", role.SCPRole)
}
Association Info in Handlers

SCP handlers can read the association's details from the request context without changing the Handler interface:

scp.SetHandler(&network.StorageHandler{
    OnStore: func(ctx context.Context, sopClass, sopInstance string, ds *dataset.Dataset) uint16 {
        // Returns nil when called outside an association, so check it.
        if info := network.AssociationInfoFromContext(ctx); info != nil {
            log.Printf("from %s (%s) via %s",
                info.CallingAE, info.RemoteAddr, info.PeerImplementationVersion)
        }
        return network.StatusSuccess
    },
})

Features

DICOM Standards Compliance
Standard Status
DICOM PS3.5 - Data Structures and Encoding Supported (incl. nested sequences, undefined-length items, even-length padding)
DICOM PS3.6 - Data Dictionary Supported (5,000+ tags)
DICOM PS3.7 - Message Exchange (DIMSE) Supported
DICOM PS3.8 - Network Communication (Upper Layer) Supported
DICOM PS3.10 - Media Storage and File Format Supported
DICOM PS3.15 - Security (TLS, de-identification) Supported — the Basic Profile covers every attribute in Table E.1-1, verified to leave none of them unchanged across pydicom's corpus
DICOM JSON Model (Part 18) Supported — dataset.ToDICOMJSON, FromDICOMJSON, verified against pydicom's to_json across its corpus. Private attributes take their VR from the shipped vendor dictionary, resolved through the file's own private creator
ISO 2022 - Character set escape sequences Supported
Performance

Measured against pydicom on its own test corpus, same machine, 300 iterations:

File go-dicom pydicom
CT_small.dcm (39 KB, 258 elements) 110 µs 499 µs 4.5x
MR_small.dcm (10 KB, 73 elements) 23 µs 219 µs 9.5x
rtplan.dcm (2.7 KB, 36 elements) 31 µs 138 µs 4.5x

Reproduce with go test ./filereader/ -bench=Parse and the corpus path in GODICOM_PYDICOM_DATA.

Conformance

CONFORMANCE.md is a DICOM Conformance Statement in the structure of PS3.2: the SOP classes negotiated in each role, the transfer syntaxes, the enforced limits, and a plainly stated list of what the library does not do. It is the document to hand to someone evaluating go-dicom for a clinical deployment, and every claim in it was checked against the code rather than described from memory.

Transfer Syntax Support

Two capabilities are distinct and worth separating: whether the data set parses, and whether pixel data can be decoded. A compressed instance transfers and stores correctly even when its pixels cannot be decompressed — which is enough for an archive or a router, and not enough for a viewer.

Transfer Syntax Data set Pixel data Network
Implicit VR Little Endian Read/Write Yes Yes
Explicit VR Little Endian Read/Write Yes Yes
Explicit VR Big Endian Read/Write Yes Yes
Deflated Explicit VR LE Read/Write Yes Yes
RLE Lossless Read/Write Yes Yes
JPEG Baseline (.50) Read/Write Yes Yes
JPEG Extended (.51) Read/Write 8-bit Yes
JPEG Lossless (.57, .70) Read/Write Yes Yes
JPEG-LS Lossless / Near-Lossless (.80, .81) Read/Write Yes Yes
JPEG 2000 Lossless / Lossy (.90, .91) Read/Write Supply a decoder Yes

Pixel data is returned in the color space the Photometric Interpretation names, so a YBR_FULL instance yields YBR rather than RGB — the same as pydicom. Both planar configurations, 1 to 64 bits, and subsampled YBR_FULL_422 are handled.

JPEG 2000 needs a decoder you supply — examples/jpeg2000 is a working one that shells out to openjpeg, verified sample-for-sample against pydicom. JPEG Extended decodes at both 8 and 12 bits, the 12-bit case in pure Go. JPEG-LS decodes at 2 to 16 bits, lossless and near-lossless, single or multi component, in both line- and sample-interleaved modes.

Values in an Explicit VR Big Endian file are normalised to little endian while parsing and converted back on write, so byte order never reaches code above filereader.

RLE Lossless decodes, single- and multi-frame, grayscale and color, as does every JPEG syntax in the table above except JPEG 2000 — all in pure Go, with no codec to install and nothing to register. Dataset.PixelArray() decompresses them without being asked. Verified against pydicom on its own test corpus, and checked in CI on every push: of the 49 files in that corpus pydicom can decode, 43 decode here to the same samples, compared whole rather than by their leading values. The six remaining are all JPEG 2000.

JPEG 2000 is the one syntax that does not decode. .90 and .91 instances parse, store, and transfer with their pixel data intact as opaque bytes, but need a decoder you supply. See CONFORMANCE.md §8.1 for why, and examples/jpeg2000 for a working one to copy.

Compressed frames can be extracted, which is the step before decoding. For a compressed instance, PixelData holds the encapsulation exactly as it appears in the file — the Basic Offset Table and each fragment with its (FFFE,E000) header, the same bytes pydicom exposes — so frames can be separated and handed to a decoder of your choosing:

frames, err := ds.ExtractEncapsulatedFrames() // fragments and offset table
frame, err := ds.GetEncapsulatedFrame(0)      // one frame, still compressed

Multi-frame compressed images split correctly; verified against pydicom on SC_rgb_rle_2frame.dcm.

To decode JPEG 2000, register a decoder:

compress.GetExternalRegistry().RegisterExternalDecoder(compress.JPEG_2000, myDecoder)

JPEG 2000 is not implemented in this module, and there is no hidden CGO path that enables it — the error messages used to name a C library and tell you to rebuild with CGO_ENABLED=1, which changed nothing because there was no CGO implementation to enable. They now say plainly that a decoder must be supplied.

Any type with Decompress([]byte) ([]byte, error) and CanDecompress([]byte) bool will do; Dataset.PixelArray() routes frames through it automatically once registered. compress.GetExternalCompressionStatus() reports which codecs currently have a decoder.

Thread Safety

All mutable data structures use sync.RWMutex for concurrent access. Datasets, sequences, and managers are safe for concurrent reads with exclusive writes. The SCP server spawns a goroutine per association for concurrent client handling.

De-identification Profiles

The anonymize package supports multiple de-identification profiles per DICOM PS3.15:

  • Basic Profile - Standard tag removal/replacement
  • Clean Descriptors - Remove text descriptions
  • Clean Graphics - Remove burned-in annotations
  • Retain Long Full Dates - Keep dates for longitudinal studies
  • Retain Patient Characteristics - Keep age, sex, size, weight
  • Retain Device Identity - Keep device information
  • Retain UIDs - Keep original UIDs
  • Retain Safe Private - Keep safe private tags

Building

# Build the library
go build ./...

# Build the CLI tool
go build -o dicom .

# Run all tests (71 network tests + file I/O tests)
go test -race ./...

# Run network tests specifically
go test -v ./network/...

# Run tests with coverage
go test -race -coverprofile=coverage.out ./... && go tool cover -html=coverage.out

# Run linter
golangci-lint run ./...

Examples

See the examples directory for complete working examples:

Contributing

Contributions are welcome. Please read CONTRIBUTING.md for guidelines.

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/my-feature)
  3. Make your changes with tests
  4. Run make all to verify
  5. Submit a pull request

Security

For security concerns, especially regarding Protected Health Information (PHI), please see SECURITY.md.

License

MIT License - see LICENSE for details.

Acknowledgments

  • DICOM Standard - The foundation this library is built on
  • pydicom - Python DICOM library that inspired the API design
  • pynetdicom - Python DICOM networking library that inspired the network module
  • Go Community - Excellent standard library and ecosystem

Resources

Documentation

Overview

Command dicom is a command-line interface for reading, writing, and networking DICOM (Digital Imaging and Communications in Medicine) data.

It is the executable front end to the go-dicom library. Every subcommand is a thin wrapper over the packages listed under [Library packages] below, so anything the CLI does can also be done programmatically.

Installation

go install github.com/amrshadid/go-dicom@latest

Prebuilt binaries for Linux, macOS, and Windows are attached to each release at https://github.com/amrshadid/go-dicom/releases.

File commands

Inspect and convert DICOM files. These accept .dcm, .ima, DICOMDIR, and raw DICOM streams.

dicom show patient.dcm              # display the data elements
dicom info patient.dcm              # display file metadata
dicom convert patient.dcm out.json  # convert to DICOM JSON, CSV, or NIfTI
dicom tag-doc 0010,0010             # look up a tag in the data dictionary
dicom codify patient.dcm            # emit Go source that rebuilds the file

Network commands

Act as a DICOM Service Class User (client) or Service Class Provider (server) over the DICOM Upper Layer Protocol.

dicom echoscu pacs.hospital.com:11112              # C-ECHO verification
dicom echoscp -port 11112                          # verification server
dicom storescu -aec PACS pacs:11112 study/*.dcm    # send files
dicom storescp -port 11112 -output ./received/     # receive and save files
dicom findscu -patient-name "Smith*" pacs:11112    # query
dicom movescu -dest MY_SCP -study 1.2.3.4 pacs:11112
dicom getscu -study 1.2.3.4 pacs:11112
dicom qrscp -port 11112                            # combined store + Q/R server

Run "dicom help <command>" for the flags a given subcommand accepts.

Library packages

The library is organized into focused packages. The most common entry points are:

Supporting packages cover character sets (github.com/amrshadid/go-dicom/charset), compression (github.com/amrshadid/go-dicom/compress), pixel data (github.com/amrshadid/go-dicom/pixels), overlays, waveforms, structured reports, and the DICOM JSON Model (github.com/amrshadid/go-dicom/jsonrep).

Reading a file

file, err := os.Open("patient.dcm")
if err != nil {
	log.Fatal(err)
}
defer file.Close()

dicomFile, err := filereader.ReadDICOMFile(filebase.NewFileReader(file))
if err != nil {
	log.Fatal(err)
}

ds := dicomFile.GetDataset()
if elem, ok := ds.Get(tag.New(0x0010, 0x0010)); ok {
	fmt.Printf("Patient: %s\n", elem.GetValue())
}

Receiving over the network

scp := network.NewSCP(network.SCPConfig{AETitle: "MY_SCP", Port: 11112})
scp.SetHandler(&network.StorageHandler{
	OnStore: func(ctx context.Context, sopClass, sopInstance string, ds *dataset.Dataset) uint16 {
		// persist, forward, or index the received instance
		return network.StatusSuccess
	},
})
log.Fatal(scp.ListenAndServe(context.Background()))

Handling protected health information

DICOM data routinely contains protected health information. The github.com/amrshadid/go-dicom/anonymize package implements the de-identification profiles in DICOM PS3.15 Annex E. Note that PHI can appear in places a tag-based profile will not reach, including burned-in annotations in pixel data, private vendor tags, and structured report content. See SECURITY.md for the project's guidance.

Standards

go-dicom implements PS3.5 (data structures and encoding), PS3.6 (the data dictionary), PS3.7 (message exchange), PS3.8 (network communication), PS3.10 (media storage and the file format), PS3.15 (security profiles), and the DICOM JSON Model from PS3.18.

Known gaps are listed in Section 8 of CONFORMANCE.md and the Limitations section of the README rather than left implicit. The two most significant: JPEG 2000 pixel data needs a decoder you supply, and RLE Lossless is the only transfer syntax this library compresses to, so a C-STORE over any other compressed context fails rather than sending mislabelled bytes.

Directories

Path Synopsis
Package anonymize removes protected health information from DICOM data sets, implementing the de-identification profiles defined in DICOM PS3.15 Annex E.
Package anonymize removes protected health information from DICOM data sets, implementing the de-identification profiles defined in DICOM PS3.15 Annex E.
Package charset provides DICOM character set encoding and decoding support.
Package charset provides DICOM character set encoding and decoding support.
Package cli provides a command-line interface framework for DICOM tools.
Package cli provides a command-line interface framework for DICOM tools.
Package compress provides comprehensive compression and encapsulation handling for DICOM pixel data.
Package compress provides comprehensive compression and encapsulation handling for DICOM pixel data.
Package config provides centralized, thread-safe global configuration management for DICOM operations.
Package config provides centralized, thread-safe global configuration management for DICOM operations.
Package dataelem provides core DICOM data element structures and operations.
Package dataelem provides core DICOM data element structures and operations.
Package dataset provides high-level data structure and operations for in-memory DICOM datasets.
Package dataset provides high-level data structure and operations for in-memory DICOM datasets.
Package dcmstore is an on-disk store of DICOM instances with an index that answers the hierarchical queries a C-FIND asks.
Package dcmstore is an on-disk store of DICOM instances with an index that answers the hierarchical queries a C-FIND asks.
Package encaps provides DICOM encapsulation parsing and frame extraction.
Package encaps provides DICOM encapsulation parsing and frame extraction.
Package errors provides comprehensive error handling for DICOM operations.
Package errors provides comprehensive error handling for DICOM operations.
examples
input_output/read_element_values command
Example: Read and Access DICOM Element Values
Example: Read and Access DICOM Element Values
jpeg2000
Package jpeg2000 is a reference external decoder for JPEG 2000 pixel data.
Package jpeg2000 is a reference external decoder for JPEG 2000 pixel data.
networking command
Example: DICOM Networking with go-dicom
Example: DICOM Networking with go-dicom
Package filebase provides low-level file I/O abstractions for DICOM file operations.
Package filebase provides low-level file I/O abstractions for DICOM file operations.
Package filereader provides comprehensive DICOM file reading support.
Package filereader provides comprehensive DICOM file reading support.
Package fileset provides comprehensive management of DICOM file collections organized in directory structures.
Package fileset provides comprehensive management of DICOM file collections organized in directory structures.
Package fileutil provides comprehensive file and data utilities for DICOM processing.
Package fileutil provides comprehensive file and data utilities for DICOM processing.
Package filewriter provides comprehensive DICOM file writing support.
Package filewriter provides comprehensive DICOM file writing support.
Package hooks provides DICOM parsing and processing hook support.
Package hooks provides DICOM parsing and processing hook support.
Package jsonrep provides DICOM JSON Model representation support.
Package jsonrep provides DICOM JSON Model representation support.
Package multival provides type-safe multi-value lists with constructor-based type enforcement.
Package multival provides type-safe multi-value lists with constructor-based type enforcement.
Package network implements DICOM networking: the Upper Layer Protocol from PS3.8, the DIMSE message exchange from PS3.7, and the service classes that run over them.
Package network implements DICOM networking: the Upper Layer Protocol from PS3.8, the DIMSE message exchange from PS3.7, and the service classes that run over them.
Package overlays provides comprehensive support for DICOM overlay management.
Package overlays provides comprehensive support for DICOM overlay management.
Package pixels provides comprehensive access to and manipulation of DICOM pixel data.
Package pixels provides comprehensive access to and manipulation of DICOM pixel data.
scripts
jpeglossless-check command
Command jpeglossless-check decodes dcmtk-encoded lossless JPEG fixtures and compares them with the uncompressed pixels they were made from.
Command jpeglossless-check decodes dcmtk-encoded lossless JPEG fixtures and compares them with the uncompressed pixels they were made from.
roundtrip-check command
Command roundtrip-check reads every DICOM file in a directory and writes it back out, so another toolkit can judge the result.
Command roundtrip-check reads every DICOM file in a directory and writes it back out, so another toolkit can judge the result.
Package sequence provides a thread-safe ordered sequence container for DICOM datasets.
Package sequence provides a thread-safe ordered sequence container for DICOM datasets.
Package sr provides comprehensive support for DICOM Structured Reports.
Package sr provides comprehensive support for DICOM Structured Reports.
Package tag provides DICOM tag handling and dictionary lookup functionality.
Package tag provides DICOM tag handling and dictionary lookup functionality.
Package uid provides utilities for DICOM Unique Identifier (UID) management.
Package uid provides utilities for DICOM Unique Identifier (UID) management.
Package util provides utility functions for DICOM data manipulation and analysis.
Package util provides utility functions for DICOM data manipulation and analysis.
Package valuerep provides utilities for DICOM Value Representation (VR) handling and validation.
Package valuerep provides utilities for DICOM Value Representation (VR) handling and validation.
Package values provides utilities for DICOM value conversion and handling.
Package values provides utilities for DICOM value conversion and handling.
Package waveforms provides support for managing and analyzing DICOM waveform data.
Package waveforms provides support for managing and analyzing DICOM waveform data.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL