#dicom #library #dimse

medicom

A library for reading and writing DICOM, the DIMSE network protocol, and decoding DICOM images

1 unstable release

new 0.5.0 Jan 2, 2025

#340 in Encoding

Download history 180/week @ 2024-12-31

180 downloads per month
Used in 2 crates

Apache-2.0

3MB
64K SLoC

medicom

This crate is the core DICOM reading/writing library. This crate is focused only on basic reading/writing of DICOM datasets and has few dependencies. It does not depend on the DICOM standard dictionary, instead it is able to parse through dicom based only on knowing a minimal set of DICOM constants.

Standard DICOM Dictionary

The standard DICOM dictionary is an optional feature of this crate. The reading and writing functionality is not dependent on the standard dictionary, however for parsing element values the dictionary can be used for Implicit VR encodings.

The standard dictionary can be included using the feature stddicom.

The build script in the build folder generates the standard DICOM dictionary.

Files generated by the build script:

  • src/dict/lookup.rs
  • src/dict/tags.rs
  • src/dict/transfer_syntaxes.rs
  • src/dict/uids.rs

Parsing Examples

Simple use of parsing a DICOM file and printing some element values to stdout.

let mut parser: Parser<'_, File> = ParserBuilder::default()
    // Stops parsing once the PixelData element is seen.
    .stop(TagStop::BeforeTagValue(&PixelData))
    // The dictionary is used during parsing for Implicit VR transfer syntaxes,
    // and associates the resolved VR to the resulting elements for parsing the
    // element values.
    .build(file, &STANDARD_DICOM_DICTIONARY);

// The parser is an iterator over elements.
for element_res in parser {
    let element: DicomElement = element_res?;
    let value: RawValue = element.parse_value()?;
    match value {
        RawValue::Strings(strings) => println!("{:?}", strings[0]),
        RawValue::UShorts(ushorts) => println!("{:?}", ushorts[0]),
        _ => {},
    }

    // Simplify handling of elements with single values. RawValue::string()
    // returns Option<String> if the value could parse to a string.
    let _string = value.string().unwrap();

    // Parse using a VR separate from what was specified in the DICOM dataset.
    let _value: Option<String> = element.parse_value_as(&LT)?.string();
}

Load the DICOM file into a DicomObject, a hierarchical structure.

let mut parser: Parser<'_, File> = ParserBuilder::default()
    .stop(TagStop::BeforeTagValue(&PixelData))
    .build(file, &STANDARD_DICOM_DICTIONARY);

// Parsing into object returns Result<Option<DicomObject>>, returning Ok(None)
// if the file isn't DICOM.
let dcmroot: DicomRoot = DicomRoot::parse(parser)
    .unwrap().unwrap();

// Builds a path for
//    ReferencedFrameOfReferenceSequence[1]
//      .RTReferencedStudySequence[1]
//        .RTReferencedSeriesSequence[1]
//          .ContourImageSequence[11]
//            .ReferencedSOPInstanceUID
let tagpath = TagPath::from(vec![
    TagNode::from(&ReferencedFrameofReferenceSequence),
    TagNode::from(&RTReferencedStudySequence),
    TagNode::from(&RTReferencedSeriesSequence),
    TagNode::from((&ContourImageSequence, 11)),
    TagNode::from(&ReferencedSOPInstanceUID),
]);

// If all desired indexes are `1` then this can be simplified:
let _ = TagPath::from(vec![&SourceImageSequence, &ReferencedSOPInstanceUID]);

// Tag paths can be parsed/represented as strings, including item indexing:
let _parsed: Option<TagPath> = TagPath::parse(
    "SourceImageSequence[2].ReferencedSOPInstanceUID",
    Some(&STANDARD_DICOM_DICTIONARY),
)

// Get the value for the element at the tag path.
let ref_sopuid: Option<RawValue> = dcmroot.get_value_by_tagpath(tagpath);

if let Some(RawValue::Uid(uid)) = ref_sopuid {
    println!("Referenced SOP Instance UID: {}", uid);
}

Integration Tests

Test fixtures are files used by some tests. Due to the large size of these test datasets they are not included in the repository. To set up these test fixtures:

  1. Download the fixtures (700mb .7z).
  2. Extract the downloaded archive into this directory.
  3. The resulting extraction should create a medicom/tests/fixtures folder with subfolders containing the test datasets.

These fixtures are a suite of dicom files gathered from several open sources:

Dependencies

~3.5–5MB
~151K SLoC