diff options
author | Silas Bartha <silas@exvacuum.dev> | 2024-05-27 14:20:08 -0400 |
---|---|---|
committer | Silas Bartha <silas@exvacuum.dev> | 2024-05-27 14:20:08 -0400 |
commit | ccb19be9d0e918070029f31a86c7eb546121bd87 (patch) | |
tree | 6192bc514a7ae815a8863a23b4cc59405c18ec37 /src/lossless/champleve.rs | |
parent | d088553bd19c58543b908936ba8bae2bfa877b50 (diff) |
Updated docs
Diffstat (limited to 'src/lossless/champleve.rs')
-rw-r--r-- | src/lossless/champleve.rs | 139 |
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 - }, -} |