axum-image 0.2.0

Image extractors for Axum
Documentation
use std::{
    fs::File,
    io::{BufWriter, Write},
};

/// Create an image buffer given an input of `bytes`.
pub fn save_image_buffer(
    path: &str,
    bytes: Vec<u8>,
    format: crate::ImageFormat,
) -> std::io::Result<()> {
    let pre_img_buffer = match image::load_from_memory(&bytes) {
        Ok(i) => i,
        Err(_) => {
            return Err(std::io::Error::new(
                std::io::ErrorKind::InvalidData,
                "Image failed",
            ));
        }
    };

    let file = File::create(path)?;
    let mut writer = BufWriter::new(file);

    if pre_img_buffer.write_to(&mut writer, format).is_err() {
        return Err(std::io::Error::new(
            std::io::ErrorKind::Other,
            "Image conversion failed",
        ));
    };

    Ok(())
}

const WEBP_ENCODE_QUALITY: f32 = 85.0;

fn build_webp_buffer(bytes: Vec<u8>, quality: Option<f32>) -> std::io::Result<Vec<u8>> {
    let img = match image::load_from_memory(&bytes) {
        Ok(i) => i,
        Err(_) => {
            return Err(std::io::Error::new(
                std::io::ErrorKind::InvalidData,
                "Image failed",
            ));
        }
    };

    let encoder = match webp::Encoder::from_image(&img) {
        Ok(e) => e,
        Err(e) => {
            return Err(std::io::Error::new(
                std::io::ErrorKind::Other,
                e.to_string(),
            ));
        }
    };

    let mem = encoder.encode(quality.unwrap_or(WEBP_ENCODE_QUALITY));
    Ok(mem.to_vec())
}

/// Create a WEBP image buffer given an input of `bytes`.
///
/// This function should be used over [`save_image_buffer`] for WEBP because the `image`
/// library only supports lossless WEBP, while this function uses libwebp for lossy encoding.
pub fn save_webp_buffer(path: &str, bytes: Vec<u8>, quality: Option<f32>) -> std::io::Result<()> {
    if std::fs::write(path, &build_webp_buffer(bytes, quality)?).is_err() {
        return Err(std::io::Error::new(
            std::io::ErrorKind::Other,
            "Image conversion failed",
        ));
    };

    Ok(())
}

/// [`save_webp_buffer`], but the file is *also* gzip encoded
pub fn save_webp_buffer_gz(
    path: &str,
    bytes: Vec<u8>,
    quality: Option<f32>,
) -> std::io::Result<()> {
    let data = build_webp_buffer(bytes, quality)?;

    let mut encoder = flate2::write::GzEncoder::new(Vec::new(), flate2::Compression::best());
    encoder.write_all(&data).unwrap();

    if std::fs::write(path, &encoder.finish().unwrap()).is_err() {
        return Err(std::io::Error::new(
            std::io::ErrorKind::Other,
            "Image conversion failed",
        ));
    };

    Ok(())
}