Skip to content

DICOM JSON

The DICOM JSON Model (PS3.18 Annex F) is what DICOMweb speaks. The dicomjson package converts datasets to and from it.

go
import "github.com/godicom-dev/godicom/dicomjson"

Both directions

go
jsonData, err := dicomjson.MarshalDataset(ds.Dataset)
parsed, err := dicomjson.ParseDataset(jsonData)

arr, err := dicomjson.MarshalDatasets([]*godicom.Dataset{ds1, ds2})
dss, err := dicomjson.ParseDatasets(arr)
FunctionFor
MarshalDataset(ds, opts…)one dataset → JSON bytes, tag-sorted
MarshalDatasetString(ds, opts…)the same, as a string
MarshalDatasets(dss, opts…)a JSON array of datasets — a QIDO-RS result
ParseDataset(data, opts…)JSON bytes → *godicom.Dataset
ParseDatasets(data, opts…)a JSON array → []*godicom.Dataset
DecodeDataset(r, opts…)straight from an io.Reader
DatasetToMap(ds, opts…)map[string]Element, if you want to post-process before encoding

Output is sorted by tag, so two runs over the same dataset produce byte-identical JSON — which matters more than it sounds when you are diffing fixtures or signing payloads.

The element shape

go
type Element struct {
	VR           string            `json:"vr"`
	Value        []json.RawMessage `json:"Value,omitempty"`
	InlineBinary string            `json:"InlineBinary,omitempty"`
	BulkDataURI  string            `json:"BulkDataURI,omitempty"`
}

Value stays as json.RawMessage, so a number that arrived as 1.0 does not become 1 on the way through.

Bulk data

A 20 MB Pixel Data element base64-encoded inline is technically valid JSON and practically a mistake. Past a threshold, emit a reference instead:

go
jsonData, err := dicomjson.MarshalDataset(ds.Dataset,
	dicomjson.WithBulkDataThreshold(1024),
	dicomjson.WithBulkDataURIBuilder(func(t godicom.Tag, vr godicom.VR, value []byte) (string, error) {
		return store(t, value) // return the URI you stored it at
	}),
)

and on the way back in, resolve them:

go
parsed, err := dicomjson.ParseDataset(jsonData,
	dicomjson.WithBulkDataURIReader(func(t godicom.Tag, vr godicom.VR, uri string) ([]byte, error) {
		return fetch(uri)
	}),
)

Below the threshold, values are carried in InlineBinary as base64. With no builder set, nothing is externalised.

Elements that will not marshal

WithSuppressInvalidTags() drops elements that fail marshaling instead of failing the whole document. Use it when you are exporting from files you do not control and a single bad element should not cost you the other four hundred:

go
jsonData, err := dicomjson.MarshalDataset(ds.Dataset, dicomjson.WithSuppressInvalidTags())

Without it, a marshal error is returned — which is the right default, because silently losing an element is exactly the kind of thing you find out about six months later.

With DICOMweb

gonetdicom's DICOMweb client already returns parsed metadata for the WADO-RS and QIDO-RS transactions, so you normally reach for dicomjson directly only when you are building the payloads yourself or implementing a server.

Released under the MIT License.