zune_image/
traits.rs

1/*
2 * Copyright (c) 2023.
3 *
4 * This software is free software; You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license
5 */
6//! Various encapsulations of common image operations
7//!
8//! This contains traits that allow homogenous implementation of various items in different stages
9//! of the image processing timeline and the use of this via encapsulation without worrying of implementation
10//!
11//! The main traits are divided into the following
12//! - decoding: `DecoderTrait`: Implementing this for a format means the library can decode such formats
13//! - image processing `OperationsTrait`: Implementing this means one can modify the image or extract information from it
14//! - encoding: `EncoderTrait`: Implementing this means the image can be saved to a certain format
15//!
16#![allow(unused_variables)]
17use zune_core::bit_depth::{BitDepth, BitType};
18use zune_core::bytestream::ZReaderTrait;
19use zune_core::colorspace::{ColorSpace, ALL_COLORSPACES};
20use zune_core::log::{trace, warn};
21use zune_core::options::EncoderOptions;
22
23use crate::codecs::ImageFormat;
24use crate::core_filters::colorspace::ColorspaceConv;
25use crate::core_filters::depth::Depth;
26use crate::errors::{ImageErrors, ImageOperationsErrors};
27use crate::image::Image;
28use crate::metadata::AlphaState::NonPreMultiplied;
29use crate::metadata::{AlphaState, ImageMetadata};
30use crate::pipelines::EncodeResult;
31
32/// Encapsulates an image decoder.
33///
34/// All supported image decoders must implement this class
35pub trait DecoderTrait<T: ZReaderTrait> {
36    /// Decode a buffer already in memory
37    ///
38    /// The buffer to be decoded is the one passed
39    /// to the decoder when initializing the decoder
40    ///
41    /// # Returns
42    /// - Image -> Pixels decoded from the image as interleaved pixels.
43    ///
44    /// # Errors
45    ///  - Any image decoding errors will be propagated to the caller.
46    ///
47    /// # Example
48    /// ```no_run
49    /// #[cfg(feature = "jpeg")]
50    /// {
51    ///     use zune_image::traits::DecoderTrait;
52    ///     use zune_jpeg::JpegDecoder;
53    ///     let mut decoder = JpegDecoder::new(&[0xFF,0xD8]);
54    ///
55    ///     decoder.decode().unwrap();
56    /// }
57    /// #[cfg(not(feature="jpeg"))]
58    /// ()
59    /// ```
60    fn decode(&mut self) -> Result<Image, crate::errors::ImageErrors>;
61
62    /// Get width and height of the image
63    ///
64    /// # Returns
65    /// - Some(width,height)
66    /// - None -> If image hasn't been decoded and we can't extract
67    ///  the width and height.
68    fn dimensions(&self) -> Option<(usize, usize)>;
69
70    /// Get the colorspace that the decoded pixels
71    /// are stored in.
72    fn out_colorspace(&self) -> ColorSpace;
73
74    /// Get the name of the decoder
75    fn name(&self) -> &'static str;
76
77    /// Return true whether or not this codec is fully supported
78    /// and well tested to handle various formats.
79    ///
80    /// Currently set to true but a codec that is experimental should override it
81    /// to be false
82    fn is_experimental(&self) -> bool {
83        false
84    }
85    /// Read image metadata returning the values as
86    /// a struct
87    fn read_headers(&mut self) -> Result<Option<ImageMetadata>, crate::errors::ImageErrors> {
88        Ok(None)
89    }
90}
91
92/// This encapsulates an image operation.
93///
94/// All operations that can be stored in a workflow
95/// need to encapsulate this struct.
96pub trait OperationsTrait {
97    /// Get the name of this operation
98    fn name(&self) -> &'static str;
99
100    /// Execute a simple operation on the image
101    /// manipulating the image struct
102    ///
103    /// An object should implement this function, but
104    /// a caller should call [`execute`], which does some error checking
105    /// before calling this method
106    ///
107    /// [`execute`]: Self::execute
108    fn execute_impl(&self, image: &mut Image) -> Result<(), ImageErrors>;
109
110    /// Return the supported colorspaces this operation supports
111    ///
112    /// Some operations cannot work on all colorspaces, e.g rgb to grayscale will
113    /// only work on RGB colorspace, not YUV or YCbCr colorspace, hence such an operation
114    /// must only declare support for such colorspace
115    ///
116    /// During execution, the image colorspace will be matched to this colorspace and
117    /// if it doesn't support it, an error will be raised during execution
118    fn supported_colorspaces(&self) -> &'static [ColorSpace] {
119        &ALL_COLORSPACES
120    }
121    /// Get supported bit types for this operation
122    ///
123    /// Not all operations are supported for all bit types and
124    /// o each support requires careful analysis to ensure it's doing
125    /// the right things
126    fn supported_types(&self) -> &'static [BitType];
127
128    /// Execute an operation
129    ///
130    /// This does come common error checking operations, e.g
131    /// it checks that image dimensions match array length and that this operation
132    /// supports the image colorspace, before calling [`execute_impl`]
133    ///
134    /// # Arguments
135    /// - image: A mutable reference to an image which
136    /// this operation will manipulate
137    ///
138    ///
139    /// # Errors
140    /// Any operations error will be propagated to the caller
141    ///
142    ///
143    /// [`execute_impl`]: Self::execute_impl
144    fn execute(&self, image: &mut Image) -> Result<(), ImageErrors> {
145        // Confirm colorspace
146        let colorspace = image.colorspace();
147
148        let supported = self
149            .supported_colorspaces()
150            .iter()
151            .any(|x| *x == colorspace);
152
153        if !supported {
154            return Err(ImageErrors::UnsupportedColorspace(
155                colorspace,
156                self.name(),
157                self.supported_colorspaces()
158            ));
159        }
160        // if image.metadata.alpha != self.alpha_state()
161        // {
162        //     PremultiplyAlpha::new(self.alpha_state());
163        // }
164        // check we support the bit depth
165        let bit_type = image.metadata.get_depth().bit_type();
166
167        let supported = self.supported_types().iter().any(|x| *x == bit_type);
168
169        if !supported {
170            return Err(ImageErrors::OperationsError(
171                ImageOperationsErrors::UnsupportedType(self.name(), bit_type)
172            ));
173        }
174
175        confirm_invariants(image)?;
176
177        self.execute_impl(image)
178            .map_err(<ImageErrors as Into<ImageErrors>>::into)?;
179
180        confirm_invariants(image)?;
181
182        Ok(())
183    }
184    /// Alpha state for which the image operation works in
185    ///
186    /// Most image expect a premultiplied alpha state to work correctly
187    /// this allows one to override the alpha state the image will
188    /// be converted into before carrying out an operation
189    fn alpha_state(&self) -> AlphaState {
190        AlphaState::PreMultiplied
191    }
192
193    /// Clone the image and execute the operation on it, returning
194    /// a new image instead of modifying the existing one
195    ///
196    /// This is provided as a convenience function for when one
197    /// doesn't want to modify the existing image
198    fn clone_and_execute(&self, image: &Image) -> Result<Image, ImageErrors> {
199        let mut c_img = image.clone();
200        self.execute(&mut c_img)?;
201        Ok(c_img)
202    }
203}
204
205/// Confirm that image invariants have been respected across image
206/// operations
207fn confirm_invariants(image: &Image) -> Result<(), ImageErrors> {
208    // Ensure dimensions are correct
209
210    for frame in image.frames_ref() {
211        if frame.channels.len() != image.colorspace().num_components() {
212            {
213                return Err(ImageErrors::GenericString(format!(
214                    "Components mismatch, expected {} channels since image format is {:?}, but found {}",
215                    image.colorspace().num_components(),
216                    image.colorspace(),
217                    frame.channels.len()
218                )));
219            }
220        }
221    }
222
223    let (width, height) = image.dimensions();
224    // check the number of channels match the length
225
226    let expected_length = image.depth().size_of() * width * height;
227
228    for channel in image.channels_ref(true) {
229        if channel.len() != expected_length {
230            return Err(ImageErrors::DimensionsMisMatch(
231                expected_length,
232                channel.len()
233            ));
234        }
235    }
236
237    Ok(())
238}
239
240/// The trait dealing with image encoding and saving
241pub trait EncoderTrait {
242    /// Get the name of the encoder
243    fn name(&self) -> &'static str;
244
245    /// Encode and write to a file
246    ///
247    /// The file is stored internally by the decoder, e.g
248    /// by asking for it during initialization
249    ///
250    /// # Arguments
251    /// - image: An image which we are trying to encode.
252    ///
253    /// # Returns
254    /// - `Ok(Vec<u8>)`: The inner `Vec<u8>` contains the encoded data
255    /// in the format [ImageFormat]
256    ///
257    /// - Err : An unrecoverable error occurred
258    ///
259    fn encode_inner(&mut self, image: &Image) -> Result<Vec<u8>, ImageErrors>;
260
261    /// Return all colorspaces supported by this encoder.
262    ///
263    /// An encoder should reject any other colorspace and should not try to write
264    /// an unknown colorspace
265    fn supported_colorspaces(&self) -> &'static [ColorSpace];
266
267    /// Encode the actual image into the specified format
268    ///
269    /// This also covers conversion where possible,
270    /// allowing things like bit-depth conversion where possible
271    ///
272    /// After doing some book keeping, this will eventually call `encode_inner` which
273    /// actually carries out the encoding
274    ///
275    /// # Arguments
276    /// - image: The image to encode
277    ///
278    /// # Returns
279    /// - `Ok(Vec<u8>)`: The inner `Vec<u8>` contains the encoded data
280    /// in the format [ImageFormat]
281    ///
282    /// - Err : An unrecoverable error occurred
283    ///
284    /// # Note
285    /// The library may clone `image` depending on configurations of the encoder
286    /// e.g to do colorspace conversions or bit-depth conversions, hence it
287    /// is recommended to have the image in a format that can be encoded
288    /// directly to prevent such
289    fn encode(&mut self, image: &Image) -> Result<Vec<u8>, ImageErrors> {
290        // confirm things hold themselves
291        confirm_invariants(image)?;
292
293        // check colorspace is correct.
294        let colorspace = image.colorspace();
295        let supported_colorspaces = self.supported_colorspaces();
296
297        // deal convert bit depths
298        let depth = image.depth();
299
300        if image.is_animated() && !self.supports_animated_images() {
301            warn!("The current image is animated but the encoder ({:?}) doesn't support animated images, this will only encode the first frame",self.name());
302        }
303        if !supported_colorspaces.contains(&colorspace)
304            || !self.supported_bit_depth().contains(&depth)
305            || image.metadata.alpha != NonPreMultiplied
306        {
307            let mut image_clone = image.clone();
308
309            if !supported_colorspaces.contains(&colorspace) {
310                // get default colorspace
311                let default_colorspace = self.default_colorspace(colorspace);
312                let image_format = self.format();
313
314                trace!("Image is in {colorspace:?} colorspace,converting it to {default_colorspace:?} which is the default configured colorspace of {image_format:?}");
315                // try converting  it to a supported colorspace
316                let converter = ColorspaceConv::new(default_colorspace);
317
318                converter.execute(&mut image_clone)?
319            }
320            let image_depth = image.depth();
321
322            if !self.supported_bit_depth().contains(&depth) {
323                trace!(
324                    "Image depth is in {:?}, but {} encoder supports {:?}",
325                    image.depth(),
326                    self.name(),
327                    self.supported_bit_depth()
328                );
329                trace!(
330                    "Converting image to a depth of {:?}",
331                    self.default_depth(image_depth)
332                );
333
334                let depth = Depth::new(self.default_depth(image_depth));
335
336                depth.execute(&mut image_clone)?;
337            }
338
339            // confirm again we didn't mess up
340            confirm_invariants(&image_clone)?;
341
342            self.encode_inner(&image_clone)
343        } else {
344            self.encode_inner(image)
345        }
346    }
347    /// Return the image format for which this
348    /// encoder will encode the format in
349    ///
350    /// # Example
351    ///  Get jpeg encoder format
352    ///-  Requires jpeg feature to work
353    /// ```
354    /// use zune_image::codecs::ImageFormat;
355    /// use zune_image::codecs::jpeg::JpegEncoder;
356    /// use zune_image::traits::EncoderTrait;
357    ///
358    /// let encoder = JpegEncoder::new();
359    /// assert_eq!(encoder.format(),ImageFormat::JPEG);
360    /// ```
361    fn format(&self) -> ImageFormat;
362
363    /// Call `encode` and then store the image
364    /// and format in `EncodeResult`
365    fn encode_to_result(&mut self, image: &Image) -> Result<EncodeResult, ImageErrors> {
366        let data = self.encode(image)?;
367
368        Ok(EncodeResult {
369            data,
370            format: self.format()
371        })
372    }
373    /// Get supported bit-depths for this image
374    ///
375    /// This should return all supported bit depth
376    /// for the encoder
377    fn supported_bit_depth(&self) -> &'static [BitDepth];
378
379    /// Returns the common/expected bit depth for this image
380    ///
381    /// This is used in conjunction with [`supported_bit_depth`]
382    /// for cases where we want to convert the image to a bit depth
383    /// since the image is not in one of the supported image formats
384    ///
385    /// [`supported_bit_depth`]:EncoderTrait::supported_bit_depth
386    fn default_depth(&self, depth: BitDepth) -> BitDepth;
387
388    /// Returns the default colorspace to use when the image
389    /// contains a different colorspace
390    ///
391    /// Default is RGB
392    ///
393    /// # Arguments
394    /// - colorspace: The colorspace the image is currently in
395    fn default_colorspace(&self, _: ColorSpace) -> ColorSpace {
396        ColorSpace::RGB
397    }
398
399    /// Set encoder options for this encoder
400    ///
401    /// This allows one to configure specific settings for an encoder where supported
402    fn set_options(&mut self, _: EncoderOptions) {}
403
404    /// Return true if the encoder can encode multiple image frames as one animated Image.
405    ///
406    /// This returns true if the format and encoder can encode animated images, false otherwise
407    ///
408    /// If false, the encoder will only encode one frame from the image otherwise it will
409    /// encode all frames as a single animated image
410    fn supports_animated_images(&self) -> bool {
411        false
412    }
413}
414
415/// Trait that encapsulates supported
416/// integers which work with the image crates
417pub trait ZuneInts<T> {
418    fn depth() -> BitDepth;
419
420    ///Maximum value for this type
421    ///
422    /// For integers its the maximum value they can hold
423    /// For float values it's 1.0
424    fn max_value() -> T;
425}
426
427impl ZuneInts<u8> for u8 {
428    #[inline(always)]
429    fn depth() -> BitDepth {
430        BitDepth::Eight
431    }
432    #[inline(always)]
433    fn max_value() -> u8 {
434        255
435    }
436}
437
438impl ZuneInts<u16> for u16 {
439    #[inline(always)]
440    fn depth() -> BitDepth {
441        BitDepth::Sixteen
442    }
443    #[inline(always)]
444    fn max_value() -> u16 {
445        u16::MAX
446    }
447}
448
449impl ZuneInts<f32> for f32 {
450    #[inline(always)]
451    fn depth() -> BitDepth {
452        BitDepth::Float32
453    }
454    #[inline(always)]
455    fn max_value() -> f32 {
456        1.0
457    }
458}
459
460/// Trait that encapsulates image decoders that
461/// can write data as raw native endian into
462/// a buffer of u8
463pub trait DecodeInto {
464    /// Decode raw image bytes into a buffer that can
465    /// hold u8 bytes
466    ///
467    /// The rationale is that u8 bytes can alias any type
468    /// and higher bytes offer ways to construct types from
469    /// u8's hence they can be used as a base type
470    fn decode_into(&mut self, buffer: &mut [u8]) -> Result<(), ImageErrors>;
471
472    /// Minimum buffer length which is needed to decode this image
473    ///
474    /// This may call `decode_headers` for the image routine to fetch the
475    /// expected output size.
476    fn output_buffer_size(&mut self) -> Result<usize, ImageErrors>;
477}
478/// Convert something into an image by consuming it
479pub trait IntoImage {
480    /// Consumes this and returns an image
481    fn into_image(self) -> Result<Image, ImageErrors>;
482}
483
484impl IntoImage for Image {
485    fn into_image(self) -> Result<Image, ImageErrors> {
486        Ok(self)
487    }
488}