Esempio n. 1
0
 def test_invalid_sop_file_meta(self):
     """Test exception raised if SOP Class is not Media Storage Directory"""
     ds = dcmread(get_testdata_file('CT_small.dcm'))
     with pytest.raises(InvalidDicomError,
                        match=r"SOP Class is not Media Storage "
                        r"Directory \(DICOMDIR\)"):
         DicomDir("some_name", ds, b'\x00' * 128, ds.file_meta, True, True)
Esempio n. 2
0
 def test_invalid_sop_no_file_meta(self):
     """Test exception raised if invalid sop class but no file_meta"""
     ds = dcmread(get_testdata_file('CT_small.dcm'))
     with pytest.raises(AttributeError,
                        match="'DicomDir' object has no attribute "
                        "'DirectoryRecordSequence'"):
         DicomDir("some_name", ds, b'\x00' * 128, None, True, True)
Esempio n. 3
0
 def test_invalid_sop_no_file_meta(self, allow_reading_invalid_values):
     """Test exception raised if invalid sop class but no file_meta"""
     ds = dcmread(get_testdata_file('CT_small.dcm'))
     with pytest.raises(AttributeError,
                        match="'DicomDir' object has no attribute "
                        "'DirectoryRecordSequence'"):
         with pytest.warns(UserWarning, match=r"Invalid transfer syntax"):
             DicomDir("some_name", ds, b'\x00' * 128, None, True, True)
Esempio n. 4
0
def read_partial(fileobj, stop_when=None, defer_size=None, force=False):
    """Parse a DICOM file until a condition is met.

    Parameters
    ----------
    fileobj : a file-like object
        Note that the file will not close when the function returns.
    stop_when :
        Stop condition. See ``read_dataset`` for more info.
    defer_size : int, str, None, optional
        See ``read_file`` for parameter info.
    force : boolean
        See ``read_file`` for parameter info.

    Notes
    -----
    Use ``read_file`` unless you need to stop on some condition other than
    reaching pixel data.

    Returns
    -------
    FileDataset instance or DicomDir instance.

    See Also
    --------
    read_file
        More generic file reading function.
    """
    # Read File Meta Information

    # Read preamble (if present)
    preamble = read_preamble(fileobj, force)
    # Read any File Meta Information group (0002,eeee) elements (if present)
    file_meta_dataset = _read_file_meta_info(fileobj)

    # Read Dataset

    # Read any Command Set group (0000,eeee) elements (if present)
    command_set = _read_command_set_elements(fileobj)

    # Check to see if there's anything left to read
    peek = fileobj.read(1)
    fileobj.seek(-1, 1)

    # `filobj` should be positioned at the start of the dataset by this point.
    # Ensure we have appropriate values for `is_implicit_VR` and
    # `is_little_endian` before we try decoding. We assume an initial
    # transfer syntax of implicit VR little endian and correct it as necessary
    is_implicit_VR = True
    is_little_endian = True
    transfer_syntax = file_meta_dataset.get("TransferSyntaxUID")
    if peek == b'':  # EOF
        pass
    elif transfer_syntax is None:  # issue 258
        # If no TransferSyntaxUID element then we have to try and figure out
        #   the correct values for `is_little_endian` and `is_implicit_VR`.
        # Peek at the first 6 bytes to get the first element's tag group and
        #   (possibly) VR
        group, _, VR = unpack("<HH2s", fileobj.read(6))
        fileobj.seek(-6, 1)

        # Test the VR to see if it's valid, and if so then assume explicit VR
        from pydicom.values import converters
        if not in_py2:
            VR = VR.decode(default_encoding)
        if VR in converters.keys():
            is_implicit_VR = False
            # Big endian encoding can only be explicit VR
            #   Big endian 0x0004 decoded as little endian will be 1024
            #   Big endian 0x0100 decoded as little endian will be 1
            # Therefore works for big endian tag groups up to 0x00FF after
            #   which it will fail, in which case we leave it as little endian
            #   and hope for the best (big endian is retired anyway)
            if group >= 1024:
                is_little_endian = False
    elif transfer_syntax == pydicom.uid.ImplicitVRLittleEndian:
        pass
    elif transfer_syntax == pydicom.uid.ExplicitVRLittleEndian:
        is_implicit_VR = False
    elif transfer_syntax == pydicom.uid.ExplicitVRBigEndian:
        is_implicit_VR = False
        is_little_endian = False
    elif transfer_syntax == pydicom.uid.DeflatedExplicitVRLittleEndian:
        # See PS3.6-2008 A.5 (p 71)
        # when written, the entire dataset following
        #     the file metadata was prepared the normal way,
        #     then "deflate" compression applied.
        #  All that is needed here is to decompress and then
        #     use as normal in a file-like object
        zipped = fileobj.read()
        # -MAX_WBITS part is from comp.lang.python answer:
        # groups.google.com/group/comp.lang.python/msg/e95b3b38a71e6799
        unzipped = zlib.decompress(zipped, -zlib.MAX_WBITS)
        fileobj = BytesIO(unzipped)  # a file-like object
        is_implicit_VR = False
    else:
        # Any other syntax should be Explicit VR Little Endian,
        #   e.g. all Encapsulated (JPEG etc) are ExplVR-LE
        #        by Standard PS 3.5-2008 A.4 (p63)
        is_implicit_VR = False

    # Try and decode the dataset
    #   By this point we should be at the start of the dataset and have
    #   the transfer syntax (whether read from the file meta or guessed at)
    try:
        dataset = read_dataset(fileobj,
                               is_implicit_VR,
                               is_little_endian,
                               stop_when=stop_when,
                               defer_size=defer_size)
    except EOFError:
        pass  # error already logged in read_dataset

    # Add the command set elements to the dataset (if any)
    dataset.update(command_set)

    class_uid = file_meta_dataset.get("MediaStorageSOPClassUID", None)
    if class_uid and class_uid == "Media Storage Directory Storage":
        return DicomDir(fileobj, dataset, preamble, file_meta_dataset,
                        is_implicit_VR, is_little_endian)
    else:
        return FileDataset(fileobj, dataset, preamble, file_meta_dataset,
                           is_implicit_VR, is_little_endian)
