zune_image/codecs/
webp.rs1#![cfg(feature = "webp")]
2
3use std::io::{BufRead, Seek, Write};
4
5use image_webp::{ColorType, DecodingError, WebPEncoder};
6use jxl_oxide::color::WhitePoint::E;
7use zune_core::bit_depth::BitDepth;
8use zune_core::bytestream::ZByteWriterTrait;
9use zune_core::colorspace::ColorSpace;
10use zune_core::log::{trace, warn};
11
12use crate::codecs::{create_options_for_encoder, ImageFormat};
13use crate::errors::{ImageErrors, ImgEncodeErrors};
14use crate::image::Image;
15use crate::metadata::{AlphaState, ImageMetadata};
16use crate::traits::{DecoderTrait, EncoderTrait};
17
18pub struct ZuneWebpDecoder<T: BufRead + Seek> {
19 inner: image_webp::WebPDecoder<T>
20}
21impl<T: BufRead + Seek> ZuneWebpDecoder<T> {
22 pub fn new(r: T) -> Result<Self, ImageErrors> {
23 let decoder = image_webp::WebPDecoder::new(r).map_err(|e| {
24 println!("{:?}", e);
25 ImageErrors::ImageDecodeErrors(e.to_string())
26 })?;
27 return Ok(ZuneWebpDecoder { inner: decoder });
28 }
29}
30impl<T: BufRead + Seek> DecoderTrait for ZuneWebpDecoder<T> {
31 fn decode(&mut self) -> Result<Image, ImageErrors> {
32 let (w, h) = self.dimensions().expect("Failed to determine dimensions");
33 let mut raw_pixels = vec![
34 0_u8;
35 self.inner
36 .output_buffer_size()
37 .expect("Max output size greater than usize max")
38 ];
39 self.inner
40 .read_image(&mut raw_pixels)
41 .map_err(|e| ImageErrors::ImageDecodeErrors(e.to_string()))?;
42
43 let mut img = Image::from_u8(&raw_pixels, w, h, self.out_colorspace());
44 img.metadata.format = Some(ImageFormat::WEBP);
45
46 Ok(img)
47 }
48
49 fn dimensions(&self) -> Option<(usize, usize)> {
50 let (w, h) = self.inner.dimensions();
51
52 Some((w as usize, h as usize))
53 }
54
55 fn out_colorspace(&self) -> ColorSpace {
56 match self.inner.has_alpha() {
59 true => ColorSpace::RGBA,
60 false => ColorSpace::RGB
61 }
62 }
63
64 fn name(&self) -> &'static str {
65 "Webp Decoder (image-rs)"
66 }
67 fn read_headers(&mut self) -> Result<Option<ImageMetadata>, ImageErrors> {
68 let (w, h) = self.dimensions().expect("Failed to determine dimensions");
69 return Ok(Some(ImageMetadata {
70 color_trc: None,
71 default_gamma: None,
72 width: w,
73 height: h,
74 colorspace: self.out_colorspace(),
75 depth: BitDepth::Eight,
76 format: Some(ImageFormat::WEBP),
77 alpha: AlphaState::NonPreMultiplied,
78 #[cfg(feature = "metadata")]
79 exif: None,
80 icc_chunk: None,
81 is_linear: false
82 }));
83 }
84}
85
86pub struct ZuneWebpImageEncoder {}
87impl ZuneWebpImageEncoder {
88 pub fn new() -> Self {
89 Self {}
90 }
91}
92impl EncoderTrait for ZuneWebpImageEncoder {
93 fn name(&self) -> &'static str {
94 "Webp Image Encoder"
95 }
96
97 fn encode_inner<T: ZByteWriterTrait>(
98 &mut self, image: &Image, mut sink: T
99 ) -> Result<usize, ImageErrors> {
100 trace!("Starting webp encoder");
101 let options = create_options_for_encoder(None, image);
103 let data = &image.to_u8()[0];
104 let mut output = Vec::with_capacity(data.len());
105
106 let mut encoder = WebPEncoder::new(&mut output);
107
108 #[cfg(feature = "metadata")]
109 {
110 use exif::experimental::Writer;
111
112 let mut inner_buff = std::io::Cursor::new(Vec::with_capacity(300));
113 if !options.strip_metadata() {
114 trace!("Writing exif data");
115 if let Some(fields) = &image.metadata.exif {
116 let mut writer = Writer::new();
117
118 for metadatum in fields {
119 writer.push_field(metadatum);
120 }
121 let result = writer.write(&mut inner_buff, false);
122 if result.is_ok() {
123 encoder.set_exif_metadata(inner_buff.into_inner())
124 } else {
125 warn!("Writing exif failed {:?}", result);
126 }
127 }
128 }
129 }
130
131 let color_type = match options.colorspace() {
132 ColorSpace::RGBA => ColorType::Rgba8,
133 ColorSpace::RGB => ColorType::Rgb8,
134 ColorSpace::Luma => ColorType::L8,
135 ColorSpace::LumaA => ColorType::La8,
136 _ => {
137 return Err(ImageErrors::EncodeErrors(
138 ImgEncodeErrors::UnsupportedColorspace(
139 options.colorspace(),
140 self.supported_colorspaces()
141 )
142 ))
143 }
144 };
145 encoder
146 .encode(
147 data,
148 options.width() as u32,
149 options.height() as u32,
150 color_type
151 )
152 .map_err(|e| ImageErrors::EncodeErrors(ImgEncodeErrors::Generic(e.to_string())))?;
153
154 sink.write_all_bytes(output.as_ref())?;
155 Ok(output.len())
156 }
157 fn supported_colorspaces(&self) -> &'static [ColorSpace] {
158 &[
159 ColorSpace::RGB,
160 ColorSpace::RGBA,
161 ColorSpace::Luma,
162 ColorSpace::LumaA
163 ]
164 }
165 fn format(&self) -> ImageFormat {
166 ImageFormat::WEBP
167 }
168 fn supported_bit_depth(&self) -> &'static [BitDepth] {
169 &[BitDepth::Eight]
170 }
171 fn default_depth(&self, depth: BitDepth) -> BitDepth {
172 BitDepth::Eight
173 }
174}