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}