基于rust与flutter开发的图像处理雏形
之前在写shine_http的时候就考虑过要写一个做图片处理的包。
原因在于image在一个app是最常用到的资源,大量的图片,不光会消耗庞大的内存,也会给dart很大的压力。
所以决定用rust做个图形的插件包。
本篇由于刚开始,只暂时实现analyze图片,resize图片。目前所有处理的图片都以webp格式的编码返回,不过也可能考虑改为全面支持avif。
图像处理库的简单需求
上传方向
graph TD
APP --> 上传需求 --> 获取本地图片or输入url --> 尺寸处理,滤镜风格化选择,统一的压缩格式 -->返回带有原图信息的图片和处理过的图片信息类 --> 上传
使用方向
graph TD
获取图片 --> 解析图片 --> 缓存缩略图片 --> 显示压缩图 --> 点击显示原图 --> 切换原图,缓存原图,移除缩略图缓存 --> 回收资源
Frist - 解析图片
解析图片我采取的思路是通过rust下载图片并解析为dart的uint8list的类型,通过frb的零拷贝方式返回给dart后,通过image.memory来显示,原先我还根据图片类型进行了判断,不同格式的图片进行decoder。
不过尝试了gif,png,jpeg,webp等多种主流格式后,发现并不需要对应的decoder,所以就直接解析返回了,代码也就非常简单了。
#[tokio::main(flavor = "current_thread")]
pub async fn analyze_image(url:String) -> Result<ZeroCopyBuffer<Vec<u8>>> {
let res = reqwest::get(url)
.await
.expect("图片下载失败");
let bytes = res.bytes().await.expect("转换字节码错误").to_vec();
Ok(ZeroCopyBuffer(bytes))
}
如果后续测试有发现解析字节流的方式不可行,那么根据判断更新一下对应的解码代码应该就可以了。
Second - 上传图片
上传的目前简单写了一些图片格式的逻辑,其他格式其实处理也不难,这里不写只是因为做个最小型验证。
#[tokio::main(flavor = "current_thread")]
pub async fn compression_image(pixel: Vec<u8>,width:u32,height:u32) -> Result<ZeroCopyBuffer<Vec<u8>>>{
if let Ok(o) = guess_format(&pixel) {
match o {
ImageFormat::Jpeg | ImageFormat::Pnm | ImageFormat::Tiff | ImageFormat::Tga | ImageFormat::Dds | ImageFormat::Bmp | ImageFormat::Ico | ImageFormat::Hdr | ImageFormat::OpenExr | ImageFormat::Farbfeld => {
let converted = image::load_from_memory(&pixel).expect("图片加载内存失败").resize(width, height,FilterType::CatmullRom);
default_write_image(converted).await
},
ImageFormat::Gif => {
let gifdecoder = GifDecoder::new(pixel.as_slice())?;
let decoder_frames = gifdecoder.into_frames();
let frames = decoder_frames.collect_frames()?;
animation_write_image(frames,(width,height)).await
}
ImageFormat::WebP => {
Err(anyhow!("WebP逻辑待编写"))
}
ImageFormat::Png => {
Err(anyhow!("png逻辑待编写"))
}
ImageFormat::Avif => {
Err(anyhow!("avif逻辑待编写"))
}
_ => Err(anyhow!("我是未被支持的格式"))
}
} else {
Err(anyhow!("无法识别图片格式"))
}
}
主逻辑在这,具体的事物处理逻辑被分为了default_write_image
与animation_write_image
,前者是普通的单图处理,后者是多帧的动图处理。
由于webp,png,avif是同时具有单图与动图的格式,所以可以单独匹配处理。
Third - 结尾
既然简单的编写完了,那么我们肯定得赶紧试试,逻辑是否是通的。
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text("You're running on"),
FutureBuilder<List<dynamic>>(
future: Future.wait([imageU8]),
builder: (context, snap) {
final data = snap.data;
if (data == null) return const CircularProgressIndicator();
return Container(
child: Column(
children: [
Text("rust处理"),
Image.memory(
data[0],
width: 100,
height: 100,
),
],
),
);
},
),
Text("dart处理"),
Image.network(
"https://isparta.github.io/compare-webp/image/gif_webp/webp/2.webp",
width: 100,
height: 100,
)
],
),
),
ok,let's go!
嗯,看着没毛病。
compression_image
测试也没问题,但是忘了录屏了,有点懒得重写了。
由于这个功能还得基于image.memory封装成plugin,目前这样使用肯定不够实用的,所以就摆烂到下一个篇章再展示吧!
嗯嗯,我感觉到宇宙中有只闪耀宝可梦诞生了,我得去蹲闪光拿下!!!就这样,bye了个bye~