Beispiel #1
0
 def test_lt_diff_class(self):
     """Test __lt__ of two classes with different type."""
     self.assertTrue(BaseTag(0x00000000) < 1)
     self.assertFalse(BaseTag(0x00000001) < 1)
     self.assertFalse(BaseTag(0x00000001) < 0)
Beispiel #2
0
 def test_le_tuple(self):
     """Test __le__ of tuple with BaseTag."""
     assert BaseTag(0x00010001) <= (0x0001, 0x0002)
     assert BaseTag(0x00010002) <= (0x0001, 0x0002)
     assert not BaseTag(0x00010002) <= (0x0001, 0x0001)
Beispiel #3
0
 def test_raise():
     BaseTag(0x00010002) <= 'Somethin'
Beispiel #4
0
 def test_hash(self):
     """Test hash of BaseTag class."""
     assert hash(BaseTag(0x00010001)) == hash(BaseTag(0x00010001))
     assert hash(BaseTag(0x00010001)) != hash(BaseTag(0x00010002))
     assert hash(BaseTag(0x00020001)) != hash(BaseTag(0x00010002))
Beispiel #5
0
 def test_group(self):
     """Test BaseTag.group returns correct values."""
     assert BaseTag(0x00000001).group == 0x0000
     assert BaseTag(0x00020001).group == 0x0002
     assert BaseTag(0xFFFF0001).group == 0xFFFF
Beispiel #6
0
 def test_ne_same_class(self):
     """Test __ne__ of two classes with same type."""
     assert not BaseTag(0x00000000) != BaseTag(0x00000000)
     assert BaseTag(0x00000001) != BaseTag(0x00000000)
Beispiel #7
0
 def test_ne_diff_class(self):
     """Test __ne__ of two classes with different type."""
     assert not BaseTag(0x00000000) != 0
     assert BaseTag(0x00000001) != 0
Beispiel #8
0
 def test_group(self):
     """Test BaseTag.group returns correct values."""
     assert 0x0000 == BaseTag(0x00000001).group
     assert 0x0002 == BaseTag(0x00020001).group
     assert 0xFFFF == BaseTag(0xFFFF0001).group
Beispiel #9
0
def read_dataset(fp,
                 is_implicit_VR,
                 is_little_endian,
                 bytelength=None,
                 stop_when=None,
                 defer_size=None,
                 parent_encoding=default_encoding,
                 specific_tags=None,
                 at_top_level=True):
    """Return a :class:`~pydicom.dataset.Dataset` instance containing the next
    dataset in the file.

    Parameters
    ----------
    fp : file-like
        An opened file-like object.
    is_implicit_VR : bool
        ``True`` if file transfer syntax is implicit VR.
    is_little_endian : bool
        ``True`` if file has little endian transfer syntax.
    bytelength : int, None, optional
        ``None`` to read until end of file or ItemDeliterTag, else a fixed
        number of bytes to read
    stop_when : None, optional
        Optional call_back function which can terminate reading. See help for
        :func:`data_element_generator` for details
    defer_size : int, None, optional
        Size to avoid loading large elements in memory. See :func:`dcmread` for
        more parameter info.
    parent_encoding :
        Optional encoding to use as a default in case (0008,0005) *Specific
        Character Set* isn't specified.
    specific_tags : list or None
        See :func:`dcmread` for parameter info.
    at_top_level: bool
        If dataset is top level (not within a sequence).
        Used to turn off explicit VR heuristic within sequences

    Returns
    -------
    dataset.Dataset
        A Dataset instance.

    See Also
    --------
    dataset.Dataset
        A collection (dictionary) of DICOM ``DataElement`` instances.
    """
    raw_data_elements = dict()
    fp_start = fp.tell()
    if at_top_level:
        is_implicit_VR = _is_implicit_vr(fp, is_implicit_VR, is_little_endian,
                                         stop_when)
    fp.seek(fp_start)
    de_gen = data_element_generator(fp, is_implicit_VR, is_little_endian,
                                    stop_when, defer_size, parent_encoding,
                                    specific_tags)
    try:
        while (bytelength is None) or (fp.tell() - fp_start < bytelength):
            raw_data_element = next(de_gen)
            # Read data elements. Stop on some errors, but return what was read
            tag = raw_data_element.tag
            # Check for ItemDelimiterTag --dataset is an item in a sequence
            if tag == BaseTag(0xFFFEE00D):
                break
            raw_data_elements[tag] = raw_data_element
    except StopIteration:
        pass
    except EOFError as details:
        if config.enforce_valid_values:
            raise
        msg = str(details) + " in file " + getattr(fp, "name", "<no filename>")
        warnings.warn(msg, UserWarning)
    except NotImplementedError as details:
        logger.error(details)

    ds = Dataset(raw_data_elements)
    if 0x00080005 in raw_data_elements:
        char_set = DataElement_from_raw(raw_data_elements[0x00080005])
        encoding = convert_encodings(char_set)
    else:
        encoding = parent_encoding
    ds.set_original_encoding(is_implicit_VR, is_little_endian, encoding)
    return ds
