-
-
Notifications
You must be signed in to change notification settings - Fork 13
/
decoder.rs
129 lines (124 loc) · 3.02 KB
/
decoder.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use crate::anim::settings::AnimSettings;
use crate::anim::Frames;
use crate::app::{AppError, AppResult};
use crate::edit::ImageOps;
use image::Frame;
use std::io::{self, Write};
/* Animation decoder and settings */
pub struct AnimDecoder<'a> {
imageops: ImageOps<'a>,
settings: &'a AnimSettings,
}
impl<'a> AnimDecoder<'a> {
/**
* Create a new AnimDecoder object.
*
* @param imageops
* @param settings
* @return AnimDecoder
*/
pub fn new(imageops: ImageOps<'a>, settings: &'a AnimSettings) -> Self {
Self { imageops, settings }
}
/**
* Update frames to cut the duration.
*
* @param frames
* @param cut
* @param fps
* @return Vector of Frame
*/
fn cut_duration(
frames: &mut Vec<Frame>,
cut: (f32, f32),
fps: u32,
) -> Vec<Frame> {
if cut != (0., 0.) {
let (start, end) = cut;
let frame_delay = 1000_u32.checked_div(fps).unwrap_or_default() as f32;
frames
.drain(
((start / frame_delay) as u32)
.try_into()
.unwrap_or_default()
..frames.len().saturating_sub((end / frame_delay) as usize),
)
.collect()
} else {
frames.to_vec()
}
}
/**
* Update and return the frames.
*
* @param frames
* @return Frames (Result)
*/
pub fn update_frames(mut self, mut frames: Vec<Frame>) -> AppResult<Frames> {
let first_frame = frames.first().ok_or_else(|| {
AppError::FrameError(String::from("No frames found to process"))
})?;
self.imageops
.init(first_frame.clone().into_buffer().dimensions());
let fps = ((1e3 / first_frame.delay().numer_denom_ms().0 as f32)
* self.settings.speed) as u32;
debug!("FPS: {:?}", fps);
let frames = Self::cut_duration(&mut frames, self.settings.cut, fps);
let mut images = Vec::new();
for (i, frame) in frames.iter().enumerate() {
let percentage = ((i + 1) as f64 / frames.len() as f64) * 100.;
info!("Processing the frames... ({:.1}%)\r", percentage);
debug!(
"Processing the frames... ({:.1}%) [{}/{}]\r",
percentage,
i + 1,
frames.len()
);
io::stdout().flush()?;
images.push(
self.imageops
.process(frame.clone().into_buffer())
.get_image(),
);
}
info!("\n");
Ok((images, fps))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::edit::settings::EditSettings;
use crate::image::geometry::Geometry;
use image::{Delay, Frame, RgbaImage};
use pretty_assertions::assert_eq;
#[test]
fn test_anim_decoder() {
let anim_settings = AnimSettings {
cut: (500., 0.),
speed: 2.0,
..Default::default()
};
let mut edit_settings = EditSettings::default();
edit_settings.image.ratio = 2.0;
let frames = AnimDecoder::new(edit_settings.get_imageops(), &anim_settings)
.update_frames(vec![
Frame::from_parts(
RgbaImage::new(1, 1),
0,
0,
Delay::from_numer_denom_ms(1000, 1),
),
Frame::from_parts(
RgbaImage::new(1, 1),
0,
0,
Delay::from_numer_denom_ms(10, 1),
),
])
.unwrap();
assert_eq!(2, frames.1);
assert_eq!(1, frames.0.len());
assert_eq!(Geometry::new(0, 0, 2, 2), frames.0[0].geometry);
}
}