def unpack_data_from_file(file, fmt, offset=0): """Retrieve data from given file and unpack them according to specified format. file: The path name of the file or an opened file object fmt: Format specification offset: Offset from the start of the file from where to start the unpacking operation """ if isinstance(file, str): if not os.path.isfile(file): raise ValueError('"{}" is not a regular file'.format(file)) else: if not hasattr(file, 'read'): raise ValueError('Invalid file object') if hasattr(file, 'mode') and file.mode != 'rb': raise ValueError('Invalid opening mode') if not isinstance(offset, int) or offset < 0: raise ValueError('Invalid offset value') with fileutil.open_file(file, 'rb') as fp: file_len = fileutil.file_size(fp) pack_size = struct.calcsize(fmt) if file_len <= offset: return fp.seek(offset, os.SEEK_SET) if (file_len - offset) % pack_size == 0: if sys.version_info >= (3, 3): #return struct.iter_unpack(fmt, fp.read()) # Fix issue #1 yield from struct.iter_unpack(fmt, fp.read()) else: for unpacked_data in struct.iter_unpack(fmt, fp.read()): yield unpacked_data else: # The length of the file isn't the multiple of struct.calcsize(fmt), so # don't call struct.iter_unpack directly. data = fp.read(pack_size) while data: if len(data) == pack_size: yield struct.unpack(fmt, data) else: break data = fp.read(pack_size)
def _generate_waveform_sequence(self): if self._is_12_lead_ecg: maximum_waveform_sequences = 5 # PS3.3 A.34.3.4.3 Waveform Sequence maximum_waveform_samples = 16384 # PS3.3 A.34.3.4.5 Number of Waveform Samples else: maximum_waveform_sequences = 4 # PS3.3 A.34.4.4.2 Waveform Sequence maximum_waveform_samples = 2 ** 32 - 1 # NumberOfWaveformSamples's VR is `UL`. data_file_len = fileutil.file_size(self._file) pack_size = struct.calcsize(self._format) data_file_total_samples = data_file_len // pack_size saved_samples = maximum_waveform_sequences * maximum_waveform_samples if data_file_total_samples > saved_samples: warn_msg = ( 'File "{}" is too big. File size: {}, pack size: {}, format string: {}, ' "total samples: {}, saved samples: {}, saved size: {}.".format( fileutil.file_name(self._file), data_file_len, pack_size, self._format, data_file_total_samples, saved_samples, saved_samples * pack_size, ) ) if not _frozen: # Fix issue #7 warnings.warn(warn_msg) logger.warn(warn_msg) data_file_total_samples = saved_samples waveform_seq = dicom.sequence.Sequence() data_unpacker = unpacker.unpack_data_from_file(self._file, self._format) target_fmt = "<{}".format("h" * self._channels) adjusted_data = map(lambda v: map(self._adjust_callback, v), data_unpacker) while data_file_total_samples > 0: seq_item = dicom.dataset.Dataset() seq_item.WaveformOriginality = "ORIGINAL" # Type 1 seq_item.NumberOfWaveformChannels = self._channels # Type 1. if self._is_12_lead_ecg: assert 1 <= seq_item.NumberOfWaveformChannels <= 13 # PS3.3 A.34.3.4.4 else: assert 1 <= seq_item.NumberOfWaveformChannels <= 24 # PS3.3 A.34.4.4.3 Number of Waveform Channels if data_file_total_samples >= maximum_waveform_samples: seq_item.NumberOfWaveformSamples = maximum_waveform_samples # Type 1. UL. else: seq_item.NumberOfWaveformSamples = data_file_total_samples # Type 1. UL. data_file_total_samples -= seq_item.NumberOfWaveformSamples assert 200 <= self._sampling_frequency <= 1000 # DICOM PS3.3-2015a A.34.3.4.6 seq_item.SamplingFrequency = "{:d}".format(self._sampling_frequency) # Type 1. DS. seq_item.ChannelDefinitionSequence = self._generate_channel_definition_sequence() # Type 1. seq_item.WaveformBitsAllocated = ( 16 ) # Type 1. PS3.3 C.10.9.1.5 Waveform Bits Allocated and Waveform Sample Interpretation seq_item.WaveformSampleInterpretation = "SS" # Type 1. PS3.3 A.34.3.4.8 Waveform Sample Interpretation # The VR of `Waveform Padding Value` may be OB or OW, so: # seq_item.WaveformPaddingValue = b'\x00\x00' # will not work, instead: seq_item.add_new((0x5400, 0x100A), "OW", b"\x00\x80") # Type 1C. OB or OW. data = bytearray() for i, d in zip(range(seq_item.NumberOfWaveformSamples), adjusted_data): data.extend(struct.pack(target_fmt, *d)) seq_item.add_new((0x5400, 0x1010), "OW", bytes(data)) # WaveformData. Type 1. OB or OW. waveform_seq.append(seq_item) return waveform_seq
def _generate_waveform_sequence(self): if self._is_12_lead_ecg: maximum_waveform_sequences = 5 # PS3.3 A.34.3.4.3 Waveform Sequence maximum_waveform_samples = 16384 # PS3.3 A.34.3.4.5 Number of Waveform Samples else: maximum_waveform_sequences = 4 # PS3.3 A.34.4.4.2 Waveform Sequence maximum_waveform_samples = 2**32 - 1 # NumberOfWaveformSamples's VR is `UL`. data_file_len = fileutil.file_size(self._file) pack_size = struct.calcsize(self._format) data_file_total_samples = data_file_len // pack_size saved_samples = maximum_waveform_sequences * maximum_waveform_samples if data_file_total_samples > saved_samples: warn_msg = 'File "{}" is too big. File size: {}, pack size: {}, format string: {}, ' \ 'total samples: {}, saved samples: {}, saved size: {}.'.format( fileutil.file_name(self._file), data_file_len, pack_size, self._format, data_file_total_samples, saved_samples, saved_samples * pack_size) if not _frozen: # Fix issue #7 warnings.warn(warn_msg) logger.warn(warn_msg) data_file_total_samples = saved_samples waveform_seq = dicom.sequence.Sequence() data_unpacker = unpacker.unpack_data_from_file(self._file, self._format) target_fmt = '<{}'.format('h' * self._channels) adjusted_data = map(lambda v: map(self._adjust_callback, v), data_unpacker) while data_file_total_samples > 0: seq_item = dicom.dataset.Dataset() seq_item.WaveformOriginality = 'ORIGINAL' # Type 1 seq_item.NumberOfWaveformChannels = self._channels # Type 1. if self._is_12_lead_ecg: assert 1 <= seq_item.NumberOfWaveformChannels <= 13 # PS3.3 A.34.3.4.4 else: assert 1 <= seq_item.NumberOfWaveformChannels <= 24 # PS3.3 A.34.4.4.3 Number of Waveform Channels if data_file_total_samples >= maximum_waveform_samples: seq_item.NumberOfWaveformSamples = maximum_waveform_samples # Type 1. UL. else: seq_item.NumberOfWaveformSamples = data_file_total_samples # Type 1. UL. data_file_total_samples -= seq_item.NumberOfWaveformSamples assert 200 <= self._sampling_frequency <= 1000 # DICOM PS3.3-2015a A.34.3.4.6 seq_item.SamplingFrequency = '{:d}'.format( self._sampling_frequency) # Type 1. DS. seq_item.ChannelDefinitionSequence = self._generate_channel_definition_sequence( ) # Type 1. seq_item.WaveformBitsAllocated = 16 # Type 1. PS3.3 C.10.9.1.5 Waveform Bits Allocated and Waveform Sample Interpretation seq_item.WaveformSampleInterpretation = 'SS' # Type 1. PS3.3 A.34.3.4.8 Waveform Sample Interpretation # The VR of `Waveform Padding Value` may be OB or OW, so: #seq_item.WaveformPaddingValue = b'\x00\x00' # will not work, instead: seq_item.add_new((0x5400, 0x100A), 'OW', b'\x00\x80') # Type 1C. OB or OW. data = bytearray() for i, d in zip(range(seq_item.NumberOfWaveformSamples), adjusted_data): data.extend(struct.pack(target_fmt, *d)) seq_item.add_new((0x5400, 0x1010), 'OW', bytes(data)) # WaveformData. Type 1. OB or OW. waveform_seq.append(seq_item) return waveform_seq
def _generate_waveform_sequence(self): if self._is_12_lead_ecg: maximum_waveform_sequences = 5 # PS3.3 A.34.3.4.3 Waveform Sequence maximum_waveform_samples = 16384 # PS3.3 A.34.3.4.5 Number of Waveform Samples else: maximum_waveform_sequences = 4 # PS3.3 A.34.4.4.2 Waveform Sequence maximum_waveform_samples = 2 ** 32 - 1 # NumberOfWaveformSamples's VR is `UL`. data_file_len = fileutil.file_size(self._file) pack_size = struct.calcsize(self._format) data_file_total_samples = data_file_len // pack_size saved_samples = maximum_waveform_sequences * maximum_waveform_samples if data_file_total_samples > saved_samples: data_file_total_samples = saved_samples self._channel_labels = list(self._channel_labels) channel_cnt = len(self._channel_labels) waveform_seq = dicom.sequence.Sequence() data_unpacker = unpacker.unpack_data_from_file(self._file, self._format) target_fmt = '<{}'.format('h' * channel_cnt) if self._adjust_callback and hasattr(self._adjust_callback, '__call__'): adjusted_data = map(lambda v: map(self._adjust_callback, v), data_unpacker) else: adjusted_data = data_unpacker if self._is_12_lead_ecg: assert 1 <= channel_cnt <= 13 # PS3.3 A.34.3.4.4 else: assert 1 <= channel_cnt <= 24 # PS3.3 A.34.4.4.3 Number of Waveform Channels assert 200 <= self._sampling_frequency <= 1000 # DICOM PS3.3-2015a A.34.3.4.6 while data_file_total_samples > 0: seq_item = dicom.dataset.Dataset() seq_item.WaveformOriginality = 'ORIGINAL' # Type 1 seq_item.NumberOfWaveformChannels = channel_cnt # Type 1. if data_file_total_samples >= maximum_waveform_samples: seq_item.NumberOfWaveformSamples = maximum_waveform_samples # Type 1. UL. else: seq_item.NumberOfWaveformSamples = data_file_total_samples # Type 1. UL. data_file_total_samples -= seq_item.NumberOfWaveformSamples seq_item.SamplingFrequency = '{:d}'.format(self._sampling_frequency) # Type 1. DS. seq_item.ChannelDefinitionSequence = self._generate_channel_definition_sequence() # Type 1. seq_item.WaveformBitsAllocated = 16 # Type 1. PS3.3 C.10.9.1.5 Waveform Bits Allocated and Waveform Sample Interpretation seq_item.WaveformSampleInterpretation = 'SS' # Type 1. PS3.3 A.34.3.4.8 Waveform Sample Interpretation # The VR of `Waveform Padding Value` may be OB or OW, so: #seq_item.WaveformPaddingValue = b'\x00\x00' # will not work, instead: seq_item.add_new((0x5400, 0x100A), 'OW', b'\x00\x80') # Type 1C. OB or OW. data = bytearray() for i, d in zip(range(seq_item.NumberOfWaveformSamples), adjusted_data): data.extend(struct.pack(target_fmt, *d)) seq_item.add_new((0x5400, 0x1010), 'OW', bytes(data)) # WaveformData. Type 1. OB or OW. waveform_seq.append(seq_item) return waveform_seq