summaryrefslogtreecommitdiff
path: root/src/lossless
diff options
context:
space:
mode:
Diffstat (limited to 'src/lossless')
-rw-r--r--src/lossless/lsb.rs (renamed from src/lossless/champleve.rs)35
-rw-r--r--src/lossless/mod.rs4
2 files changed, 28 insertions, 11 deletions
diff --git a/src/lossless/champleve.rs b/src/lossless/lsb.rs
index 948408c..59dcc0b 100644
--- a/src/lossless/champleve.rs
+++ b/src/lossless/lsb.rs
@@ -5,21 +5,29 @@ use thiserror::Error;
use crate::codec::Codec;
+/// Least-significant bit (LSB) steganography encodes data in the least-significant bits of colors
+/// in an image. This implementation reduces the colors in the carrier (irreversibly) in order to
+/// allow a byte of data to fit in each pixel of the image. 3 bits of data are encoded per pixel,
+/// and the 9th bit is used to signal the end of data.
#[derive(Debug)]
-pub struct ChampleveCodec;
+pub struct LsbCodec;
-impl Codec for ChampleveCodec {
+impl Codec for LsbCodec {
type Carrier = DynamicImage;
type Payload = Vec<u8>;
type Output = Self::Carrier;
- type Error = ChampleveError;
+ type Error = LsbError;
- fn encode(&self, carrier: impl Into<Self::Carrier>, payload: impl Into<Self::Payload>) -> Result<Self::Output, Self::Error> {
+ fn encode<C, P>(&self, carrier: C, payload: P) -> Result<Self::Output, Self::Error>
+ where
+ C: Into<Self::Carrier>,
+ P: Into<Self::Payload>,
+ {
let mut image: DynamicImage = carrier.into();
let payload: Vec<u8> = payload.into();
if image.pixels().count() < payload.len() {
- return Err(ChampleveError::PayloadTooBig);
+ return Err(LsbError::PayloadTooBig);
}
let mut payload_iter = payload.iter();
@@ -43,13 +51,16 @@ impl Codec for ChampleveCodec {
}
}
},
- _ => return Err(ChampleveError::UnsupportedFormat { format: image.color() })
+ _ => return Err(LsbError::UnsupportedFormat { format: image.color() })
}
Ok(image)
}
- fn decode(&self, carrier: impl Into<Self::Output>) -> Result<(Self::Carrier, Self::Payload), ChampleveError> {
+ fn decode<E>(&self, carrier: E) -> Result<(Self::Carrier, Self::Payload), LsbError>
+ where
+ E: Into<Self::Output>,
+ {
let mut image: DynamicImage = carrier.into();
let mut payload: Vec<u8> = Vec::new();
@@ -72,7 +83,7 @@ impl Codec for ChampleveCodec {
}
}
},
- _ => return Err(ChampleveError::UnsupportedFormat { format: image.color() })
+ _ => return Err(LsbError::UnsupportedFormat { format: image.color() })
}
Ok((image, payload))
@@ -128,12 +139,18 @@ fn decode_pixel<P: Pixel<Subpixel = u8>>(pixel: &mut P) -> Option<u8> {
Some(payload_byte)
}
+/// Errors thrown by the LSB Codec.
#[derive(Error, Debug)]
-pub enum ChampleveError {
+pub enum LsbError {
+
+ /// Error thrown when payload is too big for the carrier.
#[error("Payload is too big for the carrier. Choose a smaller payload or an image with greater pixel dimensions.")]
PayloadTooBig,
+
+ /// Error thrown when pixel format is unsupported.
#[error("Specified image format ({format:?}) is unsupported.")]
UnsupportedFormat {
+ /// Provided (invalid) format.
format: ColorType
},
}
diff --git a/src/lossless/mod.rs b/src/lossless/mod.rs
index a9ae225..a6bda54 100644
--- a/src/lossless/mod.rs
+++ b/src/lossless/mod.rs
@@ -1,2 +1,2 @@
-mod champleve;
-pub use champleve::*;
+mod lsb;
+pub use lsb::*;