Esempio n. 5
0
def read_partial(
    fileobj: BinaryIO,
    stop_when: Optional[Callable[[BaseTag, Optional[str], int], bool]] = None,
    defer_size: Optional[Union[int, str, float]] = None,
    force: bool = False,
    specific_tags: Optional[List[BaseTag]] = None
) -> Union[FileDataset, DicomDir]:
    """Parse a DICOM file until a condition is met.

    Parameters
    ----------
    fileobj : a file-like object
        Note that the file will not close when the function returns.
    stop_when :
        Stop condition. See :func:`read_dataset` for more info.
    defer_size : int, str or float, optional
        See :func:`dcmread` for parameter info.
    force : bool
        See :func:`dcmread` for parameter info.
    specific_tags : list or None
        See :func:`dcmread` for parameter info.

    Notes
    -----
    Use :func:`dcmread` unless you need to stop on some condition other than
    reaching pixel data.

    Returns
    -------
    dataset.FileDataset or dicomdir.DicomDir
        The read dataset.

    See Also
    --------
    dcmread
        More generic file reading function.
    """
    # Read File Meta Information

    # Read preamble (if present)
    preamble = read_preamble(fileobj, force)
    # Read any File Meta Information group (0002,eeee) elements (if present)
    file_meta_dataset = _read_file_meta_info(fileobj)

    # Read Dataset

    # Read any Command Set group (0000,eeee) elements (if present)
    command_set = _read_command_set_elements(fileobj)

    # Check to see if there's anything left to read
    peek = fileobj.read(1)
    if peek != b'':
        fileobj.seek(-1, 1)

    # `filobj` should be positioned at the start of the dataset by this point.
    # Ensure we have appropriate values for `is_implicit_VR` and
    # `is_little_endian` before we try decoding. We assume an initial
    # transfer syntax of implicit VR little endian and correct it as necessary
    is_implicit_VR = True
    is_little_endian = True
    transfer_syntax = file_meta_dataset.get("TransferSyntaxUID")
    if peek == b'':  # EOF
        pass
    elif transfer_syntax is None:  # issue 258
        # If no TransferSyntaxUID element then we have to try and figure out
        #   the correct values for `is_little_endian` and `is_implicit_VR`.
        # Peek at the first 6 bytes to get the first element's tag group and
        #   (possibly) VR
        group, _, VR = unpack("<HH2s", fileobj.read(6))
        fileobj.seek(-6, 1)

        # Test the VR to see if it's valid, and if so then assume explicit VR
        from pydicom.values import converters
        VR = VR.decode(default_encoding)
        if VR in converters.keys():
            is_implicit_VR = False
            # Big endian encoding can only be explicit VR
            #   Big endian 0x0004 decoded as little endian will be 1024
            #   Big endian 0x0100 decoded as little endian will be 1
            # Therefore works for big endian tag groups up to 0x00FF after
            #   which it will fail, in which case we leave it as little endian
            #   and hope for the best (big endian is retired anyway)
            if group >= 1024:
                is_little_endian = False
    elif transfer_syntax == pydicom.uid.ImplicitVRLittleEndian:
        pass
    elif transfer_syntax == pydicom.uid.ExplicitVRLittleEndian:
        is_implicit_VR = False
    elif transfer_syntax == pydicom.uid.ExplicitVRBigEndian:
        is_implicit_VR = False
        is_little_endian = False
    elif transfer_syntax == pydicom.uid.DeflatedExplicitVRLittleEndian:
        # See PS3.5 section A.5
        # when written, the entire dataset following
        #     the file metadata was prepared the normal way,
        #     then "deflate" compression applied.
        #  All that is needed here is to decompress and then
        #     use as normal in a file-like object
        zipped = fileobj.read()
        # -MAX_WBITS part is from comp.lang.python answer:
        # groups.google.com/group/comp.lang.python/msg/e95b3b38a71e6799
        unzipped = zlib.decompress(zipped, -zlib.MAX_WBITS)
        fileobj = BytesIO(unzipped)  # a file-like object
        is_implicit_VR = False
    else:
        # Any other syntax should be Explicit VR Little Endian,
        #   e.g. all Encapsulated (JPEG etc) are ExplVR-LE
        #        by Standard PS 3.5-2008 A.4 (p63)
        is_implicit_VR = False

    # Try and decode the dataset
    #   By this point we should be at the start of the dataset and have
    #   the transfer syntax (whether read from the file meta or guessed at)
    try:
        dataset = read_dataset(
            fileobj,
            is_implicit_VR,
            is_little_endian,
            stop_when=stop_when,
            defer_size=defer_size,
            specific_tags=specific_tags,
        )
    except EOFError:
        if config.enforce_valid_values:
            raise
        # warning already logged in read_dataset

    # Add the command set elements to the dataset (if any)
    dataset.update(command_set)

    class_uid = cast(
        pydicom.uid.UID, file_meta_dataset.get("MediaStorageSOPClassUID", None)
    )
    ds: Union[DicomDir, FileDataset]
    if class_uid and class_uid.name == "Media Storage Directory Storage":
        warnings.warn(
            "The 'DicomDir' class is deprecated and will be removed in v3.0, "
            "after which 'dcmread()' will return a normal 'FileDataset' "
            "instance for 'Media Storage Directory' SOP Instances.",
            DeprecationWarning
        )
        ds = DicomDir(
            fileobj,
            dataset,
            preamble,
            file_meta_dataset,
            is_implicit_VR,
            is_little_endian,
        )
    else:
        ds = FileDataset(
            fileobj,
            dataset,
            preamble,
            file_meta_dataset,
            is_implicit_VR,
            is_little_endian,
        )
    # save the originally read transfer syntax properties in the dataset
    ds.set_original_encoding(
        is_implicit_VR, is_little_endian, dataset._character_set
    )
    return ds