Beispiel #10
0
 def test_ne_diff_class(self):
     """Test __ne__ of two classes with different type."""
     # Make sure to test BaseTag.__ne__() not int.__ne__()
     assert not BaseTag(0x00000000) != 0
     assert BaseTag(0x00000001) != 0
Beispiel #11
0
 def test_ne_tuple(self):
     """Test __ne__ of tuple with BaseTag."""
     # Make sure to test BaseTag.__ne__() not tuple.__ne__()
     assert not BaseTag(0x00010002) != (0x0001, 0x0002)
     assert BaseTag(0x00010001) != (0x0001, 0x0002)
Beispiel #12
0
 def test_ge_diff_class(self):
     """Test __ge__ of two classes with different type."""
     self.assertFalse(BaseTag(0x00000000) >= 1)
     self.assertTrue(BaseTag(0x00000001) >= 1)
     self.assertTrue(BaseTag(0x00000001) >= 0)
Beispiel #13
0
 def test_ge_same_class(self):
     """Test __ge__ of two classes with same type."""
     self.assertFalse(BaseTag(0x00000000) >= BaseTag(0x00000001))
     self.assertTrue(BaseTag(0x00000001) >= BaseTag(0x00000001))
     self.assertTrue(BaseTag(0x00000001) >= BaseTag(0x00000000))
Beispiel #14
0
 def test_lt_tuple(self):
     """Test __lt__ of tuple with BaseTag."""
     self.assertTrue(BaseTag(0x00010001) < (0x0001, 0x0002))
     self.assertFalse(BaseTag(0x00010002) < (0x0001, 0x0002))
     self.assertFalse(BaseTag(0x00010002) < (0x0001, 0x0001))
Beispiel #15
0
 def test_eq_tuple(self):
     """Test __eq__ of tuple with BaseTag."""
     assert BaseTag(0x00010002) == (0x0001, 0x0002)
     assert not BaseTag(0x00010001) == (0x0001, 0x0002)
Beispiel #16
0
def read_dataset(fp,
                 is_implicit_VR,
                 is_little_endian,
                 bytelength=None,
                 stop_when=None,
                 defer_size=None,
                 parent_encoding=default_encoding,
                 specific_tags=None):
    """Return a Dataset instance containing the next dataset in the file.

    Parameters
    ----------
    fp : an opened file object
    is_implicit_VR : boolean
        True if file transfer syntax is implicit VR.
    is_little_endian : boolean
        True if file has little endian transfer syntax.
    bytelength : int, None, optional
        None to read until end of file or ItemDeliterTag, else
        a fixed number of bytes to read
    stop_when : None, optional
        optional call_back function which can terminate reading.
        See help for data_element_generator for details
    defer_size : int, None, optional
        Size to avoid loading large elements in memory.
        See ``dcmread`` for more parameter info.
    parent_encoding :
        optional encoding to use as a default in case
        a Specific Character Set (0008,0005) isn't specified
    specific_tags : list or None
        See ``dcmread`` for parameter info.

    Returns
    -------
    a Dataset instance

    See Also
    --------
    pydicom.dataset.Dataset
        A collection (dictionary) of Dicom `DataElement` instances.
    """
    raw_data_elements = dict()
    fp_start = fp.tell()
    is_implicit_VR = _is_implicit_vr(fp, is_implicit_VR, is_little_endian,
                                     stop_when)
    fp.seek(fp_start)
    de_gen = data_element_generator(fp, is_implicit_VR, is_little_endian,
                                    stop_when, defer_size, parent_encoding,
                                    specific_tags)
    try:
        while (bytelength is None) or (fp.tell() - fp_start < bytelength):
            raw_data_element = next(de_gen)
            # Read data elements. Stop on some errors, but return what was read
            tag = raw_data_element.tag
            # Check for ItemDelimiterTag --dataset is an item in a sequence
            if tag == BaseTag(0xFFFEE00D):
                break
            raw_data_elements[tag] = raw_data_element
    except StopIteration:
        pass
    except EOFError as details:
        # XXX is this error visible enough to user code with just logging?
        logger.error(
            str(details) + " in file " + getattr(fp, "name", "<no filename>"))
    except NotImplementedError as details:
        logger.error(details)

    ds = Dataset(raw_data_elements)
    if 0x00080005 in raw_data_elements:
        char_set = DataElement_from_raw(raw_data_elements[0x00080005])
        encoding = convert_encodings(char_set)
    else:
        encoding = parent_encoding
    ds.set_original_encoding(is_implicit_VR, is_little_endian, encoding)
    return ds
