1#![cfg_attr(feature = "docs", doc(cfg(feature = "ppm")))]
9#![cfg(feature = "ppm")]
10use zune_core::bit_depth::BitDepth;
12use zune_core::bytestream::{ZByteReaderTrait, ZByteWriterTrait};
13use zune_core::colorspace::ColorSpace;
14use zune_core::options::EncoderOptions;
15use zune_core::result::DecodingResult;
16pub use zune_ppm::{PPMDecodeErrors, PPMDecoder, PPMEncodeErrors, PPMEncoder as PPMEnc};
17
18use crate::codecs::{create_options_for_encoder, ImageFormat};
19use crate::errors::{ImageErrors, ImgEncodeErrors};
20use crate::image::Image;
21use crate::metadata::ImageMetadata;
22use crate::traits::{DecoderTrait, EncoderTrait};
23
24#[derive(Copy, Clone, Default)]
25pub struct PPMEncoder {
26 options: Option<EncoderOptions>
27}
28
29impl PPMEncoder {
30 pub fn new() -> PPMEncoder {
31 PPMEncoder { options: None }
32 }
33 pub fn new_with_options(options: EncoderOptions) -> PPMEncoder {
34 PPMEncoder {
35 options: Some(options)
36 }
37 }
38}
39
40impl EncoderTrait for PPMEncoder {
41 fn name(&self) -> &'static str {
42 "PPM Encoder"
43 }
44
45 fn encode_inner<T: ZByteWriterTrait>(
46 &mut self, image: &Image, sink: T
47 ) -> Result<usize, ImageErrors> {
48 let options = create_options_for_encoder(self.options, image);
49
50 let data = &image.to_u8()[0];
51
52 let ppm_encoder = PPMEnc::new(data, options);
53
54 let bytes_written = ppm_encoder
55 .encode(sink)
56 .map_err(<PPMEncodeErrors as Into<ImgEncodeErrors>>::into)?;
57
58 Ok(bytes_written)
59 }
60
61 fn supported_colorspaces(&self) -> &'static [ColorSpace] {
62 &[
63 ColorSpace::RGB, ColorSpace::Luma, ColorSpace::RGBA, ColorSpace::LumaA
67 ]
68 }
69
70 fn format(&self) -> ImageFormat {
71 ImageFormat::PPM
72 }
73
74 fn supported_bit_depth(&self) -> &'static [BitDepth] {
75 &[BitDepth::Sixteen, BitDepth::Eight]
76 }
77
78 fn default_depth(&self, depth: BitDepth) -> BitDepth {
82 match depth {
83 BitDepth::Float32 | BitDepth::Sixteen => BitDepth::Sixteen,
84 _ => BitDepth::Eight
85 }
86 }
87 fn set_options(&mut self, opts: EncoderOptions) {
88 self.options = Some(opts)
89 }
90}
91
92impl<T> DecoderTrait for PPMDecoder<T>
93where
94 T: ZByteReaderTrait
95{
96 fn decode(&mut self) -> Result<Image, ImageErrors> {
97 let pixels = self.decode()?;
98
99 let depth = self.bit_depth().unwrap();
100 let (width, height) = self.dimensions().unwrap();
101 let colorspace = self.colorspace().unwrap();
102
103 let mut image = match pixels {
104 DecodingResult::U8(data) => Image::from_u8(&data, width, height, colorspace),
105 DecodingResult::U16(data) => Image::from_u16(&data, width, height, colorspace),
106 DecodingResult::F32(data) => Image::from_f32(&data, width, height, colorspace),
107 _ => unreachable!()
108 };
109
110 image.metadata.format = Some(ImageFormat::PPM);
112
113 Ok(image)
114 }
115
116 fn dimensions(&self) -> Option<(usize, usize)> {
117 self.dimensions()
118 }
119
120 fn out_colorspace(&self) -> ColorSpace {
121 self.colorspace().unwrap_or(ColorSpace::Unknown)
122 }
123
124 fn name(&self) -> &'static str {
125 "PPM Decoder"
126 }
127
128 fn read_headers(&mut self) -> Result<Option<ImageMetadata>, crate::errors::ImageErrors> {
129 self.decode_headers()
130 .map_err(<PPMDecodeErrors as Into<ImageErrors>>::into)?;
131
132 let (width, height) = self.dimensions().unwrap();
133 let depth = self.bit_depth().unwrap();
134
135 let metadata = ImageMetadata {
136 format: Some(ImageFormat::PPM),
137 colorspace: self.colorspace().unwrap(),
138 depth: depth,
139 width: width,
140 height: height,
141 ..Default::default()
142 };
143
144 Ok(Some(metadata))
145 }
146}
147
148#[cfg(feature = "ppm")]
149impl From<zune_ppm::PPMDecodeErrors> for ImageErrors {
150 fn from(from: zune_ppm::PPMDecodeErrors) -> Self {
151 let err = format!("ppm: {from:?}");
152
153 ImageErrors::ImageDecodeErrors(err)
154 }
155}
156
157#[cfg(feature = "ppm")]
158impl From<zune_ppm::PPMEncodeErrors> for ImgEncodeErrors {
159 fn from(error: zune_ppm::PPMEncodeErrors) -> Self {
160 let err = format!("ppm: {error:?}");
161
162 ImgEncodeErrors::ImageEncodeErrors(err)
163 }
164}