逐步使用Avif代替Webp图片
文章目录
背景
之前博客中出现的图片逐步从PNG和JPG迁移到了webp格式,处理webp格式图片的代码在webp-image这个项目中。
最近看到各个平台都在拥抱avif格式,比如内存峰值降60%+,动图加载快75%:爱奇艺图片库一次从'能用'到'极致'的跨越和下一代图片格式 AVIF 在 vivo 社区的落地实践,所以想尝试一下使用avif格式来处理图片,看看能不能进一步优化图片的体积和加载速度。
这次因为也没多少行代码,不想再创建一个新的github项目了,直接帖在博客里了,后续有时间再创建一个项目。
处理图片为avif的源码
[package]
name = "avif-image"
version = "0.1.0"
edition = "2024"
[dependencies]
arboard = "3.6.1"
image = "0.25.6"
uuid = { version = "1.18.0", features = ["v4"] }
ravif = "0.13.0"
rgb = "0.8"
[profile.dev]
panic = "abort"
[profile.release]
opt-level = "z"
lto = true
codegen-units = 1
panic = "abort"
strip = true
use arboard::Clipboard;
use image::DynamicImage;
use ravif::{Encoder, Img};
use rgb::RGBA8;
use std::fs;
use std::path::Path;
fn encode_and_save_avif(dyn_img: &DynamicImage, avif_path: &Path) {
let rgba = dyn_img.to_rgba8();
let width = rgba.width() as usize;
let height = rgba.height() as usize;
let pixels: Vec<RGBA8> = rgba
.pixels()
.map(|p| RGBA8 {
r: p[0],
g: p[1],
b: p[2],
a: p[3],
})
.collect();
let result = Encoder::new()
.with_quality(80.0)
.with_speed(6)
.encode_rgba(Img::new(&pixels, width, height))
.expect("avif编码失败");
fs::write(avif_path, &result.avif_file).expect("写入avif文件失败");
}
fn main() {
let mut clipboard = Clipboard::new().expect("无法访问粘贴板");
// 1. 优先尝试读取文件路径
if let Ok(text) = clipboard.get().file_list() {
if !text.is_empty() {
let path = text[0].clone();
if path.exists() && path.is_file() {
if let Ok(dyn_img) = image::open(&path) {
let avif_path = path.with_extension("avif");
encode_and_save_avif(&dyn_img, &avif_path);
println!("已保存: {}", avif_path.display());
return;
} else {
println!("文件不是有效图片: {}", path.display());
return;
}
}
}
}
// 2. 尝试读取粘贴板中的图片内容
if let Ok(img_data) = clipboard.get_image() {
let width = img_data.width as u32;
let height = img_data.height as u32;
let bytes = img_data.bytes.into_owned();
let dyn_img = DynamicImage::ImageRgba8(
image::RgbaImage::from_vec(width, height, bytes).expect("图片数据无效"),
);
let uuid = uuid::Uuid::new_v4().to_string();
let avif_filename = format!("{}.avif", &uuid[..6]);
let avif_path = Path::new(&avif_filename);
encode_and_save_avif(&dyn_img, avif_path);
println!("已保存: {}", avif_filename);
return;
}
println!("粘贴板无图片内容,也无有效图片文件路径");
}
文章作者 pengxiaochao
上次更新 2026-05-07
许可协议 不允许任何形式转载。