image_optimizer/optimization/png_optimizer.rs
1use anyhow::{Context, Result};
2use image::{DynamicImage, ImageFormat};
3use std::fs;
4use std::path::Path;
5
6use crate::cli::Cli;
7
8/// Optimizes a PNG image using oxipng with zopfli compression.
9///
10/// This function uses oxipng with zopfli compression for maximum PNG optimization.
11/// It enables alpha optimization and safe chunk stripping for the best balance
12/// between file size reduction and compatibility.
13///
14/// # Arguments
15///
16/// * `input_path` - Path to the source PNG file
17/// * `output_path` - Path where the optimized PNG will be written
18/// * `_args` - CLI configuration (currently unused for PNG optimization)
19/// * `resized_img` - Optional pre-resized image data; if None, copies from `input_path`
20///
21/// # Returns
22///
23/// Returns `Ok(())` on successful optimization.
24///
25/// # Errors
26///
27/// Returns an error if:
28/// - PNG optimization fails
29/// - File I/O operations fail (copying or saving)
30/// - Image format conversion fails
31pub fn optimize_png(
32 input_path: &Path,
33 output_path: &Path,
34 _args: &Cli,
35 resized_img: Option<DynamicImage>,
36) -> Result<()> {
37 if let Some(img) = resized_img {
38 img.save_with_format(output_path, ImageFormat::Png)?;
39 } else {
40 fs::copy(input_path, output_path)?;
41 }
42
43 let options = oxipng::Options {
44 optimize_alpha: true,
45 strip: oxipng::StripChunks::Safe,
46 ..Default::default()
47 };
48
49 let input_file = oxipng::InFile::Path(output_path.to_path_buf());
50 let output_file = oxipng::OutFile::Path {
51 path: Some(output_path.to_path_buf()),
52 preserve_attrs: true,
53 };
54
55 oxipng::optimize(&input_file, &output_file, &options).context("Failed to optimize PNG")?;
56
57 Ok(())
58}