Esempio n. 1
0
 def set_dicom_attribute(self, keyword, value):
     """Sets specified DICOM attribute according to the keyword value pair
     Parameters
     ----------
     keyword : Name of DICOM tag to set value for
     value : Value to set
     """
     if tag_for_keyword(keyword):
         if keyword in self.dataset:
             if dictionary_VR(
                     tag_for_keyword(keyword)) == "SQ" and isinstance(
                         value, list):
                 value = generate_sequence(keyword, value)
             self.dataset[tag_for_keyword(keyword)].value = value
         else:
             if dictionary_VR(
                     tag_for_keyword(keyword)) == "SQ" and isinstance(
                         value, list):
                 value = generate_sequence(keyword, value)
             de = DataElement(tag_for_keyword(keyword),
                              dictionary_VR(tag_for_keyword(keyword)),
                              value)
             self.dataset[tag_for_keyword(keyword)] = de
     else:
         print("Keyword", keyword, "is an unknown DICOM attribute")
def CodeSeqItemGenerator(code_value: str, code_meaning: str,
                         coding_shceme_designator: str) -> Dataset:
    output = Dataset()
    cv = Dictionary.tag_for_keyword('CodeValue')
    cm = Dictionary.tag_for_keyword('CodeMeaning')
    cs = Dictionary.tag_for_keyword('CodingSchemeDesignator')
    output[cv] = DataElementX(cv, Dictionary.dictionary_VR(cv), code_value)
    output[cm] = DataElementX(cm, Dictionary.dictionary_VR(cm), code_meaning)
    output[cs] = DataElementX(cs, Dictionary.dictionary_VR(cs),
                              coding_shceme_designator)
    return output
def generalfix_CheckAndFixModality(ds: Dataset, log: list) -> bool:
    fixed = False
    modality_sop = {
        CTImageStorageSOPClassUID: 'CT',
        MRImageStorageSOPClassUID: 'MR',
        PETImageStorageSOPClassUID: 'PT',
    }
    if 'SOPClassUID' in ds:
        sop_class = ds['SOPClassUID'].value
    else:
        return False
    if sop_class not in modality_sop:
        return False
    mod_tg = tag_for_keyword('Modality')
    if mod_tg in ds:
        modality = ds[mod_tg].value
    else:
        modality = ''
    if modality == '' or modality != modality_sop[sop_class]:
        ds[mod_tg] = DataElementX(mod_tg, dictionary_VR(mod_tg),
                                  modality_sop[sop_class])
        msg = ErrorInfo()
        msg.msg = 'General Fix - {}'.format("<Modality> is wrong or absent")
        msg.fix = "fixed by reading the <SOPClassUID> and setting <Modality>"\
            " from '{}' to '{}'".format(modality, modality_sop[sop_class])
        log.append(msg.getWholeMessage())
        fixed = True
    return fixed
Esempio n. 4
0
    def update_dict(self):
        """
        The dictionary to be provided as input to edit_dicom to make the file(s)
            consistent with self.fw_header
        """
        if not isinstance(self._update_dict, dict):
            if self.header_diff_dict:
                info_str = f"Differing DICOM tags:\n {pformat(self.header_diff_dict)}"

                self.log.debug(info_str)
                update_dict = {
                    k: v.fw_value
                    for k, v in self.header_diff_dict.items()
                }
                # Remove OF, SQ, UI VR tags
                exclude_keys = [
                    k for k in update_dict.keys()
                    if dictionary_VR(k) in self.exclude_vrs
                ]
                exclude_vr_tags = {k: update_dict.pop(k) for k in exclude_keys}
                if exclude_vr_tags:
                    warn_str = (
                        f"{len(exclude_vr_tags)} DICOM tags have VRs {self.exclude_vrs} "
                        "for which editing is not supported. The values for the "
                        "following tags will not be edited despite info.header.dicom"
                        f" and local values differing: {pformat(exclude_vr_tags)}"
                    )
                    self.log.warning(warn_str)
                self._update_dict = update_dict

        return self._update_dict
def generalfix_AddPresentationLUTShape(ds: Dataset, log: list) -> bool:
    fixed = False
    photo_in_tg = tag_for_keyword('PhotometricInterpretation')
    if photo_in_tg not in ds:
        return fixed
    photo_in_v = ds[photo_in_tg].value
    pres_lut_shape_tg = tag_for_keyword('PresentationLUTShape')
    if pres_lut_shape_tg in ds:
        pres_lut_shape_a = ds[pres_lut_shape_tg]
    else:
        pres_lut_shape_a = DataElementX(pres_lut_shape_tg,
                                        dictionary_VR(pres_lut_shape_tg), '')
    old_pls = pres_lut_shape_a.value
    if photo_in_v == 'MONOCHROME2' and old_pls != 'IDENTITY':
        new_pls = 'IDENTITY'
        pres_lut_shape_a.value = new_pls
        fixed = True
    elif photo_in_v == 'MONOCHROME1' and old_pls != 'INVERSE':
        new_pls = 'INVERSE'
        pres_lut_shape_a.value = new_pls
        fixed = True
    if fixed:
        ds[pres_lut_shape_tg] = pres_lut_shape_a
        msg = ErrorInfo()
        msg.msg = 'General Fix - {}'.format(
            "<PresentationLUTShape> is wrong or absent")
        msg.fix = "fixed by setting the <PresentationLUTShape>"\
            " from '{}' to '{}'".format(old_pls, new_pls)
        log.append(msg.getWholeMessage())
    return fixed
