[TSM.ID].[11031972] PXE : Platform X Ecosystem I [144 Module] +25 Missing Matrix Modules
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "xcu-watermark"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["TSM.ID <tsm@tsm.id>"]
|
||||
description = "[TSM.ID].[11031972] Video Frame Watermark Embedder"
|
||||
|
||||
[dependencies]
|
||||
@@ -0,0 +1,55 @@
|
||||
#![deny(warnings)]
|
||||
#![allow(dead_code)]
|
||||
//! [TSM.ID].[11031972] -- Platform X Ecosystem
|
||||
//! xcu-watermark -- Holographic Video Frame Watermark Embedder
|
||||
#[derive(Debug)] pub enum WmError { InvalidFrame(String), ExtractionFailed(String) }
|
||||
impl std::fmt::Display for WmError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::InvalidFrame(e)|Self::ExtractionFailed(e) => write!(f, "{e}") } } }
|
||||
impl std::error::Error for WmError {}
|
||||
#[derive(Debug, Clone, Copy)] pub enum EmbedStrength { Fragile, SemiRobust, Robust }
|
||||
impl EmbedStrength { pub fn bits_per_pixel(&self) -> u8 { match self { Self::Fragile => 1, Self::SemiRobust => 2, Self::Robust => 3 } } }
|
||||
pub struct WatermarkEncoder;
|
||||
impl WatermarkEncoder {
|
||||
pub fn embed(pixels: &mut [u8], data: &[u8], strength: EmbedStrength) -> Result<usize, WmError> {
|
||||
if pixels.is_empty() { return Err(WmError::InvalidFrame("Empty".into())); }
|
||||
let bits_pp = strength.bits_per_pixel();
|
||||
let mask = !(((1u8 << bits_pp) - 1) as u8);
|
||||
let mut bits_written = 0usize;
|
||||
for &byte in data {
|
||||
for bit_idx in 0..8 {
|
||||
let pi = bits_written; if pi >= pixels.len() { return Ok(bits_written); }
|
||||
let bit = (byte >> (7 - bit_idx)) & 1;
|
||||
pixels[pi] = (pixels[pi] & mask) | (bit & ((1 << bits_pp) - 1));
|
||||
bits_written += 1;
|
||||
}
|
||||
}
|
||||
Ok(bits_written)
|
||||
}
|
||||
pub fn extract(pixels: &[u8], data_len: usize, strength: EmbedStrength) -> Result<Vec<u8>, WmError> {
|
||||
if pixels.is_empty() { return Err(WmError::ExtractionFailed("Empty".into())); }
|
||||
let mask = ((1u8 << strength.bits_per_pixel()) - 1) as u8;
|
||||
let mut result = Vec::new();
|
||||
let mut current_byte = 0u8;
|
||||
let mut bit_count = 0;
|
||||
for &pixel in pixels.iter().take(data_len * 8) {
|
||||
let bit = pixel & mask & 1;
|
||||
current_byte = (current_byte << 1) | bit;
|
||||
bit_count += 1;
|
||||
if bit_count == 8 { result.push(current_byte); current_byte = 0; bit_count = 0; }
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
pub fn verify(original: &[u8], watermarked: &[u8], data: &[u8], strength: EmbedStrength) -> bool {
|
||||
let extracted = Self::extract(watermarked, data.len(), strength);
|
||||
match extracted { Ok(ext) => ext == data, Err(_) => false }
|
||||
}
|
||||
}
|
||||
#[cfg(test)] mod tests {
|
||||
use super::*;
|
||||
#[test] fn test_embed_extract() {
|
||||
let mut pixels = vec![128u8; 100];
|
||||
let data = b"TSM";
|
||||
WatermarkEncoder::embed(&mut pixels, data, EmbedStrength::Fragile).unwrap();
|
||||
let extracted = WatermarkEncoder::extract(&pixels, data.len(), EmbedStrength::Fragile).unwrap();
|
||||
assert_eq!(extracted, data);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user