diff --git a/packages/cli/src/opt/image.rs b/packages/cli/src/opt/image.rs index 1d6044811e..bbf687a280 100644 --- a/packages/cli/src/opt/image.rs +++ b/packages/cli/src/opt/image.rs @@ -9,6 +9,20 @@ pub(crate) fn process_image( source: &Path, output_path: &Path, ) -> anyhow::Result<()> { + // Copy verbatim if no transform is requested (#5642) + if image_options.format() == ImageFormat::Unknown + && image_options.size() == ImageSize::Automatic + { + std::fs::copy(source, output_path).with_context(|| { + format!( + "Failed to copy image from {} to {}", + source.display(), + output_path.display() + ) + })?; + return Ok(()); + } + let mut image = image::ImageReader::new(std::io::Cursor::new(&*std::fs::read(source)?)) .with_guessed_format() .context("Failed to guess image format")? @@ -141,3 +155,49 @@ pub(crate) fn compress_jpg(image: DynamicImage, output_location: &Path) -> anyho w.write_all(&jpeg_bytes)?; Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + // Write a PNG with detectable chunk/compression to verify byte-for-byte copying + fn write_source_png(path: &Path) { + let file = std::fs::File::create(path).unwrap(); + let w = BufWriter::new(file); + let mut encoder = png::Encoder::new(w, 4, 4); + encoder.set_color(png::ColorType::Rgba); + encoder.set_depth(png::BitDepth::Eight); + encoder.set_compression(png::Compression::Best); + encoder + .add_text_chunk("Comment".to_string(), "dioxus-asset-test".to_string()) + .unwrap(); + let mut writer = encoder.write_header().unwrap(); + // 4x4 RGBA pixels with varied colors. + let mut data = Vec::with_capacity(4 * 4 * 4); + for i in 0..16u8 { + data.extend_from_slice(&[i.wrapping_mul(16), 255 - i, i, 255]); + } + writer.write_image_data(&data).unwrap(); + writer.finish().unwrap(); + } + + // Test for #5642: `asset!()` must copy bytes verbatim + #[test] + fn default_options_preserve_source_bytes() { + let dir = std::env::temp_dir().join(format!("dx-image-opt-test-{}", std::process::id())); + std::fs::create_dir_all(&dir).unwrap(); + let source = dir.join("source.png"); + let output = dir.join("output.png"); + write_source_png(&source); + + process_image(&ImageAssetOptions::default(), &source, &output).unwrap(); + + assert_eq!( + std::fs::read(&source).unwrap(), + std::fs::read(&output).unwrap(), + "asset!() with default options must copy the source bytes verbatim, not re-encode" + ); + + std::fs::remove_dir_all(&dir).ok(); + } +}