Вот пример считывателя битов.Это не слишком эффективно, потому что я возвращаю считанные биты в младшей битовой позиции, а затем сдвигаюсь, чтобы накапливать следующее поле.
Сначала класс, который отслеживает битовую и байтовую позицию в byte[]
ивозвращает следующий бит.
public class BitPosition {
int bytePos = 0;
int bitPos = 0; // 0 - 7 only
Byte[] data;
public BitPosition(Byte[] src) => data = src;
static byte[] byteBitMasks = new byte[] { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
public int ReadNextBit() {
if (bytePos >= data.Length)
throw new IndexOutOfRangeException("ReadNextBit");
int bit = (data[bytePos] & byteBitMasks[bitPos]) == 0 ? 0 : 1;
if (++bitPos > 7) {
bitPos = 0;
++bytePos;
}
return bit;
}
public bool HasMoreData => bytePos < data.Length;
}
Теперь класс для описания каждой записи в сжатой цветовой палитре:
public class ColorEntry {
public byte marker;
public int color;
public int sizeInBits;
}
Примечание. Если вам нужны маркеры большего размера, вы можете заменить byte
с int
или uint
.Если вам нужны до 64-битных маркеров, вам нужно изменить ColorReader
, чтобы использовать uint64
.
И, наконец, класс ColorReader
, который считывает цвета из byte[]
, используясжатая палитра и класс BitPosition
:
public class ColorReader {
BitPosition bp;
public ColorReader(byte[] data) => bp = new BitPosition(data);
static ColorEntry[] palette = new[] {
new ColorEntry { marker = 0b0, color = 0xFFFFFF, sizeInBits = 1 },
new ColorEntry { marker = 0b10, color = 0xFF0000, sizeInBits = 2 },
new ColorEntry { marker = 0b110, color = 0xFF00DC, sizeInBits = 3 },
new ColorEntry { marker = 0b111, color = 0xFF5A0C, sizeInBits = 3 },
};
public IEnumerable<ColorEntry> Colors() {
while (bp.HasMoreData) {
int bitsSoFar = 0;
int numBits = 0;
do {
int nextBit = bp.ReadNextBit();
++numBits;
bitsSoFar |= nextBit;
var nextCE = palette.FirstOrDefault(ce => ce.sizeInBits == numBits && ce.marker == bitsSoFar);
if (nextCE != null) {
yield return nextCE;
break;
}
else
bitsSoFar <<= 1;
} while (true);
}
}
}
Вы можете использовать класс следующим образом:
var data = new byte[] { 0b01011011, 0b10101100, 0b01011100 };
var cr = new ColorReader(data);
var ans = cr.Colors().Select(c => c.color).ToList();