A pure Python package for reading and writing DICOM data
—
DICOM tag and UID management providing comprehensive functionality for tag identification, keyword conversion, UID generation, and specialized handling of DICOM identifiers with dictionary lookups and validation capabilities.
Core class for DICOM tag representation with support for multiple input formats and comparison operations.
class Tag:
"""
DICOM tag representation supporting multiple formats and operations.
Provides a consistent interface for DICOM tags whether created from
integers, tuples, or hexadecimal strings, with proper comparison and hashing.
"""
def __init__(self, *args):
"""
Create Tag from various input formats.
Parameters:
- args: Various formats supported:
- Tag(0x00100010) - Single integer
- Tag(0x0010, 0x0010) - Group, element integers
- Tag("0x00100010") - Hex string
- Tag((0x0010, 0x0010)) - Tuple of integers
"""
@property
def group(self):
"""int: Group component of the tag (upper 16 bits)."""
@property
def element(self):
"""int: Element component of the tag (lower 16 bits)."""
@property
def is_private(self):
"""bool: Whether this is a private tag (odd group number)."""
@property
def is_private_creator(self):
"""bool: Whether this is a private creator tag."""
def __int__(self):
"""Return tag as 32-bit integer."""
def __str__(self):
"""Return tag as formatted hex string."""
def __repr__(self):
"""Return detailed string representation."""
def __eq__(self, other):
"""Compare tags for equality."""
def __lt__(self, other):
"""Compare tags for ordering."""
def __hash__(self):
"""Return hash value for use as dictionary key."""Base class providing fundamental tag operations and validation.
class BaseTag:
"""
Base class for DICOM tag implementations.
Provides core functionality for tag comparison, hashing, and validation
that is shared across different tag representations.
"""
def __init__(self, group, element):
"""
Initialize base tag.
Parameters:
- group: int - Tag group (0x0000 to 0xFFFF)
- element: int - Tag element (0x0000 to 0xFFFF)
"""
def __contains__(self, tag):
"""Check if tag matches or is contained within this tag."""
def __format__(self, format_spec):
"""Format tag according to specification."""
def json_dump(self):
"""Return JSON-serializable representation."""Create Tag from group and element tuple with validation.
def TupleTag(group_element_tuple):
"""
Create Tag from (group, element) tuple.
Parameters:
- group_element_tuple: tuple - (group, element) pair
Returns:
Tag object
Raises:
ValueError - If tuple format is invalid
"""Functions for tag manipulation, validation, and context management.
def tag_in_exception(tag):
"""
Context manager for tag-specific error handling.
Parameters:
- tag: Tag or int - Tag to include in exception context
Returns:
Context manager that enriches exceptions with tag information
"""
def is_private_tag(tag):
"""
Check if tag is private (odd group number).
Parameters:
- tag: int, Tag, or tuple - Tag to check
Returns:
bool - True if tag is private
"""
def tag_has_keyword(tag):
"""
Check if tag has an associated keyword.
Parameters:
- tag: int, Tag, or tuple - Tag to check
Returns:
bool - True if tag has keyword in dictionary
"""Specialized string subclass for DICOM Unique Identifiers with validation and type checking.
class UID(str):
"""
DICOM UID string with specialized methods and validation.
String subclass providing DICOM-specific UID functionality including
transfer syntax detection, validation, and UID type identification.
"""
def __new__(cls, val):
"""
Create new UID instance.
Parameters:
- val: str - UID string value
Returns:
UID instance
"""
@property
def is_implicit_VR(self):
"""bool: Whether this UID represents implicit VR transfer syntax."""
@property
def is_little_endian(self):
"""bool: Whether this UID represents little endian transfer syntax."""
@property
def is_transfer_syntax(self):
"""bool: Whether this UID is a transfer syntax UID."""
@property
def is_deflated(self):
"""bool: Whether this UID represents deflated transfer syntax."""
@property
def is_encapsulated(self):
"""bool: Whether this UID represents encapsulated transfer syntax."""
@property
def is_compressed(self):
"""bool: Whether this UID represents compressed transfer syntax."""
@property
def is_private(self):
"""bool: Whether this is a private UID."""
@property
def is_valid(self):
"""bool: Whether this is a valid DICOM UID format."""
@property
def keyword(self):
"""str: Keyword associated with this UID (if known)."""
@property
def name(self):
"""str: Descriptive name for this UID (if known)."""
def is_retired(self):
"""
Check if UID is retired.
Returns:
bool - True if UID is marked as retired in DICOM standard
"""Functions for generating new DICOM UIDs with proper formatting and uniqueness.
def generate_uid(prefix=None, entropy_srcs=None):
"""
Generate a new DICOM UID.
Parameters:
- prefix: str - UID prefix (defaults to pydicom root)
- entropy_srcs: list - Additional entropy sources for uniqueness
Returns:
UID - Generated unique identifier
"""
def generate_uid_from_time():
"""
Generate UID using timestamp-based method.
Returns:
UID - Time-based unique identifier
"""
def generate_uid_from_uuid():
"""
Generate UID from UUID.
Returns:
UID - UUID-based unique identifier
"""Pre-defined UIDs and functions for managing transfer syntax handlers.
# Standard UID Constants
PYDICOM_IMPLEMENTATION_UID = UID("1.2.826.0.1.3680043.8.498.1")
PYDICOM_ROOT_UID = UID("1.2.826.0.1.3680043.8.498")
def register_transfer_syntax(uid, name):
"""
Register custom transfer syntax UID.
Parameters:
- uid: str or UID - Transfer syntax UID
- name: str - Descriptive name
"""
def get_transfer_syntax_names():
"""
Get dictionary of all known transfer syntax names.
Returns:
dict - Mapping of UID to name
"""
def is_deflated_transfer_syntax(uid):
"""
Check if UID represents deflated transfer syntax.
Parameters:
- uid: str or UID - Transfer syntax UID
Returns:
bool - True if deflated transfer syntax
"""
def is_implicit_VR_transfer_syntax(uid):
"""
Check if UID represents implicit VR transfer syntax.
Parameters:
- uid: str or UID - Transfer syntax UID
Returns:
bool - True if implicit VR transfer syntax
"""Functions for converting between tags and keywords using the DICOM data dictionary.
def tag_for_keyword(keyword):
"""
Get DICOM tag for keyword.
Parameters:
- keyword: str - DICOM keyword (e.g., "PatientName")
Returns:
Tag - DICOM tag for keyword
Raises:
KeyError - If keyword not found in dictionary
"""
def keyword_for_tag(tag):
"""
Get DICOM keyword for tag.
Parameters:
- tag: int, Tag, or tuple - DICOM tag
Returns:
str - DICOM keyword for tag
Raises:
KeyError - If tag not found in dictionary
"""
def repeater_has_keyword(tag):
"""
Check if repeating group tag has keyword.
Parameters:
- tag: int, Tag, or tuple - DICOM tag to check
Returns:
bool - True if repeating tag has keyword
"""Functions for handling private DICOM tags and creator identification.
def private_tag_for_keyword(private_creator, keyword):
"""
Get private tag for keyword and creator.
Parameters:
- private_creator: str - Private creator identification
- keyword: str - Private keyword
Returns:
Tag - Private DICOM tag
"""
def private_keyword_for_tag(tag, private_creator):
"""
Get private keyword for tag and creator.
Parameters:
- tag: int, Tag, or tuple - Private DICOM tag
- private_creator: str - Private creator identification
Returns:
str - Private keyword
"""
def get_private_creator_for_tag(tag):
"""
Get private creator for private tag.
Parameters:
- tag: int, Tag, or tuple - Private DICOM tag
Returns:
str - Private creator identification
"""from pydicom.tag import Tag, TupleTag
from pydicom.datadict import tag_for_keyword, keyword_for_tag
# Create tags using different methods
tag1 = Tag(0x00100010) # From integer
tag2 = Tag(0x0010, 0x0010) # From group, element
tag3 = Tag("PatientName") # From keyword
tag4 = TupleTag((0x0010, 0x0010)) # From tuple
# All represent the same tag
print(f"All equal: {tag1 == tag2 == tag3 == tag4}")
# Access tag components
print(f"Group: 0x{tag1.group:04X}")
print(f"Element: 0x{tag1.element:04X}")
print(f"Full tag: {tag1}")
# Check tag properties
print(f"Is private: {tag1.is_private}")
print(f"Is private creator: {tag1.is_private_creator}")from pydicom.datadict import tag_for_keyword, keyword_for_tag
# Convert keyword to tag
patient_name_tag = tag_for_keyword("PatientName")
print(f"PatientName tag: {patient_name_tag}")
# Convert tag to keyword
keyword = keyword_for_tag(0x00100010)
print(f"Tag 0x00100010 keyword: {keyword}")
# Handle unknown tags
try:
unknown_tag = tag_for_keyword("UnknownElement")
except KeyError:
print("Keyword not found in dictionary")from pydicom.uid import UID, generate_uid
# Create UID
transfer_syntax = UID("1.2.840.10008.1.2.1") # Explicit VR Little Endian
# Check UID properties
print(f"Is transfer syntax: {transfer_syntax.is_transfer_syntax}")
print(f"Is implicit VR: {transfer_syntax.is_implicit_VR}")
print(f"Is little endian: {transfer_syntax.is_little_endian}")
print(f"Is compressed: {transfer_syntax.is_compressed}")
# Get UID information
print(f"Name: {transfer_syntax.name}")
print(f"Keyword: {transfer_syntax.keyword}")
# Generate new UIDs
new_uid = generate_uid()
print(f"Generated UID: {new_uid}")
# Generate with custom prefix
custom_uid = generate_uid(prefix="1.2.3.4")
print(f"Custom UID: {custom_uid}")from pydicom.tag import Tag
from pydicom.datadict import private_tag_for_keyword
# Check if tag is private
private_tag = Tag(0x0009, 0x0010) # Odd group = private
print(f"Is private: {private_tag.is_private}")
# Work with private creator tags
creator_tag = Tag(0x0009, 0x0010)
print(f"Is private creator: {creator_tag.is_private_creator}")
# Get private tag for keyword and creator
try:
private_elem_tag = private_tag_for_keyword("SIEMENS CT VA0 COAD", "ImageType")
print(f"Private tag: {private_elem_tag}")
except KeyError:
print("Private keyword not found")from pydicom.uid import UID
# Various transfer syntaxes
transfer_syntaxes = [
"1.2.840.10008.1.2", # Implicit VR Little Endian
"1.2.840.10008.1.2.1", # Explicit VR Little Endian
"1.2.840.10008.1.2.2", # Explicit VR Big Endian
"1.2.840.10008.1.2.4.50", # JPEG Baseline
"1.2.840.10008.1.2.5" # RLE Lossless
]
for ts in transfer_syntaxes:
uid = UID(ts)
print(f"\nTransfer Syntax: {uid.name}")
print(f" Implicit VR: {uid.is_implicit_VR}")
print(f" Little Endian: {uid.is_little_endian}")
print(f" Compressed: {uid.is_compressed}")
print(f" Encapsulated: {uid.is_encapsulated}")from pydicom.tag import Tag, tag_in_exception
# Use context manager for better error reporting
tag = Tag("PatientName")
try:
with tag_in_exception(tag):
# Some operation that might fail
raise ValueError("Something went wrong with this element")
except ValueError as e:
print(f"Error with tag {tag}: {e}")from pydicom.tag import Tag
# Create list of tags
tags = [
Tag("StudyDate"),
Tag("PatientName"),
Tag("StudyInstanceUID"),
Tag("PatientID")
]
# Sort tags numerically
sorted_tags = sorted(tags)
print("Tags in numerical order:")
for tag in sorted_tags:
keyword = keyword_for_tag(tag)
print(f" {tag} - {keyword}")from pydicom.uid import UID
# Test different UID formats
test_uids = [
"1.2.840.10008.1.2.1", # Valid
"1.2.3", # Valid but short
"1.2.3.4.5.6.7.8.9.0.1.2.3.4", # Valid but long
"invalid.uid", # Invalid
"" # Invalid
]
for uid_str in test_uids:
uid = UID(uid_str)
print(f"\nUID: '{uid_str}'")
print(f" Valid: {uid.is_valid}")
print(f" Private: {uid.is_private}")
if uid.is_transfer_syntax:
print(f" Transfer syntax: {uid.name}")Install with Tessl CLI
npx tessl i tessl/pypi-pydicom