固定抽帧像素格式并收敛动作帧图像处理重复代码
ffmpeg 抽帧显式指定 -pix_fmt rgb24,消除 to_rgb8 截断 alpha 的隐患 抽出 compute_contain_dimensions 与 image_format_from_mime 供两条帧路径共用 尺寸已匹配时跳过无效的 Triangle 重采样 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -4287,6 +4287,8 @@ fn extract_video_frame_to_png(
|
||||
input_path.to_string_lossy().as_ref(),
|
||||
"-frames:v",
|
||||
"1",
|
||||
"-pix_fmt",
|
||||
"rgb24",
|
||||
"-f",
|
||||
"image2",
|
||||
output_path.to_string_lossy().as_ref(),
|
||||
@@ -4386,13 +4388,7 @@ fn prepare_editor_character_animation_bgfilter_input(
|
||||
target_width: u32,
|
||||
target_height: u32,
|
||||
) -> Result<FinalizedAnimationFrame, AppError> {
|
||||
let image_format = match mime_type {
|
||||
"image/png" => Some(ImageFormat::Png),
|
||||
"image/jpeg" | "image/jpg" => Some(ImageFormat::Jpeg),
|
||||
"image/webp" => Some(ImageFormat::WebP),
|
||||
_ => None,
|
||||
};
|
||||
let image = match image_format {
|
||||
let image = match image_format_from_mime(mime_type) {
|
||||
Some(format) => image::load_from_memory_with_format(source, format),
|
||||
None => image::load_from_memory(source),
|
||||
}
|
||||
@@ -4404,19 +4400,13 @@ fn prepare_editor_character_animation_bgfilter_input(
|
||||
})?
|
||||
.to_rgb8();
|
||||
|
||||
let target_width = target_width.max(1);
|
||||
let target_height = target_height.max(1);
|
||||
let source_width = image.width().max(1);
|
||||
let source_height = image.height().max(1);
|
||||
let scale = (target_width as f32 / source_width as f32)
|
||||
.min(target_height as f32 / source_height as f32);
|
||||
let draw_width = ((source_width as f32 * scale).round() as u32)
|
||||
.max(1)
|
||||
.min(target_width);
|
||||
let draw_height = ((source_height as f32 * scale).round() as u32)
|
||||
.max(1)
|
||||
.min(target_height);
|
||||
let resized = image::imageops::resize(&image, draw_width, draw_height, FilterType::Triangle);
|
||||
let (draw_width, draw_height) =
|
||||
compute_contain_dimensions(image.width(), image.height(), target_width, target_height);
|
||||
let resized = if (draw_width, draw_height) == (image.width(), image.height()) {
|
||||
image
|
||||
} else {
|
||||
image::imageops::resize(&image, draw_width, draw_height, FilterType::Triangle)
|
||||
};
|
||||
|
||||
let mut encoded = Vec::new();
|
||||
let encoder = PngEncoder::new(&mut encoded);
|
||||
@@ -4448,13 +4438,7 @@ fn finalize_animation_frame_payload(
|
||||
frame_height: u32,
|
||||
apply_chroma_key: bool,
|
||||
) -> Result<FinalizedAnimationFrame, AppError> {
|
||||
let image_format = match mime_type {
|
||||
"image/png" => Some(ImageFormat::Png),
|
||||
"image/jpeg" | "image/jpg" => Some(ImageFormat::Jpeg),
|
||||
"image/webp" => Some(ImageFormat::WebP),
|
||||
_ => None,
|
||||
};
|
||||
let mut image = match image_format {
|
||||
let mut image = match image_format_from_mime(mime_type) {
|
||||
Some(format) => image::load_from_memory_with_format(source, format),
|
||||
None => image::load_from_memory(source),
|
||||
}
|
||||
@@ -4501,8 +4485,39 @@ fn finalize_animation_frame_payload(
|
||||
|
||||
fn contain_rgba_image(source: &RgbaImage, target_width: u32, target_height: u32) -> RgbaImage {
|
||||
let mut canvas = RgbaImage::from_pixel(target_width, target_height, Rgba([0, 0, 0, 0]));
|
||||
let source_width = source.width().max(1);
|
||||
let source_height = source.height().max(1);
|
||||
let (draw_width, draw_height) =
|
||||
compute_contain_dimensions(source.width(), source.height(), target_width, target_height);
|
||||
let offset_x = ((target_width - draw_width) / 2) as i64;
|
||||
let offset_y = ((target_height - draw_height) / 2) as i64;
|
||||
if (draw_width, draw_height) == (source.width(), source.height()) {
|
||||
image::imageops::overlay(&mut canvas, source, offset_x, offset_y);
|
||||
} else {
|
||||
let resized =
|
||||
image::imageops::resize(source, draw_width, draw_height, FilterType::Triangle);
|
||||
image::imageops::overlay(&mut canvas, &resized, offset_x, offset_y);
|
||||
}
|
||||
canvas
|
||||
}
|
||||
|
||||
fn image_format_from_mime(mime_type: &str) -> Option<ImageFormat> {
|
||||
match mime_type {
|
||||
"image/png" => Some(ImageFormat::Png),
|
||||
"image/jpeg" | "image/jpg" => Some(ImageFormat::Jpeg),
|
||||
"image/webp" => Some(ImageFormat::WebP),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_contain_dimensions(
|
||||
source_width: u32,
|
||||
source_height: u32,
|
||||
target_width: u32,
|
||||
target_height: u32,
|
||||
) -> (u32, u32) {
|
||||
let target_width = target_width.max(1);
|
||||
let target_height = target_height.max(1);
|
||||
let source_width = source_width.max(1);
|
||||
let source_height = source_height.max(1);
|
||||
let scale = (target_width as f32 / source_width as f32)
|
||||
.min(target_height as f32 / source_height as f32);
|
||||
let draw_width = ((source_width as f32 * scale).round() as u32)
|
||||
@@ -4511,11 +4526,7 @@ fn contain_rgba_image(source: &RgbaImage, target_width: u32, target_height: u32)
|
||||
let draw_height = ((source_height as f32 * scale).round() as u32)
|
||||
.max(1)
|
||||
.min(target_height);
|
||||
let resized = image::imageops::resize(source, draw_width, draw_height, FilterType::Triangle);
|
||||
let offset_x = ((target_width - draw_width) / 2) as i64;
|
||||
let offset_y = ((target_height - draw_height) / 2) as i64;
|
||||
image::imageops::overlay(&mut canvas, &resized, offset_x, offset_y);
|
||||
canvas
|
||||
(draw_width, draw_height)
|
||||
}
|
||||
|
||||
async fn load_media_source_payload(
|
||||
|
||||
Reference in New Issue
Block a user