diff --git a/server-rs/crates/api-server/src/editor_project.rs b/server-rs/crates/api-server/src/editor_project.rs index eed90fe6b..7114f9952 100644 --- a/server-rs/crates/api-server/src/editor_project.rs +++ b/server-rs/crates/api-server/src/editor_project.rs @@ -4669,14 +4669,20 @@ pub async fn snap_editor_image_to_pixel_art( // 下载耗掉的时间会如实从规整预算里扣除,而不是让规整重新获得完整 30s。 let snapped_image = snap_editor_pixel_art_strict(Arc::new(source_image), Some(processing_deadline)).await?; - let (width, height) = image::load_from_memory(snapped_image.bytes.as_slice()) - .map(|image| (image.width(), image.height())) - .map_err(|error| { - editor_pixel_art_snap_failure( - StatusCode::INTERNAL_SERVER_ERROR, - format!("完美像素输出不是有效 PNG:{error}"), - ) - })?; + // 中文注释:只读 PNG 头取尺寸,不做整图解码。这里的字节是本进程 snapper 刚 encode + // 出来的内存缓冲:没有网络截断风险,编码失败会在上一步直接返回 Err,所以不需要像 + // editor_postprocessed_alpha_matches_delivery_dimensions 那样为识别截断像素数据而 + // 整图解码——那条路径处理的是 provider 经网络送来的图。在这里整图解码是纯浪费: + // 输出上限 8294400 像素,一次解码要多分配约 33 MiB 并全量 inflate,而且发生在 + // CPU 许可之外。 + let mut reader = image::ImageReader::new(Cursor::new(snapped_image.bytes.as_slice())); + reader.set_format(image::ImageFormat::Png); + let (width, height) = reader.into_dimensions().map_err(|error| { + editor_pixel_art_snap_failure( + StatusCode::INTERNAL_SERVER_ERROR, + format!("完美像素输出不是有效 PNG:{error}"), + ) + })?; let task_id = build_prefixed_uuid_id("pixel-art-snap-"); // 中文注释:尺寸已经在上一步取完,snapped_image 之后不再使用,所以按值移交给 _owned @@ -10866,6 +10872,9 @@ mod tests { // 中文注释:持久化必须走按值移交的 _owned 版本。借用版内部会 clone 一整份 // 输出图片,在同步路径上和原图同时驻留内存。 "persist_editor_generated_image(", + // 中文注释:取输出尺寸只读 PNG 头。整图解码发生在 CPU 许可之外, + // 对 8294400 像素上限的输出要多分配约 33 MiB,且不换来任何保证。 + "image::load_from_memory", ], ); }