Esempio n. 6
0
def read_partial(fileobj, stop_when=None, defer_size=None, force=False):
    """Parse a DICOM file until a condition is met.

    Parameters
    ----------
    fileobj : a file-like object
        Note that the file will not close when the function returns.
    stop_when :
        Stop condition. See ``read_dataset`` for more info.
    defer_size : int, str, None, optional
        See ``read_file`` for parameter info.
    force : boolean
        See ``read_file`` for parameter info.

    Notes
    -----
    Use ``read_file`` unless you need to stop on some condition
    other than reaching pixel data.

    Returns
    -------
    FileDataset instance or DicomDir instance.

    See Also
    --------
    read_file
        More generic file reading function.
    """
    # Read preamble -- raise an exception if missing and force=False
    preamble = read_preamble(fileobj, force)
    file_meta_dataset = Dataset()
    # Assume a transfer syntax, correct it as necessary
    is_implicit_VR = True
    is_little_endian = True
    if preamble:
        file_meta_dataset = _read_file_meta_info(fileobj)
        transfer_syntax = file_meta_dataset.TransferSyntaxUID
        if transfer_syntax == pydicom.uid.ImplicitVRLittleEndian:
            pass
        elif transfer_syntax == pydicom.uid.ExplicitVRLittleEndian:
            is_implicit_VR = False
        elif transfer_syntax == pydicom.uid.ExplicitVRBigEndian:
            is_implicit_VR = False
            is_little_endian = False
        elif transfer_syntax == pydicom.uid.DeflatedExplicitVRLittleEndian:
            # See PS3.6-2008 A.5 (p 71)
            # when written, the entire dataset following
            #     the file metadata was prepared the normal way,
            #     then "deflate" compression applied.
            #  All that is needed here is to decompress and then
            #     use as normal in a file-like object
            zipped = fileobj.read()
            # -MAX_WBITS part is from comp.lang.python answer:
            # groups.google.com/group/comp.lang.python/msg/e95b3b38a71e6799
            unzipped = zlib.decompress(zipped, -zlib.MAX_WBITS)
            fileobj = BytesIO(unzipped)  # a file-like object
            is_implicit_VR = False
        else:
            # Any other syntax should be Explicit VR Little Endian,
            #   e.g. all Encapsulated (JPEG etc) are ExplVR-LE
            #        by Standard PS 3.5-2008 A.4 (p63)
            is_implicit_VR = False
    else:  # no header -- use the is_little_endian, implicit assumptions
        file_meta_dataset.TransferSyntaxUID = pydicom.uid.ImplicitVRLittleEndian
        endian_chr = "<"
        element_struct = Struct(endian_chr + "HH2sH")
        # Try reading first 8 bytes
        group, elem, VR, length = element_struct.unpack(fileobj.read(8))
        # Rewind file object
        fileobj.seek(0)
        # If the VR is a valid VR, assume Explicit VR transfer systax
        from pydicom.values import converters
        if not in_py2:
            VR = VR.decode(default_encoding)
        if VR in converters.keys():
            is_implicit_VR = False
            # Determine if group in low numbered range (Little vs Big Endian)
            if group == 0:  # got (0,0) group length. Not helpful.
                # XX could use similar to http://www.dclunie.com/medical-image-faq/html/part2.html code example
                msg = ("Not able to guess transfer syntax when first item "
                       "is group length")
                raise NotImplementedError(msg)
            if group < 2000:
                file_meta_dataset.TransferSyntaxUID = pydicom.uid.ExplicitVRLittleEndian
            else:
                file_meta_dataset.TransferSyntaxUID = pydicom.uid.ExplicitVRBigEndian
                is_little_endian = False

    try:
        dataset = read_dataset(fileobj,
                               is_implicit_VR,
                               is_little_endian,
                               stop_when=stop_when,
                               defer_size=defer_size)
    except EOFError:
        pass  # error already logged in read_dataset

    class_uid = file_meta_dataset.get("MediaStorageSOPClassUID", None)
    if class_uid and class_uid == "Media Storage Directory Storage":
        return DicomDir(fileobj, dataset, preamble, file_meta_dataset,
                        is_implicit_VR, is_little_endian)
    else:
        return FileDataset(fileobj, dataset, preamble, file_meta_dataset,
                           is_implicit_VR, is_little_endian)
