Skip to main content

zune_image/codecs/
ppm.rs

1/*
2 * Copyright (c) 2023.
3 *
4 * This software is free software;
5 *
6 * You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license
7 */
8#![cfg_attr(feature = "docs", doc(cfg(feature = "ppm")))]
9#![cfg(feature = "ppm")]
10//! PPM and PAL image decoder and encoder
11use 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,  // p7
64            ColorSpace::Luma, // p7
65            ColorSpace::RGBA, // p7
66            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    /// Get appropriate depth for this image
79    ///
80    /// Float32 types, they are converted to Float16 types
81    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        // set metadata details
111        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}