Esempio n. 6
0
    def __init__(self,
                 tag,
                 VR,
                 value,
                 file_value_tell=None,
                 is_undefined_length=False,
                 already_converted=False):
        """Create a new :class:`DataElement`.

        Parameters
        ----------
        tag : int or or str or list or tuple
            The DICOM (group, element) tag in any form accepted by
            :func:`~pydicom.tag.Tag` such as ``[0x0010, 0x0010]``,
            ``(0x10, 0x10)``, ``0x00100010``, etc.
        VR : str
            The 2 character DICOM value representation (see DICOM Standard,
            Part 5, :dcm:`Section 6.2<part05/sect_6.2.html>`).
        value
            The value of the data element. One of the following:

            * a single string value
            * a number
            * a :class:`list` or :class:`tuple` with all strings or all numbers
            * a multi-value string with backslash separator

        file_value_tell : int or None
            Used internally by :class:`~pydicom.dataset.Dataset` to
            store the write position for the ``ReplaceDataElementValue()``
            method. Default is ``None``.
        is_undefined_length : bool
            Used internally to store whether the length field for this element
            was ``0xFFFFFFFFL``, i.e. 'undefined length'. Default is ``False``.
        already_converted : bool
            Used to determine whether or not the element's value requires
            conversion to a value with VM > 1. Default is ``False``.
        """
        if not isinstance(tag, BaseTag):
            tag = Tag(tag)
        self.tag = tag

        # a known tag shall only have the VR 'UN' if it has a length that
        # exceeds the size that can be encoded in 16 bit - all other cases
        # can be seen as an encoding error and can be corrected
        if (VR == 'UN' and not tag.is_private and
                config.replace_un_with_known_vr and
                (is_undefined_length or value is None or len(value) < 0xffff)):
            try:
                VR = dictionary_VR(tag)
            except KeyError:
                pass

        self.VR = VR  # Note: you must set VR before setting value
        if already_converted:
            self._value = value
        else:
            self.value = value  # calls property setter which will convert
        self.file_tell = file_value_tell
        self.is_undefined_length = is_undefined_length
        self.private_creator = None
def subfix_AddOrChangeAttrib(ds: Dataset, log: list, error_regexp: str,
                             fix_message: str, keyword: str, value) -> bool:
    fixed = False
    t = Dictionary.tag_for_keyword(keyword)
    if t is None:
        return False
    desc = Dictionary.dictionary_description(t)
    ErrorOccured = False
    log_l = len(log)
    for i in range(0, log_l):
        if re.match(error_regexp, log[i]) is not None:
            msg = mesgtext_cc.ErrorInfo(log[i], fix_message)
            log[i] = msg.getWholeMessage()
            ErrorOccured = True
    if ErrorOccured:
        if keyword in ds:
            ds[keyword].value = value  # just modify
            fixed = True
        else:
            vr = Dictionary.dictionary_VR(t)
            vm = 1
            elem = DataElementX(t, vr, value)
            ds[keyword] = elem
            fixed = True
    return fixed
