Skip to main content

axum_image/
encode.rs

1use std::{
2    fs::File,
3    io::{BufWriter, Write},
4};
5
6/// Create an image buffer given an input of `bytes`.
7pub fn save_image_buffer(
8    path: &str,
9    bytes: Vec<u8>,
10    format: crate::ImageFormat,
11) -> std::io::Result<()> {
12    let pre_img_buffer = match image::load_from_memory(&bytes) {
13        Ok(i) => i,
14        Err(_) => {
15            return Err(std::io::Error::new(
16                std::io::ErrorKind::InvalidData,
17                "Image failed",
18            ));
19        }
20    };
21
22    let file = File::create(path)?;
23    let mut writer = BufWriter::new(file);
24
25    if pre_img_buffer.write_to(&mut writer, format).is_err() {
26        return Err(std::io::Error::new(
27            std::io::ErrorKind::Other,
28            "Image conversion failed",
29        ));
30    };
31
32    Ok(())
33}
34
35const WEBP_ENCODE_QUALITY: f32 = 85.0;
36
37fn build_webp_buffer(bytes: Vec<u8>, quality: Option<f32>) -> std::io::Result<Vec<u8>> {
38    let img = match image::load_from_memory(&bytes) {
39        Ok(i) => i,
40        Err(_) => {
41            return Err(std::io::Error::new(
42                std::io::ErrorKind::InvalidData,
43                "Image failed",
44            ));
45        }
46    };
47
48    let encoder = match webp::Encoder::from_image(&img) {
49        Ok(e) => e,
50        Err(e) => {
51            return Err(std::io::Error::new(
52                std::io::ErrorKind::Other,
53                e.to_string(),
54            ));
55        }
56    };
57
58    let mem = encoder.encode(quality.unwrap_or(WEBP_ENCODE_QUALITY));
59    Ok(mem.to_vec())
60}
61
62/// Create a WEBP image buffer given an input of `bytes`.
63///
64/// This function should be used over [`save_image_buffer`] for WEBP because the `image`
65/// library only supports lossless WEBP, while this function uses libwebp for lossy encoding.
66pub fn save_webp_buffer(path: &str, bytes: Vec<u8>, quality: Option<f32>) -> std::io::Result<()> {
67    if std::fs::write(path, &build_webp_buffer(bytes, quality)?).is_err() {
68        return Err(std::io::Error::new(
69            std::io::ErrorKind::Other,
70            "Image conversion failed",
71        ));
72    };
73
74    Ok(())
75}
76
77/// [`save_webp_buffer`], but the file is *also* gzip encoded
78pub fn save_webp_buffer_gz(
79    path: &str,
80    bytes: Vec<u8>,
81    quality: Option<f32>,
82) -> std::io::Result<()> {
83    let data = build_webp_buffer(bytes, quality)?;
84
85    let mut encoder = flate2::write::GzEncoder::new(Vec::new(), flate2::Compression::best());
86    encoder.write_all(&data).unwrap();
87
88    if std::fs::write(path, &encoder.finish().unwrap()).is_err() {
89        return Err(std::io::Error::new(
90            std::io::ErrorKind::Other,
91            "Image conversion failed",
92        ));
93    };
94
95    Ok(())
96}