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)
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)
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)
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)
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
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)
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)