Esempio n. 8
0
def fix_separator_callback(raw_elem, **kwargs):
    """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_unkown_VR']
        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 = raw_elem.value.replace(kwargs['invalid_separator'], b"\\")
        return_val = raw_elem._replace(value=new_value)

    return return_val
Esempio n. 9
0
 def _get_vr_ord(self, key, ordinate):
     tag = keyword_dict[key]
     vr = dictionary_VR(tag)
     if vr == 'TM':
         return '%06d.000000' % ordinate
     else:
         return ordinate
Esempio n. 10
0
 def reformatJSON(self, request_json: dict):
     """
     iterate over key/values in json
     {"00080005": {"Value": ["ISO_IR 100"], "vr": "CS"}
     pydicom.datadict.dictionary_VR(tag)
     """
     pydicom_json = {}
     for key, value in request_json.items():
         if isinstance(value, list):
             scheduledsequences = []
             for item in value:
                 scheduledsequences.append(self.reformatJSON(item))
             pydicom_json[key] = {"Value": scheduledsequences, "vr": dictionary_VR(key)}
         else:
             pydicom_json[key] = {"Value": [value], "vr": dictionary_VR(key)}
     return pydicom_json
Esempio n. 11
0
 def _get_vr_ord(self, key, ordinate):
     tag = keyword_dict[key]
     vr = dictionary_VR(tag)
     if vr == 'TM':
         return '%06d.000000' % ordinate
     else:
         return ordinate
Esempio n. 12
0
def get_pydicom_header(dcm):
    # Extract the header values
    errors = walk_dicom(dcm, callbacks=[fix_VM1_callback], recursive=True)
    if errors:
        result = ""
        for error in errors:
            result += "\n  {}".format(error)
        log.warning(f"Errors found in walking dicom: {result}")
    header = {}
    exclude_tags = [
        "[Unknown]",
        "PixelData",
        "Pixel Data",
        "[User defined data]",
        "[Protocol Data Block (compressed)]",
        "[Histogram tables]",
        "[Unique image iden]",
        "ContourData",
        "EncryptedAttributesSequence",
    ]
    tags = dcm.dir()
    for tag in tags:
        try:
            if (tag not in exclude_tags) and (
                type(dcm.get(tag)) != pydicom.sequence.Sequence
            ):
                value = dcm.get(tag)
                if value or value == 0:  # Some values are zero
                    # Put the value in the header
                    if (
                        type(value) == str and len(value) < 10240
                    ):  # Max pydicom field length
                        header[tag] = format_string(value)
                    else:
                        header[tag] = assign_type(value)

                else:
                    # Strangeness between pydicom versions for backwards compatibility.
                    # Pydicom v2.0.0 reads an empty PN value as a single space, mock doing that
                    # Here so we don't accidentally try to set this value back to a space.
                    if dictionary_VR(tag) == 'PN':
                        header[tag] = format_string(' ')
                    else:
                        log.debug("No value found for tag: " + tag)

            if (tag not in exclude_tags) and type(
                dcm.get(tag)
            ) == pydicom.sequence.Sequence:
                seq_data = get_seq_data(dcm.get(tag), exclude_tags)
                # Check that the sequence is not empty
                if seq_data:
                    header[tag] = seq_data
        except:
            log.debug("Failed to get " + tag)
            pass

    fix_type_based_on_dicom_vm(header)

    return header
Esempio n. 13
0
def DataElement_from_raw(raw_data_element, encoding=None):
    """Return a :class:`DataElement` created from `raw_data_element`.

    Parameters
    ----------
    raw_data_element : RawDataElement namedtuple
        The raw data to convert to a :class:`DataElement`.
    encoding : str, optional
        The character encoding of the raw data.

    Returns
    -------
    DataElement
    """
    # XXX buried here to avoid circular import
    # filereader->Dataset->convert_value->filereader
    # (for SQ parsing)

    if in_py2:
        encoding = encoding or default_encoding
    from pydicom.values import convert_value
    raw = raw_data_element

    # If user has hooked into conversion of raw values, call his/her routine
    if config.data_element_callback:
        data_elem = config.data_element_callback
        raw = data_elem(raw_data_element,
                        **config.data_element_callback_kwargs)
    VR = raw.VR
    if VR is None:  # Can be if was implicit VR
        try:
            VR = dictionary_VR(raw.tag)
        except KeyError:
            # just read the bytes, no way to know what they mean
            if raw.tag.is_private:
                # for VR for private tags see PS3.5, 6.2.2
                if raw.tag.is_private_creator:
                    VR = 'LO'
                else:
                    VR = 'UN'

            # group length tag implied in versions < 3.0
            elif raw.tag.element == 0:
                VR = 'UL'
            else:
                msg = "Unknown DICOM tag {0:s}".format(str(raw.tag))
                msg += " can't look up VR"
                raise KeyError(msg)
    try:
        value = convert_value(VR, raw, encoding)
    except NotImplementedError as e:
        raise NotImplementedError("{0:s} in tag {1!r}".format(str(e), raw.tag))

    if raw.tag in _LUT_DESCRIPTOR_TAGS and value[0] < 0:
        # We only fix the first value as the third value is 8 or 16
        value[0] += 65536

    return DataElement(raw.tag, VR, value, raw.value_tell,
                       raw.length == 0xFFFFFFFF, already_converted=True)
Esempio n. 14
0
 def VR(self):
     """Find the correct Value Representation for this tag from pydicom"""
     try:
         return dictionary_VR(Tag(self.tag))
     except KeyError as e:
         # unknown tag. Just return set value, assuming user want to just
         # get on with it
         return VRs.LongString.short_name
Esempio n. 15
0
def tag2str(ttag: BaseTag):
    if Dictionary.dictionary_has_tag(ttag):
        desc = Dictionary.dictionary_description(ttag)
        vr = Dictionary.dictionary_VR(ttag)
        txt = "->{}:{}".format(desc, vr)
    else:
        txt = ''
    msg = "(0x{:0>4x}, 0x{:0>4x})".format(ttag.group, ttag.element, txt)
    return msg
Esempio n. 16
0
def fix_ByAddingEmptyAttrib(ds: Dataset, element: str) -> str:
    reason = ''
    ttag = tag_for_keyword(element)
    if ttag is not None:
        vr = Dic.dictionary_VR(ttag)
        element = DataElement(ttag, vr, '')
        element.value = element.empty_value
        ds[ttag] = element
        reason += "fixed by adding empty attribute"
    return reason
Esempio n. 17
0
def DataElement_from_raw(raw_data_element, encoding=None):
    """Return a DataElement created from the data in `raw_data_element`.

    Parameters
    ----------
    raw_data_element : RawDataElement namedtuple
        The raw data to convert to a DataElement
    encoding : str
        The encoding of the raw data

    Returns
    -------
    pydicom.dataelem.DataElement
    """
    # XXX buried here to avoid circular import
    # filereader->Dataset->convert_value->filereader
    # (for SQ parsing)

    if in_py2:
        encoding = encoding or default_encoding
    from pydicom.values import convert_value
    raw = raw_data_element

    # If user has hooked into conversion of raw values, call his/her routine
    if config.data_element_callback:
        data_elem = config.data_element_callback
        raw = data_elem(raw_data_element,
                        **config.data_element_callback_kwargs)
    VR = raw.VR
    if VR is None:  # Can be if was implicit VR
        try:
            VR = dictionary_VR(raw.tag)
        except KeyError:

            # just read the bytes, no way to know what they mean
            if raw.tag.is_private:
                VR = 'OB'

            # group length tag implied in versions < 3.0
            elif raw.tag.element == 0:
                VR = 'UL'
            else:
                msg = "Unknown DICOM tag {0:s}".format(str(raw.tag))
                msg += " can't look up VR"
                raise KeyError(msg)
    try:
        value = convert_value(VR, raw, encoding)
    except NotImplementedError as e:
        raise NotImplementedError("{0:s} in tag {1!r}".format(str(e), raw.tag))
    return DataElement(raw.tag,
                       VR,
                       value,
                       raw.value_tell,
                       raw.length == 0xFFFFFFFF,
                       already_converted=True)
Esempio n. 18
0
    def __init__(self,
                 tag,
                 VR,
                 value,
                 file_value_tell=None,
                 is_undefined_length=False,
                 already_converted=False):
        """Create a new DataElement.

        Parameters
        ----------
        tag
            The DICOM (group, element) tag in any form accepted by
            pydicom.tag.Tag such as [0x0010, 0x0010], (0x10, 0x10), 0x00100010,
            etc.
        VR : str
            The 2 character DICOM value representation (see DICOM standard part
            5, Section 6.2).
        value
            The value of the data element. One of the following:
            * a single string value
            * a number
            * a list or tuple with all strings or all numbers
            * a multi-value string with backslash separator
        file_value_tell : int or None
            Used internally by Dataset to store the write position for the
            ReplaceDataElementValue() method. Default is None.
        is_undefined_length : bool
            Used internally to store whether the length field for this element
            was 0xFFFFFFFFL, i.e. 'undefined length'. Default is False.
        already_converted : bool
            Used to determine whether or not `value` requires conversion to a
            value with VM > 1. Default is False.
        """
        if not isinstance(tag, BaseTag):
            tag = Tag(tag)
        self.tag = tag

        # a known tag shall only have the VR 'UN' if it has a length that
        # exceeds the size that can be encoded in 16 bit - all other cases
        # can be seen as an encoding error and can be corrected
        if VR == 'UN' and (is_undefined_length or value is None
                           or len(value) < 0xffff):
            try:
                VR = dictionary_VR(tag)
            except KeyError:
                pass

        self.VR = VR  # Note!: you must set VR before setting value
        if already_converted:
            self._value = value
        else:
            self.value = value  # calls property setter which will convert
        self.file_tell = file_value_tell
        self.is_undefined_length = is_undefined_length
Esempio n. 19
0
def DataElement_from_raw(raw_data_element, encoding=None):
    """Return a DataElement created from the data in `raw_data_element`.

    Parameters
    ----------
    raw_data_element : RawDataElement namedtuple
        The raw data to convert to a DataElement
    encoding : str
        The encoding of the raw data

    Returns
    -------
    pydicom.dataelem.DataElement
    """
    # XXX buried here to avoid circular import
    # filereader->Dataset->convert_value->filereader
    # (for SQ parsing)

    if in_py2:
        encoding = encoding or default_encoding
    from pydicom.values import convert_value
    raw = raw_data_element

    # If user has hooked into conversion of raw values, call his/her routine
    if config.data_element_callback:
        data_elem = config.data_element_callback
        raw = data_elem(raw_data_element,
                        **config.data_element_callback_kwargs)
    VR = raw.VR
    if VR is None:  # Can be if was implicit VR
        try:
            VR = dictionary_VR(raw.tag)
        except KeyError:
            # just read the bytes, no way to know what they mean
            if raw.tag.is_private:
                # for VR for private tags see PS3.5, 6.2.2
                if raw.tag.is_private_creator:
                    VR = 'LO'
                else:
                    VR = 'UN'

            # group length tag implied in versions < 3.0
            elif raw.tag.element == 0:
                VR = 'UL'
            else:
                msg = "Unknown DICOM tag {0:s}".format(str(raw.tag))
                msg += " can't look up VR"
                raise KeyError(msg)
    try:
        value = convert_value(VR, raw, encoding)
    except NotImplementedError as e:
        raise NotImplementedError("{0:s} in tag {1!r}".format(str(e), raw.tag))
    return DataElement(raw.tag, VR, value, raw.value_tell,
                       raw.length == 0xFFFFFFFF, already_converted=True)
Esempio n. 20
0
def verifyVR(elem: DataElement,
             module: str,
             element: str,
             verbose: bool,
             log: list,
             fix_trivial=False):
    # tag = getTag();

    # if (tag.isPrivateTag()) :
    #     return True
    v = elem.value
    try:
        vrd = dictionary_VR(elem.tag)
    except BaseException as err:
        print(err)
        mssg = EMsgDC("NoSuchElementInDictionary") + " "
        if len(element) != 0:
            mssg += MMsgDC("Element") + "=<" + element + ">"
        if len(module) != 0:
            mssg += MMsgDC("Module") + "=<" + module + ">"
        log.append(mssg)
        return False
    vre = elem.VR
    vrds = []
    vre_equlas_vrd = False
    if len(vrd) > 2 and len(vre) == 2:
        vrds = vrd.split(' or ')
        for dic_vr in vrds:
            if dic_vr == vre:
                vre_equlas_vrd = True
                break
    else:
        vre_equlas_vrd = (vre == vrd)
    if not vre_equlas_vrd and not(vrd == "OX" and vre == "OB" or vre == "OW") \
            and not(vrd == "XS" and vre == "US" or vre == "SS") \
            and not(vrd == "XO" and vre == "US" or vre == "SS" or vre == "OW") \
            and not(vrd == "XL" and vre == "UL" or vre == "SL"):
        mssg = EMsgDC("BadValueRepresentation") \
               + " " + vre + " (" + vrd + " " + MMsgDC("Required") + ")"
        # print(vrds,'<-->' ,vrd,'<-->', vre, '<-->', elem)
        if len(element) != 0:
            mssg += MMsgDC("Element") + "=<" + element + ">"
        if len(module) != 0:
            mssg += MMsgDC("Module") + "=<" + module + ">"
        log.append(mssg)
        if fix_trivial:
            elem.VR = vrd
            mssg += " :fixed: by changing the vr"
        return False
    else:
        return True
Esempio n. 21
0
def update_and_insert_additional_DICOM_attributes_in_ds(
        ds, keyword_and_value_dict):
    # For every keyword
    for keyword in keyword_and_value_dict:
        # Get corresponding tag and value
        tag = tag_for_keyword(keyword)
        # Verify that it is a valid keyword
        if tag is None:
            print("Unknown DICOM attribute:", keyword)
            continue
        # Get corresponding value
        value = None
        if dictionary_VR(tag) == "SQ":
            value = generate_sequence(keyword, keyword_and_value_dict[keyword])
        else:
            value = keyword_and_value_dict[keyword]
        # If keyword already set, update its value, otherwise, create a new data element
        if keyword in ds:
            ds[tag].value = value
        else:
            ds[tag] = DataElement(tag, dictionary_VR(tag), value)
    # Return edited dataset
    return ds
def add_anatomy(ds: Dataset,
                BodyPartExamined_value: str,
                AnatomicRegionSequence_value: tuple,
                log: list,
                check_consistency: bool = True):
    bpe = tag_for_keyword('BodyPartExamined')
    ars = tag_for_keyword('AnatomicRegionSequence')
    old_bpe, old_ars = get_old_anatomy(ds)
    if old_bpe is None:
        if check_consistency:
            new_bpe, new_ars = \
                CorrectAnatomicInfo(
                    BodyPartExamined_value, AnatomicRegionSequence_value)
        else:
            new_bpe, new_ars = (BodyPartExamined_value,
                                AnatomicRegionSequence_value)
    else:
        new_bpe, new_ars = CorrectAnatomicInfo(old_bpe, old_ars)

    if old_bpe != new_bpe and new_bpe is not None:
        bpe_a = DataElementX(bpe, dictionary_VR(bpe), new_bpe)
        old_bpe_txt = old_bpe if bpe not in ds else ds[bpe].value
        ds[bpe] = bpe_a
        msg = ErrorInfo()
        msg.msg = 'General Fix - {}'.format("<BodyPartExamined> is absent")
        msg.fix = "fixed by setting the <BodyPartExamined>"\
            "from {} to '{}'".format(old_bpe_txt, new_bpe)
        log.append(msg.getWholeMessage())
    if is_accurate_code_seq(new_ars) and not is_code_equal(old_ars, new_ars):
        code_value, code_meaning, coding_scheme_designator = new_ars
        if ars in ds:
            old_item_text = subfix_CodeSeqItem2txt(ds[ars], 0)
        else:
            old_item_text = 'None'
        new_item = CodeSeqItemGenerator(str(code_value), code_meaning,
                                        coding_scheme_designator)
        ars_a = DataElementX(ars, 'SQ', DicomSequence([
            new_item,
        ]))
        ds[ars] = ars_a
        msg = ErrorInfo()
        msg.msg = 'General Fix - {}'.format(
            "<AnatomicRegionSequence> is absent")
        msg.fix = "fixed by setting the <AnatomicRegionSequence>"\
            "from {} to '{}'".format(
                old_item_text,
                subfix_CodeSeqItem2txt(ars_a, 0))
        log.append(msg.getWholeMessage())
    AddLaterality(ds, log)
Esempio n. 23
0
def overwriteDicomFileTag(imagePath, dicomTag, newValue):
    try:
        if isinstance(imagePath, list):
            datasetList = readDICOM_Image.getSeriesDicomDataset(imagePath)
            for index, dataset in enumerate(datasetList):
                if isinstance(dicomTag, str):
                    try: dataset.data_element(dicomTag).value = newValue
                    except: dataset.add_new(dicomTag, dictionary_VR(dicomTag), newValue)
                else:
                    try: dataset[hex(dicomTag)].value = newValue
                    except: dataset.add_new(hex(dicomTag), dictionary_VR(hex(dicomTag)), newValue)
                saveDicomToFile(dataset, output_path=imagePath[index])
        else:
            dataset = readDICOM_Image.getDicomDataset(imagePath)
            if isinstance(dicomTag, str):
                try: dataset.data_element(dicomTag).value = newValue
                except: dataset.add_new(dicomTag, dictionary_VR(dicomTag), newValue)
            else:
                try: dataset[hex(dicomTag)].value = newValue
                except: dataset.add_new(hex(dicomTag), dictionary_VR(hex(dicomTag)), newValue)
            saveDicomToFile(dataset, output_path=imagePath)
        return
    except Exception as e:
        print('Error in saveDICOM_Image.overwriteDicomFileTag: ' + str(e))
def subfix_UpdateOrInsertCodeAttribute(seqelem: DataElementX, index: int,
                                       kw: str, value: str) -> str:
    text_fun = lambda ds, att: '{}: {}\t'.format(att, ds[att])
    out_msg = ''
    if kw in seqelem.value[index]:
        out_msg = " {} modified <{}> -> <{}>".format(
            kw, seqelem.value[index][kw].value, value)
        seqelem.value[index][kw].value = value
    else:
        out_msg = "{} = <{}> was added".format(kw, value)
        newtag = Dictionary.tag_for_keyword(kw)
        newvr = Dictionary.dictionary_VR(newtag)
        elem = DataElementX(newtag, newvr, value)
        seqelem.value[index].add(elem)
    return out_msg
def put_attribute_in_path(ds: Dataset, path: list, a: DataElementX):
    if not path:
        if a.tag not in ds:
            ds[a.tag] = a
    else:
        kw = path.pop(0)
        tg = Dictionary.tag_for_keyword(kw)
        vr = Dictionary.dictionary_VR(tg)
        if vr == 'SQ':
            if tg in ds and ds[tg].VM > 0:
                inner_sq = ds[tg]
                item = inner_sq.value[0]
            else:
                item = Dataset()
                new_element = DataElementX(tg, vr, Sequence([item]))
                ds[tg] = new_element
            put_attribute_in_path(item, path, a)
Esempio n. 26
0
 def copy_additional_dicom_attributes(self, dataset_to_copy_from,
                                      dataset_to_copy_to,
                                      additional_dicom_attributes):
     """Copies additional DICOM attributes for this module from one dataset to another
     Parameters
     ----------
     dataset_to_copy_from : Dataset to copy DICOM attributes from
     dataset_to_copy_to : Dataset to copy DICOM attributes to
     additional_dicom_attributes : List of additional DICOM attributes to copy
     """
     for dicom_attribute in additional_dicom_attributes:
         tag = tag_for_keyword(dicom_attribute)
         if dicom_attribute in dataset_to_copy_from:
             dataset_to_copy_to[tag] = dataset_to_copy_from[tag]
         else:
             de = DataElement(tag, dictionary_VR(tag), "")
             dataset_to_copy_to[tag] = de
Esempio n. 27
0
 def copy_required_dicom_attributes(self, dataset_to_copy_from,
                                    dataset_to_copy_to):
     """Copies required DICOM attributes for this module from one dataset to another
     Parameters
     ----------
     dataset_to_copy_from : Dataset to copy DICOM attributes from
     dataset_to_copy_to : Dataset to copy DICOM attributes to
     """
     for dicom_attribute in self.required_dicom_attributes:
         tag = tag_for_keyword(dicom_attribute)
         if dicom_attribute in dataset_to_copy_from:
             dataset_to_copy_to[tag] = dataset_to_copy_from[tag]
         elif dicom_attribute in dataset_to_copy_to:
             pass
         else:
             de = DataElement(tag, dictionary_VR(tag), "")
             dataset_to_copy_to[tag] = de
Esempio n. 28
0
def set_dicom_tag_value(ds, tag, value):
    """Set or update a DICOM tag value in the pydicom dataset.

    Parameters
    ----------
    ds : pydicom Dataset
        The pydicom dataset for the tag to be added/updated to.
    tag : str, int or tuple
        DICOM tag or keyword to be added.
    value : any
        New value for the tag's element.
    """
    try:
        ds[tag].value = value
    except KeyError:
        if tag in keyword_dict:  # Keyword provided rather than int or tuple
            tag = keyword_dict[tag]
        ds.add_new(tag, dictionary_VR(tag), value)
Esempio n. 29
0
def safe_get_(dcm: FileDataset, tag: int) -> Optional[ParsedElementValue]:
    try:
        element = dcm[tag]
        VR, element_value = dictionary_VR(tag), element.value

        if element_value == "" or element_value is None:
            return None

        vr_parser = DicomVRParseDictionary.get(VR, lambda value: value)
        if isinstance(element_value, MultiValue) is not isinstance(element_value, Sequence):
            return cast(ParsedElementValue, [vr_parser(item) for item in element_value])

        return vr_parser(element_value)
    except KeyError:
        logger.debug(f"Cannot find element using for tag={to_dicom_tag(tag)}")
        return None
    except ValueError as error:
        logger.warning(f"Encountered ValueError extracting element for tag={to_dicom_tag(tag)} - err={error}")
        return None
Esempio n. 30
0
    def __setattr__(self, name, value):
        """Intercept any attempts to set a value for an instance attribute.

        If name is a DICOM keyword, set the corresponding tag and DataElement.
        Else, set an instance (python) attribute as any other class would do.

        Parameters
        ----------
        name : str
            The element keyword for the DataElement you wish to add/change. If
            `name` is not a DICOM element keyword then this will be the
            name of the attribute to be added/changed.
        value
            The value for the attribute to be added/changed.
        """
        tag = tag_for_keyword(name)
        if tag is not None:  # successfully mapped name to a tag
            if tag not in self:
                # don't have this tag yet->create the data_element instance
                VR = dictionary_VR(tag)
                data_element = DataElement(tag, VR, value)
            else:
                # already have this data_element, just changing its value
                data_element = self[tag]
                data_element.value = value
            # Now have data_element - store it in this dict
            self[tag] = data_element
        elif repeater_has_keyword(name):
            # Check if `name` is repeaters element
            raise ValueError('{} is a DICOM repeating group '
                             'element and must be added using '
                             'the add() or add_new() methods.'
                             .format(name))
        else:
            # name not in dicom dictionary - setting a non-dicom instance
            # attribute
            # XXX note if user mis-spells a dicom data_element - no error!!!
            super(Dataset, self).__setattr__(name, value)
Esempio n. 31
0
    def __setattr__(self, name, value):
        """Intercept any attempts to set a value for an instance attribute.

        If name is a DICOM keyword, set the corresponding tag and DataElement.
        Else, set an instance (python) attribute as any other class would do.

        Parameters
        ----------
        name : str
            The element keyword for the DataElement you wish to add/change. If
            `name` is not a DICOM element keyword then this will be the
            name of the attribute to be added/changed.
        value
            The value for the attribute to be added/changed.
        """
        tag = tag_for_keyword(name)
        if tag is not None:  # successfully mapped name to a tag
            if tag not in self:
                # don't have this tag yet->create the data_element instance
                VR = dictionary_VR(tag)
                data_element = DataElement(tag, VR, value)
            else:
                # already have this data_element, just changing its value
                data_element = self[tag]
                data_element.value = value
            # Now have data_element - store it in this dict
            self[tag] = data_element
        elif repeater_has_keyword(name):
            # Check if `name` is repeaters element
            raise ValueError('{} is a DICOM repeating group '
                             'element and must be added using '
                             'the add() or add_new() methods.'
                             .format(name))
        else:
            # name not in dicom dictionary - setting a non-dicom instance
            # attribute
            # XXX note if user mis-spells a dicom data_element - no error!!!
            super(Dataset, self).__setattr__(name, value)
Esempio n. 32
0
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
Esempio n. 33
0
def data_element_generator(fp,
                           is_implicit_VR,
                           is_little_endian,
                           stop_when=None,
                           defer_size=None,
                           encoding=default_encoding,
                           specific_tags=None):
    """Create a generator to efficiently return the raw data elements.

    Parameters
    ----------
    fp : file-like object
    is_implicit_VR : boolean
    is_little_endian : boolean
    stop_when : None, callable, optional
        If None (default), then the whole file is read.
        A callable which takes tag, VR, length,
        and returns True or False. If it returns True,
        read_data_element will just return.
    defer_size : int, str, None, optional
        See ``dcmread`` for parameter info.
    encoding :
        Encoding scheme
    specific_tags : list or None
        See ``dcmread`` for parameter info.

    Returns
    -------
    VR : None if implicit VR, otherwise the VR read from the file
    length :
        the length as in the DICOM data element (could be
        DICOM "undefined length" 0xffffffffL)
    value_bytes :
        the raw bytes from the DICOM file
        (not parsed into python types)
    is_little_endian : boolean
        True if transfer syntax is little endian; else False.
    """
    # Summary of DICOM standard PS3.5-2008 chapter 7:
    # If Implicit VR, data element is:
    #    tag, 4-byte length, value.
    #        The 4-byte length can be FFFFFFFF (undefined length)*
    #
    # If Explicit VR:
    #    if OB, OW, OF, SQ, UN, or UT:
    #       tag, VR, 2-bytes reserved (both zero), 4-byte length, value
    #           For all but UT, the length can be FFFFFFFF (undefined length)*
    #   else: (any other VR)
    #       tag, VR, (2 byte length), value
    # * for undefined length, a Sequence Delimitation Item marks the end
    #        of the Value Field.
    # Note, except for the special_VRs, both impl and expl VR use 8 bytes;
    #    the special VRs follow the 8 bytes with a 4-byte length

    # With a generator, state is stored, so we can break down
    #    into the individual cases, and not have to check them again for each
    #    data element

    if is_little_endian:
        endian_chr = "<"
    else:
        endian_chr = ">"
    if is_implicit_VR:
        element_struct = Struct(endian_chr + "HHL")
    else:  # Explicit VR
        # tag, VR, 2-byte length (or 0 if special VRs)
        element_struct = Struct(endian_chr + "HH2sH")
        extra_length_struct = Struct(endian_chr + "L")  # for special VRs
        extra_length_unpack = extra_length_struct.unpack  # for lookup speed

    # Make local variables so have faster lookup
    fp_read = fp.read
    fp_tell = fp.tell
    logger_debug = logger.debug
    debugging = config.debugging
    element_struct_unpack = element_struct.unpack
    defer_size = size_in_bytes(defer_size)

    tag_set = set()
    has_specific_char_set = True
    if specific_tags is not None:
        for tag in specific_tags:
            if isinstance(tag, (str, compat.text_type)):
                tag = Tag(tag_for_keyword(tag))
            if isinstance(tag, BaseTag):
                tag_set.add(tag)
        has_specific_char_set = Tag(0x08, 0x05) in tag_set
        tag_set.add(Tag(0x08, 0x05))
    has_tag_set = len(tag_set) > 0

    while True:
        # Read tag, VR, length, get ready to read value
        bytes_read = fp_read(8)
        if len(bytes_read) < 8:
            return  # at end of file
        if debugging:
            debug_msg = "{0:08x}: {1}".format(fp.tell() - 8,
                                              bytes2hex(bytes_read))

        if is_implicit_VR:
            # must reset VR each time; could have set last iteration (e.g. SQ)
            VR = None
            group, elem, length = element_struct_unpack(bytes_read)
        else:  # explicit VR
            group, elem, VR, length = element_struct_unpack(bytes_read)
            if not in_py2:
                VR = VR.decode(default_encoding)
            if VR in extra_length_VRs:
                bytes_read = fp_read(4)
                length = extra_length_unpack(bytes_read)[0]
                if debugging:
                    debug_msg += " " + bytes2hex(bytes_read)
        if debugging:
            debug_msg = "%-47s  (%04x, %04x)" % (debug_msg, group, elem)
            if not is_implicit_VR:
                debug_msg += " %s " % VR
            if length != 0xFFFFFFFF:
                debug_msg += "Length: %d" % length
            else:
                debug_msg += "Length: Undefined length (FFFFFFFF)"
            logger_debug(debug_msg)

        # Positioned to read the value, but may not want to -- check stop_when
        value_tell = fp_tell()
        tag = TupleTag((group, elem))
        if stop_when is not None:
            # XXX VR may be None here!! Should stop_when just take tag?
            if stop_when(tag, VR, length):
                if debugging:
                    logger_debug("Reading ended by stop_when callback. "
                                 "Rewinding to start of data element.")
                rewind_length = 8
                if not is_implicit_VR and VR in extra_length_VRs:
                    rewind_length += 4
                fp.seek(value_tell - rewind_length)
                return

        # Reading the value
        # First case (most common): reading a value with a defined length
        if length != 0xFFFFFFFF:
            # don't defer loading of Specific Character Set value as it is
            # needed immediately to get the character encoding for other tags
            if has_tag_set and tag not in tag_set:
                # skip the tag if not in specific tags
                fp.seek(fp_tell() + length)
                continue

            if (defer_size is not None and length > defer_size
                    and tag != BaseTag(0x00080005)):
                # Flag as deferred by setting value to None, and skip bytes
                value = None
                logger_debug("Defer size exceeded. "
                             "Skipping forward to next data element.")
                fp.seek(fp_tell() + length)
            else:
                value = fp_read(length)
                if debugging:
                    dotdot = "   "
                    if length > 12:
                        dotdot = "..."
                    logger_debug("%08x: %-34s %s %r %s" %
                                 (value_tell, bytes2hex(
                                     value[:12]), dotdot, value[:12], dotdot))

            # If the tag is (0008,0005) Specific Character Set, then store it
            if tag == BaseTag(0x00080005):
                from pydicom.values import convert_string
                encoding = convert_string(value,
                                          is_little_endian,
                                          encoding=default_encoding)
                # Store the encoding value in the generator
                # for use with future elements (SQs)
                encoding = convert_encodings(encoding)
                if not has_specific_char_set:
                    continue

            yield RawDataElement(tag, VR, length, value, value_tell,
                                 is_implicit_VR, is_little_endian)

        # Second case: undefined length - must seek to delimiter,
        # unless is SQ type, in which case is easier to parse it, because
        # undefined length SQs and items of undefined lengths can be nested
        # and it would be error-prone to read to the correct outer delimiter
        else:
            # Try to look up type to see if is a SQ
            # if private tag, won't be able to look it up in dictionary,
            #   in which case just ignore it and read the bytes unless it is
            #   identified as a Sequence
            if VR is None:
                try:
                    VR = dictionary_VR(tag)
                except KeyError:
                    # Look ahead to see if it consists of items
                    # and is thus a SQ
                    next_tag = TupleTag(unpack(endian_chr + "HH", fp_read(4)))
                    # Rewind the file
                    fp.seek(fp_tell() - 4)
                    if next_tag == ItemTag:
                        VR = 'SQ'

            if VR == 'SQ':
                if debugging:
                    msg = "{0:08x}: Reading/parsing undefined length sequence"
                    logger_debug(msg.format(fp_tell()))
                seq = read_sequence(fp, is_implicit_VR, is_little_endian,
                                    length, encoding)
                if has_tag_set and tag not in tag_set:
                    continue
                yield DataElement(tag,
                                  VR,
                                  seq,
                                  value_tell,
                                  is_undefined_length=True)
            else:
                delimiter = SequenceDelimiterTag
                if debugging:
                    logger_debug("Reading undefined length data element")
                value = read_undefined_length_value(fp, is_little_endian,
                                                    delimiter, defer_size)

                # If the tag is (0008,0005) Specific Character Set,
                # then store it
                if tag == (0x08, 0x05):
                    from pydicom.values import convert_string
                    encoding = convert_string(value,
                                              is_little_endian,
                                              encoding=default_encoding)
                    # Store the encoding value in the generator for use
                    # with future elements (SQs)
                    encoding = convert_encodings(encoding)
                    if not has_specific_char_set:
                        continue

                # tags with undefined length are skipped after read
                if has_tag_set and tag not in tag_set:
                    continue
                yield RawDataElement(tag, VR, length, value, value_tell,
                                     is_implicit_VR, is_little_endian)
Esempio n. 34
0
def data_element_generator(fp,
                           is_implicit_VR,
                           is_little_endian,
                           stop_when=None,
                           defer_size=None,
                           encoding=default_encoding,
                           specific_tags=None):

    """Create a generator to efficiently return the raw data elements.

    Parameters
    ----------
    fp : file-like object
    is_implicit_VR : boolean
    is_little_endian : boolean
    stop_when : None, callable, optional
        If None (default), then the whole file is read.
        A callable which takes tag, VR, length,
        and returns True or False. If it returns True,
        read_data_element will just return.
    defer_size : int, str, None, optional
        See ``dcmread`` for parameter info.
    encoding :
        Encoding scheme
    specific_tags : list or None
        See ``dcmread`` for parameter info.

    Returns
    -------
    VR : None if implicit VR, otherwise the VR read from the file
    length :
        the length as in the DICOM data element (could be
        DICOM "undefined length" 0xffffffffL)
    value_bytes :
        the raw bytes from the DICOM file
        (not parsed into python types)
    is_little_endian : boolean
        True if transfer syntax is little endian; else False.
    """
    # Summary of DICOM standard PS3.5-2008 chapter 7:
    # If Implicit VR, data element is:
    #    tag, 4-byte length, value.
    #        The 4-byte length can be FFFFFFFF (undefined length)*
    #
    # If Explicit VR:
    #    if OB, OW, OF, SQ, UN, or UT:
    #       tag, VR, 2-bytes reserved (both zero), 4-byte length, value
    #           For all but UT, the length can be FFFFFFFF (undefined length)*
    #   else: (any other VR)
    #       tag, VR, (2 byte length), value
    # * for undefined length, a Sequence Delimitation Item marks the end
    #        of the Value Field.
    # Note, except for the special_VRs, both impl and expl VR use 8 bytes;
    #    the special VRs follow the 8 bytes with a 4-byte length

    # With a generator, state is stored, so we can break down
    #    into the individual cases, and not have to check them again for each
    #    data element

    if is_little_endian:
        endian_chr = "<"
    else:
        endian_chr = ">"
    if is_implicit_VR:
        element_struct = Struct(endian_chr + "HHL")
    else:  # Explicit VR
        # tag, VR, 2-byte length (or 0 if special VRs)
        element_struct = Struct(endian_chr + "HH2sH")
        extra_length_struct = Struct(endian_chr + "L")  # for special VRs
        extra_length_unpack = extra_length_struct.unpack  # for lookup speed

    # Make local variables so have faster lookup
    fp_read = fp.read
    fp_tell = fp.tell
    logger_debug = logger.debug
    debugging = config.debugging
    element_struct_unpack = element_struct.unpack
    defer_size = size_in_bytes(defer_size)

    tag_set = set()
    if specific_tags is not None:
        for tag in specific_tags:
            if isinstance(tag, (str, compat.text_type)):
                tag = Tag(tag_for_keyword(tag))
            if isinstance(tag, BaseTag):
                tag_set.add(tag)
        tag_set.add(Tag(0x08, 0x05))
    has_tag_set = len(tag_set) > 0

    while True:
        # Read tag, VR, length, get ready to read value
        bytes_read = fp_read(8)
        if len(bytes_read) < 8:
            return  # at end of file
        if debugging:
            debug_msg = "{0:08x}: {1}".format(fp.tell() - 8,
                                              bytes2hex(bytes_read))

        if is_implicit_VR:
            # must reset VR each time; could have set last iteration (e.g. SQ)
            VR = None
            group, elem, length = element_struct_unpack(bytes_read)
        else:  # explicit VR
            group, elem, VR, length = element_struct_unpack(bytes_read)
            if not in_py2:
                VR = VR.decode(default_encoding)
            if VR in extra_length_VRs:
                bytes_read = fp_read(4)
                length = extra_length_unpack(bytes_read)[0]
                if debugging:
                    debug_msg += " " + bytes2hex(bytes_read)
        if debugging:
            debug_msg = "%-47s  (%04x, %04x)" % (debug_msg, group, elem)
            if not is_implicit_VR:
                debug_msg += " %s " % VR
            if length != 0xFFFFFFFF:
                debug_msg += "Length: %d" % length
            else:
                debug_msg += "Length: Undefined length (FFFFFFFF)"
            logger_debug(debug_msg)

        # Positioned to read the value, but may not want to -- check stop_when
        value_tell = fp_tell()
        tag = TupleTag((group, elem))
        if stop_when is not None:
            # XXX VR may be None here!! Should stop_when just take tag?
            if stop_when(tag, VR, length):
                if debugging:
                    logger_debug("Reading ended by stop_when callback. "
                                 "Rewinding to start of data element.")
                rewind_length = 8
                if not is_implicit_VR and VR in extra_length_VRs:
                    rewind_length += 4
                fp.seek(value_tell - rewind_length)
                return

        # Reading the value
        # First case (most common): reading a value with a defined length
        if length != 0xFFFFFFFF:
            # don't defer loading of Specific Character Set value as it is
            # needed immediately to get the character encoding for other tags
            if has_tag_set and tag not in tag_set:
                # skip the tag if not in specific tags
                fp.seek(fp_tell() + length)
                continue

            if (defer_size is not None and length > defer_size and
                    tag != BaseTag(0x00080005)):
                # Flag as deferred by setting value to None, and skip bytes
                value = None
                logger_debug("Defer size exceeded. "
                             "Skipping forward to next data element.")
                fp.seek(fp_tell() + length)
            else:
                value = fp_read(length)
                if debugging:
                    dotdot = "   "
                    if length > 12:
                        dotdot = "..."
                    logger_debug("%08x: %-34s %s %r %s" % (value_tell,
                                                           bytes2hex(
                                                               value[:12]),
                                                           dotdot,
                                                           value[:12], dotdot))

            # If the tag is (0008,0005) Specific Character Set, then store it
            if tag == BaseTag(0x00080005):
                from pydicom.values import convert_string
                encoding = convert_string(value, is_little_endian)
                # Store the encoding value in the generator
                # for use with future elements (SQs)
                encoding = convert_encodings(encoding)

            yield RawDataElement(tag, VR, length, value, value_tell,
                                 is_implicit_VR, is_little_endian)

        # Second case: undefined length - must seek to delimiter,
        # unless is SQ type, in which case is easier to parse it, because
        # undefined length SQs and items of undefined lengths can be nested
        # and it would be error-prone to read to the correct outer delimiter
        else:
            # Try to look up type to see if is a SQ
            # if private tag, won't be able to look it up in dictionary,
            #   in which case just ignore it and read the bytes unless it is
            #   identified as a Sequence
            if VR is None:
                try:
                    VR = dictionary_VR(tag)
                except KeyError:
                    # Look ahead to see if it consists of items
                    # and is thus a SQ
                    next_tag = TupleTag(unpack(endian_chr + "HH", fp_read(4)))
                    # Rewind the file
                    fp.seek(fp_tell() - 4)
                    if next_tag == ItemTag:
                        VR = 'SQ'

            if VR == 'SQ':
                if debugging:
                    msg = "{0:08x}: Reading/parsing undefined length sequence"
                    logger_debug(msg.format(fp_tell()))
                seq = read_sequence(fp, is_implicit_VR,
                                    is_little_endian, length, encoding)
                if has_tag_set and tag not in tag_set:
                    continue
                yield DataElement(tag, VR, seq, value_tell,
                                  is_undefined_length=True)
            else:
                delimiter = SequenceDelimiterTag
                if debugging:
                    logger_debug("Reading undefined length data element")
                value = read_undefined_length_value(fp, is_little_endian,
                                                    delimiter, defer_size)

                # If the tag is (0008,0005) Specific Character Set,
                # then store it
                if tag == (0x08, 0x05):
                    from pydicom.values import convert_string
                    encoding = convert_string(value, is_little_endian)
                    # Store the encoding value in the generator for use
                    # with future elements (SQs)
                    encoding = convert_encodings(encoding)

                # tags with undefined length are skipped after read
                if has_tag_set and tag not in tag_set:
                    continue
                yield RawDataElement(tag, VR, length, value, value_tell,
                                     is_implicit_VR, is_little_endian)