首页 > 解决方案 > 从每两个字节获取 int 值

问题描述

我正在尝试从图像中读取字节,并从该图像中获取所有 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.

有什么想法吗?谢谢!

标签: pythonbyte

解决方案


将字节转换为整数有更好的方法:

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

然后从那里去。例如,查看Pillow/PIL 图像插件源代码;以下是暴雪 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))

其次是特定的属性分配。


推荐阅读