stegano_core/
universal_decoder.rs

1use bitstream_io::{BitWrite, BitWriter, LittleEndian};
2use enum_dispatch::enum_dispatch;
3use std::io::{BufWriter, Read, Result};
4
5use crate::media::MediaPrimitive;
6
7#[allow(unused)]
8#[enum_dispatch]
9pub enum UnveilAlgorithms {
10    OneBitUnveil,
11}
12
13/// generic unveil algorithm
14#[enum_dispatch(UnveilAlgorithms)]
15pub trait UnveilAlgorithm {
16    fn decode(&self, carrier: MediaPrimitive) -> bool;
17}
18
19/// generic stegano decoder
20pub struct UniversalDecoder<I, A>
21where
22    I: Iterator<Item = MediaPrimitive>,
23    A: UnveilAlgorithm,
24{
25    pub input: I,
26    pub algorithm: A,
27    position: usize,
28}
29
30/// generic stegano decoder constructor method
31impl<I, A> UniversalDecoder<I, A>
32where
33    I: Iterator<Item = MediaPrimitive>,
34    A: UnveilAlgorithm,
35{
36    pub fn new(input: I, algorithm: A) -> Self {
37        UniversalDecoder {
38            input,
39            algorithm,
40            position: 0,
41        }
42    }
43}
44
45impl<I, A> Read for UniversalDecoder<I, A>
46where
47    I: Iterator<Item = MediaPrimitive>,
48    A: UnveilAlgorithm,
49{
50    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
51        // TODO better let the algorithm determine the density of decoding
52        let items_to_take = buf.len() << 3; // 8 primitives = 1 byte
53        let buf_writer = BufWriter::new(buf);
54        let mut bit_buffer = BitWriter::endian(buf_writer, LittleEndian);
55
56        let mut bit_read: usize = 0;
57        for carrier in self.input.by_ref().take(items_to_take) {
58            let bit = self.algorithm.decode(carrier);
59            bit_buffer.write_bit(bit)?;
60            bit_read += 1;
61        }
62
63        if !bit_buffer.byte_aligned() {
64            bit_buffer.byte_align()?
65        }
66
67        self.position += bit_read >> 3;
68
69        Ok(bit_read >> 3)
70    }
71}
72
73/// default 1 bit unveil strategy
74#[derive(Debug)]
75pub struct OneBitUnveil;
76impl UnveilAlgorithm for OneBitUnveil {
77    #[inline]
78    fn decode(&self, carrier: MediaPrimitive) -> bool {
79        match carrier {
80            MediaPrimitive::ImageColorChannel(b) => (b & 0x1) > 0,
81            MediaPrimitive::AudioSample(b) => (b & 0x1) > 0,
82        }
83    }
84}