Esempio n. 7
0
def read_partial(fileobj, stop_when=None, defer_size=None, force=False):
    """Parse a DICOM file until a condition is met.

    Parameters
    ----------
    fileobj : a file-like object
        Note that the file will not close when the function returns.
    stop_when :
        Stop condition. See ``read_dataset`` for more info.
    defer_size : int, str, None, optional
        See ``read_file`` for parameter info.
    force : boolean
        See ``read_file`` for parameter info.

    Notes
    -----
    Use ``read_file`` unless you need to stop on some condition
    other than reaching pixel data.

    Returns
    -------
    FileDataset instance or DicomDir instance.

    See Also
    --------
    read_file
        More generic file reading function.
    """
    # Read preamble -- raise an exception if missing and force=False
    preamble = read_preamble(fileobj, force)
    file_meta_dataset = Dataset()
    # Assume a transfer syntax, correct it as necessary
    is_implicit_VR = True
    is_little_endian = True
    if preamble:
        file_meta_dataset = _read_file_meta_info(fileobj)
        transfer_syntax = file_meta_dataset.TransferSyntaxUID
        if transfer_syntax == pydicom.uid.ImplicitVRLittleEndian:
            pass
        elif transfer_syntax == pydicom.uid.ExplicitVRLittleEndian:
            is_implicit_VR = False
        elif transfer_syntax == pydicom.uid.ExplicitVRBigEndian:
            is_implicit_VR = False
            is_little_endian = False
        elif transfer_syntax == pydicom.uid.DeflatedExplicitVRLittleEndian:
            # See PS3.6-2008 A.5 (p 71)
            # when written, the entire dataset following
            #     the file metadata was prepared the normal way,
            #     then "deflate" compression applied.
            #  All that is needed here is to decompress and then
            #     use as normal in a file-like object
            zipped = fileobj.read()
            # -MAX_WBITS part is from comp.lang.python answer:
            # groups.google.com/group/comp.lang.python/msg/e95b3b38a71e6799
            unzipped = zlib.decompress(zipped, -zlib.MAX_WBITS)
            fileobj = BytesIO(unzipped)  # a file-like object
            is_implicit_VR = False
        else:
            # Any other syntax should be Explicit VR Little Endian,
            #   e.g. all Encapsulated (JPEG etc) are ExplVR-LE
            #        by Standard PS 3.5-2008 A.4 (p63)
            is_implicit_VR = False
    else:  # no header -- use the is_little_endian, implicit assumptions
        file_meta_dataset.TransferSyntaxUID = pydicom.uid.ImplicitVRLittleEndian

    try:
        dataset = read_dataset(fileobj, is_implicit_VR, is_little_endian,
                               stop_when=stop_when, defer_size=defer_size)
    except EOFError:
        pass  # error already logged in read_dataset

    class_uid = file_meta_dataset.get("MediaStorageSOPClassUID", None)
    if class_uid and class_uid == "Media Storage Directory Storage":
        return DicomDir(fileobj, dataset, preamble, file_meta_dataset,
                        is_implicit_VR, is_little_endian)
    else:
        return FileDataset(fileobj, dataset, preamble, file_meta_dataset,
                           is_implicit_VR, is_little_endian)