Files
René Mathieu 0fef8d96c5 Initial commit
2026-01-17 13:49:51 +01:00

124 lines
4.1 KiB
Python
Executable File

# Copyright 2008-2021 pydicom authors. See LICENSE file for details.
"""Code to fix non-standard dicom issues in files
"""
from typing import TYPE_CHECKING, Any
from pydicom import config
from pydicom import datadict
from pydicom import values
from pydicom.valuerep import VR
if TYPE_CHECKING: # pragma: no cover
from pydicom.dataelem import RawDataElement
def fix_separator_callback(
raw_elem: "RawDataElement", **kwargs: Any
) -> "RawDataElement":
"""Used by fix_separator as the callback function from read_dataset"""
return_val = raw_elem
try_replace = False
# If elements are implicit VR, attempt to determine the VR
if raw_elem.VR is None:
try:
vr = datadict.dictionary_VR(raw_elem.tag)
# Not in the dictionary, process if flag says to do so
except KeyError:
try_replace = kwargs["process_unknown_VRs"]
else:
try_replace = vr in kwargs["for_VRs"]
else:
try_replace = raw_elem.VR in kwargs["for_VRs"]
if try_replace:
# Note value has not been decoded yet when this function called,
# so need to replace backslash as bytes
new_value = None
if raw_elem.value is not None:
if kwargs["invalid_separator"] == b" ":
stripped_val = raw_elem.value.strip()
strip_count = len(raw_elem.value) - len(stripped_val)
new_value = (
stripped_val.replace(kwargs["invalid_separator"], b"\\")
+ b" " * strip_count
)
else:
new_value = raw_elem.value.replace(kwargs["invalid_separator"], b"\\")
return_val = raw_elem._replace(value=new_value)
return return_val
def fix_separator(
invalid_separator: bytes,
for_VRs: tuple[str, ...] = ("DS", "IS"),
process_unknown_VRs: bool = True,
) -> None:
"""A callback function to fix RawDataElement values using
some other separator than the dicom standard backslash character
Parameters
----------
invalid_separator : bytes
A single byte to replace with dicom backslash, in raw data element
values before they have been decoded or processed by pydicom
for_VRs : list, optional
A list of VRs for which the replacement will be done.
If the VR is unknown (for example, if a private element),
then process_unknown_VR is used to determine whether to replace or not.
process_unknown_VRs: bool, optional
If True (default) then attempt the fix even if the VR is not known.
Returns
-------
No return value. However, the callback function will return either
the original RawDataElement instance, or a fixed one.
"""
config.data_element_callback = fix_separator_callback
config.data_element_callback_kwargs = {
"invalid_separator": invalid_separator,
"for_VRs": for_VRs,
"process_unknown_VRs": process_unknown_VRs,
}
def fix_mismatch_callback(
raw_elem: "RawDataElement", **kwargs: Any
) -> "RawDataElement":
if raw_elem.VR is None:
return raw_elem
try:
values.convert_value(raw_elem.VR, raw_elem)
except ValueError:
for vr in kwargs["with_VRs"]:
try:
values.convert_value(vr, raw_elem)
except ValueError:
pass
else:
raw_elem = raw_elem._replace(VR=vr)
return raw_elem
def fix_mismatch(with_VRs: tuple[str, ...] = (VR.PN, VR.DS, VR.IS)) -> None:
"""A callback function to check that RawDataElements are translatable
with their provided VRs. If not, re-attempt translation using
some other translators.
Parameters
----------
with_VRs : Tuple[str]
A tuple of VR strings to attempt if the raw data element value cannot
be translated with the raw data element's VR. Default
``('PN', 'DS', 'IS')``.
Returns
-------
No return value. The callback function will return either
the original RawDataElement instance, or one with a fixed VR.
"""
config.data_element_callback = fix_mismatch_callback
config.data_element_callback_kwargs = {"with_VRs": with_VRs}