1 use std::iter::Iterator; 2 use std::time::Duration; 3 4 use num_rational::Ratio; 5 6 use crate::RgbaImage; 7 use crate::error::ImageResult; 8 9 /// An implementation dependent iterator, reading the frames as requested 10 pub struct Frames<'a> { 11 iterator: Box<dyn Iterator<Item = ImageResult<Frame>> + 'a> 12 } 13 14 impl<'a> Frames<'a> { 15 /// Creates a new `Frames` from an implementation specific iterator. new(iterator: Box<dyn Iterator<Item = ImageResult<Frame>> + 'a>) -> Self16 pub fn new(iterator: Box<dyn Iterator<Item = ImageResult<Frame>> + 'a>) -> Self { 17 Frames { iterator } 18 } 19 20 /// Steps through the iterator from the current frame until the end and pushes each frame into 21 /// a `Vec`. 22 /// If en error is encountered that error is returned instead. 23 /// 24 /// Note: This is equivalent to `Frames::collect::<ImageResult<Vec<Frame>>>()` collect_frames(self) -> ImageResult<Vec<Frame>>25 pub fn collect_frames(self) -> ImageResult<Vec<Frame>> { 26 self.collect() 27 } 28 } 29 30 impl<'a> Iterator for Frames<'a> { 31 type Item = ImageResult<Frame>; next(&mut self) -> Option<ImageResult<Frame>>32 fn next(&mut self) -> Option<ImageResult<Frame>> { 33 self.iterator.next() 34 } 35 } 36 37 /// A single animation frame 38 #[derive(Clone)] 39 pub struct Frame { 40 /// Delay between the frames in milliseconds 41 delay: Delay, 42 /// x offset 43 left: u32, 44 /// y offset 45 top: u32, 46 buffer: RgbaImage, 47 } 48 49 /// The delay of a frame relative to the previous one. 50 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd)] 51 pub struct Delay { 52 ratio: Ratio<u32>, 53 } 54 55 impl Frame { 56 /// Contructs a new frame without any delay. new(buffer: RgbaImage) -> Frame57 pub fn new(buffer: RgbaImage) -> Frame { 58 Frame { 59 delay: Delay::from_ratio(Ratio::from_integer(0)), 60 left: 0, 61 top: 0, 62 buffer, 63 } 64 } 65 66 /// Contructs a new frame from_parts(buffer: RgbaImage, left: u32, top: u32, delay: Delay) -> Frame67 pub fn from_parts(buffer: RgbaImage, left: u32, top: u32, delay: Delay) -> Frame { 68 Frame { 69 delay, 70 left, 71 top, 72 buffer, 73 } 74 } 75 76 /// Delay of this frame delay(&self) -> Delay77 pub fn delay(&self) -> Delay { 78 self.delay 79 } 80 81 /// Returns the image buffer buffer(&self) -> &RgbaImage82 pub fn buffer(&self) -> &RgbaImage { 83 &self.buffer 84 } 85 86 /// Returns a mutable image buffer buffer_mut(&mut self) -> &mut RgbaImage87 pub fn buffer_mut(&mut self) -> &mut RgbaImage { 88 &mut self.buffer 89 } 90 91 /// Returns the image buffer into_buffer(self) -> RgbaImage92 pub fn into_buffer(self) -> RgbaImage { 93 self.buffer 94 } 95 96 /// Returns the x offset left(&self) -> u3297 pub fn left(&self) -> u32 { 98 self.left 99 } 100 101 /// Returns the y offset top(&self) -> u32102 pub fn top(&self) -> u32 { 103 self.top 104 } 105 } 106 107 impl Delay { 108 /// Create a delay from a ratio of milliseconds. 109 /// 110 /// # Examples 111 /// 112 /// ``` 113 /// use image::Delay; 114 /// let delay_10ms = Delay::from_numer_denom_ms(10, 1); 115 /// ``` from_numer_denom_ms(numerator: u32, denominator: u32) -> Self116 pub fn from_numer_denom_ms(numerator: u32, denominator: u32) -> Self { 117 Delay { ratio: Ratio::new_raw(numerator, denominator) } 118 } 119 120 /// Convert from a duration, clamped between 0 and an implemented defined maximum. 121 /// 122 /// The maximum is *at least* `i32::MAX` milliseconds. It should be noted that the accuracy of 123 /// the result may be relative and very large delays have a coarse resolution. 124 /// 125 /// # Examples 126 /// 127 /// ``` 128 /// use std::time::Duration; 129 /// use image::Delay; 130 /// 131 /// let duration = Duration::from_millis(20); 132 /// let delay = Delay::from_saturating_duration(duration); 133 /// ``` from_saturating_duration(duration: Duration) -> Self134 pub fn from_saturating_duration(duration: Duration) -> Self { 135 // A few notes: The largest number we can represent as a ratio is u32::MAX but we can 136 // sometimes represent much smaller numbers. 137 // 138 // We can represent duration as `millis+a/b` (where a < b, b > 0). 139 // We must thus bound b with `b·millis + (b-1) <= u32::MAX` or 140 // > `0 < b <= (u32::MAX + 1)/(millis + 1)` 141 // Corollary: millis <= u32::MAX 142 143 const MILLIS_BOUND: u128 = u32::max_value() as u128; 144 145 let millis = duration.as_millis().min(MILLIS_BOUND); 146 let submillis = (duration.as_nanos() % 1_000_000) as u32; 147 148 let max_b = if millis > 0 { 149 ((MILLIS_BOUND + 1)/(millis + 1)) as u32 150 } else { 151 MILLIS_BOUND as u32 152 }; 153 let millis = millis as u32; 154 155 let (a, b) = Self::closest_bounded_fraction(max_b, submillis, 1_000_000); 156 Self::from_numer_denom_ms(a + b*millis, b) 157 } 158 159 /// The numerator and denominator of the delay in milliseconds. 160 /// 161 /// This is guaranteed to be an exact conversion if the `Delay` was previously created with the 162 /// `from_numer_denom_ms` constructor. numer_denom_ms(self) -> (u32, u32)163 pub fn numer_denom_ms(self) -> (u32, u32) { 164 (*self.ratio.numer(), *self.ratio.denom()) 165 } 166 from_ratio(ratio: Ratio<u32>) -> Self167 pub(crate) fn from_ratio(ratio: Ratio<u32>) -> Self { 168 Delay { ratio } 169 } 170 into_ratio(self) -> Ratio<u32>171 pub(crate) fn into_ratio(self) -> Ratio<u32> { 172 self.ratio 173 } 174 175 /// Given some fraction, compute an approximation with denominator bounded. 176 /// 177 /// Note that `denom_bound` bounds nominator and denominator of all intermediate 178 /// approximations and the end result. closest_bounded_fraction(denom_bound: u32, nom: u32, denom: u32) -> (u32, u32)179 fn closest_bounded_fraction(denom_bound: u32, nom: u32, denom: u32) -> (u32, u32) { 180 use std::cmp::Ordering::{self, *}; 181 assert!(0 < denom); 182 assert!(0 < denom_bound); 183 assert!(nom < denom); 184 185 // Avoid a few type troubles. All intermediate results are bounded by `denom_bound` which 186 // is in turn bounded by u32::MAX. Representing with u64 allows multiplication of any two 187 // values without fears of overflow. 188 189 // Compare two fractions whose parts fit into a u32. 190 fn compare_fraction((an, ad): (u64, u64), (bn, bd): (u64, u64)) -> Ordering { 191 (an*bd).cmp(&(bn*ad)) 192 } 193 194 // Computes the nominator of the absolute difference between two such fractions. 195 fn abs_diff_nom((an, ad): (u64, u64), (bn, bd): (u64, u64)) -> u64 { 196 let c0 = an*bd; 197 let c1 = ad*bn; 198 199 let d0 = c0.max(c1); 200 let d1 = c0.min(c1); 201 d0 - d1 202 } 203 204 let exact = (u64::from(nom), u64::from(denom)); 205 // The lower bound fraction, numerator and denominator. 206 let mut lower = (0u64, 1u64); 207 // The upper bound fraction, numerator and denominator. 208 let mut upper = (1u64, 1u64); 209 // The closest approximation for now. 210 let mut guess = (u64::from(nom*2 > denom), 1u64); 211 212 // loop invariant: ad, bd <= denom_bound 213 // iterates the Farey sequence. 214 loop { 215 // Break if we are done. 216 if compare_fraction(guess, exact) == Equal { 217 break; 218 } 219 220 // Break if next Farey number is out-of-range. 221 if u64::from(denom_bound) - lower.1 < upper.1 { 222 break; 223 } 224 225 // Next Farey approximation n between a and b 226 let next = (lower.0 + upper.0, lower.1 + upper.1); 227 // if F < n then replace the upper bound, else replace lower. 228 if compare_fraction(exact, next) == Less { 229 upper = next; 230 } else { 231 lower = next; 232 } 233 234 // Now correct the closest guess. 235 // In other words, if |c - f| > |n - f| then replace it with the new guess. 236 // This favors the guess with smaller denominator on equality. 237 238 // |g - f| = |g_diff_nom|/(gd*fd); 239 let g_diff_nom = abs_diff_nom(guess, exact); 240 // |n - f| = |n_diff_nom|/(nd*fd); 241 let n_diff_nom = abs_diff_nom(next, exact); 242 243 // The difference |n - f| is smaller than |g - f| if either the integral part of the 244 // fraction |n_diff_nom|/nd is smaller than the one of |g_diff_nom|/gd or if they are 245 // the same but the fractional part is larger. 246 if match (n_diff_nom/next.1).cmp(&(g_diff_nom/guess.1)) { 247 Less => true, 248 Greater => false, 249 // Note that the nominator for the fractional part is smaller than its denominator 250 // which is smaller than u32 and can't overflow the multiplication with the other 251 // denominator, that is we can compare these fractions by multiplication with the 252 // respective other denominator. 253 Equal => compare_fraction((n_diff_nom%next.1, next.1), (g_diff_nom%guess.1, guess.1)) == Less, 254 } { 255 guess = next; 256 } 257 } 258 259 (guess.0 as u32, guess.1 as u32) 260 } 261 } 262 263 impl From<Delay> for Duration { from(delay: Delay) -> Self264 fn from(delay: Delay) -> Self { 265 let ratio = delay.into_ratio(); 266 let ms = ratio.to_integer(); 267 let rest = ratio.numer() % ratio.denom(); 268 let nanos = (u64::from(rest) * 1_000_000) / u64::from(*ratio.denom()); 269 Duration::from_millis(ms.into()) + Duration::from_nanos(nanos) 270 } 271 } 272 273 #[cfg(test)] 274 mod tests { 275 use super::{Delay, Duration, Ratio}; 276 277 #[test] simple()278 fn simple() { 279 let second = Delay::from_numer_denom_ms(1000, 1); 280 assert_eq!(Duration::from(second), Duration::from_secs(1)); 281 } 282 283 #[test] fps_30()284 fn fps_30() { 285 let thirtieth = Delay::from_numer_denom_ms(1000, 30); 286 let duration = Duration::from(thirtieth); 287 assert_eq!(duration.as_secs(), 0); 288 assert_eq!(duration.subsec_millis(), 33); 289 assert_eq!(duration.subsec_nanos(), 33_333_333); 290 } 291 292 #[test] duration_outlier()293 fn duration_outlier() { 294 let oob = Duration::from_secs(0xFFFF_FFFF); 295 let delay = Delay::from_saturating_duration(oob); 296 assert_eq!(delay.numer_denom_ms(), (0xFFFF_FFFF, 1)); 297 } 298 299 #[test] duration_approx()300 fn duration_approx() { 301 let oob = Duration::from_millis(0xFFFF_FFFF) + Duration::from_micros(1); 302 let delay = Delay::from_saturating_duration(oob); 303 assert_eq!(delay.numer_denom_ms(), (0xFFFF_FFFF, 1)); 304 305 let inbounds = Duration::from_millis(0xFFFF_FFFF) - Duration::from_micros(1); 306 let delay = Delay::from_saturating_duration(inbounds); 307 assert_eq!(delay.numer_denom_ms(), (0xFFFF_FFFF, 1)); 308 309 let fine = Duration::from_millis(0xFFFF_FFFF/1000) + Duration::from_micros(0xFFFF_FFFF%1000); 310 let delay = Delay::from_saturating_duration(fine); 311 // Funnily, 0xFFFF_FFFF is divisble by 5, thus we compare with a `Ratio`. 312 assert_eq!(delay.into_ratio(), Ratio::new(0xFFFF_FFFF, 1000)); 313 } 314 315 #[test] precise()316 fn precise() { 317 // The ratio has only 32 bits in the numerator, too imprecise to get more than 11 digits 318 // correct. But it may be expressed as 1_000_000/3 instead. 319 let exceed = Duration::from_secs(333) + Duration::from_nanos(333_333_333); 320 let delay = Delay::from_saturating_duration(exceed); 321 assert_eq!(Duration::from(delay), exceed); 322 } 323 324 325 #[test] small()326 fn small() { 327 // Not quite a delay of `1 ms`. 328 let delay = Delay::from_numer_denom_ms(1 << 16, (1 << 16) + 1); 329 let duration = Duration::from(delay); 330 assert_eq!(duration.as_millis(), 0); 331 // Not precisely the original but should be smaller than 0. 332 let delay = Delay::from_saturating_duration(duration); 333 assert_eq!(delay.into_ratio().to_integer(), 0); 334 } 335 } 336