1#![cfg_attr(feature = "docs", doc(cfg(feature = "png")))]
9#![cfg(feature = "png")]
10#![allow(unused_variables)]
11
12use std::io::Cursor;
14
15use zune_core::bit_depth::BitDepth;
16use zune_core::bytestream::{ZByteReaderTrait, ZByteWriterTrait};
17use zune_core::colorspace::ColorSpace;
18use zune_core::log::warn;
19use zune_core::options::EncoderOptions;
20use zune_core::result::DecodingResult;
21use zune_png::error::PngDecodeErrors;
22use zune_png::*;
23
24pub use zune_png::PngDecoder;
25use crate::codecs::{create_options_for_encoder, ImageFormat};
26use crate::errors::ImageErrors;
27use crate::errors::ImageErrors::ImageDecodeErrors;
28use crate::errors::ImgEncodeErrors::ImageEncodeErrors;
29use crate::frame::Frame;
30use crate::image::Image;
31use crate::metadata::ImageMetadata;
32use crate::traits::{DecodeInto, DecoderTrait, EncoderTrait};
33
34impl<T> DecoderTrait for PngDecoder<T>
35where
36 T: ZByteReaderTrait
37{
38 fn decode(&mut self) -> Result<Image, ImageErrors> {
39 let metadata = self.read_headers()?.unwrap();
40
41 let depth = self.depth().unwrap();
42 let (width, height) = self.dimensions().unwrap();
43 let colorspace = self.colorspace().unwrap();
44
45 if self.is_animated() && self.options().png_decode_animated() {
46 let info = self.info().unwrap().clone();
49 let mut output = vec![0; info.width * info.height * colorspace.num_components()];
52 let mut output_frames = Vec::new();
53 while self.more_frames() {
54 self.decode_headers()?;
55
56 let mut frame = self.frame_info().unwrap();
57 if frame.dispose_op == DisposeOp::Previous {
58 frame.dispose_op = DisposeOp::None;
62 }
63 let pix = self.decode()?;
64 match pix {
65 DecodingResult::U8(pix) => {
66 post_process_image(
67 &info,
68 colorspace,
69 &frame,
70 &pix,
71 None,
72 &mut output,
73 None,
74 )?;
75 let duration = f64::from(frame.delay_num) / f64::from(frame.delay_denom);
76 let im_frame = Frame::from_u8(&output, colorspace, usize::from(frame.delay_num),usize::from(frame.delay_denom));
78 output_frames.push(im_frame);
79 }
80 _ => return Err(ImageDecodeErrors("The current image is an Animated PNG but has a depth of 16, such an image isn't supported".to_string()))
81 }
82 }
83 let mut image = Image::new_frames(output_frames, depth, width, height, colorspace);
84 image.metadata = metadata;
85
86 Ok(image)
87 } else {
88 let pixels = self
89 .decode()
90 .map_err(<error::PngDecodeErrors as Into<ImageErrors>>::into)?;
91
92 let mut image = match pixels {
93 DecodingResult::U8(data) => Image::from_u8(&data, width, height, colorspace),
94 DecodingResult::U16(data) => Image::from_u16(&data, width, height, colorspace),
95 _ => unreachable!()
96 };
97 image.metadata = metadata;
99
100 Ok(image)
101 }
102 }
103 fn dimensions(&self) -> Option<(usize, usize)> {
104 self.dimensions()
105 }
106
107 fn out_colorspace(&self) -> ColorSpace {
108 self.colorspace().unwrap()
109 }
110
111 fn name(&self) -> &'static str {
112 "PNG Decoder"
113 }
114
115 fn read_headers(&mut self) -> Result<Option<ImageMetadata>, crate::errors::ImageErrors> {
116 self.decode_headers()
117 .map_err(<error::PngDecodeErrors as Into<ImageErrors>>::into)?;
118
119 let (width, height) = self.dimensions().unwrap();
120 let depth = self.depth().unwrap();
121
122 let mut metadata = ImageMetadata {
123 format: Some(ImageFormat::PNG),
124 colorspace: self.colorspace().unwrap(),
125 depth: depth,
126 width: width,
127 height: height,
128 default_gamma: self.info().unwrap().gamma,
129 ..Default::default()
130 };
131 #[cfg(feature = "metadata")]
132 {
133 let info = self.info().unwrap();
134 if let Some(exif) = &info.exif {
136 metadata.parse_raw_exif(exif)
137 }
138 }
139 if let Some(icc) = &self.info().unwrap().icc_profile {
141 metadata.set_icc_chunk(icc.to_owned());
142 }
143
144 Ok(Some(metadata))
145 }
146}
147
148impl From<zune_png::error::PngDecodeErrors> for ImageErrors {
149 fn from(from: zune_png::error::PngDecodeErrors) -> Self {
150 let err = format!("png: {from:?}");
151
152 ImageErrors::ImageDecodeErrors(err)
153 }
154}
155
156#[derive(Default)]
157pub struct PngEncoder {
158 options: Option<EncoderOptions>
159}
160
161impl PngEncoder {
162 pub fn new() -> PngEncoder {
163 PngEncoder::default()
164 }
165 pub fn new_with_options(options: EncoderOptions) -> PngEncoder {
166 PngEncoder {
167 options: Some(options)
168 }
169 }
170}
171
172impl EncoderTrait for PngEncoder {
173 fn name(&self) -> &'static str {
174 "PNG encoder"
175 }
176
177 fn encode_inner<T: ZByteWriterTrait>(
178 &mut self, image: &Image, sink: T
179 ) -> Result<usize, ImageErrors> {
180 let options = create_options_for_encoder(self.options, image);
181
182 let frame = &image.to_u8_be()[0];
183
184 let mut encoder = zune_png::PngEncoder::new(frame, options);
185
186 #[allow(unused_mut)]
187 let mut buf: Cursor<Vec<u8>> = std::io::Cursor::new(vec![]);
188
189 #[cfg(feature = "metadata")]
190 {
191 use exif::experimental::Writer;
192
193 if !options.strip_metadata() {
194 if let Some(fields) = &image.metadata.exif {
195 let mut writer = Writer::new();
196
197 for metadatum in fields {
198 writer.push_field(metadatum);
199 }
200 let result = writer.write(&mut buf, false);
201 if result.is_ok() {
202 encoder.add_exif_segment(buf.get_ref());
203 } else {
204 warn!("Writing exif failed {:?}", result);
205 }
206 }
207 }
208 }
209 encoder
210 .encode(sink)
211 .map_err(|e| ImageErrors::EncodeErrors(ImageEncodeErrors(format!("{:?}", e))))
212 }
213
214 fn supported_colorspaces(&self) -> &'static [ColorSpace] {
215 &[
216 ColorSpace::Luma,
217 ColorSpace::LumaA,
218 ColorSpace::RGB,
219 ColorSpace::RGBA
220 ]
221 }
222
223 fn format(&self) -> ImageFormat {
224 ImageFormat::PNG
225 }
226
227 fn supported_bit_depth(&self) -> &'static [BitDepth] {
228 &[BitDepth::Eight, BitDepth::Sixteen]
229 }
230
231 fn default_depth(&self, depth: BitDepth) -> BitDepth {
232 match depth {
233 BitDepth::Sixteen | BitDepth::Float32 => BitDepth::Sixteen,
234 _ => BitDepth::Eight
235 }
236 }
237 fn set_options(&mut self, opts: EncoderOptions) {
238 self.options = Some(opts)
239 }
240}
241
242impl<T> DecodeInto for PngDecoder<T>
243where
244 T: ZByteReaderTrait
245{
246 type BufferType = u8;
247
248 fn decode_into(&mut self, buffer: &mut [Self::BufferType]) -> Result<(), ImageErrors> {
249 self.decode_into(buffer)
250 .map_err(<PngDecodeErrors as Into<ImageErrors>>::into)?;
251
252 Ok(())
253 }
254
255 fn decode_output_buffer_size(&mut self) -> Result<usize, ImageErrors> {
256 self.decode_headers()
257 .map_err(<PngDecodeErrors as Into<ImageErrors>>::into)?;
258
259 Ok(self.output_buffer_size().unwrap())
261 }
262}
263
264#[cfg(test)]
265mod tests {
266 use zune_core::bytestream::ZCursor;
267 use zune_core::colorspace::ColorSpace;
268 use zune_png::PngDecoder;
269
270 use crate::codecs::png::PngEncoder;
271 use crate::codecs::ImageFormat;
272 use crate::image::Image;
273 use crate::traits::DecodeInto;
274
275 fn create_png() -> Vec<u8> {
276 let encoder = PngEncoder::new();
277 let image = Image::fill(10_u8, ColorSpace::RGB, 100, 100);
278 image.write_to_vec(ImageFormat::PNG).unwrap()
279 }
280 #[test]
281 fn test_png_decode_into() {
282 let mut output = vec![0; 100 * 100 * 3];
283 let img = create_png();
284 let mut decoder = PngDecoder::new(ZCursor::new(&img));
285 decoder.decode_into(&mut output).unwrap();
286 }
287}