Skip to content

Commit 84e25cc

Browse files
authored
add meme backflip (#25)
1 parent 074db30 commit 84e25cc

File tree

2 files changed

+95
-0
lines changed

2 files changed

+95
-0
lines changed

meme_generator_memes/src/memes.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ mod atri_pillow;
1717
mod ayachi_holdsign;
1818
mod ba_say;
1919
mod back_to_work;
20+
mod backflip;
2021
mod bad_news;
2122
mod batitle;
2223
mod beat_head;
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use core::f32;
2+
use skia_safe::{Image, Matrix};
3+
4+
use meme_generator_core::error::Error;
5+
use meme_generator_utils::{
6+
builder::InputImage,
7+
encoder::{FrameAlign, GifInfo, make_gif_or_combined_gif},
8+
tools::{local_date, new_surface},
9+
};
10+
11+
use crate::{options::NoOptions, register_meme};
12+
13+
fn backflip(images: Vec<InputImage>, _: Vec<String>, _: NoOptions) -> Result<Vec<u8>, Error> {
14+
let img = &images[0].image;
15+
let img_w = img.width();
16+
let img_h = img.height();
17+
18+
let length = ((img_w * img_w + img_h * img_h) as f32).sqrt();
19+
let frame_w = (length * 1.3) as i32;
20+
let bounce_h = img_h as f32 * 1.2;
21+
let frame_h = (bounce_h + length / 2.0 + img_h as f32 * 0.6) as i32;
22+
let center_x = (frame_w / 2) as f32;
23+
let ground_y = (frame_h - img_h / 2) as f32;
24+
25+
let total_frames = 30;
26+
let bounce1_range = 0.0..0.3;
27+
let bounce2_range = 0.3..0.6;
28+
let rise_range = 0.6..0.65;
29+
let flip_range = 0.65..0.95;
30+
let land_range = 0.95..1.0;
31+
32+
let func = move |i: usize, images: Vec<Image>| {
33+
let t = i as f32 / total_frames as f32;
34+
35+
let (y, angle) = if bounce1_range.contains(&t) {
36+
let local_t = (t - bounce1_range.start) / (bounce1_range.end - bounce1_range.start);
37+
let y = -4.0 * bounce_h * (local_t - 0.5).powi(2) + bounce_h;
38+
let rot = 45.0 * (1.0 - 2.0 * (local_t - 0.5).abs());
39+
(ground_y - y, rot)
40+
} else if bounce2_range.contains(&t) {
41+
let local_t = (t - bounce2_range.start) / (bounce2_range.end - bounce2_range.start);
42+
let y = -4.0 * bounce_h * (local_t - 0.5).powi(2) + bounce_h;
43+
let rot = -45.0 * (1.0 - 2.0 * (local_t - 0.5).abs());
44+
(ground_y - y, rot)
45+
} else if rise_range.contains(&t) {
46+
let local_t = (t - rise_range.start) / (rise_range.end - rise_range.start);
47+
let y = bounce_h - bounce_h * (1.0 - local_t).powi(2);
48+
(ground_y - y, 0.0)
49+
} else if flip_range.contains(&t) {
50+
let local_t = (t - flip_range.start) / (flip_range.end - flip_range.start);
51+
let y = bounce_h;
52+
let rot = 360.0 * local_t;
53+
(ground_y - y, rot)
54+
} else if land_range.contains(&t) {
55+
let local_t = (t - land_range.start) / (land_range.end - land_range.start);
56+
let y = bounce_h - bounce_h * local_t.powi(2);
57+
(ground_y - y, 0.0)
58+
} else {
59+
(ground_y, 0.0)
60+
};
61+
62+
let img = &images[0];
63+
let mut surface = new_surface((frame_w, frame_h));
64+
let canvas = surface.canvas();
65+
let mut matrix = Matrix::new_identity();
66+
matrix.pre_translate((center_x, y));
67+
matrix.pre_rotate(angle, None);
68+
matrix.pre_translate((-img_w as f32 / 2.0, -img_h as f32 / 2.0));
69+
canvas.concat(&matrix);
70+
canvas.draw_image(img, (0, 0), None);
71+
72+
Ok(surface.image_snapshot())
73+
};
74+
75+
make_gif_or_combined_gif(
76+
images,
77+
func,
78+
GifInfo {
79+
frame_num: total_frames,
80+
duration: 0.05,
81+
},
82+
FrameAlign::ExtendLoop,
83+
)
84+
}
85+
86+
register_meme!(
87+
"backflip",
88+
backflip,
89+
min_images = 1,
90+
max_images = 1,
91+
keywords = &["后空翻"],
92+
date_created = local_date(2025, 6, 29),
93+
date_modified = local_date(2025, 6, 29),
94+
);

0 commit comments

Comments
 (0)