Получить значение int из каждых двух байтов - PullRequest
0 голосов
/ 17 октября 2018

Я пытаюсь прочитать байты из изображения и получить все значения int (16 бит) из этого изображения.После того, как я проанализировал заголовок изображения, я получил значения пикселей.Значения, которые я получаю, когда пара байтов похожа на b "\ xd4 \ x00", неверны.В данном случае это должно быть 54272, а не 3392.

Это части кода: я использую генератор для получения байтов:

import itertools

def osddef_generator(in_file):
    with open(in_file, mode='rb') as f:
        dat = f.read()
        for byte in dat:
            yield byte

def take_slice(in_generator, size):
    return ''.join(str(chr(i)) for i in itertools.islice(in_generator, size))

def take_single_pixel(in_generator):
    pix = itertools.islice(in_generator, 2)

    hex_list = [hex(i) for i in pix]
    hex_str = "".join(hex_list)[2:].replace("0x", '')
    intval = int(hex_str, 16)
    print("hex_list: ", hex_list)
    print("hex_str: ", hex_str)
    print("intval: ", intval)

После того, как я правильно получаю заголовок, используяtake_slice метод, я попадаю в часть со значениями пикселей, где я использую метод take_single_pixel.Здесь я получаю плохие результаты.Вот что я получаю:

hex_list:  ['0xd4', '0x0']
hex_str:  d40
intval:  3392

Но фактическая последовательность байтов, которую следует интерпретировать, равна: \xd4\x00, что равно 54272, так что мои hex_list = ['0xd4', '0x00'] и hex_str = d400.Что-то происходит, когда у меня есть последовательность байтов, когда второй \x00.

Есть какие-нибудь идеи?Спасибо!

1 Ответ

0 голосов
/ 17 октября 2018

Существуют гораздо лучшие способы преобразования байтов в целые числа:

  • int.from_bytes() принимает входные байты и аргумент порядка следования байтов:

    >>> int.from_bytes(b"\xd4\x00", 'big')
    54272
    >>> int.from_bytes(b"\xd4\x00", 'little')
    212
    
  • Функция struct.unpack() позволяет преобразовать целую серию байтов в целые числа, следуя шаблону:

    >>> import struct
    >>> struct.unpack('!4H', b'\xd4\x00\xd4\x00\xd4\x00\xd4\x00')
    (54272, 54272, 54272, 54272)
    
  • Модуль array позволяет эффективно считывать двоичные данные, представляющие однородные целочисленные данные, в структуру памяти:

    >>> array.array('H', fileobject)
    

    Однако array нельзя сказать, какой порядок байтов использовать,Вам нужно будет определить текущий порядок байтов архитектуры и вызвать arr.byteswap(), чтобы изменить порядок, если машинный порядок не соответствует порядку файлов.

При чтении данных изображения этопочти всегда предпочтительнее использовать модуль struct для анализа.Обычно вы используете file.read() звонки с определенными размерами;если заголовок состоит из 10 байтов, используйте:

headerinfo = struct.unpack('<expected header pattern for 10 bytes>', f.read(10))

и перейдите оттуда.Для примера, посмотрите исходный код Подушек / PIL-плагинов ;вот как читается заголовок формата изображения Blizzard Mipmap :

def _read_blp_header(self):
    self._blp_compression, = struct.unpack("<i", self.fp.read(4))


    self._blp_encoding, = struct.unpack("<b", self.fp.read(1))
    self._blp_alpha_depth, = struct.unpack("<b", self.fp.read(1))
    self._blp_alpha_encoding, = struct.unpack("<b", self.fp.read(1))
    self._blp_mips, = struct.unpack("<b", self.fp.read(1))


    self._size = struct.unpack("<II", self.fp.read(8))


    if self.magic == b"BLP1":
        # Only present for BLP1
        self._blp_encoding, = struct.unpack("<i", self.fp.read(4))
        self._blp_subtype, = struct.unpack("<i", self.fp.read(4))


    self._blp_offsets = struct.unpack("<16I", self.fp.read(16 * 4))
    self._blp_lengths = struct.unpack("<16I", self.fp.read(16 * 4))

Поскольку struct.unpack() всегда возвращает кортежи, вы можете назначить отдельные элементы в кортеже именам name1, name2, ... наразмер левой руки, включая single_name, = присваивания для извлечения одного результата.

Отдельный набор вызовов для чтения выше также может быть сжат в меньшее количество вызовов:

comp, enc, adepth, aenc, mips, *size = struct.unpack("<i4b2I", self.fp.read(16))
if self.magic == b"BLP1":
    # Only present for BLP1
    enc, subtype = struct.unpack("<2i", self.fp.read(8))

, за которым следует определенный атрибутзадания.

...