ruststreambytebit

Read a slice of bytes &[u8] bit by bit


I'm writing a program for hiding data in PNG files. The problem I have is reading data in the form of &[u8] (or Vec<u8>) bit by bit.


struct Data {
    bytes: Vec<u8>,
    index: usize,
}

impl Data {
    fn read_bits(&mut self, n: usize) -> u8 {
        // this function is the issue I don't know how to
        // do this I want this function to read n bits from 
        // self.bytes and return them.
        // if the current read byte is 0b11001011 and n = 2
        // the function should return 0b11 as u8 and update
        // self.index to make sure the next read returns
        // 0b10 aka the next 2 bits from 0b11001011
    }
}

The reason why I need the data in this form is I want to replace the least-significant bits of the color values in a png with the bits from a Vec<u8>

let mut red = ...; // the red channel from a pixel
red = red & 0b11111100; // remove the last 2 bits
red = red + data.read_bits(2); // read two bits from data and add it to the red channel

Solution

  • Probably not the most performant but should be what you need.

    struct BitIter<'a> {
        data: &'a [u8],
        index: usize
    }
    
    impl<'a> BitIter<'a> {
        fn next_n(&mut self, n: usize) -> u8 {
            let mut bits = 0;
            for i in 0..n {
                let bit = self.next().unwrap();
                bits |= bit << i;
            }
            bits
        }
    }
    
    impl<'a> Iterator for BitIter<'a> {
        type Item = u8;
    
        fn next(&mut self) -> Option<u8> {
            if self.index < self.data.len() * 8 {
                let bit = (self.data[self.index / 8] >> (self.index % 8)) & 1;
                self.index += 1;
                Some(bit)
            } else {
                None
            }
        }
    }