use turbojpeg;
use crate::image::{Image, ImageSize};
pub struct ImageDecoder {
pub decompressor: turbojpeg::Decompressor,
}
pub struct ImageEncoder {
pub compressor: turbojpeg::Compressor,
}
impl Default for ImageDecoder {
fn default() -> Self {
Self::new()
}
}
impl Default for ImageEncoder {
fn default() -> Self {
Self::new()
}
}
impl ImageEncoder {
pub fn new() -> ImageEncoder {
let compressor = match turbojpeg::Compressor::new() {
Ok(c) => c,
Err(e) => panic!("Error creating compressor: {}", e),
};
ImageEncoder { compressor }
}
pub fn encode(&mut self, image: Image) -> Vec<u8> {
let image_data = match image.data.as_slice() {
Some(d) => d,
None => panic!("Image data is not contiguous"),
};
let _image = turbojpeg::Image {
pixels: image_data,
width: image.image_size().width,
pitch: 3 * image.image_size().width,
height: image.image_size().height,
format: turbojpeg::PixelFormat::RGB,
};
match self.compressor.compress_to_vec(_image) {
Ok(d) => d,
Err(e) => panic!("Error compressing image: {}", e),
}
}
pub fn set_quality(&mut self, quality: i32) {
self.compressor.set_quality(quality)
}
}
impl ImageDecoder {
pub fn new() -> ImageDecoder {
let decompressor = match turbojpeg::Decompressor::new() {
Ok(d) => d,
Err(e) => panic!("Error creating decompressor: {}", e),
};
ImageDecoder { decompressor }
}
pub fn read_header(&mut self, jpeg_data: &[u8]) -> ImageSize {
let header = match self.decompressor.read_header(jpeg_data) {
Ok(h) => h,
Err(e) => panic!("Error reading header: {}", e),
};
ImageSize {
width: header.width,
height: header.height,
}
}
pub fn decode(&mut self, jpeg_data: &[u8]) -> Image {
let image_size: ImageSize = self.read_header(jpeg_data);
let mut pixels = vec![0; image_size.height * image_size.width * 3];
let image = turbojpeg::Image {
pixels: pixels.as_mut_slice(),
width: image_size.width,
pitch: 3 * image_size.width, height: image_size.height,
format: turbojpeg::PixelFormat::RGB,
};
match self.decompressor.decompress(jpeg_data, image) {
Ok(_) => {}
Err(e) => panic!("Error decompressing image: {}", e),
};
Image::new(image_size, pixels)
}
}
#[cfg(test)]
mod tests {
use crate::io::jpeg::{ImageDecoder, ImageEncoder};
#[test]
fn image_decoder() {
let jpeg_data = std::fs::read("tests/data/dog.jpeg").unwrap();
let image_size = ImageDecoder::new().read_header(&jpeg_data);
assert_eq!(image_size.width, 258);
assert_eq!(image_size.height, 195);
let image = ImageDecoder::new().decode(&jpeg_data);
assert_eq!(image.image_size().width, 258);
assert_eq!(image.image_size().height, 195);
assert_eq!(image.num_channels(), 3);
}
#[test]
fn image_encoder() {
let jpeg_data_fs = std::fs::read("tests/data/dog.jpeg").unwrap();
let image = ImageDecoder::new().decode(&jpeg_data_fs);
let jpeg_data = ImageEncoder::new().encode(image);
let image_back = ImageDecoder::new().decode(&jpeg_data);
assert_eq!(image_back.image_size().width, 258);
assert_eq!(image_back.image_size().height, 195);
assert_eq!(image_back.num_channels(), 3);
}
}