Beispiel #17
0
 def test_raise():
     BaseTag(0x00010002) == 'eraa'
Beispiel #18
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)
Beispiel #19
0
 def test_le_diff_class(self):
     """Test __le__ of two classes with different type."""
     assert BaseTag(0x00000000) <= 1
     assert BaseTag(0x00000001) <= 1
     assert not BaseTag(0x00000001) <= 0
Beispiel #20
0
 def test_raise():
     BaseTag(0x00010002) >= 'AGHIJJJJ'
Beispiel #21
0
 def test_raise():
     BaseTag(0x00010002) != 'aaag'
Beispiel #22
0
 def test_gt_diff_class(self):
     """Test __gt__ of two classes with different type."""
     assert not BaseTag(0x00000000) > 1
     assert not BaseTag(0x00000001) > 1
     assert BaseTag(0x00000001) > 0
Beispiel #23
0
 def test_str(self):
     """Test str(BaseTag) produces correct value."""
     assert str(BaseTag(0x00000000)) == '(0000, 0000)'
     assert str(BaseTag(0x00010002)) == '(0001, 0002)'
     assert str(BaseTag(0x10002000)) == '(1000, 2000)'
     assert str(BaseTag(0xFFFFFFFE)) == '(ffff, fffe)'
Beispiel #24
0
 def test_gt_tuple(self):
     """Test __gt__ of tuple with BaseTag."""
     assert not BaseTag(0x00010001) > (0x0001, 0x0002)
     assert not BaseTag(0x00010002) > (0x0001, 0x0002)
     assert BaseTag(0x00010002) > (0x0001, 0x0001)
Beispiel #25
0
 def test_element(self):
     """Test BaseTag.element returns correct values."""
     assert BaseTag(0x00010000).element == 0x0000
     assert BaseTag(0x00010002).element == 0x0002
     assert BaseTag(0x0001FFFF).element == 0xFFFF
Beispiel #26
0
 def test_raise():
     BaseTag(0x00010002) > 'BLUH'
Beispiel #27
0
 def test_tuple_tag(self):
     """Test quick tag construction with TupleTag."""
     assert TupleTag((0xFFFF, 0xFFee)) == BaseTag(0xFFFFFFEE)
Beispiel #28
0
 def test_eq_same_class(self):
     """Test __eq__ of two classes with same type."""
     assert BaseTag(0x00000000) == BaseTag(0x00000000)
     assert not BaseTag(0x00000001) == BaseTag(0x00000000)
Beispiel #29
0
 def test_lt_same_class(self):
     """Test __lt__ of two classes with same type."""
     assert BaseTag(0x00000000) < BaseTag(0x00000001)
     assert not BaseTag(0x00000001) < BaseTag(0x00000001)
     assert not BaseTag(0x00000001) < BaseTag(0x00000000)
Beispiel #30
0
 def test_tuple_tag(self):
     """Test quick tag construction with TupleTag."""
     self.assertEqual(TupleTag((0xFFFF, 0xFFee)), BaseTag(0xFFFFFFEE))