Skip to main content

cursive_image/image/compatibility/
jpeg.rs

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