def convert_ATvalue(byte_string, is_little_endian, struct_format=None): """Read and return AT (tag) data_element value(s)""" length = len(byte_string) if length == 4: return convert_tag(byte_string, is_little_endian) # length > 4 if length % 4 != 0: logger.warn("Expected length to be multiple of 4 for VR 'AT', " "got length %d", length) return MultiValue(Tag, [convert_tag(byte_string, is_little_endian, offset=x) for x in range(0, length, 4)])
def convert_numbers(byte_string, is_little_endian, struct_format): """Convert `byte_string` to a value, depending on `struct_format`. Given an encoded DICOM Element value, use `struct_format` and the endianness of the data to decode it. Parameters ---------- byte_string : bytes The raw byte data to decode. is_little_endian : bool The encoding of `byte_string`. struct_format : str The type of data encoded in `byte_string`. Returns ------- str If there is no encoded data in `byte_string` then an empty string will be returned. value If `byte_string` encodes a single value then it will be returned. list If `byte_string` encodes multiple values then a list of the decoded values will be returned. """ endianChar = '><' [is_little_endian] # "=" means use 'standard' size, needed on 64-bit systems. bytes_per_value = calcsize("=" + struct_format) length = len(byte_string) if length % bytes_per_value != 0: logger.warn("Expected length to be even multiple of number size") format_string = "%c%u%c" % (endianChar, length // bytes_per_value, struct_format) value = unpack(format_string, byte_string) # if the number is empty, then return the empty # string rather than empty list if len(value) == 0: return '' elif len(value) == 1: return value[0] else: # convert from tuple to a list so can modify if need to return list(value)
def read_delimiter_item(fp, delimiter): """Read and ignore an expected delimiter. If the delimiter is not found or correctly formed, a warning is logged. """ found = fp.read(4) if found != delimiter: logger.warn("Expected delimitor %s, got %s at file position 0x%x", Tag(delimiter), Tag(found), fp.tell() - 4) length = fp.read_UL() if length != 0: logger.warn("Expected delimiter item to have length 0, got %d at file position 0x%x", length, fp.tell() - 4)
def convert_DA_string(byte_string, is_little_endian, struct_format=None): """Read and return a DA value""" if datetime_conversion: if not in_py2: byte_string = byte_string.decode(encoding) length = len(byte_string) if length != 8: logger.warn("Expected length to be 8, got length %d", length) return DA(byte_string) else: return convert_string(byte_string, is_little_endian, struct_format)
def convert_DT_string(byte_string, is_little_endian, struct_format=None): """Read and return a DT value""" if datetime_conversion: if not in_py2: byte_string = byte_string.decode(encoding) length = len(byte_string) if length < 14 or length > 26: logger.warn("Expected length between 14 and 26, got length %d", length) return DT(byte_string) else: return convert_string(byte_string, is_little_endian, struct_format)
def convert_numbers(byte_string, is_little_endian, struct_format): """Read a "value" of type struct_format from the dicom file. "Value" can be more than one number""" endianChar = '><'[is_little_endian] bytes_per_value = calcsize("=" + struct_format) # "=" means use 'standard' size, needed on 64-bit systems. length = len(byte_string) if length % bytes_per_value != 0: logger.warn("Expected length to be even multiple of number size") format_string = "%c%u%c" % (endianChar, length // bytes_per_value, struct_format) value = unpack(format_string, byte_string) if len(value) == 1: return value[0] else: return list(value) # convert from tuple to a list so can modify if need to
def read_delimiter_item(fp, delimiter): """Read and ignore an expected delimiter. If the delimiter is not found or correctly formed, a warning is logged. """ found = fp.read(4) if found != delimiter: logger.warn("Expected delimitor %s, got %s at file position 0x%x", Tag(delimiter), Tag(found), fp.tell() - 4) length = fp.read_UL() if length != 0: logger.warn( "Expected delimiter item to have length 0, " "got %d at file position 0x%x", length, fp.tell() - 4)
def convert_numbers(byte_string, is_little_endian, struct_format): """Read a "value" of type struct_format from the dicom file. "Value" can be more than one number""" endianChar = '><'[is_little_endian] bytes_per_value = calcsize( "=" + struct_format ) # "=" means use 'standard' size, needed on 64-bit systems. length = len(byte_string) if length % bytes_per_value != 0: logger.warn("Expected length to be even multiple of number size") format_string = "%c%u%c" % (endianChar, length // bytes_per_value, struct_format) value = unpack(format_string, byte_string) if len(value) == 1: return value[0] else: return list( value) # convert from tuple to a list so can modify if need to
def convert_numbers(byte_string, is_little_endian, struct_format): """Convert `byte_string` to a value, depending on `struct_format`. Given an encoded DICOM Element value, use `struct_format` and the endianness of the data to decode it. Parameters ---------- byte_string : bytes The raw byte data to decode. is_little_endian : bool The encoding of `byte_string`. struct_format : str The type of data encoded in `byte_string`. Returns ------- str If there is no encoded data in `byte_string` then an empty string will be returned. value If `byte_string` encodes a single value then it will be returned. list If `byte_string` encodes multiple values then a list of the decoded values will be returned. """ endianChar = '><'[is_little_endian] bytes_per_value = calcsize( "=" + struct_format ) # "=" means use 'standard' size, needed on 64-bit systems. length = len(byte_string) if length % bytes_per_value != 0: logger.warn("Expected length to be even multiple of number size") format_string = "%c%u%c" % (endianChar, length // bytes_per_value, struct_format) value = unpack(format_string, byte_string) if len( value ) == 0: # if the number is empty, then return the empty string rather than empty list return '' elif len(value) == 1: return value[0] else: return list( value) # convert from tuple to a list so can modify if need to
def absorb_delimiter_item(fp, is_little_endian, delimiter): """Read (and ignore) undefined length sequence or item terminators.""" if is_little_endian: struct_format = "<HHL" else: struct_format = ">HHL" group, elem, length = unpack(struct_format, fp.read(8)) tag = TupleTag((group, elem)) if tag != delimiter: msg = "Did not find expected delimiter '%s'" % dictionary_description(delimiter) msg += ", instead found %s at file position 0x%x" % (str(tag), fp.tell() - 8) logger.warn(msg) fp.seek(fp.tell() - 8) return logger.debug("%04x: Found Delimiter '%s'", fp.tell() - 8, dictionary_description(delimiter)) if length == 0: logger.debug("%04x: Read 0 bytes after delimiter", fp.tell() - 4) else: logger.debug("%04x: Expected 0x00000000 after delimiter, found 0x%x", fp.tell() - 4, length)
def convert_ATvalue( byte_string: bytes, is_little_endian: bool, struct_format: Optional[str] = None ) -> Union[BaseTag, MutableSequence[BaseTag]]: """Return a decoded 'AT' value. Parameters ---------- byte_string : bytes The encoded 'AT' element value. is_little_endian : bool ``True`` if the value is encoded as little endian, ``False`` otherwise. struct_format : str, optional Not used. Returns ------- BaseTag or MultiValue of BaseTag The decoded value(s). """ length = len(byte_string) if length == 4: return convert_tag(byte_string, is_little_endian) # length > 4 if length % 4 != 0: logger.warn( "Expected length to be multiple of 4 for VR 'AT', " f"got length {length}" ) return MultiValue( Tag, [ convert_tag(byte_string, is_little_endian, offset=x) for x in range(0, length, 4) ] )
def absorb_delimiter_item(fp: BinaryIO, is_little_endian: bool, delimiter: BaseTag) -> None: """Read (and ignore) undefined length sequence or item terminators.""" if is_little_endian: struct_format = "<HHL" else: struct_format = ">HHL" group, elem, length = unpack(struct_format, fp.read(8)) tag = TupleTag((group, elem)) if tag != delimiter: logger.warn("Did not find expected delimiter " f"'{dictionary_description(delimiter)}', instead found " f"{tag} at file position 0x{fp.tell() - 8:X}") fp.seek(fp.tell() - 8) return logger.debug("%04x: Found Delimiter '%s'", fp.tell() - 8, dictionary_description(delimiter)) if length == 0: logger.debug("%04x: Read 0 bytes after delimiter", fp.tell() - 4) else: logger.debug("%04x: Expected 0x00000000 after delimiter, found 0x%x", fp.tell() - 4, length)
def _TM_from_byte_string(byte_string): byte_string = byte_string.rstrip() length = len(byte_string) if (length < 2 or length > 16) and length != 0: logger.warn("Expected length between 2 and 16, got length %d", length) return TM(byte_string)
def _DT_from_byte_string(byte_string): byte_string = byte_string.rstrip() length = len(byte_string) if length < 4 or length > 26: logger.warn("Expected length between 4 and 26, got length %d", length) return DT(byte_string)
def _DA_from_byte_string(byte_string): byte_string = byte_string.rstrip() length = len(byte_string) if length != 8 and length != 0: logger.warn("Expected length to be 8, got length %d", length) return DA(byte_string)