diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/workflow/extract.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/workflow/extract.rs index a5f08e433..08d8cffc4 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/workflow/extract.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/workflow/extract.rs @@ -54,15 +54,20 @@ async fn raw_extract_inner( .strip_prefix("data:") .and_then(|value| value.strip_suffix(";base64")) .unwrap_or("image/png"); - if !mime.eq_ignore_ascii_case("image/png") { - return Err("图片分离请求只支持 PNG 源图".to_string()); - } + let is_png = mime.eq_ignore_ascii_case("image/png"); let image_bytes = base64::engine::general_purpose::STANDARD .decode(data.trim()) .map_err(|error| format!("解码源图失败:{error}"))?; if image_bytes.is_empty() { return Err("源图不能为空".to_string()); } + let image_bytes = if is_png { + image_bytes + } else { + tokio::task::spawn_blocking(move || normalize_source_image_to_png(image_bytes)) + .await + .map_err(|error| format!("转换源图任务失败:{error}"))?? + }; let client = crate::http_client::agc_main_site_client_builder() .build() .map_err(|error| format!("创建图片编辑客户端失败:{error}"))?; @@ -122,6 +127,35 @@ async fn raw_extract_inner( result } +fn normalize_source_image_to_png(image_bytes: Vec) -> Result, String> { + let image = image::load_from_memory(&image_bytes) + .map_err(|error| format!("解码非 PNG 源图失败:{error}"))?; + let mut png_bytes = Vec::new(); + image + .write_to(&mut Cursor::new(&mut png_bytes), image::ImageFormat::Png) + .map_err(|error| format!("将源图转换为 PNG 失败:{error}"))?; + Ok(png_bytes) +} + +#[cfg(test)] +mod tests { + use super::normalize_source_image_to_png; + use image::{DynamicImage, ImageFormat, Rgb, RgbImage}; + use std::io::Cursor; + + #[test] + fn converts_jpeg_source_to_png() { + let image = DynamicImage::ImageRgb8(RgbImage::from_pixel(2, 2, Rgb([255, 0, 0]))); + let mut jpeg = Vec::new(); + image + .write_to(&mut Cursor::new(&mut jpeg), ImageFormat::Jpeg) + .expect("encode jpeg"); + + let png = normalize_source_image_to_png(jpeg).expect("convert jpeg"); + assert_eq!(&png[..8], b"\x89PNG\r\n\x1a\n"); + } +} + pub(super) async fn write_processed_image( processed_url: String, target: PathBuf,