///|
/// 不可见水印:LSB(最低有效位)嵌入 + key 派生 keystream 混淆。
///
/// 布局(按像素顺序,每像素 RGB 三个通道各 1 bit):
///
/// [magic 2B "MW"] [len 2B 大端] [payload 混淆数据]
///
/// 嵌入前整体与 keystream XOR(keystream 由 `key` 经 xorshift64 派生;
/// `key` 为 `None` 时 keystream 全 0,即明文嵌入)。因此错误 key 会在
/// magic 校验处被拒绝(返回 `None`),可用于观众 ID 溯源鉴权。
/// 注意:LSB 提供隐蔽性,不提供强加密,密钥用于混淆与访问控制。
///|
/// 将 `payload`(如观众 ID)以 LSB 方式嵌入图像(原地修改)。
///
/// - 容量:`width × height × 3 / 8` 字节(含 4 字节头部);超出返回 `Err`。
/// - `key`:可选混淆密钥,`None` 为明文嵌入。
/// - 返回 `Ok(图像)` / `Err(容量不足)`。
pub fn RgbaImage::embed_invisible(self : RgbaImage, payload : Bytes, key? : Int64) -> Result[RgbaImage, String] {
let capacity = self.width * self.height * 3 / 8
let need = 4 + payload.length()
if need > capacity {
return Err("payload too large: \{need} > capacity \{capacity}")
}
// 构造明文帧:magic + len + payload(Bytes 不可变,用 FixedArray 承载)
let frame = FixedArray::make(need, (0).to_byte())
frame[0] = b'M'
frame[1] = b'W'
frame[2] = ((payload.length() >> 8) & 0xFF).to_byte()
frame[3] = (payload.length() & 0xFF).to_byte()
for i in 0..> (b % 8)) & 1
let pix = b / 3
let ch = b % 3
let x = pix % self.width
let y = pix / self.width
let p = self.get_pixel(x, y)
let shift = (2 - ch) * 8 // R=16, G=8, B=0
let cur = (p >> shift) & 0xFF
let nv = (cur & 0xFE) | bit
let np = (p & (-1 ^ (0xFF << shift))) | (nv << shift)
self.set_pixel(x, y, np)
}
Ok(self)
}
///|
/// 从图像提取 LSB 不可见水印;magic 校验失败(含错误 key)返回 `None`。
pub fn extract_invisible(img : RgbaImage, key? : Int64) -> Option[Bytes] {
let capacity = img.width * img.height * 3 / 8
if capacity < 4 {
return None
}
// 读出混淆帧头部(4 字节)
let head = FixedArray::make(4, (0).to_byte())
for b in 0..<32 {
head[b / 8] = (head[b / 8].to_int() | (read_bit(img, b).to_int() << (b % 8))).to_byte()
}
let ks_head = keystream(key, 4)
for i in 0..<4 {
head[i] = (head[i].to_int() ^ ks_head[i].to_int()).to_byte()
}
if head[0] != b'M' || head[1] != b'W' {
return None
}
let len = (head[2].to_int() << 8) | head[3].to_int()
if 4 + len > capacity {
return None
}
let total = 4 + len
let frame = FixedArray::make(total, (0).to_byte())
for i in 0..<4 {
frame[i] = head[i]
}
for b in 32..<(total * 8) {
frame[b / 8] = (frame[b / 8].to_int() | (read_bit(img, b).to_int() << (b % 8))).to_byte()
}
let ks = keystream(key, total)
let out = Array::make(len, (0).to_byte())
for i in 0.. Byte {
let pix = b / 3
let ch = b % 3
let x = pix % img.width
let y = pix / img.width
let p = img.get_pixel(x, y)
let shift = (2 - ch) * 8
(((p >> shift) & 0xFF) & 1).to_byte()
}
///|
/// 由 key 派生 keystream:xorshift64 序列低 8 位;`None` 时全 0(明文模式)。
fn keystream(key : Option[Int64], len : Int) -> FixedArray[Byte] {
let out = FixedArray::make(len, (0).to_byte())
match key {
Some(k) => {
let mut st = seed_to_state(k)
for i in 0.. ()
}
out
}