1use std::io::{self, Read, Write};
6use std::ops::Deref;
7
8use image::error::{DecodingError, EncodingError, ImageFormatHint};
9use image::{
10 ColorType, DynamicImage, ImageBuffer, ImageDecoder, ImageError, ImageResult, Rgb, RgbImage,
11 Rgba, RgbaImage,
12};
13use libwebp::boxed::WebpBox;
14
15#[derive(Debug)]
16pub struct WebpReader<R: Read> {
17 reader: Reader<R>,
18 index: usize,
19}
20
21impl<R: Read> WebpReader<R> {
22 fn new(reader: Reader<R>) -> Self {
23 Self { reader, index: 0 }
24 }
25}
26
27impl<R: Read> Read for WebpReader<R> {
28 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
29 let (_, _, _, image_buf) = self.reader.data().unwrap();
30 let new_index = (self.index + buf.len()).min(image_buf.len());
31 let num_written = new_index - self.index;
32 buf[..num_written].copy_from_slice(&image_buf[self.index..new_index]);
33 self.index = new_index;
34 Ok(num_written)
35 }
36}
37
38#[derive(Debug)]
39pub struct WebpDecoder<R: Read> {
40 reader: Reader<R>,
41}
42
43#[allow(clippy::upper_case_acronyms)]
44#[derive(Debug)]
45enum WebpColor {
46 RGB,
47 RGBA,
48}
49
50impl<R: Read> WebpDecoder<R> {
51 pub fn new(reader: R) -> ImageResult<Self> {
52 Self::new_inner(reader, WebpColor::RGBA)
53 }
54
55 pub fn new_rgba(reader: R) -> ImageResult<Self> {
56 Self::new_inner(reader, WebpColor::RGBA)
57 }
58
59 pub fn new_rgb(reader: R) -> ImageResult<Self> {
60 Self::new_inner(reader, WebpColor::RGB)
61 }
62
63 fn new_inner(reader: R, colortype: WebpColor) -> ImageResult<Self> {
64 let mut reader = Reader::new(reader, colortype);
65 reader.read_info()?;
66 Ok(Self { reader })
67 }
68}
69
70impl<'a, R: Read + 'a> ImageDecoder<'a> for WebpDecoder<R> {
71 type Reader = WebpReader<R>;
72
73 fn dimensions(&self) -> (u32, u32) {
74 self.reader.info().unwrap()
75 }
76 fn color_type(&self) -> ColorType {
77 match self.reader.colortype {
78 WebpColor::RGB => ColorType::Rgb8,
79 WebpColor::RGBA => ColorType::Rgba8,
80 }
81 }
82 fn into_reader(mut self) -> ImageResult<Self::Reader> {
83 self.reader.read_data()?;
84 Ok(WebpReader::new(self.reader))
85 }
86}
87
88const READER_READ_UNIT: usize = 1024;
89
90#[derive(Debug)]
91struct Reader<R: Read> {
92 reader: R,
93 colortype: WebpColor,
94 buf: Vec<u8>,
95 info: Option<(u32, u32)>,
96 data: Option<(u32, u32, u32, WebpBox<[u8]>)>,
97}
98
99impl<R: Read> Reader<R> {
100 fn new(reader: R, colortype: WebpColor) -> Self {
101 Self {
102 reader,
103 colortype,
104 buf: Vec::new(),
105 info: None,
106 data: None,
107 }
108 }
109
110 fn info(&self) -> Option<(u32, u32)> {
111 self.info
112 }
113
114 fn read_info(&mut self) -> io::Result<()> {
115 if self.info.is_some() {
116 return Ok(());
117 }
118 loop {
119 let read_len = self.read_into_buf(READER_READ_UNIT)?;
120 if let Ok(info) = libwebp::WebPGetInfo(&self.buf) {
121 self.info = Some(info);
122 return Ok(());
123 }
124 if read_len == 0 {
125 return Err(io::Error::new(
126 io::ErrorKind::InvalidInput,
127 "Invalid webp header",
128 ));
129 }
130 }
131 }
132
133 fn data(&self) -> Option<(u32, u32, u32, &[u8])> {
134 let (w, h, s, ref buf) = *self.data.as_ref()?;
135 Some((w, h, s, buf))
136 }
137
138 fn read_data(&mut self) -> io::Result<()> {
139 self.read_info()?;
140 if self.data.is_some() {
141 return Ok(());
142 }
143
144 self.reader.read_to_end(&mut self.buf)?;
145 let data = match self.colortype {
146 WebpColor::RGB => libwebp::WebPDecodeRGB(&self.buf).map(|(w, h, b)| (w, h, w * 3, b)),
147 WebpColor::RGBA => libwebp::WebPDecodeRGBA(&self.buf).map(|(w, h, b)| (w, h, w * 4, b)),
148 }
149 .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "Invalid webp data"))?;
150 self.data = Some(data);
151 Ok(())
152 }
153
154 fn read_into_buf(&mut self, by: usize) -> io::Result<usize> {
155 let old_len = self.buf.len();
156 self.buf.resize(old_len + by, 0);
157 let result = self.reader.read(&mut self.buf[old_len..]);
158 self.buf.resize(old_len + result.as_ref().unwrap_or(&0), 0);
159 result
160 }
161}
162
163pub fn webp_load<R: Read>(r: R) -> ImageResult<DynamicImage> {
164 Ok(DynamicImage::ImageRgba8(webp_load_rgba(r)?))
165}
166
167pub fn webp_load_rgba<R: Read>(mut r: R) -> ImageResult<RgbaImage> {
168 let mut buf = Vec::new();
169 r.read_to_end(&mut buf)?;
170 webp_load_rgba_from_memory(&buf)
171}
172
173pub fn webp_load_rgb<R: Read>(mut r: R) -> ImageResult<RgbImage> {
174 let mut buf = Vec::new();
175 r.read_to_end(&mut buf)?;
176 webp_load_rgb_from_memory(&buf)
177}
178
179pub fn webp_load_from_memory(buf: &[u8]) -> ImageResult<DynamicImage> {
180 Ok(DynamicImage::ImageRgba8(webp_load_rgba_from_memory(buf)?))
181}
182
183pub fn webp_load_rgba_from_memory(buf: &[u8]) -> ImageResult<RgbaImage> {
184 let (width, height, buf) = libwebp::WebPDecodeRGBA(buf)
185 .map_err(|_| DecodingError::new(ImageFormatHint::Unknown, "Webp Format Error".to_string()))
186 .map_err(ImageError::Decoding)?;
187 Ok(ImageBuffer::from_raw(width, height, buf.to_vec()).unwrap())
188}
189
190pub fn webp_load_rgb_from_memory(buf: &[u8]) -> ImageResult<RgbImage> {
191 let (width, height, buf) = libwebp::WebPDecodeRGB(buf)
192 .map_err(|_| DecodingError::new(ImageFormatHint::Unknown, "Webp Format Error".to_string()))
193 .map_err(ImageError::Decoding)?;
194 Ok(ImageBuffer::from_raw(width, height, buf.to_vec()).unwrap())
195}
196
197pub fn webp_write<W: Write>(img: &DynamicImage, w: &mut W) -> ImageResult<()> {
198 match img {
199 DynamicImage::ImageRgb8(img) => webp_write_rgb(img, w),
200 DynamicImage::ImageRgba8(img) => webp_write_rgba(img, w),
201 DynamicImage::ImageLuma8(_) => webp_write_rgb(&img.to_rgb8(), w),
202 DynamicImage::ImageLumaA8(_) => webp_write_rgba(&img.to_rgba8(), w),
203 DynamicImage::ImageRgb16(_) => webp_write_rgb(&img.to_rgb8(), w),
204 DynamicImage::ImageRgba16(_) => webp_write_rgba(&img.to_rgba8(), w),
205 DynamicImage::ImageLuma16(_) => webp_write_rgb(&img.to_rgb8(), w),
206 DynamicImage::ImageLumaA16(_) => webp_write_rgba(&img.to_rgba8(), w),
207 DynamicImage::ImageRgb32F(_) => webp_write_rgb(&img.to_rgb8(), w),
208 DynamicImage::ImageRgba32F(_) => webp_write_rgba(&img.to_rgba8(), w),
209 _ => webp_write_rgba(&img.to_rgba8(), w),
210 }
211}
212
213pub fn webp_write_rgba<W: Write, C>(img: &ImageBuffer<Rgba<u8>, C>, w: &mut W) -> ImageResult<()>
214where
215 C: Deref<Target = [u8]>,
216{
217 let buf = libwebp::WebPEncodeRGBA(&img, img.width(), img.height(), img.width() * 4, 75.0)
218 .map_err(|_| EncodingError::new(ImageFormatHint::Unknown, "Webp Format Error".to_string()))
219 .map_err(ImageError::Encoding)?;
220 w.write_all(&buf)?;
221 Ok(())
222}
223
224pub fn webp_write_rgb<W: Write, C>(img: &ImageBuffer<Rgb<u8>, C>, w: &mut W) -> ImageResult<()>
225where
226 C: Deref<Target = [u8]>,
227{
228 let buf = libwebp::WebPEncodeRGB(&img, img.width(), img.height(), img.width() * 3, 75.0)
229 .map_err(|_| EncodingError::new(ImageFormatHint::Unknown, "Webp Format Error".to_string()))
230 .map_err(ImageError::Encoding)?;
231 w.write_all(&buf)?;
232 Ok(())
233}