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