Skip to main content

cursive_image/image/
jpeg.rs

1use super::{format::*, image::*, stream::*};
2
3use {
4    flate2::{read::*, *},
5    std::{
6        fs::*,
7        io::{self, Read},
8        path::*,
9    },
10    zune_jpeg::{
11        zune_core::{colorspace::*, options::*},
12        *,
13    },
14};
15
16impl Image {
17    /// Constructor.
18    pub fn new_owned_from_jpeg_file<PathT>(path: PathT, format: ImageFormat, compress: bool) -> io::Result<Self>
19    where
20        PathT: AsRef<Path>,
21    {
22        let mut decoder = open_jpeg(path, format)?;
23        let data = decoder.decode().map_err(io::Error::other)?;
24        let info = decoder.info().ok_or_else(|| io::Error::other("missing JPEG info"))?;
25
26        // Compress
27        let data = if compress {
28            let mut compressed = Vec::default();
29            zlib(io::Cursor::new(data)).read_to_end(&mut compressed)?;
30            compressed
31        } else {
32            data
33        };
34
35        Ok(Self::new_owned(data, compress, format, (info.width, info.height)))
36    }
37
38    /// Constructor.
39    pub fn new_stream_from_jpeg_file<PathT>(path: PathT, format: ImageFormat) -> io::Result<Self>
40    where
41        PathT: AsRef<Path>,
42    {
43        let mut decoder = open_jpeg(path.as_ref(), format)?;
44        decoder.decode_headers().map_err(io::Error::other)?; // required in order to get info
45        let info = decoder.info().ok_or_else(|| io::Error::other("missing JPEG info"))?;
46
47        Ok(Self::new_stream(JpegImageStream::new(path.as_ref().into(), format), format, (info.width, info.height)))
48    }
49}
50
51//
52// JpegImageStream
53//
54
55struct JpegImageStream {
56    path: PathBuf,
57    format: ImageFormat,
58}
59
60impl JpegImageStream {
61    fn new(path: PathBuf, format: ImageFormat) -> Self {
62        Self { path, format }
63    }
64}
65
66impl ImageStream for JpegImageStream {
67    fn open(&self) -> io::Result<(Box<dyn io::Read>, bool)> {
68        let mut decoder = open_jpeg(&self.path, self.format)?;
69
70        // We must load the entire file into memory to decode it
71        let data = decoder.decode().map_err(io::Error::other)?;
72        let reader = io::Cursor::new(data);
73
74        Ok((Box::new(reader), false))
75    }
76}
77
78// Utils
79
80fn open_jpeg<PathT>(path: PathT, format: ImageFormat) -> io::Result<JpegDecoder<io::BufReader<File>>>
81where
82    PathT: AsRef<Path>,
83{
84    let options = DecoderOptions::new_fast().jpeg_set_out_colorspace(match format {
85        ImageFormat::PNG => return Err(io::Error::other("unsupported format")),
86        ImageFormat::RGB => ColorSpace::RGB,
87        ImageFormat::RGBA => ColorSpace::RGBA,
88    });
89
90    Ok(JpegDecoder::new_with_options(io::BufReader::new(File::open(path)?), options))
91}
92
93fn zlib<ReadT>(reader: ReadT) -> ZlibEncoder<ReadT>
94where
95    ReadT: io::Read,
96{
97    ZlibEncoder::new(reader, Compression::default())
98}