Эквивалент Python для JavaScript DataView - PullRequest
1 голос
/ 21 мая 2019

Я загружаю байтовый массив из строки в кодировке base-64, и я хотел бы проанализировать его.

Однако значения кодируются по-разному, и я хотел бы повторить поведение DataView.

Пример:

function parse(data){
    view = new DataView(data.buffer);

    return {
        headerSize : view.getUint8(0),
        numberOfPlanes : view.getUint16(1, true),
        width: view.getUint16(3, true),
        height: view.getUint16(5, true),
        offset: view.getUint16(7, true)
    };
}

Использование:

data = new Uint8Array([8, 96, 0, 0, 2, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
parse(data)

Возвращает {headerSize: 8, numberOfPlanes: 96, width: 512, height: 256, offset: 8}

Позже мне нужно будет использовать DataView.getFloat32.

Прямо сейчас у меня есть что-то вроде этого:

def get_bin(a):
    ba = bin(a)[2:]
    return "0" * (8 - len(ba)) + ba


def getUInt16(arr, ind):
    a = arr[ind]
    b = arr[ind + 1]
    return int(get_bin(b) + get_bin(a), 2)

def getFloat32(arr, ind):
    return bin_to_float("".join(get(i) for i in arr[ind : ind + 4][::-1]))


def bin_to_float(binary):
    return struct.unpack("!f", struct.pack("!I", int(binary, 2)))[0]

Но библиотека может быть более эффективной и универсальной

Пример с плавающей точкой: [111, 62, 163, 36] должен дать 7.079574826789837e-17

1 Ответ

1 голос
/ 21 мая 2019

Это должно охватывать достаточное количество ваших случаев использования или, по крайней мере, привести вас к тому моменту, когда вы сможете внести незначительные изменения.Надеюсь, вы сможете немного понять, что я делаю, но не стесняйтесь задавать вопросы.

from functools import reduce
import struct
class DataView:
    def __init__(self, array, bytes_per_element=1):
        """
        bytes_per_element is the size of each element in bytes.
        By default we are assume the array is one byte per element.
        """
        self.array = array
        self.bytes_per_element = 1

    def __get_binary(self, start_index, byte_count, signed=False):
        integers = [self.array[start_index + x] for x in range(byte_count)]
        bytes = [integer.to_bytes(self.bytes_per_element, byteorder='little', signed=signed) for integer in integers]
        return reduce(lambda a, b: a + b, bytes)

    def get_uint_16(self, start_index):
        bytes_to_read = 2
        return int.from_bytes(self.__get_binary(start_index, bytes_to_read), byteorder='little')

    def get_uint_8(self, start_index):
        bytes_to_read = 1
        return int.from_bytes(self.__get_binary(start_index, bytes_to_read), byteorder='little')

    def get_float_32(self, start_index):
        bytes_to_read = 4
        binary = self.__get_binary(start_index, bytes_to_read)
        return struct.unpack('<f', binary)[0] # <f for little endian


def parse(byte_array):
    d = DataView(byte_array)
    return {
        "headerSize": d.get_uint_8(0),
        "numverOfPlanes": d.get_uint_16(1),
        "width": d.get_uint_16(3),
        "hieght": d.get_uint_16(5),
        "offset": d.get_uint_16(7),
    }

result = parse([8, 96, 0, 0, 2, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
import json
print(json.dumps(result, indent=2))

d = DataView([111, 62, 163, 36])
d.get_float_32(0)

Вывод:

{
  "headerSize": 8,
  "numverOfPlanes": 96,
  "width": 512,
  "hieght": 256,
  "offset": 8
}
7.079574826789837e-17
...