makepad_zune_core/options/
encoder.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
9use bitflags::bitflags;
10
11use crate::bit_depth::BitDepth;
12use crate::colorspace::ColorSpace;
13
14bitflags! {
15    /// Encoder options that are flags
16    #[derive(Copy,Debug,Clone)]
17    struct EncoderFlags:u64{
18        /// Whether JPEG images should be encoded as progressive images
19        const JPEG_ENCODE_PROGRESSIVE = 1<<1;
20        /// Whether JPEG images should use optimized huffman tables
21        const JPEG_OPTIMIZED_HUFFMAN  = 1<<2;
22        /// Whether to not preserve metadata across image transformations
23        const IMAGE_STRIP_METADATA    = 1<<3;
24
25    }
26}
27impl Default for EncoderFlags {
28    fn default() -> Self {
29        let mut options = EncoderFlags::empty();
30        options.set(EncoderFlags::JPEG_ENCODE_PROGRESSIVE, false);
31        options.set(EncoderFlags::JPEG_OPTIMIZED_HUFFMAN, false);
32        options.set(EncoderFlags::IMAGE_STRIP_METADATA, false);
33
34        options
35    }
36}
37
38/// Options shared by some of the encoders in
39/// the `zune-` family of image crates
40#[derive(Debug, Copy, Clone)]
41pub struct EncoderOptions {
42    width:       usize,
43    height:      usize,
44    colorspace:  ColorSpace,
45    quality:     u8,
46    depth:       BitDepth,
47    num_threads: u8,
48    effort:      u8,
49    flags:       EncoderFlags
50}
51
52impl Default for EncoderOptions {
53    fn default() -> Self {
54        Self {
55            width:       0,
56            height:      0,
57            colorspace:  ColorSpace::RGB,
58            quality:     80,
59            depth:       BitDepth::Eight,
60            num_threads: 4,
61            effort:      4,
62            flags:       EncoderFlags::default()
63        }
64    }
65}
66
67impl EncoderOptions {
68    ///  Create  new encode options
69    ///
70    /// # Arguments
71    ///  
72    /// * `width`: Image width
73    /// * `height`: Image height
74    /// * `colorspace`:  Image colorspaces
75    /// * `depth`: Image depth
76    ///
77    /// returns: EncoderOptions
78    ///
79    pub fn new(
80        width: usize, height: usize, colorspace: ColorSpace, depth: BitDepth
81    ) -> EncoderOptions {
82        EncoderOptions {
83            width,
84            height,
85            colorspace,
86            depth,
87            ..Default::default()
88        }
89    }
90    /// Get the width for which the image will be encoded in
91    pub const fn get_width(&self) -> usize {
92        self.width
93    }
94
95    /// Get height for which the image will be encoded in
96    ///
97    /// returns: usize
98    ///
99    /// # Panics
100    /// If height is zero
101    pub fn get_height(&self) -> usize {
102        assert_ne!(self.height, 0);
103        self.height
104    }
105    /// Get the depth for which the image will be encoded in
106    pub const fn get_depth(&self) -> BitDepth {
107        self.depth
108    }
109    /// Get the quality for which the image will be encoded with
110    ///
111    ///  # Lossy
112    /// - Higher quality means some images take longer to write and
113    /// are big but they look good
114    ///
115    /// - Lower quality means small images and low quality.
116    ///
117    /// # Lossless
118    /// - High quality indicates more time is spent in making the file
119    /// smaller
120    ///
121    /// - Low quality indicates less time is spent in making the file bigger
122    pub const fn get_quality(&self) -> u8 {
123        self.quality
124    }
125    /// Get the colorspace for which the image will be encoded in
126    pub const fn get_colorspace(&self) -> ColorSpace {
127        self.colorspace
128    }
129    pub const fn get_effort(&self) -> u8 {
130        self.effort
131    }
132
133    /// Set width for the image to be encoded
134    pub fn set_width(mut self, width: usize) -> Self {
135        self.width = width;
136        self
137    }
138
139    /// Set height for the image to be encoded
140    pub fn set_height(mut self, height: usize) -> Self {
141        self.height = height;
142        self
143    }
144    /// Set depth for the image to be encoded
145    pub fn set_depth(mut self, depth: BitDepth) -> Self {
146        self.depth = depth;
147        self
148    }
149    /// Set quality of the image to be encoded
150    ///
151    /// Quality is clamped from 0..100
152    ///
153    /// Quality means different options depending on the encoder, see
154    /// [get_quality](Self::get_quality)
155    pub fn set_quality(mut self, quality: u8) -> Self {
156        self.quality = quality.clamp(0, 100);
157        self
158    }
159    /// Set colorspace for the image to be encoded
160    pub fn set_colorspace(mut self, colorspace: ColorSpace) -> Self {
161        self.colorspace = colorspace;
162        self
163    }
164    /// Set the number of threads allowed for multithreaded encoding
165    /// where supported
166    ///
167    /// Zero means use a single thread
168    pub fn set_num_threads(mut self, threads: u8) -> Self {
169        self.num_threads = threads;
170
171        self
172    }
173    pub fn set_effort(mut self, effort: u8) -> Self {
174        self.effort = effort;
175        self
176    }
177
178    /// Return number of threads configured for multithreading
179    /// where possible
180    ///
181    /// This is used for multi-threaded encoders,
182    /// currently only jpeg-xl
183    pub const fn get_num_threads(&self) -> u8 {
184        self.num_threads
185    }
186
187    /// Set whether the encoder should remove metadata from the image
188    ///
189    /// When set to `true`, supported encoders will strip away metadata
190    /// from the resulting image. If set to false, where supported, encoders
191    /// will not remove metadata from images
192    pub fn set_strip_metadata(mut self, yes: bool) -> Self {
193        self.flags.set(EncoderFlags::IMAGE_STRIP_METADATA, yes);
194        self
195    }
196    /// Whether or not the encoder should remove metadata from the image
197    ///
198    /// The default value is false, and encoders that respect this try to preserve as much
199    /// data as possible from one image to another
200    pub const fn strip_metadata(&self) -> bool {
201        !self.flags.contains(EncoderFlags::IMAGE_STRIP_METADATA)
202    }
203}
204
205/// JPEG options
206impl EncoderOptions {
207    /// Whether the jpeg encoder should encode the image in progressive mode
208    ///
209    /// Default is `false`.
210    ///
211    /// This may be used to create slightly smaller images at the cost of more processing
212    /// time
213    pub const fn jpeg_encode_progressive(&self) -> bool {
214        self.flags.contains(EncoderFlags::JPEG_ENCODE_PROGRESSIVE)
215    }
216
217    /// Whether the jpeg encoder should optimize huffman tables to create smaller files
218    /// at the cost of processing time
219    ///
220    /// Default is `false`.
221    pub const fn jpeg_optimized_huffman_tables(&self) -> bool {
222        self.flags.contains(EncoderFlags::JPEG_OPTIMIZED_HUFFMAN)
223    }
224
225    /// Set whether the jpeg encoder should encode the imagei in progressive mode
226    ///
227    /// Default is `false`
228    pub fn set_jpeg_encode_progressive(mut self, yes: bool) -> Self {
229        self.flags.set(EncoderFlags::JPEG_OPTIMIZED_HUFFMAN, yes);
230        self
231    }
232}