Skip to content

Commit eb91c04

Browse files
fix(cli): preserve original image bytes when asset!() requests no transform (#5642)
1 parent f717a8e commit eb91c04

1 file changed

Lines changed: 60 additions & 0 deletions

File tree

packages/cli/src/opt/image.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,20 @@ pub(crate) fn process_image(
99
source: &Path,
1010
output_path: &Path,
1111
) -> anyhow::Result<()> {
12+
// Copy verbatim if no transform is requested (#5642)
13+
if image_options.format() == ImageFormat::Unknown
14+
&& image_options.size() == ImageSize::Automatic
15+
{
16+
std::fs::copy(source, output_path).with_context(|| {
17+
format!(
18+
"Failed to copy image from {} to {}",
19+
source.display(),
20+
output_path.display()
21+
)
22+
})?;
23+
return Ok(());
24+
}
25+
1226
let mut image = image::ImageReader::new(std::io::Cursor::new(&*std::fs::read(source)?))
1327
.with_guessed_format()
1428
.context("Failed to guess image format")?
@@ -141,3 +155,49 @@ pub(crate) fn compress_jpg(image: DynamicImage, output_location: &Path) -> anyho
141155
w.write_all(&jpeg_bytes)?;
142156
Ok(())
143157
}
158+
159+
#[cfg(test)]
160+
mod tests {
161+
use super::*;
162+
163+
// Write a PNG with detectable chunk/compression to verify byte-for-byte copying
164+
fn write_source_png(path: &Path) {
165+
let file = std::fs::File::create(path).unwrap();
166+
let w = BufWriter::new(file);
167+
let mut encoder = png::Encoder::new(w, 4, 4);
168+
encoder.set_color(png::ColorType::Rgba);
169+
encoder.set_depth(png::BitDepth::Eight);
170+
encoder.set_compression(png::Compression::Best);
171+
encoder
172+
.add_text_chunk("Comment".to_string(), "dioxus-asset-test".to_string())
173+
.unwrap();
174+
let mut writer = encoder.write_header().unwrap();
175+
// 4x4 RGBA pixels with varied colors.
176+
let mut data = Vec::with_capacity(4 * 4 * 4);
177+
for i in 0..16u8 {
178+
data.extend_from_slice(&[i.wrapping_mul(16), 255 - i, i, 255]);
179+
}
180+
writer.write_image_data(&data).unwrap();
181+
writer.finish().unwrap();
182+
}
183+
184+
// Test for #5642: `asset!()` must copy bytes verbatim
185+
#[test]
186+
fn default_options_preserve_source_bytes() {
187+
let dir = std::env::temp_dir().join(format!("dx-image-opt-test-{}", std::process::id()));
188+
std::fs::create_dir_all(&dir).unwrap();
189+
let source = dir.join("source.png");
190+
let output = dir.join("output.png");
191+
write_source_png(&source);
192+
193+
process_image(&ImageAssetOptions::default(), &source, &output).unwrap();
194+
195+
assert_eq!(
196+
std::fs::read(&source).unwrap(),
197+
std::fs::read(&output).unwrap(),
198+
"asset!() with default options must copy the source bytes verbatim, not re-encode"
199+
);
200+
201+
std::fs::remove_dir_all(&dir).ok();
202+
}
203+
}

0 commit comments

Comments
 (0)