1mod av1encoder;
12
13mod error;
14pub use av1encoder::ColorModel;
15pub use error::Error;
16
17#[doc(hidden)]
18#[deprecated = "Renamed to `ColorModel`"]
19pub type ColorSpace = ColorModel;
20
21pub use av1encoder::{AlphaColorMode, BitDepth, EncodedImage, Encoder};
22#[doc(inline)]
23pub use rav1e::prelude::{MatrixCoefficients, PixelRange};
24
25mod dirtyalpha;
26
27#[doc(no_inline)]
28pub use imgref::Img;
29#[doc(no_inline)]
30pub use rgb::{RGB8, RGBA8};
31
32#[cfg(not(feature = "threading"))]
33mod rayoff {
34 pub fn current_num_threads() -> usize {
35 std::thread::available_parallelism().map(|v| v.get()).unwrap_or(1)
36 }
37
38 pub fn join<A, B>(a: impl FnOnce() -> A, b: impl FnOnce() -> B) -> (A, B) {
39 (a(), b())
40 }
41}
42
43#[test]
44fn encode8_with_alpha() {
45 let img = imgref::ImgVec::new((0..200).flat_map(|y| (0..256).map(move |x| {
46 RGBA8::new(x as u8, y as u8, 255, (x + y) as u8)
47 })).collect(), 256, 200);
48
49 let enc = Encoder::new()
50 .with_quality(22.0)
51 .with_bit_depth(BitDepth::Eight)
52 .with_speed(1)
53 .with_alpha_quality(22.0)
54 .with_alpha_color_mode(AlphaColorMode::UnassociatedDirty)
55 .with_num_threads(Some(2));
56 let EncodedImage { avif_file, color_byte_size, alpha_byte_size , .. } = enc.encode_rgba(img.as_ref()).unwrap();
57 assert!(color_byte_size > 50 && color_byte_size < 1000);
58 assert!(alpha_byte_size > 50 && alpha_byte_size < 1000); let parsed = avif_parse::read_avif(&mut avif_file.as_slice()).unwrap();
61 assert!(parsed.alpha_item.is_some());
62 assert!(parsed.primary_item.len() > 100);
63 assert!(parsed.primary_item.len() < 1000);
64
65 let md = parsed.primary_item_metadata().unwrap();
66 assert_eq!(md.max_frame_width.get(), 256);
67 assert_eq!(md.max_frame_height.get(), 200);
68 assert_eq!(md.bit_depth, 8);
69}
70
71#[test]
72fn encode8_opaque() {
73 let img = imgref::ImgVec::new((0..101).flat_map(|y| (0..129).map(move |x| {
74 RGBA8::new(255, 100 + x as u8, y as u8, 255)
75 })).collect(), 129, 101);
76
77 let enc = Encoder::new()
78 .with_quality(33.0)
79 .with_speed(10)
80 .with_alpha_quality(33.0)
81 .with_bit_depth(BitDepth::Auto)
82 .with_alpha_color_mode(AlphaColorMode::UnassociatedDirty)
83 .with_num_threads(Some(1));
84 let EncodedImage { avif_file, color_byte_size, alpha_byte_size , .. } = enc.encode_rgba(img.as_ref()).unwrap();
85 assert_eq!(0, alpha_byte_size); let tmp_path = format!("/tmp/ravif-encode-test-failure-{color_byte_size}.avif");
87 if color_byte_size <= 150 || color_byte_size >= 500 {
88 std::fs::write(&tmp_path, &avif_file).expect(&tmp_path);
89 }
90 assert!(color_byte_size > 150 && color_byte_size < 500, "size = {color_byte_size}; expected ~= 215; see {tmp_path}");
91
92 let parsed1 = avif_parse::read_avif(&mut avif_file.as_slice()).unwrap();
93 assert_eq!(None, parsed1.alpha_item);
94
95 let md = parsed1.primary_item_metadata().unwrap();
96 assert_eq!(md.max_frame_width.get(), 129);
97 assert_eq!(md.max_frame_height.get(), 101);
98 assert!(md.still_picture);
99 assert_eq!(md.bit_depth, 10);
100
101 let img = img.map_buf(|b| b.into_iter().map(|px| px.rgb()).collect::<Vec<_>>());
102
103 let enc = Encoder::new()
104 .with_quality(33.0)
105 .with_speed(10)
106 .with_bit_depth(BitDepth::Ten)
107 .with_alpha_quality(33.0)
108 .with_alpha_color_mode(AlphaColorMode::UnassociatedDirty)
109 .with_num_threads(Some(1));
110
111 let EncodedImage { avif_file, color_byte_size, alpha_byte_size , .. } = enc.encode_rgb(img.as_ref()).unwrap();
112 assert_eq!(0, alpha_byte_size); assert!(color_byte_size > 50 && color_byte_size < 1000);
114
115 let parsed2 = avif_parse::read_avif(&mut avif_file.as_slice()).unwrap();
116
117 assert_eq!(parsed1.alpha_item, parsed2.alpha_item);
118 assert_eq!(parsed1.primary_item, parsed2.primary_item); }
120
121#[test]
122fn encode8_cleans_alpha() {
123 let img = imgref::ImgVec::new((0..200).flat_map(|y| (0..256).map(move |x| {
124 RGBA8::new((((x/ 5 + y ) & 0xF) << 4) as u8, (7 * x + y / 2) as u8, ((x * y) & 0x3) as u8, ((x + y) as u8 & 0x7F).saturating_sub(100))
125 })).collect(), 256, 200);
126
127 let enc = Encoder::new()
128 .with_quality(66.0)
129 .with_speed(6)
130 .with_alpha_quality(88.0)
131 .with_alpha_color_mode(AlphaColorMode::UnassociatedDirty)
132 .with_num_threads(Some(1));
133
134 let dirty = enc
135 .encode_rgba(img.as_ref())
136 .unwrap();
137
138 let clean = enc
139 .with_alpha_color_mode(AlphaColorMode::UnassociatedClean)
140 .encode_rgba(img.as_ref())
141 .unwrap();
142
143 assert_eq!(clean.alpha_byte_size, dirty.alpha_byte_size); assert!(clean.alpha_byte_size > 200 && clean.alpha_byte_size < 1000);
145 assert!(clean.color_byte_size > 2000 && clean.color_byte_size < 6000);
146 assert!(clean.color_byte_size < dirty.color_byte_size / 2); }