fastpack_compress/backends/
jpeg.rs1#[cfg(not(feature = "jpeg-turbo"))]
2use std::io::Cursor;
3
4#[cfg(not(feature = "jpeg-turbo"))]
5use image::codecs::jpeg::JpegEncoder;
6
7use crate::{
8 compressor::{CompressInput, CompressOutput, Compressor},
9 error::CompressError,
10};
11
12pub struct JpegCompressor;
18
19impl Compressor for JpegCompressor {
20 fn compress(&self, input: &CompressInput<'_>) -> Result<CompressOutput, CompressError> {
21 compress_jpeg(input)
22 }
23
24 fn format_id(&self) -> &'static str {
25 "jpeg"
26 }
27
28 fn file_extension(&self) -> &'static str {
29 "jpg"
30 }
31}
32
33fn compress_jpeg(input: &CompressInput<'_>) -> Result<CompressOutput, CompressError> {
34 let quality = input.quality;
35
36 #[cfg(feature = "jpeg-turbo")]
37 return compress_mozjpeg(input.image, quality);
38
39 #[cfg(not(feature = "jpeg-turbo"))]
40 {
41 let rgb = input.image.to_rgb8();
42 let mut buf = Cursor::new(Vec::new());
43 let mut encoder = JpegEncoder::new_with_quality(&mut buf, quality);
44 encoder.encode(
45 rgb.as_raw(),
46 rgb.width(),
47 rgb.height(),
48 image::ExtendedColorType::Rgb8,
49 )?;
50 Ok(CompressOutput {
51 data: buf.into_inner(),
52 })
53 }
54}
55
56#[cfg(feature = "jpeg-turbo")]
57fn compress_mozjpeg(
58 image: &image::DynamicImage,
59 quality: u8,
60) -> Result<CompressOutput, CompressError> {
61 let rgb = image.to_rgb8();
62 let (width, height) = rgb.dimensions();
63 let raw = rgb.as_raw();
64
65 let mut comp = mozjpeg::Compress::new(mozjpeg::ColorSpace::JCS_RGB);
66 comp.set_size(width as usize, height as usize);
67 comp.set_quality(quality as f32);
68
69 let mut buf = Vec::new();
70 let mut comp = comp
71 .start_compress(&mut buf)
72 .map_err(|e| CompressError::Other(e.to_string()))?;
73 comp.write_scanlines(raw)
74 .map_err(|e| CompressError::Other(e.to_string()))?;
75 comp.finish()
76 .map_err(|e| CompressError::Other(e.to_string()))?;
77 Ok(CompressOutput { data: buf })
78}