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;
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); assert!(color_byte_size > 50 && color_byte_size < 1000);
87
88 let parsed1 = avif_parse::read_avif(&mut avif_file.as_slice()).unwrap();
89 assert_eq!(None, parsed1.alpha_item);
90
91 let md = parsed1.primary_item_metadata().unwrap();
92 assert_eq!(md.max_frame_width.get(), 129);
93 assert_eq!(md.max_frame_height.get(), 101);
94 assert!(md.still_picture);
95 assert_eq!(md.bit_depth, 10);
96
97 let img = img.map_buf(|b| b.into_iter().map(|px| px.rgb()).collect::<Vec<_>>());
98
99 let enc = Encoder::new()
100 .with_quality(33.0)
101 .with_speed(10)
102 .with_bit_depth(BitDepth::Ten)
103 .with_alpha_quality(33.0)
104 .with_alpha_color_mode(AlphaColorMode::UnassociatedDirty)
105 .with_num_threads(Some(1));
106
107 let EncodedImage { avif_file, color_byte_size, alpha_byte_size , .. } = enc.encode_rgb(img.as_ref()).unwrap();
108 assert_eq!(0, alpha_byte_size); assert!(color_byte_size > 50 && color_byte_size < 1000);
110
111 let parsed2 = avif_parse::read_avif(&mut avif_file.as_slice()).unwrap();
112
113 assert_eq!(parsed1.alpha_item, parsed2.alpha_item);
114 assert_eq!(parsed1.primary_item, parsed2.primary_item); }
116
117#[test]
118fn encode8_cleans_alpha() {
119 let img = imgref::ImgVec::new((0..200).flat_map(|y| (0..256).map(move |x| {
120 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))
121 })).collect(), 256, 200);
122
123 let enc = Encoder::new()
124 .with_quality(66.0)
125 .with_speed(6)
126 .with_alpha_quality(88.0)
127 .with_alpha_color_mode(AlphaColorMode::UnassociatedDirty)
128 .with_num_threads(Some(1));
129
130 let dirty = enc
131 .encode_rgba(img.as_ref())
132 .unwrap();
133
134 let clean = enc
135 .with_alpha_color_mode(AlphaColorMode::UnassociatedClean)
136 .encode_rgba(img.as_ref())
137 .unwrap();
138
139 assert_eq!(clean.alpha_byte_size, dirty.alpha_byte_size); assert!(clean.alpha_byte_size > 200 && clean.alpha_byte_size < 1000);
141 assert!(clean.color_byte_size > 2000 && clean.color_byte_size < 6000);
142 assert!(clean.color_byte_size < dirty.color_byte_size / 2); }