summaryrefslogtreecommitdiff
path: root/src/lossless/champleve.rs
diff options
context:
space:
mode:
authorLibravatar Silas Bartha <silas@exvacuum.dev>2024-05-27 14:20:08 -0400
committerLibravatar Silas Bartha <silas@exvacuum.dev>2024-05-27 14:20:08 -0400
commitccb19be9d0e918070029f31a86c7eb546121bd87 (patch)
tree6192bc514a7ae815a8863a23b4cc59405c18ec37 /src/lossless/champleve.rs
parentd088553bd19c58543b908936ba8bae2bfa877b50 (diff)
Updated docs
Diffstat (limited to 'src/lossless/champleve.rs')
-rw-r--r--src/lossless/champleve.rs139
1 files changed, 0 insertions, 139 deletions
diff --git a/src/lossless/champleve.rs b/src/lossless/champleve.rs
deleted file mode 100644
index 948408c..0000000
--- a/src/lossless/champleve.rs
+++ /dev/null
@@ -1,139 +0,0 @@
-use std::cmp::Ordering;
-
-use image::{ColorType, DynamicImage, GenericImageView, Pixel};
-use thiserror::Error;
-
-use crate::codec::Codec;
-
-#[derive(Debug)]
-pub struct ChampleveCodec;
-
-impl Codec for ChampleveCodec {
- type Carrier = DynamicImage;
- type Payload = Vec<u8>;
- type Output = Self::Carrier;
- type Error = ChampleveError;
-
- fn encode(&self, carrier: impl Into<Self::Carrier>, payload: impl Into<Self::Payload>) -> Result<Self::Output, Self::Error> {
- let mut image: DynamicImage = carrier.into();
- let payload: Vec<u8> = payload.into();
-
- if image.pixels().count() < payload.len() {
- return Err(ChampleveError::PayloadTooBig);
- }
-
- let mut payload_iter = payload.iter();
-
- match image {
- DynamicImage::ImageRgba8(ref mut image) => {
- for pixel in image.pixels_mut() {
- if let Some(payload_byte) = payload_iter.next() {
- encode_pixel(pixel, *payload_byte, false);
- } else {
- encode_pixel(pixel, 0, true);
- }
- }
- },
- DynamicImage::ImageRgb8(ref mut image) => {
- for pixel in image.pixels_mut() {
- if let Some(payload_byte) = payload_iter.next() {
- encode_pixel(pixel, *payload_byte, false);
- } else {
- encode_pixel(pixel, 0, true);
- }
- }
- },
- _ => return Err(ChampleveError::UnsupportedFormat { format: image.color() })
- }
-
- Ok(image)
- }
-
- fn decode(&self, carrier: impl Into<Self::Output>) -> Result<(Self::Carrier, Self::Payload), ChampleveError> {
- let mut image: DynamicImage = carrier.into();
- let mut payload: Vec<u8> = Vec::new();
-
- match image {
- DynamicImage::ImageRgba8(ref mut image) => {
- for pixel in image.pixels_mut() {
- if let Some(payload_byte) = decode_pixel(pixel) {
- payload.push(payload_byte);
- } else {
- break;
- }
- }
- },
- DynamicImage::ImageRgb8(ref mut image) => {
- for pixel in image.pixels_mut() {
- if let Some(payload_byte) = decode_pixel(pixel) {
- payload.push(payload_byte);
- } else {
- break;
- }
- }
- },
- _ => return Err(ChampleveError::UnsupportedFormat { format: image.color() })
- }
-
- Ok((image, payload))
- }
-}
-
-fn encode_pixel<P: Pixel<Subpixel = u8>>(pixel: &mut P, payload_byte: u8, end_of_data: bool) {
- let mut bits_remaining: i32 = 8;
- for channel in pixel.channels_mut() {
- *channel &= 0b11111000;
- bits_remaining -= 3;
- if bits_remaining <= -3 {
- break;
- }
-
- let mask = match bits_remaining.cmp(&0) {
- Ordering::Less => payload_byte << -bits_remaining,
- _ => payload_byte >> bits_remaining,
- } & 0b00000111;
-
- *channel |= mask;
- }
-
- // Add end-of-data marker to final bit if necessary
- if end_of_data {
- *pixel.channels_mut().last_mut().unwrap() |= 1;
- }
-}
-
-fn decode_pixel<P: Pixel<Subpixel = u8>>(pixel: &mut P) -> Option<u8> {
-
- // Final bit as end-of-data marker
- if pixel.channels().last().unwrap() & 1 == 1 {
- return None;
- }
-
- let mut bits_remaining: i32 = 8;
- let mut payload_byte: u8 = 0;
- for channel in pixel.channels_mut() {
- bits_remaining -= 3;
- if bits_remaining <= -3 {
- break;
- }
-
- let channel_bits = *channel & 0b00000111;
- *channel &= 0b11111000;
- let mask = match bits_remaining.cmp(&0) {
- Ordering::Less => channel_bits >> -bits_remaining,
- _ => channel_bits << bits_remaining,
- };
- payload_byte |= mask;
- }
- Some(payload_byte)
-}
-
-#[derive(Error, Debug)]
-pub enum ChampleveError {
- #[error("Payload is too big for the carrier. Choose a smaller payload or an image with greater pixel dimensions.")]
- PayloadTooBig,
- #[error("Specified image format ({format:?}) is unsupported.")]
- UnsupportedFormat {
- format: ColorType
- },
-}