Rust使用image crate调整图片透明度时编码错误的解决
Rust image crate 保存图片编码错误解决
使用Rust的image crate遍历目录中的JPG、PNG格式图片,调整透明度为50%后保存时,出现如下编码错误:
Failed to save image: Encoding(EncodingError { format: Exact(Png), underlying: Some(ColorType(Rgba32F)) })
错误原因
该错误的核心是Rgba32F颜色类型不被PNG编码器支持。原始代码中调用.to_rgba32f()将图片转为32位浮点RGBA格式,但image crate的PNG编码器仅支持8位整数格式(如Rgba8)的图像保存。
原始代码
use clap::Parser; use std::{process, thread}; #[derive(Parser,Debug)] #[command(author,version,about,long_about=None)] struct Args { #[arg(long,value_hint=clap::ValueHint::DirPath, default_value="./")] picture_dir: std::path::PathBuf, #[arg(long, default_value="300")] draw_time: u64, #[arg(long, default_value="3")] start_delay: u64, #[arg(long)] dry_run: bool, } fn main() { let args = Args::parse(); println!("{}", args.picture_dir.as_os_str().to_str().unwrap()); let dir = args.picture_dir.as_os_str().to_str().unwrap(); let dir = format!("{}/*.*", dir); let extensions_supported = vec!("png","jpg","bmp"); for path in glob::glob(&dir).expect("Failed to list directory") { let path = path.unwrap(); let copy_from_path = path.clone(); let file_name = path.file_name().unwrap(); let mut cachepath = std::env::temp_dir(); cachepath.push(file_name.to_str().unwrap()); let str_path = cachepath.to_str().unwrap(); let path_extension = path.extension().unwrap().to_str().unwrap(); if !extensions_supported.contains(&path_extension) { println!("We don't support that file type"); continue; } println!("{}", str_path); let start = std::time::Instant::now(); // 启动外部程序 let cmd_str = format!("cmd.exe /C clipstudiopaint.exe {}", str_path); let mut child: Option<process::Child> = None; if args.dry_run { println!("{}",cmd_str); } else { std::fs::copy(copy_from_path,cachepath.clone()).expect("Failed to create temporary file"); let cache_image_path = cachepath.clone(); let cache_image_path = cache_image_path.to_str().unwrap(); let save_image_path = cachepath.clone(); let mut image = image::open(cache_image_path) .expect("Failed to open image for editing").to_rgba32f(); image.pixels_mut().for_each(|p| p[3] /= 2.0); image.save(save_image_path.to_str().unwrap()).expect("Failed to save image"); child = Some(process::Command::new("cmd") .arg("/C") .arg("clipstudiopaint.exe") .arg(cachepath.to_str().unwrap()) .spawn() .expect("Failed to run clipstudiopaint")); } // 等待程序加载 loop { if start.elapsed().as_secs() > args.start_delay { break; } } let start = std::time::Instant::now(); // 等待指定绘制时间 println!("Starting timer"); loop { if start.elapsed().as_secs() > args.draw_time { break; } } // 终止进程 if !args.dry_run { child.unwrap().kill().expect("Failed to kill childprocess"); std::fs::remove_file(cachepath).expect("Failed to remove temp file"); } let start = std::time::Instant::now(); loop { if start.elapsed().as_secs() > 2 { break; } } } }
修正后的关键代码片段
std::fs::copy(copy_from_path,cachepath.clone()).expect("Failed to create temporary file"); let image_edit_path = image_edit_path.clone(); let image_edit_path = image_edit_path.to_str().unwrap(); let save_image_path = cachepath.clone(); println!("Opening: {} for editing", image_edit_path); let mut image = image::open(image_edit_path) .expect("Failed to open image for editing"); let mut target_image = image::DynamicImage::new_rgba8(image.width(), image.height()); let mut target_image = target_image.to_rgba8(); target_image.pixels_mut().for_each(|p| *p = image::Rgba{0: [246, 244, 237, 255]}); let mut image = image.to_rgba8(); image.pixels_mut().for_each(|p| p[3] = 127); // 127对应50%透明度 image::imageops::overlay(&mut target_image, &image, 0, 0); let target_image = image::DynamicImage::ImageRgba8(target_image); target_image.save(save_image_path.to_str().unwrap()).expect("Failed to save image");
修正要点
- 替换Rgba32F格式为编码器支持的Rgba8(8位整数RGBA)格式,彻底解决编码不兼容问题
- 直接设置alpha通道的整数值(127对应50%透明度,可按需调整)
- 通过创建纯色背景图并叠加处理后的图像,确保最终图像格式完全符合PNG编码器要求
内容的提问来源于stack exchange,提问作者J. Martin
相关产品推荐
相关产品推荐

