¿Cómo empaquetar secuencias de bits arbitrarias en Python?

Quiero codificar / comprimir algunos datos de imágenes binarias como una secuencia de bits. (En general, esta secuencia tendrá una longitud que no se ajusta perfectamente a un número entero de tipos de enteros estándar).

¿Cómo puedo hacer esto sin perder espacio? (Me doy cuenta de que, a menos que la secuencia de bits tenga una longitud “bonita”, siempre tendrá que haber una pequeña cantidad [<1 byte] de espacio sobrante al final).

FWIW, estimo que, como máximo, se necesitarán 3 bits por el símbolo que quiero codificar. ¿Python tiene herramientas integradas para este tipo de trabajo?

No hay nada muy conveniente incorporado, pero hay módulos de terceros como bitstring y bitarray que están diseñados para esto.

from bitstring import BitArray s = BitArray('0b11011') s += '0b100' s += 'uint:5=9' s += [0, 1, 1, 0, 1] ... s.tobytes() 

Para unir una secuencia de números de 3 bits (es decir, rango 0-> 7) puede usar

 >>> symbols = [0, 4, 5, 3, 1, 1, 7, 6, 5, 2, 6, 2] >>> BitArray().join(BitArray(uint=x, length=3) for x in symbols) BitArray('0x12b27eab2') >>> _.tobytes() '\x12\xb2~\xab ' 

Algunas preguntas relacionadas:

  • ¿Cuál es la mejor manera de hacer la manipulación de Bit Field en Python?
  • Implementaciones de Python Bitstream

¿Has intentado simplemente comprimir toda la secuencia con bz2 ? Si la secuencia es larga, debe usar el compresor bz2.BZ2 para permitir el procesamiento fragmentado, de lo contrario, use bz2.compress en todo el proceso. La compresión probablemente no sea ideal, pero normalmente se acercará mucho cuando se trate de datos dispersos.

Espero que ayude.

Dado que tiene una asignación de símbolos a una cadena de 3 bits, bitarray hace un buen trabajo de encoding y deencoding de listas de símbolos hacia y desde matrices de bits:

 from bitarray import bitarray from random import choice symbols = { '0' : bitarray('000'), 'a' : bitarray('001'), 'b' : bitarray('010'), 'c' : bitarray('011'), 'd' : bitarray('100'), 'e' : bitarray('101'), 'f' : bitarray('110'), 'g' : bitarray('111'), } seedstring = ''.join(choice(symbols.keys()) for _ in range(40)) # construct bitarray using symbol->bitarray mapping ba = bitarray() ba.encode(symbols, seedstring) print seedstring print ba # what does bitarray look like internally? ba_string = ba.tostring() print repr(ba_string) print len(ba_string) 

Huellas dactilares:

 egb0dbebccde0gfdfbc0d0ccfcg0acgg0ccfga00 bitarray('10111101000010001010101001101110010100... etc. '\xbd\x08\xaanQ\xf4\xc9\x88\x1b\xcf\x82\xff\r\xee@' 15 

Puede ver que esta lista de 40 símbolos (120 bits) se codifica en un bitarray de 15 bytes.