use webpx::*;
#[cfg(feature = "streaming")]
fn rgba_fixture(width: u32, height: u32) -> Vec<u8> {
let mut rgba = Vec::with_capacity((width * height * 4) as usize);
for y in 0..height {
for x in 0..width {
rgba.extend_from_slice(&[
(x * 40 + 10) as u8,
(y * 50 + 20) as u8,
(x * 17 + y * 19 + 30) as u8,
255,
]);
}
}
rgba
}
#[cfg(feature = "streaming")]
fn encode_lossless_rgba(rgba: &[u8], width: u32, height: u32) -> Vec<u8> {
Encoder::new_rgba(rgba, width, height)
.lossless(true)
.encode(Unstoppable)
.expect("lossless encode should succeed")
}
#[test]
fn argb_lossless_encode_must_not_mutate_shared_input() {
let argb = vec![0x00_ff_00_00u32];
let original = argb.clone();
Encoder::new_argb(&argb, 1, 1)
.lossless(true)
.encode(Unstoppable)
.expect("lossless argb encode should succeed");
assert_eq!(
argb, original,
"safe ARGB encoding mutated data passed through an immutable slice"
);
}
#[test]
fn yuv_encode_must_not_mutate_shared_planes() {
let width = 8;
let height = 8;
let y: Vec<u8> = (0..(width * height)).map(|v| v as u8).collect();
let u: Vec<u8> = (0..((width / 2) * (height / 2)))
.map(|v| (64 + v) as u8)
.collect();
let v: Vec<u8> = (0..((width / 2) * (height / 2)))
.map(|v| (128 + v) as u8)
.collect();
let a = vec![0u8; (width * height) as usize];
let original_y = y.clone();
let original_u = u.clone();
let original_v = v.clone();
let planes = YuvPlanesRef {
y: &y,
y_stride: width as usize,
u: &u,
u_stride: (width / 2) as usize,
v: &v,
v_stride: (width / 2) as usize,
a: Some(&a),
a_stride: width as usize,
width,
height,
};
Encoder::new_yuv(planes)
.encode(Unstoppable)
.expect("yuv encode should succeed");
assert_eq!(
y, original_y,
"safe YUV encoding mutated the Y plane passed through an immutable slice"
);
assert_eq!(
u, original_u,
"safe YUV encoding mutated the U plane passed through an immutable slice"
);
assert_eq!(
v, original_v,
"safe YUV encoding mutated the V plane passed through an immutable slice"
);
}
#[test]
fn yuv_encode_must_reject_planes_shorter_than_stride_height() {
let width = 2;
let height = 2;
let hidden_tail = [16u8, 235, 235, 235];
let u = [128u8];
let v = [128u8];
let planes = YuvPlanesRef {
y: &hidden_tail[..1],
y_stride: width as usize,
u: &u,
u_stride: 1,
v: &v,
v_stride: 1,
a: None,
a_stride: 0,
width,
height,
};
let result = Encoder::new_yuv(planes).encode(Unstoppable);
assert!(
result.is_err(),
"safe YUV encoding accepted a Y plane shorter than y_stride * height"
);
}
#[cfg(feature = "streaming")]
#[test]
fn streaming_decoder_with_buffer_safe_usage() {
let width = 16;
let height = 16;
let rgba = rgba_fixture(width, height);
let webp = encode_lossless_rgba(&rgba, width, height);
let stride = (width * 4) as usize;
let mut output = vec![0u8; stride * height as usize];
let mut decoder = StreamingDecoder::with_buffer(&mut output, stride, ColorMode::Rgba)
.expect("streaming decoder with external buffer");
decoder.append(&webp).expect("streaming decode append");
let (decoded, decoded_width, decoded_height) =
decoder.finish().expect("finish on caller-owned buffer");
assert_eq!((decoded_width, decoded_height), (width, height));
assert_eq!(decoded, rgba);
}