python - Splitting a byte list into a list of dicts -
i have byte data (say image):
00 19 01 21 09 0f 01 15 .. ff
i parse , store byte list:
[b'\x00', b'\x19', b'\x01', b'\x21', b'\x09', b'\x0f', b'\x01', b'\x15', ...]
these rgba values (little endian, 2 bytes) need parse dict format follows:
[{'red':0x0019, 'green':0x2101, 'blue':0x0f09, 'alpha':0x1501}, {'red':...},...]
note: image data terminates once reach 0xff
. values can stored in hex or decimal, doesn't matter long it's consistent.
my attempt:
# our dict keys keys = ['red', 'green', 'blue', 'alpha'] # first, grab bytes until hit 0xff img = list(takewhile(lambda x: x != b'\xff', bitstream)) # traverse img 2 bytes @ time , join them rgba = [] i,j in zip(img[0::2],img[1::2]): rgba.append(b''.join([j,i]) # j first since byteorder 'little'
so far output [0x0019, 0x2101, 0x0f09, ...]
now i'm stuck on how create list of dicts "pythonically". can use loop , pop 4 items list @ time that's not using python's features potential. advice?
note: example, keys can (not related images). overlook issues len(img) % len(keys) != 0
.
first, use stringio
create file-like object bitstream facilitate grabbing 8-byte chunks 1 @ time. then, use struct.unpack
convert each 8-byte chunk tuple of 4 integers, zip tuple of keys create list can passed directly dict
. wrapped in list comprehension create rgba
in 1 pass.
(i use functools.partial
, itertools.imap
improve readabililty.)
import stringio import re itertools import imap functools import partial keys = ("red", "green", "blue", "alpha") # create object can read str_iter = stringio.stringio(re.sub("\xff.*", "", bitstream)) # callable reads 8 bytes @ time str_iter read_8_bytes = partial(str_iter.read, 8) # convert 8-byte string tuple of 4 integer values unpack_rgba = partial(struct.unpack, "<hhhh") # iterable of 8-byte strings chunk_iter = iter(read_8_bytes, '') # map unpack_rgba on iterator iterator of 4-tuples, # zip each 4-tuple key tuple create desired dict rgba = [dict(zip(keys, rgba_values)) rgba_values in imap(unpack_rgba, chunk_iter)]
(if getting binary data like
with open('somefile', 'rb') fh: bitstream = fh.read()
then can use file iterator in place of str_iter
, read bytes file need them, rather @ once.)
Comments
Post a Comment